初始化提交

This commit is contained in:
王立帮
2024-07-20 22:09:06 +08:00
commit c247dd07a6
6876 changed files with 2743096 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1,9 @@
.PHONY: travis-build
travis-build:
ifdef PLATFORMIO_CI_ARGS
platformio ci --lib="." $(PLATFORMIO_CI_ARGS)
else
platformio ci --lib="." --board=leonardo
endif

View File

@@ -0,0 +1,193 @@
![TinyGSM logo](https://cdn.rawgit.com/vshymanskyy/TinyGSM/d18e93dc51fe988a0b175aac647185457ef640b5/extras/logo.svg)
A small Arduino library for GSM modules, that just works.
<!---
[![GitHub download](https://img.shields.io/github/downloads/vshymanskyy/TinyGSM/total.svg)](https://github.com/vshymanskyy/TinyGSM/releases/latest)--->
[![GitHub version](https://img.shields.io/github/release/vshymanskyy/TinyGSM.svg)](https://github.com/vshymanskyy/TinyGSM/releases/latest)
[![Build status](https://img.shields.io/travis/vshymanskyy/TinyGSM.svg)](https://travis-ci.org/vshymanskyy/TinyGSM)
[![GitHub issues](https://img.shields.io/github/issues/vshymanskyy/TinyGSM.svg)](https://github.com/vshymanskyy/TinyGSM/issues)
[![GitHub wiki](https://img.shields.io/badge/Wiki-available-brightgreen.svg)](https://github.com/vshymanskyy/TinyGSM/wiki)
[![GitHub stars](https://img.shields.io/github/stars/vshymanskyy/TinyGSM.svg)](https://github.com/vshymanskyy/TinyGSM/stargazers)
[![License](https://img.shields.io/badge/license-LGPL3-blue.svg)](https://github.com/vshymanskyy/TinyGSM/blob/master/LICENSE)
If you like **TinyGSM** - give it a star, or fork it and contribute!
[![GitHub stars](https://img.shields.io/github/stars/vshymanskyy/TinyGSM.svg?style=social&label=Star)](https://github.com/vshymanskyy/TinyGSM/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/vshymanskyy/TinyGSM.svg?style=social&label=Fork)](https://github.com/vshymanskyy/TinyGSM/network)
You can also join our chat:
[![Gitter](https://img.shields.io/gitter/room/vshymanskyy/TinyGSM.svg)](https://gitter.im/tinygsm)
### 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.
![examples](/extras/examples.png)
### TinyGSM is tiny
The complete WebClient example for Arduino Uno (via Software Serial) takes little resources:
```
Sketch uses 15022 bytes (46%) of program storage space. Maximum is 32256 bytes.
Global variables use 574 bytes (28%) of dynamic memory, leaving 1474 bytes for local variables. Maximum is 2048 bytes.
```
Arduino GSM library uses 15868 bytes (49%) of Flash and 1113 bytes (54%) of RAM in a similar scenario.
TinyGSM also pulls data gently from the modem (whenever possible), so it can operate on very little RAM.
**Now, you have more space for your experiments.**
## Features
Feature \ Modem | SIM8xx | u-Blox | A6/A7/A20 | M590 | ESP8266 | XBee
--- | --- | --- | --- | --- | --- | ---
**Data connections**
TCP (HTTP, MQTT, Blynk, ...) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔
UDP | ◌ | ◌ | | | | ◌
SSL/TLS (HTTPS) | ✔¹ | ✔ | 🅧 | 🅧 | ✔¹ | ✔¹
**USSD**
Sending USSD requests | ✔ | | ✔ | ✔ | 🅧 |
Decoding 7,8,16-bit response | ✔ | | ✔ | ✔ | 🅧 |
**SMS**
Sending | ✔ | ✔ | ✔ | ✔ | 🅧 | ✔
Sending Unicode | ✔ | | ◌ | 🅧 | 🅧 |
Reading | | | | | 🅧 |
Incoming message event | | | | ? | 🅧 |
**Calls**
Dial, hangup | ✔ | | ✔ | 🅧 | 🅧 | 🅧
Receiving calls | ✔ | | ✔ | 🅧 | 🅧 | 🅧
Incoming event (RING) | ◌ | | ◌ | 🅧 | 🅧 | 🅧
DTMF sending | ✔ | | ✔ | 🅧 | 🅧 | 🅧
DTMF decoding | ◌ | | 🅧 | 🅧 | 🅧 | 🅧
**Location**
GSM location service | ✔ | ✔ | 🅧 | 🅧 | 🅧 | ✔
GPS/GNSS | ✔¹ | 🅧 | ◌¹ | 🅧 | 🅧 | 🅧
✔ - implemented◌ - planned🅧 - not available on this modem
¹ - only some device models or firmware revisions have this feature (SIM8xx R14.18, A7, etc.)
## Supported modems
- SIMCom SIM800 series (SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868)
- SIMCom SIM900 series (SIM900A, SIM900D, SIM908, SIM968)
- AI-Thinker A6, A6C, A7, A20
- ESP8266 (AT commands interface, similar to GSM modems)
- Digi XBee WiFi and Cellular (using XBee command mode)
- Neoway M590
- u-blox Cellular Modems (LEON-G100, LISA-U2xx, SARA-G3xx, SARA-U2xx, TOBY-L2xx, LARA-R2xx, MPCI-L2xx)
- Quectel BG96 ***(alpha)***
### Supported boards/modules
- Arduino MKR GSM 1400
- GPRSbee
- Microduino GSM
- Adafruit FONA (Mini Cellular GSM Breakout)
- Adafruit FONA 800/808 Shield
- Industruino GSM
- RAK WisLTE ***(alpha)***
- ... other modules, based on supported modems. Some boards require [**special configuration**](https://github.com/vshymanskyy/TinyGSM/wiki/Board-configuration).
More modems may be supported later:
- [ ] Quectel M10, M35, M95, UG95, EC21
- [ ] Sequans Monarch LTE Cat M1/NB1
- [ ] SIMCom SIM5320, SIM5360, SIM5216, SIM7xxx
- [ ] Telit GL865
- [ ] ZTE MG2639
- [ ] Hi-Link HLK-RM04
Watch this repo for new updates! And of course, contributions are welcome ;)
## Donation
[![Donate BountySource](https://img.shields.io/badge/Donate-BountySource-149E5E.svg)](https://salt.bountysource.com/checkout/amount?team=tinygsm-dev)
[![Donate Bitcoin](https://img.shields.io/badge/Donate-Bitcoin-orange.svg)](http://tny.im/aen)
If you have found TinyGSM to be useful in your work, research or company, please consider making a donation to the project commensurate with your resources. Any amount helps!
**All donations will be used strictly to fund the development of TinyGSM:**
- Covering cellular network expences
- Buying new hardware and modems for integration
- Bounty Budget (to reward other developers for their contributions)
- Implementing new features
- Quality Assurance
## Getting Started
1. Using your phone:
- Disable PIN code on the SIM card
- Check your balance
- Check that APN,User,Pass are correct and you have internet
2. Ensure the SIM card is correctly inserted into the module
3. Ensure that GSM antenna is firmly attached
4. Check if serial connection is working (Hardware Serial is recommended)
Send an ```AT``` command using [this sketch](tools/AT_Debug/AT_Debug.ino)
If you have any issues:
1. Read the whole README (you're looking at it!)
2. Some boards require [**special configuration**](https://github.com/vshymanskyy/TinyGSM/wiki/Board-configuration).
3. Try running the Diagnostics sketch
4. Check for [**highlighted topics here**](https://github.com/vshymanskyy/TinyGSM/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22for+reference%22+)
5. If you have a question, please post it in our [Gitter chat](https://gitter.im/tinygsm)
## How does it work?
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.
## API Reference
For GPRS data streams, this library provides the standard [Arduino Client](https://www.arduino.cc/en/Reference/ClientConstructor) interface.
For additional functions, please refer to [this example sketch](examples/AllFunctions/AllFunctions.ino)
## Troubleshooting
### Diagnostics sketch
Use this sketch to diagnose your SIM card and GPRS connection:
File -> Examples -> TynyGSM -> tools -> [Diagnostics](https://github.com/vshymanskyy/TinyGSM/blob/master/tools/Diagnostics/Diagnostics.ino)
### Ensure stable data & power connection
Most modules require up to 2A and specific voltage - according to the module documentation.
So this actually solves stability problems in **many** cases:
- Provide a good stable power supply. Read about [**powering your module**](https://github.com/vshymanskyy/TinyGSM/wiki/Powering-GSM-module).
- Keep your wires as short as possible
- Consider soldering them for a stable connection
- Do not put your wires next to noisy signal sources (buck converters, antennas, oscillators etc.)
### SoftwareSerial problems
When using ```SoftwareSerial``` (on Uno, Nano, etc), the speed **115200** may not work.
Try selecting **57600**, **38400**, or even lower - the one that works best for you.
In some cases **9600** is unstable, but using **38400** helps, etc.
Be sure to set correct TX/RX pins in the sketch. Please note that not every Arduino pin can serve as TX or RX pin.
**Read more about SoftSerial options and configuration [here](https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html) and [here](https://www.arduino.cc/en/Reference/SoftwareSerial).**
### ESP32 HardwareSerial
When using ESP32 `HardwareSerial`, you may need to specify additional parameters to the `.begin()` call.
Please [refer to this comment](https://github.com/vshymanskyy/TinyGSM/issues/91#issuecomment-356024747).
### SAMD21
When using SAMD21-based boards, you may need to use a sercom uart port instead of `Serial1`.
Please [refer to this comment](https://github.com/vshymanskyy/TinyGSM/issues/102#issuecomment-345548941).
### Broken initial configuration
Sometimes (especially if you played with AT comands), your module configuration may become invalid.
This may result in problems such as:
* Can't connect to the GPRS network
* Can't connect to the server
* Sent/recieved data contains invalid bytes
* etc.
To return module to **Factory Defaults**, use this sketch:
File -> Examples -> TinyGSM -> tools -> [FactoryReset](https://github.com/vshymanskyy/TinyGSM/blob/master/tools/FactoryReset/FactoryReset.ino)
### Goouuu Tech IOT-GA6 vs AI-Thinker A6 confusion
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).
__________
### License
This project is released under
The GNU Lesser General Public License (LGPL-3.0)

View File

@@ -0,0 +1,202 @@
/**************************************************************
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
* NOTE:
* Some of the functions may be unavailable for your modem.
* Just comment them out.
*
**************************************************************/
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
// Set serial for AT commands (to the module)
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
//#define DUMP_AT_COMMANDS
#define TINY_GSM_DEBUG SerialMon
// Set phone numbers, if you want to test SMS and Calls
//#define SMS_TARGET "+380xxxxxxxxx"
//#define CALL_TARGET "+380xxxxxxxxx"
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
#include <TinyGsmClient.h>
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set your reset, enable, power pins here
delay(3000);
// Set GSM module baud rate
TinyGsmAutoBaud(SerialAT);
}
void loop() {
// Restart takes quite some time
// To skip it, call init() instead of restart()
DBG("Initializing modem...");
if (!modem.restart()) {
delay(10000);
return;
}
String modemInfo = modem.getModemInfo();
DBG("Modem:", modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
DBG("Waiting for network...");
if (!modem.waitForNetwork()) {
delay(10000);
return;
}
if (modem.isNetworkConnected()) {
DBG("Network connected");
}
DBG("Connecting to", apn);
if (!modem.gprsConnect(apn, user, pass)) {
delay(10000);
return;
}
bool res = modem.isGprsConnected();
DBG("GPRS status:", res ? "connected" : "not connected");
String ccid = modem.getSimCCID();
DBG("CCID:", ccid);
String imei = modem.getIMEI();
DBG("IMEI:", imei);
String cop = modem.getOperator();
DBG("Operator:", cop);
IPAddress local = modem.localIP();
DBG("Local IP:", local);
int csq = modem.getSignalQuality();
DBG("Signal quality:", csq);
// This is NOT supported on M590
int battLevel = modem.getBattPercent();
DBG("Battery lavel:", battLevel);
// This is only supported on SIMxxx series
float battVoltage = modem.getBattVoltage() / 1000.0F;
DBG("Battery voltage:", battVoltage);
// This is only supported on SIMxxx series
String gsmLoc = modem.getGsmLocation();
DBG("GSM location:", gsmLoc);
// This is only supported on SIMxxx series
String gsmTime = modem.getGSMDateTime(DATE_TIME);
DBG("GSM Time:", gsmTime);
String gsmDate = modem.getGSMDateTime(DATE_DATE);
DBG("GSM Date:", gsmDate);
String ussd_balance = modem.sendUSSD("*111#");
DBG("Balance (USSD):", ussd_balance);
String ussd_phone_num = modem.sendUSSD("*161#");
DBG("Phone number (USSD):", ussd_phone_num);
#if defined(TINY_GSM_MODEM_SIM808)
modem.enableGPS();
String gps_raw = modem.getGPSraw();
modem.disableGPS();
DBG("GPS raw data:", gps_raw);
#endif
#if defined(SMS_TARGET)
res = modem.sendSMS(SMS_TARGET, String("Hello from ") + imei);
DBG("SMS:", res ? "OK" : "fail");
// This is only supported on SIMxxx series
res = modem.sendSMS_UTF16(SMS_TARGET, u"Привіііт!", 9);
DBG("UTF16 SMS:", res ? "OK" : "fail");
#endif
#if defined(CALL_TARGET)
DBG("Calling:", CALL_TARGET);
// This is NOT supported on M590
res = modem.callNumber(CALL_TARGET);
DBG("Call:", res ? "OK" : "fail");
if (res) {
delay(1000L);
// Play DTMF A, duration 1000ms
modem.dtmfSend('A', 1000);
// Play DTMF 0..4, default duration (100ms)
for (char tone='0'; tone<='4'; tone++) {
modem.dtmfSend(tone);
}
delay(5000);
res = modem.callHangup();
DBG("Hang up:", res ? "OK" : "fail");
}
#endif
modem.gprsDisconnect();
if (!modem.isGprsConnected()) {
DBG("GPRS disconnected");
} else {
DBG("GPRS disconnect: Failed.");
}
// Try to power-off (modem may decide to restart automatically)
// To turn off modem completely, please use Reset/Enable pins
modem.poweroff();
DBG("Poweroff.");
// Do nothing forevermore
while (true) {
modem.maintain();
}
}

View File

@@ -0,0 +1,98 @@
/**************************************************************
*
* For this example, you need to install Blynk library:
* https://github.com/blynkkk/blynk-library/releases/latest
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
**************************************************************
*
* Blynk is a platform with iOS and Android apps to control
* Arduino, Raspberry Pi and the likes over the Internet.
* You can easily build graphic interfaces for all your
* projects by simply dragging and dropping widgets.
*
* Blynk supports many development boards with WiFi, Ethernet,
* GSM, Bluetooth, BLE, USB/Serial connection methods.
* See more in Blynk library examples and community forum.
*
* http://www.blynk.io/
*
* Change GPRS apm, user, pass, and Blynk auth token to run :)
**************************************************************/
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
// Default heartbeat interval for GSM is 60
// If you want override this value, uncomment and set this option:
//#define BLYNK_HEARTBEAT 30
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_XBEE
#include <TinyGsmClient.h>
#include <BlynkSimpleSIM800.h>
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
const char auth[] = "YourAuthToken";
TinyGsm modem(SerialAT);
void setup()
{
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print("Modem: ");
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
Blynk.begin(auth, modem, apn, user, pass);
}
void loop()
{
Blynk.run();
}

View File

@@ -0,0 +1,207 @@
/**************************************************************
*
* For this example, you need to install CRC32 library:
* https://github.com/bakercp/CRC32
* or from http://librarymanager/all#CRC32+checksum
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
* ATTENTION! Downloading big files requires of knowledge of
* the TinyGSM internals and some modem specifics,
* so this is for more experienced developers.
*
**************************************************************/
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_XBEE
// Increase RX buffer if needed
#define TINY_GSM_RX_BUFFER 1024
#include <TinyGsmClient.h>
#include <CRC32.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// Server details
const char server[] = "vsh.pp.ua";
const int port = 80;
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);
#else
TinyGsm modem(SerialAT);
#endif
TinyGsmClient client(modem);
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println(F("Initializing modem..."));
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print(F("Modem: "));
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
}
void printPercent(uint32_t readLength, uint32_t contentLength) {
// If we know the total length
if (contentLength != -1) {
SerialMon.print("\r ");
SerialMon.print((100.0 * readLength) / contentLength);
SerialMon.print('%');
} else {
SerialMon.println(readLength);
}
}
void loop() {
SerialMon.print(F("Waiting for network..."));
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(server);
if (!client.connect(server, port)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
// Make a HTTP GET request:
client.print(String("GET ") + resource + " HTTP/1.0\r\n");
client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n");
long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000L) {
SerialMon.println(F(">>> Client Timeout !"));
client.stop();
delay(10000L);
return;
}
}
SerialMon.println(F("Reading response header"));
uint32_t contentLength = knownFileSize;
while (client.available()) {
String line = client.readStringUntil('\n');
line.trim();
//SerialMon.println(line); // Uncomment this to show response header
line.toLowerCase();
if (line.startsWith("content-length:")) {
contentLength = line.substring(line.lastIndexOf(':') + 1).toInt();
} else if (line.length() == 0) {
break;
}
}
SerialMon.println(F("Reading response data"));
timeout = millis();
uint32_t readLength = 0;
CRC32 crc;
unsigned long timeElapsed = millis();
printPercent(readLength, contentLength);
while (readLength < contentLength && client.connected() && millis() - timeout < 10000L) {
while (client.available()) {
uint8_t c = client.read();
//SerialMon.print((char)c); // Uncomment this to show data
crc.update(c);
readLength++;
if (readLength % (contentLength / 13) == 0) {
printPercent(readLength, contentLength);
}
timeout = millis();
}
}
printPercent(readLength, contentLength);
timeElapsed = millis() - timeElapsed;
SerialMon.println();
// Shutdown
client.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
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");
// Do nothing forevermore
while (true) {
delay(1000);
}
}

View File

@@ -0,0 +1,160 @@
/**************************************************************
*
* This sketch connects to a website and downloads a page.
* It can be used to perform HTTP/RESTful API calls.
*
* For this example, you need to install ArduinoHttpClient library:
* https://github.com/arduino-libraries/ArduinoHttpClient
* or from http://librarymanager/all#ArduinoHttpClient
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
* For more HTTP API examples, see ArduinoHttpClient library
*
**************************************************************/
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_ESP8266
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// Server details
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";
const int port = 80;
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
TinyGsmClient client(modem);
HttpClient http(client, server, port);
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println(F("Initializing modem..."));
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print(F("Modem: "));
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
}
void loop() {
SerialMon.print(F("Waiting for network..."));
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Performing HTTP GET request... "));
int err = http.get(resource);
if (err != 0) {
SerialMon.println(F("failed to connect"));
delay(10000);
return;
}
int status = http.responseStatusCode();
SerialMon.println(status);
if (!status) {
delay(10000);
return;
}
while (http.headerAvailable()) {
String headerName = http.readHeaderName();
String headerValue = http.readHeaderValue();
//SerialMon.println(headerName + " : " + headerValue);
}
int length = http.contentLength();
if (length >= 0) {
SerialMon.print(F("Content length is: "));
SerialMon.println(length);
}
if (http.isResponseChunked()) {
SerialMon.println(F("The response is chunked"));
}
String body = http.responseBody();
SerialMon.println(F("Response:"));
SerialMon.println(body);
SerialMon.print(F("Body length is: "));
SerialMon.println(body.length());
// Shutdown
http.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
// Do nothing forevermore
while (true) {
delay(1000);
}
}

View File

@@ -0,0 +1,162 @@
/**************************************************************
*
* This sketch connects to a website and downloads a page.
* It can be used to perform HTTP/RESTful API calls.
*
* For this example, you need to install ArduinoHttpClient library:
* https://github.com/arduino-libraries/ArduinoHttpClient
* or from http://librarymanager/all#ArduinoHttpClient
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
* SSL/TLS is currently supported only with: SIM8xx, uBlox
*
* For more HTTP API examples, see ArduinoHttpClient library
*
**************************************************************/
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_UBLOX
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// Server details
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";
const int port = 443;
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
TinyGsmClientSecure client(modem);
HttpClient http(client, server, port);
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println(F("Initializing modem..."));
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print(F("Modem: "));
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
if (!modem.hasSSL()) {
SerialMon.println(F("SSL is not supported by this modem"));
while(true) { delay(1000); }
}
}
void loop() {
SerialMon.print(F("Waiting for network..."));
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Performing HTTPS GET request... "));
http.connectionKeepAlive(); // Currently, this is needed for HTTPS
int err = http.get(resource);
if (err != 0) {
SerialMon.println(F("failed to connect"));
delay(10000);
return;
}
int status = http.responseStatusCode();
SerialMon.println(status);
if (!status) {
delay(10000);
return;
}
while (http.headerAvailable()) {
String headerName = http.readHeaderName();
String headerValue = http.readHeaderValue();
//SerialMon.println(headerName + " : " + headerValue);
}
int length = http.contentLength();
if (length >= 0) {
SerialMon.print(F("Content length is: "));
SerialMon.println(length);
}
if (http.isResponseChunked()) {
SerialMon.println(F("The response is chunked"));
}
String body = http.responseBody();
SerialMon.println(F("Response:"));
SerialMon.println(body);
SerialMon.print(F("Body length is: "));
SerialMon.println(body.length());
// Shutdown
http.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
// Do nothing forevermore
while (true) {
delay(1000);
}
}

View File

@@ -0,0 +1,174 @@
/**************************************************************
*
* For this example, you need to install PubSubClient library:
* https://github.com/knolleary/pubsubclient
* or from http://librarymanager/all#PubSubClient
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
* 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/
*
* 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 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
*
**************************************************************/
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_ESP8266
// #define TINY_GSM_MODEM_XBEE
#include <TinyGsmClient.h>
#include <PubSubClient.h>
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// MQTT details
const char* broker = "test.mosquitto.org";
const char* topicLed = "GsmClientTest/led";
const char* topicInit = "GsmClientTest/init";
const char* topicLedStatus = "GsmClientTest/ledStatus";
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqtt(client);
#define LED_PIN 13
int ledStatus = LOW;
long lastReconnectAttempt = 0;
void setup() {
pinMode(LED_PIN, OUTPUT);
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print("Modem: ");
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
SerialMon.print("Waiting for network...");
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
while (true);
}
SerialMon.println(" OK");
SerialMon.print("Connecting to ");
SerialMon.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
while (true);
}
SerialMon.println(" OK");
// MQTT Broker setup
mqtt.setServer(broker, 1883);
mqtt.setCallback(mqttCallback);
}
boolean mqttConnect() {
SerialMon.print("Connecting to ");
SerialMon.print(broker);
// Connect to MQTT Broker
boolean status = mqtt.connect("GsmClientTest");
// Or, if you want to authenticate MQTT:
//boolean status = mqtt.connect("GsmClientName", "mqtt_user", "mqtt_pass");
if (status == false) {
SerialMon.println(" fail");
return false;
}
SerialMon.println(" OK");
mqtt.publish(topicInit, "GsmClientTest started");
mqtt.subscribe(topicLed);
return mqtt.connected();
}
void loop() {
if (!mqtt.connected()) {
SerialMon.println("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds
unsigned long t = millis();
if (t - lastReconnectAttempt > 10000L) {
lastReconnectAttempt = t;
if (mqttConnect()) {
lastReconnectAttempt = 0;
}
}
delay(100);
return;
}
mqtt.loop();
}
void mqttCallback(char* topic, byte* payload, unsigned int len) {
SerialMon.print("Message arrived [");
SerialMon.print(topic);
SerialMon.print("]: ");
SerialMon.write(payload, len);
SerialMon.println();
// Only proceed if incoming message's topic matches
if (String(topic) == topicLed) {
ledStatus = !ledStatus;
digitalWrite(LED_PIN, ledStatus);
mqtt.publish(topicLedStatus, ledStatus ? "1" : "0");
}
}

View File

@@ -0,0 +1,148 @@
/**************************************************************
*
* This sketch connects to a website and downloads a page.
* It can be used to perform HTTP/RESTful API calls.
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
**************************************************************/
// Select your modem:
#define TINY_GSM_MODEM_SIM800
// #define TINY_GSM_MODEM_SIM808
// #define TINY_GSM_MODEM_SIM900
// #define TINY_GSM_MODEM_UBLOX
// #define TINY_GSM_MODEM_BG96
// #define TINY_GSM_MODEM_A6
// #define TINY_GSM_MODEM_A7
// #define TINY_GSM_MODEM_M590
// #define TINY_GSM_MODEM_ESP8266
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// Uncomment this if you want to use SSL
//#define USE_SSL
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// or Software Serial on Uno, Nano
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// Server details
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
#ifdef USE_SSL
TinyGsmClientSecure client(modem);
const int port = 443;
#else
TinyGsmClient client(modem);
const int port = 80;
#endif
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println(F("Initializing modem..."));
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print(F("Modem: "));
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
}
void loop() {
SerialMon.print(F("Waiting for network..."));
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(server);
if (!client.connect(server, port)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
// Make a HTTP GET request:
client.print(String("GET ") + resource + " HTTP/1.0\r\n");
client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
// Print available data
while (client.available()) {
char c = client.read();
SerialMon.print(c);
timeout = millis();
}
}
SerialMon.println();
// Shutdown
client.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
// Do nothing forevermore
while (true) {
delay(1000);
}
}

View File

@@ -0,0 +1,135 @@
/**************************************************************
*
* This sketch connects to a website and downloads a page.
* It can be used to perform HTTP/RESTful API calls.
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
**************************************************************/
// Hologram Dash uses UBLOX U2 modems
#define TINY_GSM_MODEM_UBLOX
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// Uncomment this if you want to use SSL
//#define USE_SSL
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
// We'll be using SerialSystem in Passthrough mode
#define SerialAT SerialSystem
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// Server details
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm mdm(debugger);
#else
TinyGsm mdm(SerialAT);
#endif
#ifdef USE_SSL
TinyGsmClientSecure client(mdm);
const int port = 443;
#else
TinyGsmClient client(mdm);
const int port = 80;
#endif
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set up Passthrough
HologramCloud.enterPassthrough();
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println(F("Initializing modem..."));
mdm.restart();
String modemInfo = mdm.getModemInfo();
SerialMon.print(F("Modem: "));
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//mdm.simUnlock("1234");
}
void loop() {
SerialMon.print(F("Waiting for network..."));
if (!mdm.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!mdm.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(server);
if (!client.connect(server, port)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
// Make a HTTP GET request:
client.print(String("GET ") + resource + " HTTP/1.0\r\n");
client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
// Print available data
while (client.available()) {
char c = client.read();
SerialMon.print(c);
timeout = millis();
}
}
SerialMon.println();
// Shutdown
client.stop();
SerialMon.println(F("Server disconnected"));
mdm.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
// Do nothing forevermore
while (true) {
delay(1000);
}
}

View File

@@ -0,0 +1,160 @@
/**************************************************************
*
* This sketch connects to a website and downloads a page.
* It can be used to perform HTTP/RESTful API calls.
*
* For this example, you need to install ArduinoHttpClient library:
* https://github.com/arduino-libraries/ArduinoHttpClient
* or from http://librarymanager/all#ArduinoHttpClient
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
* For more HTTP API examples, see ArduinoHttpClient library
*
**************************************************************/
// Industruino uses SIM800H
#define TINY_GSM_MODEM_SIM800
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// Uncomment this if you want to use SSL
//#define USE_SSL
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon SerialUSB
// Select Serial1 or Serial depending on your module configuration
#define SerialAT Serial1
// Your GPRS credentials
// Leave empty, if missing user or pass
const char apn[] = "YourAPN";
const char user[] = "";
const char pass[] = "";
// Server details
const char server[] = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
#ifdef USE_SSL
TinyGsmClientSecure client(modem);
HttpClient http(client, server, 443);
#else
TinyGsmClient client(modem);
HttpClient http(client, server, 80);
#endif
void setup() {
// Turn on modem with 1 second pulse on D6
pinMode(6, OUTPUT);
digitalWrite(6, HIGH);
delay(1000);
digitalWrite(6, LOW);
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println(F("Initializing modem..."));
modem.restart();
String modemInfo = modem.getModemInfo();
SerialMon.print(F("Modem: "));
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
}
void loop() {
SerialMon.print(F("Waiting for network..."));
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" OK");
SerialMon.print(F("Performing HTTP GET request... "));
int err = http.get(resource);
if (err != 0) {
SerialMon.println(F("failed to connect"));
delay(10000);
return;
}
int status = http.responseStatusCode();
SerialMon.println(status);
if (!status) {
delay(10000);
return;
}
while (http.headerAvailable()) {
String headerName = http.readHeaderName();
String headerValue = http.readHeaderValue();
//SerialMon.println(headerName + " : " + headerValue);
}
int length = http.contentLength();
if (length >= 0) {
SerialMon.print(F("Content length is: "));
SerialMon.println(length);
}
if (http.isResponseChunked()) {
SerialMon.println(F("The response is chunked"));
}
String body = http.responseBody();
SerialMon.println(F("Response:"));
SerialMon.println(body);
SerialMon.print(F("Body length is: "));
SerialMon.println(body.length());
// Shutdown
http.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
// Do nothing forevermore
while (true) {
delay(1000);
}
}

View File

@@ -0,0 +1,36 @@
const char cert[] PROGMEM =
"-----BEGIN CERTIFICATE-----\n"
"MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\n"
"hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n"
"A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\n"
"BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5\n"
"MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\n"
"EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n"
"Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh\n"
"dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR\n"
"6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X\n"
"pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC\n"
"9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV\n"
"/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf\n"
"Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z\n"
"+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w\n"
"qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah\n"
"SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC\n"
"u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf\n"
"Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq\n"
"crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\n"
"FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB\n"
"/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl\n"
"wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM\n"
"4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV\n"
"2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna\n"
"FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ\n"
"CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK\n"
"boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke\n"
"jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL\n"
"S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb\n"
"QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl\n"
"0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB\n"
"NVOFBkpdn627G190\n"
"-----END CERTIFICATE-----\n";

View File

@@ -0,0 +1,74 @@
const char cert[] PROGMEM =
{
0x30, 0x82, 0x03, 0x4a, 0x30, 0x82, 0x02, 0x32, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x10, 0x44, 0xaf, 0xb0, 0x80, 0xd6, 0xa3, 0x27, 0xba, 0x89,
0x30, 0x39, 0x86, 0x2e, 0xf8, 0x40, 0x6b, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x3f,
0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b, 0x44,
0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x43,
0x6f, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x0e, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
0x20, 0x58, 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x39, 0x33,
0x30, 0x32, 0x31, 0x31, 0x32, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x31,
0x30, 0x39, 0x33, 0x30, 0x31, 0x34, 0x30, 0x31, 0x31, 0x35, 0x5a, 0x30,
0x3f, 0x31, 0x24, 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1b,
0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x53, 0x69, 0x67, 0x6e,
0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
0x43, 0x6f, 0x2e, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x0e, 0x44, 0x53, 0x54, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
0x41, 0x20, 0x58, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0x00, 0xdf, 0xaf, 0xe9, 0x97, 0x50, 0x08, 0x83, 0x57, 0xb4, 0xcc, 0x62,
0x65, 0xf6, 0x90, 0x82, 0xec, 0xc7, 0xd3, 0x2c, 0x6b, 0x30, 0xca, 0x5b,
0xec, 0xd9, 0xc3, 0x7d, 0xc7, 0x40, 0xc1, 0x18, 0x14, 0x8b, 0xe0, 0xe8,
0x33, 0x76, 0x49, 0x2a, 0xe3, 0x3f, 0x21, 0x49, 0x93, 0xac, 0x4e, 0x0e,
0xaf, 0x3e, 0x48, 0xcb, 0x65, 0xee, 0xfc, 0xd3, 0x21, 0x0f, 0x65, 0xd2,
0x2a, 0xd9, 0x32, 0x8f, 0x8c, 0xe5, 0xf7, 0x77, 0xb0, 0x12, 0x7b, 0xb5,
0x95, 0xc0, 0x89, 0xa3, 0xa9, 0xba, 0xed, 0x73, 0x2e, 0x7a, 0x0c, 0x06,
0x32, 0x83, 0xa2, 0x7e, 0x8a, 0x14, 0x30, 0xcd, 0x11, 0xa0, 0xe1, 0x2a,
0x38, 0xb9, 0x79, 0x0a, 0x31, 0xfd, 0x50, 0xbd, 0x80, 0x65, 0xdf, 0xb7,
0x51, 0x63, 0x83, 0xc8, 0xe2, 0x88, 0x61, 0xea, 0x4b, 0x61, 0x81, 0xec,
0x52, 0x6b, 0xb9, 0xa2, 0xe2, 0x4b, 0x1a, 0x28, 0x9f, 0x48, 0xa3, 0x9e,
0x0c, 0xda, 0x09, 0x8e, 0x3e, 0x17, 0x2e, 0x1e, 0xdd, 0x20, 0xdf, 0x5b,
0xc6, 0x2a, 0x8a, 0xab, 0x2e, 0xbd, 0x70, 0xad, 0xc5, 0x0b, 0x1a, 0x25,
0x90, 0x74, 0x72, 0xc5, 0x7b, 0x6a, 0xab, 0x34, 0xd6, 0x30, 0x89, 0xff,
0xe5, 0x68, 0x13, 0x7b, 0x54, 0x0b, 0xc8, 0xd6, 0xae, 0xec, 0x5a, 0x9c,
0x92, 0x1e, 0x3d, 0x64, 0xb3, 0x8c, 0xc6, 0xdf, 0xbf, 0xc9, 0x41, 0x70,
0xec, 0x16, 0x72, 0xd5, 0x26, 0xec, 0x38, 0x55, 0x39, 0x43, 0xd0, 0xfc,
0xfd, 0x18, 0x5c, 0x40, 0xf1, 0x97, 0xeb, 0xd5, 0x9a, 0x9b, 0x8d, 0x1d,
0xba, 0xda, 0x25, 0xb9, 0xc6, 0xd8, 0xdf, 0xc1, 0x15, 0x02, 0x3a, 0xab,
0xda, 0x6e, 0xf1, 0x3e, 0x2e, 0xf5, 0x5c, 0x08, 0x9c, 0x3c, 0xd6, 0x83,
0x69, 0xe4, 0x10, 0x9b, 0x19, 0x2a, 0xb6, 0x29, 0x57, 0xe3, 0xe5, 0x3d,
0x9b, 0x9f, 0xf0, 0x02, 0x5d, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x42,
0x30, 0x40, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55,
0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xc4, 0xa7,
0xb1, 0xa4, 0x7b, 0x2c, 0x71, 0xfa, 0xdb, 0xe1, 0x4b, 0x90, 0x75, 0xff,
0xc4, 0x15, 0x60, 0x85, 0x89, 0x10, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01,
0x01, 0x00, 0xa3, 0x1a, 0x2c, 0x9b, 0x17, 0x00, 0x5c, 0xa9, 0x1e, 0xee,
0x28, 0x66, 0x37, 0x3a, 0xbf, 0x83, 0xc7, 0x3f, 0x4b, 0xc3, 0x09, 0xa0,
0x95, 0x20, 0x5d, 0xe3, 0xd9, 0x59, 0x44, 0xd2, 0x3e, 0x0d, 0x3e, 0xbd,
0x8a, 0x4b, 0xa0, 0x74, 0x1f, 0xce, 0x10, 0x82, 0x9c, 0x74, 0x1a, 0x1d,
0x7e, 0x98, 0x1a, 0xdd, 0xcb, 0x13, 0x4b, 0xb3, 0x20, 0x44, 0xe4, 0x91,
0xe9, 0xcc, 0xfc, 0x7d, 0xa5, 0xdb, 0x6a, 0xe5, 0xfe, 0xe6, 0xfd, 0xe0,
0x4e, 0xdd, 0xb7, 0x00, 0x3a, 0xb5, 0x70, 0x49, 0xaf, 0xf2, 0xe5, 0xeb,
0x02, 0xf1, 0xd1, 0x02, 0x8b, 0x19, 0xcb, 0x94, 0x3a, 0x5e, 0x48, 0xc4,
0x18, 0x1e, 0x58, 0x19, 0x5f, 0x1e, 0x02, 0x5a, 0xf0, 0x0c, 0xf1, 0xb1,
0xad, 0xa9, 0xdc, 0x59, 0x86, 0x8b, 0x6e, 0xe9, 0x91, 0xf5, 0x86, 0xca,
0xfa, 0xb9, 0x66, 0x33, 0xaa, 0x59, 0x5b, 0xce, 0xe2, 0xa7, 0x16, 0x73,
0x47, 0xcb, 0x2b, 0xcc, 0x99, 0xb0, 0x37, 0x48, 0xcf, 0xe3, 0x56, 0x4b,
0xf5, 0xcf, 0x0f, 0x0c, 0x72, 0x32, 0x87, 0xc6, 0xf0, 0x44, 0xbb, 0x53,
0x72, 0x6d, 0x43, 0xf5, 0x26, 0x48, 0x9a, 0x52, 0x67, 0xb7, 0x58, 0xab,
0xfe, 0x67, 0x76, 0x71, 0x78, 0xdb, 0x0d, 0xa2, 0x56, 0x14, 0x13, 0x39,
0x24, 0x31, 0x85, 0xa2, 0xa8, 0x02, 0x5a, 0x30, 0x47, 0xe1, 0xdd, 0x50,
0x07, 0xbc, 0x02, 0x09, 0x90, 0x00, 0xeb, 0x64, 0x63, 0x60, 0x9b, 0x16,
0xbc, 0x88, 0xc9, 0x12, 0xe6, 0xd2, 0x7d, 0x91, 0x8b, 0xf9, 0x3d, 0x32,
0x8d, 0x65, 0xb4, 0xe9, 0x7c, 0xb1, 0x57, 0x76, 0xea, 0xc5, 0xb6, 0x28,
0x39, 0xbf, 0x15, 0x65, 0x1c, 0xc8, 0xf6, 0x77, 0x96, 0x6a, 0x0a, 0x8d,
0x77, 0x0b, 0xd8, 0x91, 0x0b, 0x04, 0x8e, 0x07, 0xdb, 0x29, 0xb6, 0x0a,
0xee, 0x9d, 0x82, 0x35, 0x35, 0x10
};

View File

@@ -0,0 +1,22 @@
const char cert[] PROGMEM =
"-----BEGIN CERTIFICATE-----\n"
"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n"
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n"
"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n"
"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n"
"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"
"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n"
"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n"
"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n"
"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n"
"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n"
"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n"
"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n"
"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n"
"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n"
"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n"
"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n"
"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n"
"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n"
"-----END CERTIFICATE-----\n";

View File

@@ -0,0 +1,97 @@
/**************************************************************
*
* This sketch uploads SSL certificates to the SIM8xx
*
* TinyGSM Getting Started guide:
* https://tiny.cc/tinygsm-readme
*
**************************************************************/
// This example is specific to SIM8xx
#define TINY_GSM_MODEM_SIM800
// Select your certificate:
#include "DSTRootCAX3.h"
//#include "DSTRootCAX3.der.h"
//#include "COMODORSACertificationAuthority.h"
// Select the file you want to write into
// (the file is stored on the modem)
#define CERT_FILE "C:\\USER\\CERT.CRT"
#include <TinyGsmClient.h>
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
// Use Hardware Serial for AT commands
#define SerialAT Serial1
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(10);
// Set GSM module baud rate
SerialAT.begin(115200);
delay(3000);
SerialMon.println(F("Initializing modem..."));
modem.init();
modem.sendAT(GF("+FSCREATE=" CERT_FILE));
if (modem.waitResponse() != 1) return;
const int cert_size = sizeof(cert);
modem.sendAT(GF("+FSWRITE=" CERT_FILE ",0,"), cert_size, GF(",10"));
if (modem.waitResponse(GF(">")) != 1) {
return;
}
for (int i = 0; i < cert_size; i++) {
char c = pgm_read_byte(&cert[i]);
modem.stream.write(c);
}
modem.stream.write(GSM_NL);
modem.stream.flush();
if (modem.waitResponse(2000) != 1) return;
modem.sendAT(GF("+SSLSETCERT=\"" CERT_FILE "\""));
if (modem.waitResponse() != 1) return;
if (modem.waitResponse(5000L, GF(GSM_NL "+SSLSETCERT:")) != 1) return;
const int retCode = modem.stream.readStringUntil('\n').toInt();
SerialMon.println();
SerialMon.println();
SerialMon.println(F("****************************"));
SerialMon.print(F("Setting Certificate: "));
SerialMon.println((0 == retCode) ? "OK" : "FAILED");
SerialMon.println(F("****************************"));
}
void loop() {
if (SerialAT.available()) {
SerialMon.write(SerialAT.read());
}
if (SerialMon.available()) {
SerialAT.write(SerialMon.read());
}
delay(0);
}

View File

@@ -0,0 +1,29 @@
#######################################
# Data types (KEYWORD1)
#######################################
TinyGsm KEYWORD1
TinyGsmClient KEYWORD1
TinyGsmClientSecure KEYWORD1
SerialAT KEYWORD1
SerialMon KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
restart KEYWORD2
waitForNetwork KEYWORD2
getSimStatus KEYWORD2
gprsConnect KEYWORD2
gprsDisconnect KEYWORD2
isGprsConnected KEYWORD2
isNetworkConnected KEYWORD2
factoryReset KEYWORD2
#######################################
# Literals (LITERAL1)
#######################################
DATE_FULL LITERAL1
DATE_TIME LITERAL1
DATE_DATE LITERAL1

View File

@@ -0,0 +1,24 @@
{
"name": "TinyGSM",
"version": "0.3.6",
"description": "A small Arduino library for GPRS modules, that just works. Includes examples for Blynk, MQTT, File Download, and Web Client. Supports GSM modules with AT command interface: SIM800, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900, SIM900A, SIM900D, SIM908, SIM968",
"keywords": "GSM, AT commands, AT, SIM800, SIM900, A6, A7, M590, ESP8266, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968",
"authors":
{
"name": "Volodymyr Shymanskyy",
"url": "https://github.com/vshymanskyy",
"maintainer": true
},
"repository":
{
"type": "git",
"url": "https://github.com/vshymanskyy/TinyGSM.git"
},
"homepage": "https://github.com/vshymanskyy/TinyGSM",
"export": {
"exclude": [ "extras/*", "tools/*" ]
},
"frameworks": [ "arduino", "energia", "wiringpi" ],
"platforms": "*",
"examples": "examples/*/*.ino"
}

View File

@@ -0,0 +1,9 @@
name=TinyGSM
version=0.3.6
author=Volodymyr Shymanskyy
maintainer=Volodymyr Shymanskyy
sentence=A small Arduino library for GPRS modules, that just works.
paragraph=Includes examples for Blynk, MQTT, File Download, and Web Client. Supports GSM modules with AT command interface: SIM800, SIM900, A6, A7, M590, ESP8266, SIM800A, SIM800C, SIM800L, SIM800H, SIM808, SIM868, SIM900A, SIM900D, SIM908, SIM968
category=Communication
url=https://github.com/vshymanskyy/TinyGSM
architectures=*

View File

@@ -0,0 +1,45 @@
/*
Client.h - Base class that provides Client
Copyright (c) 2011 Adrian McEwen. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef client_h
#define client_h
#include "Print.h"
#include "Stream.h"
#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;
protected:
uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); };
};
#endif

View File

@@ -0,0 +1,146 @@
/*
IPAddress.h - Base class that provides IPAddress
Copyright (c) 2011 Adrian McEwen. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef IPAddress_h
#define IPAddress_h
#include <stdint.h>
#include "Printable.h"
#include "WString.h"
// A class to make it easier to handle and pass around IP addresses
class IPAddress : public Printable {
private:
union {
uint8_t bytes[4]; // IPv4 address
uint32_t dword;
} _address;
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t* raw_address() { return _address.bytes; };
public:
// Constructors
IPAddress() {
_address.dword = 0;
}
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
_address.bytes[0] = first_octet;
_address.bytes[1] = second_octet;
_address.bytes[2] = third_octet;
_address.bytes[3] = fourth_octet;
}
IPAddress(uint32_t address) {
_address.dword = address;
}
IPAddress(const uint8_t *address) {
memcpy(_address.bytes, address, sizeof(_address.bytes));
}
bool fromString(const char *address) {
uint16_t acc = 0; // Accumulator
uint8_t dots = 0;
while (*address)
{
char c = *address++;
if (c >= '0' && c <= '9')
{
acc = acc * 10 + (c - '0');
if (acc > 255) {
// Value out of [0..255] range
return false;
}
}
else if (c == '.')
{
if (dots == 3) {
// Too much dots (there must be 3 dots)
return false;
}
_address.bytes[dots++] = acc;
acc = 0;
}
else
{
// Invalid char
return false;
}
}
if (dots != 3) {
// Too few dots (there must be 3 dots)
return false;
}
_address.bytes[3] = acc;
return true;
}
bool fromString(const String &address) { return fromString(address.c_str()); }
// Overloaded cast operator to allow IPAddress objects to be used where a pointer
// to a four-byte uint8_t array is expected
operator uint32_t() const { return _address.dword; };
bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; };
bool operator==(const uint8_t* addr) const {
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
}
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const { return _address.bytes[index]; };
uint8_t& operator[](int index) { return _address.bytes[index]; };
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
IPAddress& operator=(const uint8_t *address) {
memcpy(_address.bytes, address, sizeof(_address.bytes));
return *this;
}
IPAddress& operator=(uint32_t address) {
_address.dword = address;
return *this;
}
virtual size_t printTo(Print& p) const {
size_t n = 0;
for (int i =0; i < 3; i++)
{
n += p.print(_address.bytes[i], DEC);
n += p.print('.');
}
n += p.print(_address.bytes[3], DEC);
return n;
}
friend class EthernetClass;
friend class UDP;
friend class Client;
friend class Server;
friend class DhcpClass;
friend class DNSClient;
};
const IPAddress INADDR_NONE(0,0,0,0);
#endif

View File

@@ -0,0 +1,78 @@
/**
* @file TinyGsmClient.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClient_h
#define TinyGsmClient_h
#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_UBLOX) || defined(TINY_GSM_MODEM_ESP8266)
#define TINY_GSM_MODEM_HAS_SSL
#endif
#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7)
#define TINY_GSM_MODEM_HAS_GPS
#endif
#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM900)
#define TINY_GSM_MODEM_HAS_GPRS
#include <TinyGsmClientSIM800.h>
typedef TinyGsmSim800 TinyGsm;
typedef TinyGsmSim800::GsmClient TinyGsmClient;
typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868)
#define TINY_GSM_MODEM_HAS_GPRS
#include <TinyGsmClientSIM808.h>
typedef TinyGsmSim808 TinyGsm;
typedef TinyGsmSim808::GsmClient TinyGsmClient;
typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_UBLOX)
#define TINY_GSM_MODEM_HAS_GPRS
#include <TinyGsmClientUBLOX.h>
typedef TinyGsmUBLOX TinyGsm;
typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_BG96)
#define TINY_GSM_MODEM_HAS_GPRS
#include <TinyGsmClientBG96.h>
typedef TinyGsmBG96 TinyGsm;
typedef TinyGsmBG96::GsmClient TinyGsmClient;
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
#define TINY_GSM_MODEM_HAS_GPRS
#include <TinyGsmClientA6.h>
typedef TinyGsmA6 TinyGsm;
typedef TinyGsmA6::GsmClient TinyGsmClient;
#elif defined(TINY_GSM_MODEM_M590)
#define TINY_GSM_MODEM_HAS_GPRS
#include <TinyGsmClientM590.h>
typedef TinyGsmM590 TinyGsm;
typedef TinyGsmM590::GsmClient TinyGsmClient;
#elif defined(TINY_GSM_MODEM_ESP8266)
#define TINY_GSM_MODEM_HAS_WIFI
#include <TinyGsmClientESP8266.h>
typedef TinyGsmESP8266 TinyGsm;
typedef TinyGsmESP8266::GsmClient TinyGsmClient;
typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure;
#elif defined(TINY_GSM_MODEM_XBEE)
#define TINY_GSM_MODEM_HAS_GPRS
#define TINY_GSM_MODEM_HAS_WIFI
#include <TinyGsmClientXBee.h>
typedef TinyGsmXBee TinyGsm;
typedef TinyGsmXBee::GsmClient TinyGsmClient;
typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure;
#else
#error "Please define GSM modem model"
#endif
#endif

View File

@@ -0,0 +1,808 @@
/**
* @file TinyGsmClientA6.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClientA6_h
#define TinyGsmClientA6_h
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 256
#endif
#define TINY_GSM_MUX_COUNT 8
#include <TinyGsmCommon.h>
#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;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus {
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_OK_HOME = 1,
REG_OK_ROAMING = 5,
REG_UNKNOWN = 4,
};
//============================================================================//
//============================================================================//
// Declaration of the TinyGsmA6 Class
//============================================================================//
//============================================================================//
class TinyGsmA6
{
//============================================================================//
//============================================================================//
// The Internal A6 Client Class
//============================================================================//
//============================================================================//
public:
class GsmClient : public Client
{
friend class TinyGsmA6;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
GsmClient(TinyGsmA6& modem) {
init(&modem);
}
bool init(TinyGsmA6* modem) {
this->at = modem;
this->mux = -1;
sock_connected = false;
return true;
}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
uint8_t newMux = -1;
sock_connected = at->modemConnect(host, port, &newMux);
if (sock_connected) {
mux = newMux;
at->sockets[mux] = this;
}
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
String host; host.reserve(16);
host += ip[0];
host += ".";
host += ip[1];
host += ".";
host += ip[2];
host += ".";
host += ip[3];
return connect(host.c_str(), port);
}
virtual void stop() {
TINY_GSM_YIELD();
at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false;
at->waitResponse();
rx.clear();
}
virtual size_t write(const uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
//at->maintain();
return at->modemSend(buf, size, mux);
}
virtual size_t write(uint8_t c) {
return write(&c, 1);
}
virtual size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual int available() {
TINY_GSM_YIELD();
if (!rx.size() && sock_connected) {
at->maintain();
}
return rx.size();
}
virtual int read(uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
size_t cnt = 0;
while (cnt < size) {
size_t chunk = TinyGsmMin(size-cnt, rx.size());
if (chunk > 0) {
rx.get(buf, chunk);
buf += chunk;
cnt += chunk;
continue;
}
// TODO: Read directly into user buffer?
if (!rx.size() && sock_connected) {
at->maintain();
//break;
}
}
return cnt;
}
virtual int read() {
uint8_t c;
if (read(&c, 1) == 1) {
return c;
}
return -1;
}
virtual int peek() { return -1; } //TODO
virtual void flush() { at->stream.flush(); }
virtual uint8_t connected() {
if (available()) {
return true;
}
return sock_connected;
}
virtual operator bool() { return connected(); }
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmA6* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
};
//============================================================================//
//============================================================================//
// The A6 does not have a secure client!
//============================================================================//
//============================================================================//
//============================================================================//
//============================================================================//
// The A6 Modem Functions
//============================================================================//
//============================================================================//
public:
#ifdef GSM_DEFAULT_STREAM
TinyGsmA6(Stream& stream = GSM_DEFAULT_STREAM)
#else
TinyGsmA6(Stream& stream)
#endif
: stream(stream)
{
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin() {
return init();
}
bool init() {
if (!testAT()) {
return false;
}
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
if (waitResponse() != 1) {
return false;
}
sendAT(GF("+CMEE=0"));
waitResponse();
sendAT(GF("+CMER=3,0,0,2"));
waitResponse();
getSimStatus();
return true;
}
void setBaud(unsigned long baud) {
sendAT(GF("+IPR="), baud);
}
bool testAT(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF(""));
if (waitResponse(200) == 1) {
delay(100);
return true;
}
delay(100);
}
return false;
}
void maintain() {
waitResponse(10, NULL, NULL);
}
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
String getModemInfo() {
sendAT(GF("I"));
String res;
if (waitResponse(1000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
return res;
}
bool hasSSL() {
return false;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
sendAT(GF("+RST=1"));
delay(3000);
return init();
}
bool poweroff() {
sendAT(GF("+CPOF"));
return waitResponse() == 1;
}
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
bool simUnlock(const char *pin) {
sendAT(GF("+CPIN=\""), pin, GF("\""));
return waitResponse() == 1;
}
String getSimCCID() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
String getIMEI() {
sendAT(GF("+GSN"));
if (waitResponse(GF(GSM_NL)) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
SimStatus getSimStatus(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
RegStatus getRegistrationStatus() {
sendAT(GF("+CREG?"));
if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
return REG_UNKNOWN;
}
streamSkipUntil(','); // Skip format (0)
int status = stream.readStringUntil('\n').toInt();
waitResponse();
return (RegStatus)status;
}
String getOperator() {
sendAT(GF("+COPS=3,0")); // Set format
waitResponse();
sendAT(GF("+COPS?"));
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
return "";
}
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* Generic network functions
*/
int getSignalQuality() {
sendAT(GF("+CSQ"));
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
return 99;
}
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res;
}
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
bool waitForNetwork(unsigned long timeout = 60000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (isNetworkConnected()) {
return true;
}
delay(250);
}
return false;
}
/*
* WiFi functions
*/
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
gprsDisconnect();
sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1)
return false;
// TODO: wait AT+CGATT?
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
waitResponse();
if (!user) user = "";
if (!pwd) pwd = "";
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
if (waitResponse(60000L) != 1) {
return false;
}
sendAT(GF("+CGACT=1,1"));
waitResponse(60000L);
sendAT(GF("+CIPMUX=1"));
if (waitResponse() != 1) {
return false;
}
return true;
}
bool gprsDisconnect() {
// Shut the TCP/IP connection
sendAT(GF("+CIPSHUT"));
if (waitResponse(60000L) != 1)
return false;
for (int i = 0; i<3; i++) {
sendAT(GF("+CGATT=0"));
if (waitResponse(5000L) == 1)
return true;
}
return false;
}
bool isGprsConnected() {
sendAT(GF("+CGATT?"));
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
return false;
}
int res = stream.readStringUntil('\n').toInt();
waitResponse();
return (res == 1);
}
String getLocalIP() {
sendAT(GF("+CIFSR"));
String res;
if (waitResponse(10000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, "");
res.trim();
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() {
sendAT(GF("A"));
return waitResponse() == 1;
}
// Returns true on pick-up, false on error/busy
bool callNumber(const String& number) {
if (number == GF("last")) {
sendAT(GF("DLST"));
} else {
sendAT(GF("D\""), number, "\";");
}
if (waitResponse(5000L) != 1) {
return false;
}
if (waitResponse(60000L,
GF(GSM_NL "+CIEV: \"CALL\",1"),
GF(GSM_NL "+CIEV: \"CALL\",0"),
GFP(GSM_ERROR)) != 1)
{
return false;
}
int rsp = waitResponse(60000L,
GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
GF(GSM_NL "+CIEV: \"CALL\",0"));
int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL));
return rsp == 1 && rsp2 == 0;
}
bool callHangup() {
sendAT(GF("H"));
return waitResponse() == 1;
}
// 0-9,*,#,A,B,C,D
bool dtmfSend(char cmd, unsigned duration_ms = 100) {
duration_ms = constrain(duration_ms, 100, 1000);
// The duration parameter is not working, so we simulate it using delay..
// TODO: Maybe there's another way...
//sendAT(GF("+VTD="), duration_ms / 100);
//waitResponse();
sendAT(GF("+VTS="), cmd);
if (waitResponse(10000L) == 1) {
delay(duration_ms);
return true;
}
return false;
}
/*
* Audio functions
*/
bool audioSetHeadphones() {
sendAT(GF("+SNFS=0"));
return waitResponse() == 1;
}
bool audioSetSpeaker() {
sendAT(GF("+SNFS=1"));
return waitResponse() == 1;
}
bool audioMuteMic(bool mute) {
sendAT(GF("+CMUT="), mute);
return waitResponse() == 1;
}
/*
* Messaging functions
*/
String sendUSSD(const String& code) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("+CUSD=1,\""), code, GF("\",15"));
if (waitResponse(10000L) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (dcs == 15) {
return TinyGsmDecodeHex7bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
/*
* Location functions
*/
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int getBattPercent() {
sendAT(GF("+CBC?"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return false;
}
stream.readStringUntil(',');
int res = stream.readStringUntil('\n').toInt();
waitResponse();
return res;
}
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t* mux) {
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
if (waitResponse(75000L, GF(GSM_NL "+CIPNUM:")) != 1) {
return false;
}
int newMux = stream.readStringUntil('\n').toInt();
int rsp = waitResponse(75000L,
GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL));
if (waitResponse() != 1) {
return false;
}
*mux = newMux;
return (1 == rsp);
}
int modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+CIPSEND="), mux, ',', len);
if (waitResponse(2000L, GF(GSM_NL ">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
stream.flush();
if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) {
return 0;
}
return len;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+CIPSTATUS")); //TODO mux?
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\""));
waitResponse();
return 1 == res;
}
public:
/* Utilities */
template<typename T>
void streamWrite(T last) {
stream.print(last);
}
template<typename T, typename... Args>
void streamWrite(T head, Args... tail) {
stream.print(head);
streamWrite(tail...);
}
bool streamSkipUntil(char c) {
const unsigned long timeout = 1000L;
unsigned long startMillis = millis();
while (millis() - startMillis < timeout) {
while (millis() - startMillis < timeout && !stream.available()) {
TINY_GSM_YIELD();
}
if (stream.read() == c)
return true;
}
return false;
}
template<typename... Args>
void sendAT(Args... cmd) {
streamWrite("AT", cmd..., GSM_NL);
stream.flush();
TINY_GSM_YIELD();
//DBG("### AT:", cmd...);
}
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+CIPRCV:"))) {
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(',').toInt();
int len_orig = len;
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
}
while (len--) {
while (!stream.available()) { TINY_GSM_YIELD(); }
sockets[mux]->rx.put(stream.read());
}
if (len_orig > sockets[mux]->available()) { // TODO
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
}
data = "";
} else if (data.endsWith(GF("+TCPCLOSED:"))) {
int mux = stream.readStringUntil('\n').toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
}
}
} while (millis() - startMillis < timeout);
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
data = "";
}
//DBG('<', index, '>');
return index;
}
uint8_t waitResponse(uint32_t timeout,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
String data;
return waitResponse(timeout, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
return waitResponse(1000, r1, r2, r3, r4, r5);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
};
#endif

View File

@@ -0,0 +1,813 @@
/**
* @file TinyGsmClientBG96.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Apr 2018
*/
#ifndef TinyGsmClientBG96_h
#define TinyGsmClientBG96_h
//#define TINY_GSM_DEBUG Serial
//#define TINY_GSM_USE_HEX
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
#define TINY_GSM_MUX_COUNT 12
#include <TinyGsmCommon.h>
#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;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus {
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_OK_HOME = 1,
REG_OK_ROAMING = 5,
REG_UNKNOWN = 4,
};
//============================================================================//
//============================================================================//
// Declaration of the TinyGsmBG96 Class
//============================================================================//
//============================================================================//
class TinyGsmBG96
{
//============================================================================//
//============================================================================//
// The Internal BG96 Client Class
//============================================================================//
//============================================================================//
public:
class GsmClient : public Client
{
friend class TinyGsmBG96;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) {
init(&modem, mux);
}
bool init(TinyGsmBG96* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_available = 0;
sock_connected = false;
got_data = false;
at->sockets[mux] = this;
return true;
}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux);
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
String host; host.reserve(16);
host += ip[0];
host += ".";
host += ip[1];
host += ".";
host += ip[2];
host += ".";
host += ip[3];
return connect(host.c_str(), port);
}
virtual void stop() {
TINY_GSM_YIELD();
at->sendAT(GF("+QICLOSE="), mux);
sock_connected = false;
at->waitResponse();
rx.clear();
}
virtual size_t write(const uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
at->maintain();
return at->modemSend(buf, size, mux);
}
virtual size_t write(uint8_t c) {
return write(&c, 1);
}
virtual size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual int available() {
TINY_GSM_YIELD();
if (!rx.size()) {
at->maintain();
}
return rx.size() + sock_available;
}
virtual int read(uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
at->maintain();
size_t cnt = 0;
while (cnt < size) {
size_t chunk = TinyGsmMin(size-cnt, rx.size());
if (chunk > 0) {
rx.get(buf, chunk);
buf += chunk;
cnt += chunk;
continue;
}
// TODO: Read directly into user buffer?
at->maintain();
if (sock_available > 0) {
sock_available -= at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux);
} else {
break;
}
}
return cnt;
}
virtual int read() {
uint8_t c;
if (read(&c, 1) == 1) {
return c;
}
return -1;
}
virtual int peek() { return -1; } //TODO
virtual void flush() { at->stream.flush(); }
virtual uint8_t connected() {
if (available()) {
return true;
}
return sock_connected;
}
virtual operator bool() { return connected(); }
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmBG96* at;
uint8_t mux;
uint16_t sock_available;
bool sock_connected;
bool got_data;
RxFifo rx;
};
//============================================================================//
//============================================================================//
// The BG96 Secure Client
//============================================================================//
//============================================================================//
class GsmClientSecure : public GsmClient
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true);
return sock_connected;
}
};
//============================================================================//
//============================================================================//
// The BG96 Modem Functions
//============================================================================//
//============================================================================//
public:
#ifdef GSM_DEFAULT_STREAM
TinyGsmBG96(Stream& stream = GSM_DEFAULT_STREAM)
#else
TinyGsmBG96(Stream& stream)
#endif
: stream(stream)
{
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin() {
return init();
}
bool init() {
if (!testAT()) {
return false;
}
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
if (waitResponse() != 1) {
return false;
}
getSimStatus();
return true;
}
void setBaud(unsigned long baud) {
sendAT(GF("+IPR="), baud);
}
bool testAT(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF(""));
if (waitResponse(200) == 1) {
delay(100);
return true;
}
delay(100);
}
return false;
}
void maintain() {
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
GsmClient* sock = sockets[mux];
if (sock && sock->got_data) {
sock->got_data = false;
sock->sock_available = modemGetAvailable(mux);
}
}
while (stream.available()) {
waitResponse(10, NULL, NULL);
}
}
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+IPR=0")); // Auto-baud
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
String getModemInfo() {
sendAT(GF("I"));
String res;
if (waitResponse(1000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
return res;
}
bool hasSSL() {
return false; // TODO: For now
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
sendAT(GF("+CFUN=1,1"));
if (waitResponse(60000L, GF("POWERED DOWN")) != 1) {
return false;
}
delay(3000);
return init();
}
bool poweroff() {
sendAT(GF("+QPOWD"));
return waitResponse(GF("POWERED DOWN")) == 1; // TODO
}
bool radioOff() {
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return true;
}
/*
* SIM card functions
*/
bool simUnlock(const char *pin) {
sendAT(GF("+CPIN=\""), pin, GF("\""));
return waitResponse() == 1;
}
String getSimCCID() {
sendAT(GF("+ICCID"));
if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
String getIMEI() {
sendAT(GF("+GSN"));
if (waitResponse(GF(GSM_NL)) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
SimStatus getSimStatus(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
RegStatus getRegistrationStatus() {
sendAT(GF("+CREG?"));
if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
return REG_UNKNOWN;
}
streamSkipUntil(','); // Skip format (0)
int status = stream.readStringUntil('\n').toInt();
waitResponse();
return (RegStatus)status;
}
String getOperator() {
sendAT(GF("+COPS?"));
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
return "";
}
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* Generic network functions
*/
int getSignalQuality() {
sendAT(GF("+CSQ"));
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
return 99;
}
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res;
}
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
bool waitForNetwork(unsigned long timeout = 60000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (isNetworkConnected()) {
return true;
}
delay(250);
}
return false;
}
/*
* WiFi functions
*/
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
gprsDisconnect();
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
if (waitResponse() != 1) {
return false;
}
sendAT(GF("+QIACT=1"));
if (waitResponse(150000L) != 1) {
return false;
}
sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1) {
return false;
}
return true;
}
bool gprsDisconnect() {
sendAT(GF("+QIDEACT=1")); // Deactivate the bearer context
if (waitResponse(40000L) != 1)
return false;
return true;
}
bool isGprsConnected() {
sendAT(GF("+CGATT?"));
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
return false;
}
int res = stream.readStringUntil('\n').toInt();
waitResponse();
if (res != 1)
return false;
return localIP() != 0;
}
String getLocalIP() {
sendAT(GF("+CGPADDR=1"));
if (waitResponse(10000L, GF(GSM_NL "+CGPADDR:")) != 1) {
return "";
}
streamSkipUntil(',');
String res = stream.readStringUntil('\n');
if (waitResponse() != 1) {
return "";
}
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() {
sendAT(GF("A"));
return waitResponse() == 1;
}
// Returns true on pick-up, false on error/busy
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callHangup() {
sendAT(GF("H"));
return waitResponse() == 1;
}
// 0-9,*,#,A,B,C,D
bool dtmfSend(char cmd, int duration_ms = 100) { // TODO: check
duration_ms = constrain(duration_ms, 100, 1000);
sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second
waitResponse();
sendAT(GF("+VTS="), cmd);
return waitResponse(10000L) == 1;
}
/*
* Messaging functions
*/
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSMP=17,167,0,8"));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
uint16_t* t = (uint16_t*)text;
for (size_t i=0; i<len; i++) {
uint8_t c = t[i] >> 8;
if (c < 0x10) { stream.print('0'); }
stream.print(c, HEX);
c = t[i] & 0xFF;
if (c < 0x10) { stream.print('0'); }
stream.print(c, HEX);
}
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
/*
* Location functions
*/
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_IMPLEMENTED;
int getBattPercent() TINY_GSM_ATTR_NOT_IMPLEMENTED;
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
int rsp;
sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0"));
rsp = waitResponse();
if (waitResponse(20000L, GF(GSM_NL "+QIOPEN:")) != 1) {
return false;
}
if (stream.readStringUntil(',').toInt() != mux) {
return false;
}
// Read status
rsp = stream.readStringUntil('\n').toInt();
return (0 == rsp);
}
int modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+QISEND="), mux, ',', len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
return 0;
}
// TODO: Wait for ACK? AT+QISEND=id,0
return len;
}
size_t modemRead(size_t size, uint8_t mux) {
sendAT(GF("+QIRD="), mux, ',', size);
if (waitResponse(GF("+QIRD:")) != 1) {
return 0;
}
size_t len = stream.readStringUntil('\n').toInt();
for (size_t i=0; i<len; i++) {
while (!stream.available()) { TINY_GSM_YIELD(); }
char c = stream.read();
sockets[mux]->rx.put(c);
}
waitResponse();
DBG("### READ:", mux, ",", len);
return len;
}
size_t modemGetAvailable(uint8_t mux) {
sendAT(GF("+QIRD="), mux, GF(",0"));
size_t result = 0;
if (waitResponse(GF("+QIRD:")) == 1) {
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip have read
result = stream.readStringUntil('\n').toInt();
DBG("### STILL:", mux, "has", result);
waitResponse();
}
if (!result) {
sockets[mux]->sock_connected = modemGetConnected(mux);
}
return result;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+QISTATE=1,"), mux);
//+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
if (waitResponse(GF("+QISTATE:")))
return false;
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
waitResponse();
// 0 Initial, 1 Opening, 2 Connected, 3 Listening, 4 Closing
return 2 == res;
}
public:
/* Utilities */
template<typename T>
void streamWrite(T last) {
stream.print(last);
}
template<typename T, typename... Args>
void streamWrite(T head, Args... tail) {
stream.print(head);
streamWrite(tail...);
}
bool streamSkipUntil(char c) {
const unsigned long timeout = 1000L;
unsigned long startMillis = millis();
while (millis() - startMillis < timeout) {
while (millis() - startMillis < timeout && !stream.available()) {
TINY_GSM_YIELD();
}
if (stream.read() == c)
return true;
}
return false;
}
template<typename... Args>
void sendAT(Args... cmd) {
streamWrite("AT", cmd..., GSM_NL);
stream.flush();
TINY_GSM_YIELD();
//DBG("### AT:", cmd...);
}
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+QIURC:"))) {
stream.readStringUntil('\"');
String urc = stream.readStringUntil('\"');
stream.readStringUntil(',');
if (urc == "recv") {
int mux = stream.readStringUntil('\n').toInt();
DBG("### URC RECV:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->got_data = true;
}
} else if (urc == "closed") {
int mux = stream.readStringUntil('\n').toInt();
DBG("### URC CLOSE:", mux);
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
} else {
stream.readStringUntil('\n');
}
data = "";
}
}
} while (millis() - startMillis < timeout);
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
data = "";
}
//DBG('<', index, '>');
return index;
}
uint8_t waitResponse(uint32_t timeout,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
String data;
return waitResponse(timeout, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
return waitResponse(1000, r1, r2, r3, r4, r5);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
};
#endif

View File

@@ -0,0 +1,598 @@
/**
* @file TinyGsmClientESP8266.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClientESP8266_h
#define TinyGsmClientESP8266_h
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 512
#endif
#define TINY_GSM_MUX_COUNT 5
#include <TinyGsmCommon.h>
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
// <stat> status of ESP8266 station interface
// 2 : ESP8266 station connected to an AP and has obtained IP
// 3 : ESP8266 station created a TCP or UDP transmission
// 4 : the TCP or UDP transmission of ESP8266 station disconnected
// 5 : ESP8266 station did NOT connect to an AP
enum RegStatus {
REG_OK_IP = 2,
REG_OK_TCP = 3,
REG_UNREGISTERED = 4,
REG_DENIED = 5,
REG_UNKNOWN = 6,
};
//============================================================================//
//============================================================================//
// Declaration of the TinyGsmESP8266 Class
//============================================================================//
//============================================================================//
class TinyGsmESP8266
{
//============================================================================//
//============================================================================//
// The ESP8266 Internal Client Class
//============================================================================//
//============================================================================//
public:
class GsmClient : public Client
{
friend class TinyGsmESP8266;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
init(&modem, mux);
}
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_connected = false;
at->sockets[mux] = this;
return true;
}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux);
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
String host; host.reserve(16);
host += ip[0];
host += ".";
host += ip[1];
host += ".";
host += ip[2];
host += ".";
host += ip[3];
return connect(host.c_str(), port);
}
virtual void stop() {
TINY_GSM_YIELD();
at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false;
at->waitResponse();
rx.clear();
}
virtual size_t write(const uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
//at->maintain();
return at->modemSend(buf, size, mux);
}
virtual size_t write(uint8_t c) {
return write(&c, 1);
}
virtual size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual int available() {
TINY_GSM_YIELD();
if (!rx.size() && sock_connected) {
at->maintain();
}
return rx.size();
}
virtual int read(uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
size_t cnt = 0;
while (cnt < size) {
size_t chunk = TinyGsmMin(size-cnt, rx.size());
if (chunk > 0) {
rx.get(buf, chunk);
buf += chunk;
cnt += chunk;
continue;
}
// TODO: Read directly into user buffer?
if (!rx.size() && sock_connected) {
at->maintain();
//break;
}
}
return cnt;
}
virtual int read() {
uint8_t c;
if (read(&c, 1) == 1) {
return c;
}
return -1;
}
virtual int peek() { return -1; } //TODO
virtual void flush() { at->stream.flush(); }
virtual uint8_t connected() {
if (available()) {
return true;
}
return sock_connected;
}
virtual operator bool() { return connected(); }
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmESP8266* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
};
//============================================================================//
//============================================================================//
// The Secure ESP8266 Client Class
//============================================================================//
//============================================================================//
class GsmClientSecure : public GsmClient
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux, true);
return sock_connected;
}
};
//============================================================================//
//============================================================================//
// The ESP8266 Modem Functions
//============================================================================//
//============================================================================//
public:
#ifdef GSM_DEFAULT_STREAM
TinyGsmESP8266(Stream& stream = GSM_DEFAULT_STREAM)
#else
TinyGsmESP8266(Stream& stream)
#endif
: stream(stream)
{
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin() {
return init();
}
bool init() {
if (!testAT()) {
return false;
}
sendAT(GF("E0")); // Echo Off
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;
}
return true;
}
void setBaud(unsigned long baud) {
sendAT(GF("+IPR="), baud);
}
bool testAT(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF(""));
if (waitResponse(200) == 1) {
delay(100);
return true;
}
delay(100);
}
return false;
}
void maintain() {
waitResponse(10, NULL, NULL);
}
bool factoryDefault() {
sendAT(GF("+RESTORE"));
return waitResponse() == 1;
}
String getModemInfo() {
sendAT(GF("+GMR"));
String res;
if (waitResponse(1000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
return res;
}
bool hasSSL() {
return true;
}
/*
* Power functions
*/
bool restart() {
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();
}
bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
RegStatus getRegistrationStatus() {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
int status = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
waitResponse(); // Returns an OK after the status
return (RegStatus)status;
}
/*
* Generic network functions
*/
int getSignalQuality() {
sendAT(GF("+CWJAP_CUR?"));
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
if (res1 != 2) {
waitResponse();
return 0;
}
streamSkipUntil(','); // Skip SSID
streamSkipUntil(','); // Skip BSSID/MAC address
streamSkipUntil(','); // Skip Chanel number
int res2 = stream.parseInt(); // Read RSSI
waitResponse(); // Returns an OK after the value
return res2;
}
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_IP || s == REG_OK_TCP);
}
bool waitForNetwork(unsigned long timeout = 60000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF("+CIPSTATUS"));
int res1 = waitResponse(3000, GF("busy p..."), GF("STATUS:"));
if (res1 == 2) {
int res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
if (res2 == 2 || res2 == 3) {
waitResponse();
return true;
}
}
delay(250);
}
return false;
}
/*
* WiFi functions
*/
bool networkConnect(const char* ssid, const char* pwd) {
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;
}
bool networkDisconnect() {
sendAT(GF("+CWQAP"));
bool retVal = waitResponse(10000L) == 1;
waitResponse(GF("WIFI DISCONNECT"));
return retVal;
}
String getLocalIP() {
sendAT(GF("+CIPSTA_CUR??"));
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
if (res1 != 2) {
return "";
}
String res2 = stream.readStringUntil('"');
waitResponse();
return res2;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* GPRS functions
*/
/*
* Messaging functions
*/
/*
* Location functions
*/
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) {
if (ssl) {
sendAT(GF("+CIPSSLSIZE=4096"));
waitResponse();
}
sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE);
// TODO: Check mux
int rsp = waitResponse(75000L,
GFP(GSM_OK),
GFP(GSM_ERROR),
GF("ALREADY CONNECT"));
// if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT"
return (1 == rsp);
}
int modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+CIPSEND="), mux, ',', len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
stream.flush();
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) {
return 0;
}
return len;
}
bool modemGetConnected(uint8_t mux) {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_IP || s == REG_OK_TCP);
}
public:
/* Utilities */
template<typename T>
void streamWrite(T last) {
stream.print(last);
}
template<typename T, typename... Args>
void streamWrite(T head, Args... tail) {
stream.print(head);
streamWrite(tail...);
}
bool streamSkipUntil(char c) {
const unsigned long timeout = 1000L;
unsigned long startMillis = millis();
while (millis() - startMillis < timeout) {
while (millis() - startMillis < timeout && !stream.available()) {
TINY_GSM_YIELD();
}
if (stream.read() == c)
return true;
}
return false;
}
template<typename... Args>
void sendAT(Args... cmd) {
streamWrite("AT", cmd..., GSM_NL);
stream.flush();
TINY_GSM_YIELD();
//DBG("### AT:", cmd...);
}
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+IPD,"))) {
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(':').toInt();
int len_orig = len;
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
}
while (len--) {
while (!stream.available()) { TINY_GSM_YIELD(); }
sockets[mux]->rx.put(stream.read());
}
if (len_orig > sockets[mux]->available()) { // TODO
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
}
data = "";
} else if (data.endsWith(GF("CLOSED"))) {
int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8));
int coma = data.indexOf(',', muxStart);
int mux = data.substring(muxStart, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
}
}
} while (millis() - startMillis < timeout);
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
data = "";
}
//DBG('<', index, '>');
return index;
}
uint8_t waitResponse(uint32_t timeout,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
String data;
return waitResponse(timeout, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
return waitResponse(1000, r1, r2, r3, r4, r5);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
};
#endif

View File

@@ -0,0 +1,755 @@
/**
* @file TinyGsmClientM590.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClientM590_h
#define TinyGsmClientM590_h
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 256
#endif
#define TINY_GSM_MUX_COUNT 2
#include <TinyGsmCommon.h>
#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;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus {
REG_UNREGISTERED = 0,
REG_SEARCHING = 3,
REG_DENIED = 2,
REG_OK_HOME = 1,
REG_OK_ROAMING = 5,
REG_UNKNOWN = 4,
};
//============================================================================//
//============================================================================//
// Declaration of the TinyGsmM590 Class
//============================================================================//
//============================================================================//
class TinyGsmM590
{
//============================================================================//
//============================================================================//
// The M590 Internal Client Class
//============================================================================//
//============================================================================//
public:
class GsmClient : public Client
{
friend class TinyGsmM590;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
GsmClient(TinyGsmM590& modem, uint8_t mux = 1) {
init(&modem, mux);
}
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_connected = false;
at->sockets[mux] = this;
return true;
}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, mux);
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
String host; host.reserve(16);
host += ip[0];
host += ".";
host += ip[1];
host += ".";
host += ip[2];
host += ".";
host += ip[3];
return connect(host.c_str(), port);
}
virtual void stop() {
TINY_GSM_YIELD();
at->sendAT(GF("+TCPCLOSE="), mux);
sock_connected = false;
at->waitResponse();
rx.clear();
}
virtual size_t write(const uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
//at->maintain();
return at->modemSend(buf, size, mux);
}
virtual size_t write(uint8_t c) {
return write(&c, 1);
}
virtual size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual int available() {
TINY_GSM_YIELD();
if (!rx.size() && sock_connected) {
at->maintain();
}
return rx.size();
}
virtual int read(uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
size_t cnt = 0;
while (cnt < size) {
size_t chunk = TinyGsmMin(size-cnt, rx.size());
if (chunk > 0) {
rx.get(buf, chunk);
buf += chunk;
cnt += chunk;
continue;
}
// TODO: Read directly into user buffer?
if (!rx.size() && sock_connected) {
at->maintain();
//break;
}
}
return cnt;
}
virtual int read() {
uint8_t c;
if (read(&c, 1) == 1) {
return c;
}
return -1;
}
virtual int peek() { return -1; } //TODO
virtual void flush() { at->stream.flush(); }
virtual uint8_t connected() {
if (available()) {
return true;
}
return sock_connected;
}
virtual operator bool() { return connected(); }
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmM590* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
};
//============================================================================//
//============================================================================//
// The M590 Has no Secure client!
//============================================================================//
//============================================================================//
//============================================================================//
//============================================================================//
// The M590 Modem Functions
//============================================================================//
//============================================================================//
public:
#ifdef GSM_DEFAULT_STREAM
TinyGsmM590(Stream& stream = GSM_DEFAULT_STREAM)
#else
TinyGsmM590(Stream& stream)
#endif
: stream(stream)
{
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin() {
return init();
}
bool init() {
if (!testAT()) {
return false;
}
sendAT(GF("&FZE0")); // Factory + Reset + Echo Off
if (waitResponse() != 1) {
return false;
}
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2"));
waitResponse();
#endif
getSimStatus();
return true;
}
void setBaud(unsigned long baud) {
sendAT(GF("+IPR="), baud);
}
bool testAT(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF(""));
if (waitResponse(200) == 1) {
delay(100);
return true;
}
delay(100);
}
return false;
}
void maintain() {
//while (stream.available()) {
waitResponse(10, NULL, NULL);
//}
}
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
waitResponse();
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
waitResponse();
sendAT(GF("+XISP=0")); // Use internal stack
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
String getModemInfo() {
sendAT(GF("I"));
String res;
if (waitResponse(1000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
return res;
}
bool hasSSL() {
return false;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
sendAT(GF("+CFUN=15"));
if (waitResponse(10000L) != 1) {
return false;
}
//MODEM:STARTUP
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
return init();
}
bool poweroff() {
sendAT(GF("+CPWROFF"));
return waitResponse(3000L) == 1;
}
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) {
sendAT(GF("+ENPWRSAVE="), enable);
return waitResponse() == 1;
}
/*
* SIM card functions
*/
bool simUnlock(const char *pin) {
sendAT(GF("+CPIN=\""), pin, GF("\""));
return waitResponse() == 1;
}
String getSimCCID() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL "+CCID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
String getIMEI() {
sendAT(GF("+GSN"));
if (waitResponse(GF(GSM_NL)) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
SimStatus getSimStatus(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
RegStatus getRegistrationStatus() {
sendAT(GF("+CREG?"));
if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
return REG_UNKNOWN;
}
streamSkipUntil(','); // Skip format (0)
int status = stream.readStringUntil('\n').toInt();
waitResponse();
return (RegStatus)status;
}
String getOperator() {
sendAT(GF("+COPS?"));
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
return "";
}
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* Generic network functions
*/
int getSignalQuality() {
sendAT(GF("+CSQ"));
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
return 99;
}
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res;
}
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
bool waitForNetwork(unsigned long timeout = 60000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (isNetworkConnected()) {
return true;
}
delay(250);
}
return false;
}
/*
* WiFi functions
*/
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
gprsDisconnect();
sendAT(GF("+XISP=0"));
waitResponse();
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
waitResponse();
if (!user) user = "";
if (!pwd) pwd = "";
sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\""));
waitResponse();
sendAT(GF("+XIIC=1"));
waitResponse();
const unsigned long timeout = 60000L;
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (isGprsConnected()) {
//goto set_dns; // TODO
return true;
}
delay(500);
}
return false;
// set_dns: // TODO
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
// waitResponse();
//
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
// waitResponse();
return true;
}
bool gprsDisconnect() {
// TODO: There is no command in AT command set
// XIIC=0 does not work
return true;
}
bool isGprsConnected() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
return false;
}
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res == 1;
}
String getLocalIP() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
return "";
}
stream.readStringUntil(',');
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Messaging functions
*/
String sendUSSD(const String& code) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("D"), code);
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (waitResponse() != 1) {
return "";
}
if (dcs == 15) {
return TinyGsmDecodeHex8bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len)
TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Location functions
*/
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux) {
for (int i=0; i<3; i++) { // TODO: no need for loop?
String ip = dnsIpQuery(host);
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
int rsp = waitResponse(75000L,
GF(",OK" GSM_NL),
GF(",FAIL" GSM_NL),
GF("+TCPSETUP:Error" GSM_NL));
if (1 == rsp) {
return true;
} else if (3 == rsp) {
sendAT(GF("+TCPCLOSE="), mux);
waitResponse();
}
delay(1000);
}
return false;
}
int modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+TCPSEND="), mux, ',', len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
stream.write((char)0x0D);
stream.flush();
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) {
return 0;
}
stream.readStringUntil('\n');
return len;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+CIPSTATUS="), mux);
int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\""));
waitResponse();
return 1 == res;
}
String dnsIpQuery(const char* host) {
sendAT(GF("+DNS=\""), host, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse(GF("+DNS:OK" GSM_NL));
res.trim();
return res;
}
public:
/* Utilities */
template<typename T>
void streamWrite(T last) {
stream.print(last);
}
template<typename T, typename... Args>
void streamWrite(T head, Args... tail) {
stream.print(head);
streamWrite(tail...);
}
bool streamSkipUntil(char c) {
const unsigned long timeout = 1000L;
unsigned long startMillis = millis();
while (millis() - startMillis < timeout) {
while (millis() - startMillis < timeout && !stream.available()) {
TINY_GSM_YIELD();
}
if (stream.read() == c)
return true;
}
return false;
}
template<typename... Args>
void sendAT(Args... cmd) {
streamWrite("AT", cmd..., GSM_NL);
stream.flush();
TINY_GSM_YIELD();
//DBG("### AT:", cmd...);
}
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF("+TCPRECV:"))) {
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(',').toInt();
int len_orig = len;
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
}
while (len--) {
while (!stream.available()) { TINY_GSM_YIELD(); }
sockets[mux]->rx.put(stream.read());
}
if (len_orig > sockets[mux]->available()) { // TODO
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
}
data = "";
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
int mux = stream.readStringUntil(',').toInt();
stream.readStringUntil('\n');
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed: ", mux);
}
}
} while (millis() - startMillis < timeout);
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
data = "";
}
//DBG('<', index, '>');
return index;
}
uint8_t waitResponse(uint32_t timeout,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
String data;
return waitResponse(timeout, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
return waitResponse(1000, r1, r2, r3, r4, r5);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
/**
* @file TinyGsmClientSIM808.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClientSIM808_h
#define TinyGsmClientSIM808_h
#include <TinyGsmClientSIM800.h>
//============================================================================//
//============================================================================//
// Declaration and Definitio of the TinyGsmSim808 Class
//============================================================================//
//============================================================================//
class TinyGsmSim808: public TinyGsmSim800
{
public:
TinyGsmSim808(Stream& stream)
: TinyGsmSim800(stream)
{}
/*
* GPS location functions
*/
// enable GPS
bool enableGPS() {
uint16_t state;
sendAT(GF("+CGNSPWR=1"));
if (waitResponse() != 1) {
return false;
}
return true;
}
bool disableGPS() {
uint16_t state;
sendAT(GF("+CGNSPWR=0"));
if (waitResponse() != 1) {
return false;
}
return true;
}
// get the RAW GPS output
// works only with ans SIM808 V2
String getGPSraw() {
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
// get GPS informations
// works only with ans SIM808 V2
bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
//String buffer = "";
char chr_buffer[12];
bool fix = false;
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return false;
}
stream.readStringUntil(','); // mode
if ( stream.readStringUntil(',').toInt() == 1 ) fix = true;
stream.readStringUntil(','); //utctime
*lat = stream.readStringUntil(',').toFloat(); //lat
*lon = stream.readStringUntil(',').toFloat(); //lon
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites
if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites
stream.readStringUntil('\n');
waitResponse();
return fix;
}
// get GPS time
// works only with SIM808 V2
bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) {
bool fix = false;
char chr_buffer[12];
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return false;
}
for (int i = 0; i < 3; i++) {
String buffer = stream.readStringUntil(',');
buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
switch (i) {
case 0:
//mode
break;
case 1:
//fixstatus
if ( buffer.toInt() == 1 ) {
fix = buffer.toInt();
}
break;
case 2:
*year = buffer.substring(0,4).toInt();
*month = buffer.substring(4,6).toInt();
*day = buffer.substring(6,8).toInt();
*hour = buffer.substring(8,10).toInt();
*minute = buffer.substring(10,12).toInt();
*second = buffer.substring(12,14).toInt();
break;
default:
// if nothing else matches, do the default
// default is optional
break;
}
}
String res = stream.readStringUntil('\n');
waitResponse();
if (fix) {
return true;
} else {
return false;
}
}
};
#endif

