# quectel-bg77 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](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html) 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 ```rust 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, at_timer, modem_timer, }; // 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( bg77_hal, radio_config, 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 = "192.168.1.1:8080".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 bg77.close(socket).unwrap(); ``` ## Examples There are a few examples which can be run on appropriate hardware. This driver was initially developed alongside the [Sensing Puck](https://www.silicon-economy.com/neue-open-source-hardware-sensing-puck-laesst-sich-einfach-integrieren/) 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` ## Features - `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. ## License Open Logistics Foundation License\ Version 1.3, January 2023 See the LICENSE file in the top-level directory. ## Contact Fraunhofer IML Embedded Rust Group -