A C++17 library for the Raspberry Pi Pico that drives a SIMCom SIM7080G LTE Cat-M / NB-IoT modem over UART via AT commands.
Built from a real GPS/LTE car-tracker project. The library covers the full connectivity lifecycle: modem startup, network attachment, PDP context activation, MQTT publish/subscribe, and TLS certificate upload to modem flash.
- Interrupt-driven UART receive buffer with unsolicited result code (URC) dispatch
- AT command helper that waits for final results (
OK,ERROR,+CME,+CMS) instead of returning on partial response substrings - Prompt/payload command helper for MQTT, HTTP body upload, SMS, TCP sends and modem file uploads
- Basic modem identity commands (
ATI,CGMI,CGMM,CGMR,CGSN,GCAP) - SIM identity/status helpers (
CPIN,CIMI,CCID, optional PIN unlock) - LTE Cat-M / NB-IoT mode selection and full network attachment sequence (SIM PIN check, signal quality, GPRS attachment polling, APN, PDP context)
- 3GPP PDP helpers (
CGATT,CGDCONT,CGACT,CGPADDR,CGAUTH) - App Network helpers (
CNCFG,CNACT, typedCNACT?state) - MQTT configure, connect (with retry), publish, subscribe, unsubscribe, state and disconnect
- HTTP(S) command wrappers (
SHCONF,SHSSL,SHCONN,SHBOD,SHREQ, length-basedSHREAD) - TLS file upload and SSL context configuration (
CFS*,CSSLCFG) - GNSS power/start/info parsing and wait-for-fix helper (
CGNS*) - SMS text-mode send/list/read/delete helpers
- Thin TCP/UDP wrappers for the
CA*command family - Power, reboot, slow-clock, PSM and eDRX wrappers
- Battery status reading (charge state, level %, voltage)
- Comprehensive
AT+CPSI?response parser — handles GSM and LTE variants, missing fields represented viastd::optional - Modular CMake build: three static libraries (
at_commands→sim7080g→ app)
| Signal | GPIO | Note |
|---|---|---|
| Modem UART TX | GP0 | Pico → modem RXD |
| Modem UART RX | GP1 | Modem TXD → Pico |
| Modem power key | GP14 | 2.5 s active-high pulse to boot module |
| Debug stdio TX | GP4 | UART1 — connect to your debug probe/USB |
| Debug stdio RX | GP5 | UART1 |
| LED | GP25 | Onboard Pico LED |
All modem pins are configurable through SIM7080GConfig before calling
sim7080g_init(config).
Pico SIM7080G breakout
──────────────── ──────────────────
GP0 (UART0 TX) ──────► RXD
GP1 (UART0 RX) ◄────── TXD
GP14 (GPIO OUT) ──────► PWRKEY
3V3 ──────► VCC (verify your breakout — some require 4.2 V / 5 V)
GND ────── GND
| Dependency | Version | How |
|---|---|---|
| Raspberry Pi Pico SDK | ≥ 2.1.0 | Set PICO_SDK_PATH or use the VS Code extension |
| nlohmann/json | 3.x | Single-header bundled in json/json.hpp |
git clone https://github.com/BRobin55/sim7080g_showcase
cd sim7080g_showcase
cmake -S . -B build -DPICO_BOARD=pico
cmake --build build --parallelFlash build/sim7080g_showcase.uf2 to your Pico (hold BOOTSEL while connecting USB).
If the Pico SDK is not on
PATH, pass-DPICO_SDK_PATH=/path/to/pico-sdkto the first cmake command or set the environment variablePICO_SDK_PATH.
sim7080g_showcase/
├── sim7080g/ # Modem library (libsim7080g.a)
│ ├── SIM7080G.h/.cpp # UART init, IRQ buffer, URC dispatch
│ ├── AT.h/.cpp # AT command send/receive with timeout
│ ├── Network.h/.cpp # High-level network lifecycle
│ ├── MQTT.h/.cpp # MQTT helpers (config, connect, pub, sub)
│ ├── FileSystem.h/.cpp # TLS credential file upload
│ └── at_commands/ # Low-level AT wrappers (libat_commands.a)
│ ├── basic.h/.cpp # AT / ATE / ATI / CGMI / CGSN / GCAP
│ ├── battery.h/.cpp # AT+CBC — battery status
│ ├── file_system.h/.cpp # AT+CFSTERM / CFSINIT / CFSWFILE
│ ├── gnss.h/.cpp # AT+CGNSPWR / CGNSINF / starts / waitForFix
│ ├── http.h/.cpp # AT+SHCONF / SHBOD / SHREQ / SHREAD / SHDISC
│ ├── mqtt.h/.cpp # AT+SMCONF / SMSSL / SMCONN / SMPUB / SMSUB / SMDISC
│ ├── network.h/.cpp # AT+CFUN / CNMP / CMNB / CPIN / CGATT / CPSI / CNACT / CNCFG
│ ├── parser.h/.cpp # quoted CSV and response-line helpers
│ ├── pdp.h/.cpp # AT+CGATT / CGDCONT / CGACT / CGPADDR / CGAUTH
│ ├── power.h/.cpp # boot probe, power cycle, PSM/eDRX, reboot
│ ├── sim.h/.cpp # CPIN / CIMI / CCID / CNUM
│ ├── sms.h/.cpp # CMGF / CMGS / CMGL / CMGR / CMGD
│ ├── ssl.h/.cpp # CSSLCFG generic SSL context helpers
│ └── tcp_udp.h/.cpp # CA* thin TCP/UDP wrappers
├── json/ # JSON payload helper (libjson.a)
│ ├── json.hpp # nlohmann/json (bundled single-header)
│ ├── j.h # createMqttPayload declaration
│ └── json.cpp # Payload builder
├── sim7080g_showcase.cpp # Example application
└── CMakeLists.txt
Dependency order: at_commands ← sim7080g ← application
#include "SIM7080G.h"
#include "power.h"
// Default config: UART0, GP0/GP1, power key GP14, 115200 baud
sim7080g_init();
// Register a handler for unsolicited result codes (e.g. MQTT messages)
sim7080g_set_urc_handler([](const std::string &line) {
if (line.find("+SMSUB:") != std::string::npos)
printf("MQTT message: %s\n", line.c_str());
});
check_start(); // probe, power-cycle if needed, retry up to 10×#include "Network.h"
set_network(LTE_ONLY, CAT_M); // AT+CNMP / AT+CMNB
check_network(); // SIM PIN, signal, GPRS, APN, PDP activate#include "MQTT.h"
#include "json/j.h"
MqttConnectionConfig cfg;
cfg.host = "your-broker.example.com";
cfg.port = "1883";
cfg.client_id = "pico-001";
cfg.use_tls = false;
mqttSetUpAndConnect(cfg); // configure + connect, up to 10 retries
std::string payload = createMqttPayload(STATE, "online", cfg.client_id);
// → {"type":"state","data":"online","device_id":"pico-001"}
mqttPublishMessage("device/pico-001/state", payload);
mqttSubscribeToTopic("device/pico-001/cmd");while (true) {
process_uart_messages(); // dispatch any buffered URC lines
sleep_ms(100);
}The SIM7080G stores TLS material in its own flash. The library uploads it
over AT commands using AT+CFSWFILE.
Credential headers are excluded from version control by .gitignore.
Use sim7080g/ssl_files/credentials.example.h as the template:
// credentials.h (never commit this file)
static const unsigned char root_ca[] = { /* DER bytes */ };
static const size_t root_ca_len = sizeof(root_ca);
static const unsigned char client_cert[] = { /* DER bytes */ };
static const size_t client_cert_len = sizeof(client_cert);
static const unsigned char private_key[] = { /* DER bytes */ };
static const size_t private_key_len = sizeof(private_key);Then pass them to loadSSLFiles():
#include "FileSystem.h"
#include "ssl_files/credentials.h"
SIM7080GTlsCredentials creds;
creds.root_ca = root_ca;
creds.root_ca_size = root_ca_len;
creds.client_cert = client_cert;
creds.client_cert_size = client_cert_len;
creds.private_key = private_key;
creds.private_key_size = private_key_len;
loadSSLFiles(creds);Set kUseTls = true and point MqttConnectionConfig::port at 8883 (or your
broker's TLS port).
sim7080g_showcase.cpp walks through the complete workflow end-to-end.
Edit the constants at the top before flashing:
constexpr char kMqttHost[] = "broker.example.com"; // ← your broker
constexpr char kMqttPort[] = "1883";
constexpr char kMqttClientId[] = "pico-sim7080g-demo";
constexpr char kPublishTopic[] = "sim7080g/demo/state";
constexpr char kSubscribeTopic[] = "sim7080g/demo/config";
constexpr bool kUseTls = false;Flow:
stdio_init_all()— debug output on UART1 (GP4/GP5)- LED blink — visible boot indicator
sim7080g_init()+check_start()— probe modem, power-cycle if silentget_battery_status()— log charge state and voltage- Safety gate: exits early if
kMqttHoststill containsexample.com set_network(LTE_ONLY, CAT_M)— configure radiocheck_network()— wait for attachment and activate PDPmqttSetUpAndConnect()— connect to broker- Publish
{"type":"state","data":"online",...} mqttSubscribeToTopic()— listen for inbound commands- Main loop:
process_uart_messages()every 3 s dispatches URC lines
Expected serial output (115200 baud on GP4/GP5):
Start
Charge Status: 0
Battery Level: 87%
Voltage: 4102 mV
AT+CNMP=38 -> OK
AT+CMNB=1 -> OK
...
AT+SMCONN -> OK
AT+SMPUB="sim7080g/demo/state",... -> OK
AT+SMSUB="sim7080g/demo/config",0 -> OK
Key AT commands used by this library:
| AT command | Purpose |
|---|---|
AT+CFUN |
Phone functionality (min / full / reset) |
AT+CNMP |
Preferred network mode (GSM / LTE / Auto) |
AT+CMNB |
Cat-M / NB-IoT selection |
AT+CPIN |
SIM PIN status / unlock |
AT+CSQ |
Signal quality report (RSSI / BER) |
AT+CGATT |
GPRS attachment status |
AT+CGDCONT |
3GPP PDP context configuration |
AT+CGACT |
3GPP PDP context activation |
AT+CGPADDR |
Read PDP address |
AT+CPSI |
UE system information (operator, band, RSRP) |
AT+CGNAPN |
Read network-provided APN |
AT+CNCFG |
PDP context configuration |
AT+CNACT |
Application network activation |
AT+SHCONF |
HTTP parameter configuration |
AT+SHBOD |
HTTP request body upload |
AT+SHREQ |
HTTP request |
AT+SHREAD |
HTTP response read |
AT+SMCONF |
MQTT parameter configuration |
AT+SMCONN |
MQTT connect |
AT+SMPUB |
MQTT publish |
AT+SMSUB |
MQTT subscribe |
AT+SMDISC |
MQTT disconnect |
AT+CSSLCFG |
SSL/TLS parameter configuration |
AT+SMSSL |
Bind SSL context to MQTT |
AT+CFSINIT |
Initialize modem file system buffer |
AT+CFSWFILE |
Write file to modem flash |
AT+CGNSPWR |
GNSS power |
AT+CGNSINF |
GNSS fix/status information |
AT+CMGF |
SMS format |
AT+CMGS |
SMS text send |
AT+CAOPEN |
TCP/UDP open |
AT+CASEND |
TCP/UDP send |
AT+CBC |
Battery and charge status |
AT+CPOWD |
Power down modem |
AT+CREBOOT |
Reboot modem |
AT+CSCLK |
Slow clock / sleep configuration |
AT+CPSMS |
3GPP Power Saving Mode |
AT+CEDRXS |
eDRX configuration |
Full AT command reference: SIM7080G AT Command Manual
- Unit tests with a mocked UART transport
- Production reconnect / exponential-backoff state machine
- Watchdog / health-monitor integration
- Complete voice, FTP, CoAP, SIM Toolkit or vendor-special command coverage
MIT — see LICENSE.