View File

@@ -0,0 +1,807 @@
/**
* @file TinyGsmClientUBLOX.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClientUBLOX_h
#define TinyGsmClientUBLOX_h
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
#define TINY_GSM_MUX_COUNT 5
#include <TinyGsmCommon.h>
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus {
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_OK_HOME = 1,
REG_OK_ROAMING = 5,
REG_UNKNOWN = 4,
};
//============================================================================//
//============================================================================//
// Declaration of the TinyGsmUBLOX Class
//============================================================================//
//============================================================================//
class TinyGsmUBLOX
{
//============================================================================//
//============================================================================//
// The UBLOX Internal Client Class
//============================================================================//
//============================================================================//
public:
class GsmClient : public Client
{
friend class TinyGsmUBLOX;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 1) {
init(&modem, mux);
}
bool init(TinyGsmUBLOX* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_available = 0;
sock_connected = false;
got_data = false;
return true;
}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, &mux);
at->sockets[mux] = this;
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
String host; host.reserve(16);
host += ip[0];
host += ".";
host += ip[1];
host += ".";
host += ip[2];
host += ".";
host += ip[3];
return connect(host.c_str(), port);
}
virtual void stop() {
TINY_GSM_YIELD();
at->sendAT(GF("+USOCL="), mux);
sock_connected = false;
at->waitResponse();
rx.clear();
}
virtual size_t write(const uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
at->maintain();
return at->modemSend(buf, size, mux);
}
virtual size_t write(uint8_t c) {
return write(&c, 1);
}
virtual size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual int available() {
TINY_GSM_YIELD();
if (!rx.size() && sock_connected) {
at->maintain();
}
return rx.size() + sock_available;
}
virtual int read(uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
at->maintain();
size_t cnt = 0;
while (cnt < size) {
size_t chunk = TinyGsmMin(size-cnt, rx.size());
if (chunk > 0) {
rx.get(buf, chunk);
buf += chunk;
cnt += chunk;
continue;
}
// TODO: Read directly into user buffer?
at->maintain();
if (sock_available > 0) {
sock_available -= at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available), mux);
} else {
break;
}
}
return cnt;
}
virtual int read() {
uint8_t c;
if (read(&c, 1) == 1) {
return c;
}
return -1;
}
virtual int peek() { return -1; } //TODO
virtual void flush() { at->stream.flush(); }
virtual uint8_t connected() {
if (available()) {
return true;
}
return sock_connected;
}
virtual operator bool() { return connected(); }
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmUBLOX* at;
uint8_t mux;
uint16_t sock_available;
bool sock_connected;
bool got_data;
RxFifo rx;
};
//============================================================================//
//============================================================================//
// The Secure UBLOX Client Class
//============================================================================//
//============================================================================//
class GsmClientSecure : public GsmClient
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmUBLOX& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
public:
virtual int connect(const char *host, uint16_t port) {
stop();
TINY_GSM_YIELD();
rx.clear();
sock_connected = at->modemConnect(host, port, &mux, true);
at->sockets[mux] = this;
return sock_connected;
}
};
//============================================================================//
//============================================================================//
// The UBLOX Modem Functions
//============================================================================//
//============================================================================//
public:
#ifdef GSM_DEFAULT_STREAM
TinyGsmUBLOX(Stream& stream = GSM_DEFAULT_STREAM)
#else
TinyGsmUBLOX(Stream& stream)
#endif
: stream(stream)
{
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
if (!testAT()) {
return false;
}
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
int ret = getSimStatus();
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
}
return (getSimStatus() == SIM_READY);
}
void setBaud(unsigned long baud) {
sendAT(GF("+IPR="), baud);
}
bool testAT(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF(""));
if (waitResponse(200) == 1) {
delay(100);
return true;
}
delay(100);
}
return false;
}
void maintain() {
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
GsmClient* sock = sockets[mux];
if (sock && sock->got_data) {
sock->got_data = false;
sock->sock_available = modemGetAvailable(mux);
}
}
while (stream.available()) {
waitResponse(10, NULL, NULL);
}
}
bool factoryDefault() {
sendAT(GF("+UFACTORY=0,1")); // Factory + Reset + Echo Off
waitResponse();
sendAT(GF("+CFUN=16")); // Auto-baud
return waitResponse() == 1;
}
String getModemInfo() {
sendAT(GF("I"));
String res;
if (waitResponse(1000L, res) != 1) {
return "";
}
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
return res;
}
bool hasSSL() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
sendAT(GF("+CFUN=16"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return init();
}
bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool radioOff() {
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return true;
}
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
bool simUnlock(const char *pin) {
sendAT(GF("+CPIN=\""), pin, GF("\""));
return waitResponse() == 1;
}
String getSimCCID() {
sendAT(GF("+CCID"));
if (waitResponse(GF(GSM_NL "+CCID:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
String getIMEI() {
sendAT(GF("+CGSN"));
if (waitResponse(GF(GSM_NL)) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
SimStatus getSimStatus(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
RegStatus getRegistrationStatus() {
sendAT(GF("+CGREG?"));
if (waitResponse(GF(GSM_NL "+CGREG:")) != 1) {
return REG_UNKNOWN;
}
streamSkipUntil(','); // Skip format (0)
int status = stream.readStringUntil('\n').toInt();
waitResponse();
return (RegStatus)status;
}
String getOperator() {
sendAT(GF("+COPS?"));
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
return "";
}
streamSkipUntil('"'); // Skip mode and format
String res = stream.readStringUntil('"');
waitResponse();
return res;
}
/*
* Generic network functions
*/
int getSignalQuality() {
sendAT(GF("+CSQ"));
if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) {
return 99;
}
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res;
}
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
bool waitForNetwork(unsigned long timeout = 60000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (isNetworkConnected()) {
return true;
}
delay(250);
}
return false;
}
/*
* WiFi functions
*/
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
gprsDisconnect();
sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1) {
return false;
}
sendAT(GF("+UPSD=0,1,\""), apn, '"');
waitResponse();
if (user && strlen(user) > 0) {
sendAT(GF("+UPSD=0,2,\""), user, '"');
waitResponse();
}
if (pwd && strlen(pwd) > 0) {
sendAT(GF("+UPSD=0,3,\""), pwd, '"');
waitResponse();
}
sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP
waitResponse();
sendAT(GF("+UPSDA=0,3"));
if (waitResponse(60000L) != 1) {
return false;
}
// Open a GPRS context
sendAT(GF("+UPSND=0,8"));
if (waitResponse(GF(",8,1")) != 1) {
return false;
}
waitResponse();
return true;
}
bool gprsDisconnect() {
sendAT(GF("+UPSDA=0,4"));
if (waitResponse(60000L) != 1)
return false;
sendAT(GF("+CGATT=0"));
if (waitResponse(60000L) != 1)
return false;
return true;
}
bool isGprsConnected() {
sendAT(GF("+CGATT?"));
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
return false;
}
int res = stream.readStringUntil('\n').toInt();
waitResponse();
if (res != 1)
return false;
return localIP() != 0;
}
String getLocalIP() {
sendAT(GF("+UPSND=0,0"));
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
return "";
}
streamSkipUntil(','); // Skip PSD profile
streamSkipUntil('\"'); // Skip request type
String res = stream.readStringUntil('\"');
if (waitResponse() != 1) {
return "";
}
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Messaging functions
*/
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CSCS=\"GSM\"")); // Set GSM default alphabet
waitResponse();
sendAT(GF("+CMGF=1")); // Set preferred message format to text mode
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\"")); // set the phone number
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text); // Actually send the message
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Location functions
*/
String getGsmLocation() {
sendAT(GF("+ULOC=2,3,0,120,1"));
if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
/*
* Battery functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int getBattPercent() {
sendAT(GF("+CIND?"));
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) {
return 0;
}
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res;
}
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false) {
sendAT(GF("+USOCR=6"));
if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) {
return false;
}
*mux = stream.readStringUntil('\n').toInt();
waitResponse();
if (ssl) {
sendAT(GF("+USOSEC="), *mux, ",1");
waitResponse();
}
// Enable NODELAY
sendAT(GF("+USOSO="), *mux, GF(",6,1,1"));
waitResponse();
// Enable KEEPALIVE, 30 sec
//sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
//waitResponse();
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
int rsp = waitResponse(75000L);
return (1 == rsp);
}
int modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+USOWR="), mux, ',', len);
if (waitResponse(GF("@")) != 1) {
return 0;
}
// 50ms delay, see AT manual section 25.10.4
delay(50);
stream.write((uint8_t*)buff, len);
stream.flush();
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip mux
int sent = stream.readStringUntil('\n').toInt();
waitResponse();
return sent;
}
size_t modemRead(size_t size, uint8_t mux) {
sendAT(GF("+USORD="), mux, ',', size);
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip mux
size_t len = stream.readStringUntil(',').toInt();
streamSkipUntil('\"');
for (size_t i=0; i<len; i++) {
while (!stream.available()) { TINY_GSM_YIELD(); }
char c = stream.read();
sockets[mux]->rx.put(c);
}
streamSkipUntil('\"');
waitResponse();
return len;
}
size_t modemGetAvailable(uint8_t mux) {
sendAT(GF("+USORD="), mux, ",0");
size_t result = 0;
if (waitResponse(GF(GSM_NL "+USORD:")) == 1) {
streamSkipUntil(','); // Skip mux
result = stream.readStringUntil('\n').toInt();
waitResponse();
}
if (!result) {
sockets[mux]->sock_connected = modemGetConnected(mux);
}
return result;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+USOCTL="), mux, ",10");
if (waitResponse(GF(GSM_NL "+USOCTL:")) != 1)
return false;
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type
int result = stream.readStringUntil('\n').toInt();
waitResponse();
return result != 0;
}
public:
/* Utilities */
template<typename T>
void streamWrite(T last) {
stream.print(last);
}
template<typename T, typename... Args>
void streamWrite(T head, Args... tail) {
stream.print(head);
streamWrite(tail...);
}
bool streamSkipUntil(char c) {
const unsigned long timeout = 1000L;
unsigned long startMillis = millis();
while (millis() - startMillis < timeout) {
while (millis() - startMillis < timeout && !stream.available()) {
TINY_GSM_YIELD();
}
if (stream.read() == c)
return true;
}
return false;
}
template<typename... Args>
void sendAT(Args... cmd) {
streamWrite("AT", cmd..., GSM_NL);
stream.flush();
TINY_GSM_YIELD();
//DBG("### AT:", cmd...);
}
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
int a = stream.read();
if (a < 0) continue;
data += (char)a;
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
} else if (data.endsWith(GF(GSM_NL "+UUSORD:"))) {
int mux = stream.readStringUntil(',').toInt();
streamSkipUntil('\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(GSM_NL "+UUSOCL:"))) {
int mux = stream.readStringUntil('\n').toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
data = "";
DBG("### Closed:", mux);
}
}
} while (millis() - startMillis < timeout);
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
data = "";
}
//DBG('<', index, '>');
return index;
}
uint8_t waitResponse(uint32_t timeout,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
String data;
return waitResponse(timeout, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
return waitResponse(1000, r1, r2, r3, r4, r5);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
};
#endif

View File

@@ -0,0 +1,882 @@
/**
* @file TinyGsmClientXBee.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmClientXBee_h
#define TinyGsmClientXBee_h
//#define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 1 // Multi-plexing isn't supported using command mode
#include <TinyGsmCommon.h>
#define GSM_NL "\r"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus {
REG_OK = 0,
REG_UNREGISTERED = 1,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_UNKNOWN = 4,
};
// These are responses to the HS command to get "hardware series"
enum XBeeType {
XBEE_S6B_WIFI = 0x601, // Digi XBee® Wi-Fi
XBEE_LTE1_VZN = 0xB01, // Digi XBee® Cellular LTE Cat 1
XBEE_3G = 0xB02, // Digi XBee® Cellular 3G
XBEE3_LTE1_ATT = 1, // Digi XBee3™ Cellular LTE CAT 1 -- HS unknown to SRGD
XBEE3_LTEM_ATT = 2, // Digi XBee3™ Cellular LTE-M -- HS unknown to SRGD
XBEE3_LTENB = 3, // Digi XBee3™ Cellular NB-IoT -- HS unknown to SRGD
};
//============================================================================//
//============================================================================//
// Declaration of the TinyGsmXBee Class
//============================================================================//
//============================================================================//
class TinyGsmXBee
{
//============================================================================//
//============================================================================//
// The XBee Internal Client Class
//============================================================================//
//============================================================================//
public:
class GsmClient : public Client
{
friend class TinyGsmXBee;
public:
GsmClient() {}
GsmClient(TinyGsmXBee& modem, uint8_t mux = 0) {
init(&modem, mux);
}
bool init(TinyGsmXBee* modem, uint8_t mux = 0) {
this->at = modem;
this->mux = mux;
sock_connected = false;
at->sockets[mux] = this;
return true;
}
public:
virtual int connect(const char *host, uint16_t port) {
at->streamClear(); // Empty anything remaining in the buffer;
bool sock_connected = false;
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode
sock_connected = at->modemConnect(host, port, mux, false);
at->writeChanges();
at->exitCommand();
}
at->streamClear(); // Empty anything remaining in the buffer;
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
at->streamClear(); // Empty anything remaining in the buffer;
bool sock_connected = false;
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode
sock_connected = at->modemConnect(ip, port, mux, false);
at->writeChanges();
at->exitCommand();
}
at->streamClear(); // Empty anything remaining in the buffer;
return sock_connected;
}
// This is a hack to shut the socket by setting the timeout to zero and
// then sending an empty line to the server.
virtual void stop() {
at->streamClear(); // Empty anything remaining in the buffer;
at->commandMode();
at->sendAT(GF("TM0")); // Set socket timeout to 0;
at->waitResponse();
at->writeChanges();
at->exitCommand();
at->modemSend("", 1, mux);
at->commandMode();
at->sendAT(GF("TM64")); // Set socket timeout back to 10 seconds;
at->waitResponse();
at->writeChanges();
at->exitCommand();
at->streamClear(); // Empty anything remaining in the buffer;
sock_connected = false;
}
virtual size_t write(const uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
return at->modemSend(buf, size, mux);
}
virtual size_t write(uint8_t c) {
return write(&c, 1);
}
virtual size_t write(const char *str) {
if (str == NULL) return 0;
return write((const uint8_t *)str, strlen(str));
}
virtual int available() {
TINY_GSM_YIELD();
return at->stream.available();
}
virtual int read(uint8_t *buf, size_t size) {
TINY_GSM_YIELD();
return at->stream.readBytes((char*)buf, size);
}
virtual int read() {
TINY_GSM_YIELD();
return at->stream.read();
}
virtual int peek() { return at->stream.peek(); }
virtual void flush() { at->stream.flush(); }
virtual uint8_t connected() {
if (available()) {
return true;
}
return sock_connected;
}
virtual operator bool() { return connected(); }
/*
* Extended API
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmXBee* at;
uint8_t mux;
bool sock_connected;
};
//============================================================================//
//============================================================================//
// The Secure XBee Client Class
//============================================================================//
//============================================================================//
class GsmClientSecure : public GsmClient
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmXBee& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
public:
virtual int connect(const char *host, uint16_t port) {
at->streamClear(); // Empty anything remaining in the buffer;
bool sock_connected = false;
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode
sock_connected = at->modemConnect(host, port, mux, true);
at->writeChanges();
at->exitCommand();
}
at->streamClear(); // Empty anything remaining in the buffer;
return sock_connected;
}
virtual int connect(IPAddress ip, uint16_t port) {
at->streamClear(); // Empty anything remaining in the buffer;
bool sock_connected = false;
if (at->commandMode()) { // Don't try if we didn't successfully get into command mode
sock_connected = at->modemConnect(ip, port, mux, true);
at->writeChanges();
at->exitCommand();
}
at->streamClear(); // Empty anything remaining in the buffer;
return sock_connected;
}
};
//============================================================================//
//============================================================================//
// The XBee Modem Functions
//============================================================================//
//============================================================================//
public:
#ifdef GSM_DEFAULT_STREAM
TinyGsmXBee(Stream& stream = GSM_DEFAULT_STREAM)
#else
TinyGsmXBee(Stream& stream)
#endif
: stream(stream)
{}
/*
* Basic functions
*/
bool begin() {
return init();
}
bool init() {
guardTime = 1100; // Start with a default guard time of 1 second
if (!commandMode(10)) return false; // Try up to 10 times for the init
sendAT(GF("AP0")); // Put in transparent mode
bool ret_val = waitResponse() == 1;
ret_val &= writeChanges();
sendAT(GF("GT64")); // shorten the guard time to 100ms
ret_val &= waitResponse();
ret_val &= writeChanges();
if (ret_val) guardTime = 125;
sendAT(GF("HS")); // Get the "Hardware Series";
String res = readResponse();
char buf[4] = {0,}; // Set up buffer for response
res.toCharArray(buf, 4);
int intRes = strtol(buf, 0, 16);
beeType = (XBeeType)intRes;
exitCommand();
return ret_val;
}
void setBaud(unsigned long baud) {
if (!commandMode()) return;
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;
default: {
DBG(GF("Specified baud rate is unsupported! Setting to 9600 baud."));
sendAT(GF("BD3")); // Set to default of 9600
break;
}
}
waitResponse();
writeChanges();
exitCommand();
}
bool testAT(unsigned long timeout = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (commandMode())
{
sendAT();
if (waitResponse(200) == 1) {
return true;
}
exitCommand();
}
delay(100);
}
return false;
}
void maintain() {}
bool factoryDefault() {
if (!commandMode()) return false; // Return immediately
sendAT(GF("RE"));
bool ret_val = waitResponse() == 1;
ret_val &= writeChanges();
exitCommand();
return ret_val;
}
String getModemInfo() {
String modemInf = "";
if (!commandMode()) return modemInf; // Try up to 10 times for the init
sendAT(GF("HS")); // Get the "Hardware Series"
modemInf += readResponse();
exitCommand();
return modemInf;
}
bool hasSSL() {
if (beeType == XBEE_S6B_WIFI) return false;
else return true;
}
XBeeType getBeeType() {
return beeType;
}
String getBeeName() {
switch (beeType){
case XBEE_S6B_WIFI: return "Digi XBee® Wi-Fi";
case XBEE_LTE1_VZN: return "Digi XBee® Cellular LTE Cat 1";
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";
case XBEE3_LTENB: return "Digi XBee3™ Cellular NB-IoT";
}
}
/*
* Power functions
*/
bool restart() {
if (!commandMode()) return false; // Return immediately
sendAT(GF("AM1")); // Digi suggests putting into airplane mode before restarting
// This allows the sockets and connections to close cleanly
writeChanges();
if (waitResponse() != 1) goto fail;
sendAT(GF("FR"));
if (waitResponse() != 1) goto fail;
delay (2000); // Actually resets about 2 seconds later
// Wait until reboot complete and responds to command mode call again
for (unsigned long start = millis(); millis() - start < 60000L; ) {
if (commandMode(1)) {
sendAT(GF("AM0")); // Turn off airplane mode
writeChanges();
exitCommand();
delay(250); // wait a litle before trying again
}
}
return true;
fail:
exitCommand();
return false;
}
void setupPinSleep(bool maintainAssociation = false) {
if (!commandMode()) return; // Return immediately
sendAT(GF("SM"),1); // Pin sleep
waitResponse();
if (beeType == XBEE_S6B_WIFI && !maintainAssociation) {
sendAT(GF("SO"),200); // For lowest power, dissassociated deep sleep
waitResponse();
}
else if (!maintainAssociation){
sendAT(GF("SO"),1); // For lowest power, dissassociated deep sleep
// Not supported by all modules, will return "ERROR"
waitResponse();
}
writeChanges();
exitCommand();
}
bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
bool simUnlock(const char *pin) { // Not supported
return false;
}
String getSimCCID() {
if (!commandMode()) return ""; // Return immediately
sendAT(GF("S#"));
String res = readResponse();
exitCommand();
return res;
}
String getIMEI() {
if (!commandMode()) return ""; // Return immediately
sendAT(GF("IM"));
String res = readResponse();
exitCommand();
return res;
}
SimStatus getSimStatus(unsigned long timeout = 10000L) {
return SIM_READY; // unsupported
}
RegStatus getRegistrationStatus() {
if (!commandMode()) return REG_UNKNOWN; // Return immediately
sendAT(GF("AI"));
String res = readResponse();
char buf[3] = {0,}; // Set up buffer for response
res.toCharArray(buf, 3);
int intRes = strtol(buf, 0, 16);
RegStatus stat = REG_UNKNOWN;
switch (beeType){
case XBEE_S6B_WIFI: {
if(intRes == 0x00) // 0x00 Successfully joined an access point, established IP addresses and IP listening sockets
stat = REG_OK;
else if(intRes == 0x01) // 0x01 Wi-Fi transceiver initialization in progress.
stat = REG_SEARCHING;
else if(intRes == 0x02) // 0x02 Wi-Fi transceiver initialized, but not yet scanning for access point.
stat = REG_SEARCHING;
else if(intRes == 0x13) { // 0x13 Disconnecting from access point.
restart(); // Restart the device; the S6B tends to get stuck "disconnecting"
stat = REG_UNREGISTERED;
}
else if(intRes == 0x23) // 0x23 SSID not configured.
stat = REG_UNREGISTERED;
else if(intRes == 0x24) // 0x24 Encryption key invalid (either NULL or invalid length for WEP).
stat = REG_DENIED;
else if(intRes == 0x27) // 0x27 SSID was found, but join failed.
stat = REG_DENIED;
else if(intRes == 0x40) // 0x40 Waiting for WPA or WPA2 Authentication.
stat = REG_SEARCHING;
else if(intRes == 0x41) // 0x41 Device joined a network and is waiting for IP configuration to complete
stat = REG_SEARCHING;
else if(intRes == 0x42) // 0x42 Device is joined, IP is configured, and listening sockets are being set up.
stat = REG_SEARCHING;
else if(intRes == 0xFF) // 0xFF Device is currently scanning for the configured SSID.
stat = REG_SEARCHING;
else stat = REG_UNKNOWN;
break;
}
default: {
if(intRes == 0x00) // 0x00 Connected to the Internet.
stat = REG_OK;
else if(intRes == 0x22) // 0x22 Registering to cellular network.
stat = REG_SEARCHING;
else if(intRes == 0x23) // 0x23 Connecting to the Internet.
stat = REG_SEARCHING;
else if(intRes == 0x24) // 0x24 The cellular component is missing, corrupt, or otherwise in error.
stat = REG_UNKNOWN;
else if(intRes == 0x25) // 0x25 Cellular network registration denied.
stat = REG_DENIED;
else if(intRes == 0x2A) { // 0x2A Airplane mode.
sendAT(GF("AM0")); // Turn off airplane mode
waitResponse();
writeChanges();
stat = REG_UNKNOWN;
}
else if(intRes == 0x2F) { // 0x2F Bypass mode active.
sendAT(GF("AP0")); // Set back to transparent mode
waitResponse();
writeChanges();
stat = REG_UNKNOWN;
}
else if(intRes == 0xFF) // 0xFF Device is currently scanning for the configured SSID.
stat = REG_SEARCHING;
else stat = REG_UNKNOWN;
break;
}
}
exitCommand();
return stat;
}
String getOperator() {
if (!commandMode()) return ""; // Return immediately
sendAT(GF("MN"));
String res = readResponse();
exitCommand();
return res;
}
/*
* Generic network functions
*/
int getSignalQuality() {
if (!commandMode()) return 0; // Return immediately
if (beeType == XBEE_S6B_WIFI) sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity
else sendAT(GF("DB")); // ask for the cell strength in dBm
String res = readResponse(); // it works better if we read in as a string
exitCommand();
char buf[3] = {0,}; // Set up buffer for response
res.toCharArray(buf, 3);
int intRes = strtol(buf, 0, 16);
if (beeType == XBEE_S6B_WIFI) return -93 + intRes; // the maximum sensitivity is -93dBm
else return -1*intRes; // need to convert to negative number
}
bool isNetworkConnected() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK);
}
bool waitForNetwork(unsigned long timeout = 60000L) {
for (unsigned long start = millis(); millis() - start < timeout; ) {
if (isNetworkConnected()) {
return true;
}
// delay(250); // Enough delay going in and out of command mode
}
return false;
}
/*
* WiFi functions
*/
bool networkConnect(const char* ssid, const char* pwd) {
if (!commandMode()) return false; // return immediately
sendAT(GF("EE"), 2); // Set security to WPA2
if (waitResponse() != 1) goto fail;
sendAT(GF("ID"), ssid);
if (waitResponse() != 1) goto fail;
sendAT(GF("PK"), pwd);
if (waitResponse() != 1) goto fail;
writeChanges();
exitCommand();
return true;
fail:
exitCommand();
return false;
}
bool networkDisconnect() {
if (!commandMode()) return false; // return immediately
sendAT(GF("NR0")); // Do a network reset in order to disconnect
int res = (1 == waitResponse(5000));
writeChanges();
exitCommand();
return res;
}
String getLocalIP() {
if (!commandMode()) return ""; // Return immediately
sendAT(GF("MY"));
String IPaddr; IPaddr.reserve(16);
// wait for the response - this response can be very slow
IPaddr = readResponse(30000);
exitCommand();
IPaddr.trim();
return IPaddr;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
if (!commandMode()) return false; // Return immediately
sendAT(GF("AN"), apn); // Set the APN
waitResponse();
writeChanges();
exitCommand();
return true;
}
bool gprsDisconnect() {
if (!commandMode()) return false; // return immediately
sendAT(GF("AM1")); // Cheating and disconnecting by turning on airplane mode
int res = (1 == waitResponse(5000));
writeChanges();
sendAT(GF("AM0")); // Airplane mode off
waitResponse(5000);
writeChanges();
exitCommand();
return res;
}
bool isGprsConnected() {
return isNetworkConnected();
}
/*
* Messaging functions
*/
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sendSMS(const String& number, const String& text) {
if (!commandMode()) return false; // Return immediately
sendAT(GF("IP"), 2); // Put in text messaging mode
if (waitResponse() !=1) goto fail;
sendAT(GF("PH"), number); // Set the phone number
if (waitResponse() !=1) goto fail;
sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriage return)
if (waitResponse() !=1) goto fail;
if (!writeChanges()) goto fail;
exitCommand();
streamWrite(text);
stream.write((char)0x0D); // close off with the carriage return
return true;
fail:
exitCommand();
return false;
}
/*
* Location functions
*/
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery functions
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) {
String strIP; strIP.reserve(16);
unsigned long startMillis = millis();
bool gotIP = false;
// XBee's require a numeric IP address for connection, but do provide the
// functionality to look up the IP address from a fully qualified domain name
while (!gotIP && millis() - startMillis < 45000L) // the lookup can take a while
{
sendAT(GF("LA"), host);
while (stream.available() < 4) {}; // wait for any response
strIP = stream.readStringUntil('\r'); // read result
strIP.trim();
DBG("<<< ", strIP);
if (!strIP.endsWith(GF("ERROR"))) gotIP = true;
delay(100); // short wait before trying again
}
if (gotIP) { // No reason to continue if we don't know the IP address
IPAddress ip = TinyGsmIpFromString(strIP);
return modemConnect(ip, port, mux, ssl);
}
else return false;
}
bool modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false) {
bool success = true;
String host; host.reserve(16);
host += ip[0];
host += ".";
host += ip[1];
host += ".";
host += ip[2];
host += ".";
host += ip[3];
if (ssl) {
sendAT(GF("IP"), 4); // Put in SSL over TCP communication mode
success &= (1 == waitResponse());
} else {
sendAT(GF("IP"), 1); // Put in TCP mode
success &= (1 == waitResponse());
}
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());
return success;
}
int modemSend(const void* buff, size_t len, uint8_t mux = 0) {
stream.write((uint8_t*)buff, len);
stream.flush();
return len;
}
bool modemGetConnected(uint8_t mux = 0) {
if (!commandMode()) return false;
sendAT(GF("AI"));
int res = waitResponse(GF("0"));
exitCommand();
return 1 == res;
}
public:
/* Utilities */
template<typename T>
void streamWrite(T last) {
stream.print(last);
}
template<typename T, typename... Args>
void streamWrite(T head, Args... tail) {
stream.print(head);
streamWrite(tail...);
}
void streamClear(void) {
TINY_GSM_YIELD();
while (stream.available()) { stream.read(); }
}
bool commandMode(int retries = 2) {
int triesMade = 0;
bool success = false;
streamClear(); // Empty everything in the buffer before starting
while (!success and triesMade < retries) {
// Cannot send anything for 1 "guard time" before entering command mode
// Default guard time is 1s, but the init fxn decreases it to 250 ms
delay(guardTime);
streamWrite(GF("+++")); // enter command mode
DBG("+++");
success = (1 == waitResponse(guardTime*2));
triesMade ++;
}
return success;
}
bool writeChanges(void) {
sendAT(GF("WR")); // Write changes to flash
if (1 != waitResponse()) return false;
sendAT(GF("AC")); // Apply changes
if (1 != waitResponse()) return false;
return true;
}
void exitCommand(void) {
sendAT(GF("CN")); // Exit command mode
waitResponse();
}
String readResponse(uint32_t timeout = 1000) {
TINY_GSM_YIELD();
unsigned long startMillis = millis();
while (!stream.available() && millis() - startMillis < timeout) {};
String res = stream.readStringUntil('\r'); // lines end with carriage returns
res.trim();
DBG("<<< ", res);
return res;
}
template<typename... Args>
void sendAT(Args... cmd) {
streamWrite("AT", cmd..., GSM_NL);
stream.flush();
TINY_GSM_YIELD();
//DBG("### AT:", cmd...);
}
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
String r4s(r4); r4s.trim();
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(16); // Should never be getting much here for the XBee
int index = 0;
unsigned long startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
} else if (r2 && data.endsWith(r2)) {
index = 2;
goto finish;
} else if (r3 && data.endsWith(r3)) {
index = 3;
goto finish;
} else if (r4 && data.endsWith(r4)) {
index = 4;
goto finish;
} else if (r5 && data.endsWith(r5)) {
index = 5;
goto finish;
}
}
} while (millis() - startMillis < timeout);
finish:
if (!index) {
data.trim();
data.replace(GSM_NL GSM_NL, GSM_NL);
data.replace(GSM_NL, "\r\n ");
if (data.length()) {
DBG("### Unhandled:", data, "\r\n");
} else {
DBG("### NO RESPONSE!\r\n");
}
} else {
data.trim();
data.replace(GSM_NL GSM_NL, GSM_NL);
data.replace(GSM_NL, "\r\n ");
if (data.length()) {
// DBG("<<< ", data);
}
}
return index;
}
uint8_t waitResponse(uint32_t timeout,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
String data;
return waitResponse(timeout, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
return waitResponse(1000, r1, r2, r3, r4, r5);
}
public:
Stream& stream;
protected:
int guardTime;
XBeeType beeType;
GsmClient* sockets[TINY_GSM_MUX_COUNT];
};
#endif

