coddingtonbear / arduino-async-modem

Asynchronously interact with your SIM7000 LTE modem
8 stars 3 forks source link

Arduino-Async-Modem

If you've ever used one of the many modem-handling libraries that exist, you're familiar with the frustration that is waiting for a response from a long-running command. Between sending your command and receiving a response (or worse -- that command timing out), your program is halted, and your microcontroller is wasiting valuable cycles. This library aims to fix that problem by allowing you to queue commands that will be asynchronously sent to your device without blocking your microcontroller loop.

Supported Devices

Examples

Initialization

The setup procedure for an LTE modem involves sending a series of commands and waiting for their responses. Using most libraries, this would mean that your microcontroller would be halted waiting to compare the returned responses with what it was expecting. Using AsyncModem, setup will complete immediately and the LTE modem will be initialized automatically behind the scenes:

#include <AsyncModem.h>

AsyncModem::SIM7000 lte = AsyncModem::SIM7000();

void setup() {
    lte.begin(&Serial1);  // If your modem is on a different serial port, use that instead
    lte.enableGPRS("hologram");
}

void loop() {
    lte.loop();
}

Sending an SMS

Executing the below will queue relevant commands for dispatching the SMS message:

lte.sendSMS("+15555555555", "My Message");

If you would like to display a message when the message is sent (or fails to send), you can pass callacks to do so:

lte.sendSMS(
    "+15555555555",
    "My Message",
    [](MatchState ms) {
        Serial.println("Sent :-)");
    },
    [](ManagedSerialDevice::Command* cmd) {
        Serial.println("Failed to send :-(");
    },
);

Sending arbitrary commands

Say that you want to turn on GPS; on the SIM7000, that is controlled by sending the command AT+CGNSPWR=1; you can send that command by running:

lte.execute("AT+CGNSWPR=1")

But what if you wanted to make sure it was successful? Looking at the docs, this can return either "OK" or "ERROR". To help out with that, execute accepts a few more optional parameters:

For example; to first turn on GPS and then, if it's successful, fetch the latest GPS coordinates, you can write this call:

float latitude = 0;
float longitude = 0;

lte.execute(
    "AT+CGNSWPR=1",
    "OK",
    [&lte,&latitude,&longitude](MatchState ms) {
        lte.AsyncExecute(
            "AT+CGNSINF",
            "%+CGNSINF:[%d]+,[%d]+,[%d]+,([%d.%+%-]+),([%d.%+%-]+),.*",
            [](MatchState ms) {
                char latitudeBuffer[12];
                char longitudeBuffer[12];
                ms.GetCapture(latitudeBuffer, 0);
                ms.GetCapture(longitudeBuffer, 0);

                latitude = atof(latitudeBuffer);
                longitude = atof(latitudeBuffer);

                Serial.print("Latitude: ");
                Serial.println(latitude);
                Serial.print("Longitude: ");
                Serial.println(longitude);
            },
            [](Command*) {
                "Did not receive the expected response from the LTE modem."
            }
        )
    },
    [](Command*) {
        Serial.println("Failed to turn on GPS.")
    }
)

For more options regarding how to execute and chain together commands, see the documentation for Arduino Async Duplex.

Requirements