created_at2024-02-16 15:40:05.554623
updated_at2024-02-28 08:36:26.962204
descriptionDriver for Quectel's BG77 and BG770 eMTC and NB-IoT Modems
Fraunhofer IML Embedded Rust Group (embedded-rust-iml-user)




This crate implements a driver for the Quectel BG77 and BG770 eMTC and NB-IoT modems using the embedded-hal traits for the underlying hardware abstractions and implementing the embedded-nal traits for users of this library. Currently, TcpClientStack and UdpClientStack are supported for both modems. From the Dns trait, only the get_host_by_name requesting only IPv4 addresses is supported. Thus far, this has only been working for BG77. To select which modem is used, activate either the bg77 or the bg770 feature.

The driver supports up to 12 sockets at the same time and implements Drop/RAII on the socket handle types to prevent resource leaks. This is accomplished by using the interior mutability pattern: All socket handles hold a reference to the driver type which owns the hardware. Whenever they need to access the hardware, the driver is mutably borrowed (checked at runtime). This always works because no mutable borrow outlives any method call.

Currently, AT commands are not run partially which would complicate the interior state handling and increase the number of possible error causes, e.g. when multiple sockets try to access the modem at the same time. As a consequence, all method calls are effectively blocking. The only exception is receive which returns nb::Error::WouldBlock if no data at all is available. For the send method, this is not a huge problem because it only blocks until the data is transferred to the modem (the actual transmission happens in the background then). Only connecting the modem to the network blocks for a long time.

Usage Example

use embedded_nal::TcpClientStack;

// The hardware abstraction used for the Bg77Hal must implement the respective embedded-hal
// traits
let bg77_hal = quectel_bg77::Bg77Hal {
    pin_enable: bg77_enable,
    pin_reset_n: bg77_reset_n,
    pin_pwrkey: bg77_pwrkey,
    tx: bg77_tx,
    rx: bg77_rx,
// choose which radio technologies and bands to use
let radio_config = quectel_bg77::RadioConfig::OnlyNbiot {
    bands: quectel_bg77::NbiotBand::B8.into(),
let mut bg77 = quectel_bg77::Bg77Driver::new(
    Some("iot.1nce.net"),                   // configure APN
    Some("26201"),                          // configure operator
    core::time::Duration::from_secs(60),    // configure connection/attach timeout
    core::time::Duration::from_millis(500), // configure internal safety delays
    core::time::Duration::from_millis(20),  // configure internal safety delays
let mut bg77 = quectel_bg77::Bg77ClientStack::new(&mut bg77);
// request a new socket handle, this only fails if all sockets are already in use
let mut socket = bg77.socket().unwrap();
// turn on the modem and try to attach to the network; generally, this takes the most time
let socket_address: embedded_nal::SocketAddr = "".parse().unwrap();
nb::block!(bg77.connect(&mut socket, socket_address))?;
// transmit data via the socket
nb::block!(bg77.send(&mut socket, b"Hello, BG77"))?;
// close the socket; when the last socket is closed, this also turns off the modem
// with this driver, this never fails


There are a few examples which can be run on appropriate hardware. This driver was initially developed alongside the Sensing Puck so this was the only supported board in the beginning. Later, support for MotionAI was added. The board in use can be selected by activating either the sensing_puck or the motion2se feature which will automatically activate the right modem feature (bg77 or bg770).

If required, more boards can be added under examples/boards with appropriate features in Cargo.toml. Still, the memory.x file has to be adjusted and possibly the build target, depending on the MCU architecture.

Since only STM32L452-based boards are supported at the moment, an appropriate memory.x is shipped. Therefore, running the examples should be as easy as, e.g.: cargo run --example tcp-client --features sensing_puck --target thumbv7em-none-eabihf. This uses probe-run to flash the firmware.

Unit tests

Since the examples only build for the appropriate architecture, the tests need to be run with the --lib flag: cargo test --lib


  • bg77 / bg770 selects the modem in use
  • sensing_puck / motion2se selects the board for the examples
  • direct-serial-access Enables direct access to the underlying serial port. This should be used for development/debugging only.


Open Logistics Foundation License
Version 1.3, January 2023

See the LICENSE file in the top-level directory.


Fraunhofer IML Embedded Rust Group - embedded-rust@iml.fraunhofer.de

Commit count: 0

cargo fmt