View File

@@ -0,0 +1,197 @@
/**
* @file TinyGsmCommon.h
* @author Volodymyr Shymanskyy
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
*/
#ifndef TinyGsmCommon_h
#define TinyGsmCommon_h
#if defined(SPARK) || defined(PARTICLE)
#include "Particle.h"
#elif defined(ARDUINO)
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#endif
#if defined(ARDUINO_DASH)
#include <ArduinoCompat/Client.h>
#else
#include <Client.h>
#endif
#include <TinyGsmFifo.h>
#ifndef TINY_GSM_YIELD
#define TINY_GSM_YIELD() { delay(0); }
#endif
#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type")))
#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented")))
#if defined(__AVR__)
#define TINY_GSM_PROGMEM PROGMEM
typedef const __FlashStringHelper* GsmConstStr;
#define GFP(x) (reinterpret_cast<GsmConstStr>(x))
#define GF(x) F(x)
#else
#define TINY_GSM_PROGMEM
typedef const char* GsmConstStr;
#define GFP(x) x
#define GF(x) x
#endif
#ifdef TINY_GSM_DEBUG
namespace {
template<typename T>
static void DBG_PLAIN(T last) {
TINY_GSM_DEBUG.println(last);
}
template<typename T, typename... Args>
static void DBG_PLAIN(T head, Args... tail) {
TINY_GSM_DEBUG.print(head);
TINY_GSM_DEBUG.print(' ');
DBG_PLAIN(tail...);
}
template<typename... Args>
static void DBG(Args... args) {
TINY_GSM_DEBUG.print(GF("["));
TINY_GSM_DEBUG.print(millis());
TINY_GSM_DEBUG.print(GF("] "));
DBG_PLAIN(args...);
}
}
#else
#define DBG(...)
#endif
template<class T>
const T& TinyGsmMin(const T& a, const T& b)
{
return (b < a) ? b : a;
}
template<class T>
const T& TinyGsmMax(const T& a, const T& b)
{
return (b < a) ? a : b;
}
template<class T>
uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200)
{
static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 };
for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) {
uint32_t rate = rates[i];
if (rate < minimum || rate > maximum) continue;
DBG("Trying baud rate", rate, "...");
SerialAT.begin(rate);
delay(10);
for (int i=0; i<3; i++) {
SerialAT.print("AT\r\n");
String input = SerialAT.readString();
if (input.indexOf("OK") >= 0) {
DBG("Modem responded at rate", rate);
return rate;
}
}
}
return 0;
}
static inline
IPAddress TinyGsmIpFromString(const String& strIP) {
int Parts[4] = {0, };
int Part = 0;
for (uint8_t i=0; i<strIP.length(); i++) {
char c = strIP[i];
if (c == '.') {
Part++;
if (Part > 3) {
return IPAddress(0,0,0,0);
}
continue;
} else if (c >= '0' && c <= '9') {
Parts[Part] *= 10;
Parts[Part] += c - '0';
} else {
if (Part == 3) break;
}
}
return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]);
}
static inline
String TinyGsmDecodeHex7bit(String &instr) {
String result;
byte reminder = 0;
int bitstate = 7;
for (unsigned i=0; i<instr.length(); i+=2) {
char buf[4] = { 0, };
buf[0] = instr[i];
buf[1] = instr[i+1];
byte b = strtol(buf, NULL, 16);
byte bb = b << (7 - bitstate);
char c = (bb + reminder) & 0x7F;
result += c;
reminder = b >> bitstate;
bitstate--;
if (bitstate == 0) {
char c = reminder;
result += c;
reminder = 0;
bitstate = 7;
}
}
return result;
}
static inline
String TinyGsmDecodeHex8bit(String &instr) {
String result;
for (unsigned i=0; i<instr.length(); i+=2) {
char buf[4] = { 0, };
buf[0] = instr[i];
buf[1] = instr[i+1];
char b = strtol(buf, NULL, 16);
result += b;
}
return result;
}
static inline
String TinyGsmDecodeHex16bit(String &instr) {
String result;
for (unsigned i=0; i<instr.length(); i+=4) {
char buf[4] = { 0, };
buf[0] = instr[i];
buf[1] = instr[i+1];
char b = strtol(buf, NULL, 16);
if (b) { // If high byte is non-zero, we can't handle it ;(
#if defined(TINY_GSM_UNICODE_TO_HEX)
result += "\\x";
result += instr.substring(i, i+4);
#else
result += "?";
#endif
} else {
buf[0] = instr[i+2];
buf[1] = instr[i+3];
b = strtol(buf, NULL, 16);
result += b;
}
}
return result;
}
#endif

View File

@@ -0,0 +1,136 @@
#ifndef TinyGsmFifo_h
#define TinyGsmFifo_h
template <class T, unsigned N>
class TinyGsmFifo
{
public:
TinyGsmFifo()
{
clear();
}
void clear()
{
_r = 0;
_w = 0;
}
// writing thread/context API
//-------------------------------------------------------------
bool writeable(void)
{
return free() > 0;
}
int free(void)
{
int s = _r - _w;
if (s <= 0)
s += N;
return s - 1;
}
bool put(const T& c)
{
int i = _w;
int j = i;
i = _inc(i);
if (i == _r) // !writeable()
return false;
_b[j] = c;
_w = i;
return true;
}
int put(const T* p, int n, bool t = false)
{
int c = n;
while (c)
{
int f;
while ((f = free()) == 0) // wait for space
{
if (!t) return n - c; // no more space and not blocking
/* nothing / just wait */;
}
// check free space
if (c < f) f = c;
int w = _w;
int m = N - w;
// check wrap
if (f > m) f = m;
memcpy(&_b[w], p, f);
_w = _inc(w, f);
c -= f;
p += f;
}
return n - c;
}
// reading thread/context API
// --------------------------------------------------------
bool readable(void)
{
return (_r != _w);
}
size_t size(void)
{
int s = _w - _r;
if (s < 0)
s += N;
return s;
}
bool get(T* p)
{
int r = _r;
if (r == _w) // !readable()
return false;
*p = _b[r];
_r = _inc(r);
return true;
}
int get(T* p, int n, bool t = false)
{
int c = n;
while (c)
{
int f;
for (;;) // wait for data
{
f = size();
if (f) break; // free space
if (!t) return n - c; // no space and not blocking
/* nothing / just wait */;
}
// check available data
if (c < f) f = c;
int r = _r;
int m = N - r;
// check wrap
if (f > m) f = m;
memcpy(p, &_b[r], f);
_r = _inc(r, f);
c -= f;
p += f;
}
return n - c;
}
private:
int _inc(int i, int n = 1)
{
return (i + n) % N;
}
T _b[N];
int _w;
int _r;
};
#endif