Expand description
nRF-Modem
This is a library that provides a high-level async API for the nRF9160 modem.
It can be used with any executor.
Errors and recovery
Dropping LteLink and Gnss (which also include all sockets and GnssStream) can lead to the modem staying active.
There’s an internal mutex that can be locked. Panicking is the only sane reaction to that.
If you have a better idea, please open an issue or PR!
The async deactivate
function is way less likely to go wrong and you’ll get a Result back so you know that something has gone wrong.
If anything does go wrong, has_runtime_state_error()
will return true.
Everything should stay working, but it’s likely that the modem won’t be properly turned off.
This can be recovered by calling the reset_runtime_state()
function when you’ve made sure nothing of the modem is used anymore.
Setup
There are a couple of things you must do to be able to use the library.
First of which, make sure to have the llvm-tools
installed.
This can be done using rustup component add llvm-tools-preview
.
The library also needs some libc
functions.
The best way to import them is with tinyrlibc.
As of writing the newest release is 0.3.0
. This version does not include a needed API,
so it’s better to include the latest master branch or any newer released version.
This library has been tested with modem firmware version 1.3.4
but might work with earlier versions.
When this library starts to require a newer version, then that will be seen as a breaking change.
But it’s easy to miss something, so this is a ‘best effort’ guarantee only.
Nonsecure
Nordic has made it so that the modem can only be used when in the nonsecure context. Make sure you are in that context by using e.g. the SPM.
Interrupts
The EGU1
and IPC
interrupts must be routed to the modem software.
// Interrupt Handler for LTE related hardware. Defer straight to the library.
#[interrupt]
#[allow(non_snake_case)]
fn IPC() {
nrf_modem::ipc_irq_handler();
}
let mut cp = unwrap!(cortex_m::Peripherals::take());
// Enable the modem interrupts
unsafe {
NVIC::unmask(pac::Interrupt::IPC);
cp.NVIC.set_priority(pac::Interrupt::IPC, 0 << 5);
}
Power
The DC/DC converter is automatically enabled for you when the library is initialized. This is required for certified operation of the modem.
Initialization
Now it’s time to initialize the library. Here you can make a selection for the connectivity for the modem:
nrf_modem::init(SystemMode {
lte_support: true,
lte_psm_support: true,
nbiot_support: true,
gnss_support: true,
preference: ConnectionPreference::None,
})
.await
.unwrap();
Now the library is ready to be used.
AT Commands
let response = nrf_modem::send_at::<64>("AT+CGMI").await.unwrap();
assert_eq!(response, "AT+CGMI\n\rNordic Semiconductor ASA\n\rOK\n\r");
DNS request
let google_ip = nrf_modem::get_host_by_name("www.google.com").await.unwrap();
Tcp connection
let stream = nrf_modem::TcpStream::connect(SocketAddr::from((google_ip, 80))).await.unwrap();
stream
.write("GET / HTTP/1.0\nHost: google.com\r\n\r\n".as_bytes())
.await
.unwrap();
let mut buffer = [0; 1024];
let received = stream.receive(&mut buffer).await.unwrap();
println!("Google response: {}", core::str::from_utf8(received).unwrap());
// Drop the stream async (normal Drop is ok too, but that's blocking)
stream.deactivate().await.unwrap();
Udp socket
let socket =
nrf_modem::UdpSocket::bind(SocketAddr::from_str("0.0.0.0:53").unwrap())
.await
.unwrap();
// Do a DNS request
socket
.send_to(
&[
0xdb, 0x42, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77,
0x77, 0x77, 0x0C, 0x6E, 0x6F, 0x72, 0x74, 0x68, 0x65, 0x61, 0x73, 0x74, 0x65, 0x72,
0x6E, 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01,
],
SocketAddr::from_str("8.8.8.8:53").unwrap(),
)
.await
.unwrap();
let (response, source_addr) = socket.receive_from(&mut buffer).await.unwrap();
println!("Result: {:X}", response);
println!("Source: {}", source_addr);
Re-exports
pub use no_std_net;
pub use nrfxlib_sys;
Modules
- FFI (Foreign Function Interface) Module
Structs
- An async stream of all AT notifications.
- A token you can pass to certain async functions that let you cancel them.
- A GNSS objects that controls the GPS of the modem.
- An async stream of gnss data.
- An object that keeps the modem connected. As long as there is an instance, the modem will be kept on. The drop function disables the modem if there is no link left.
- The memory layout used by the modem library.
- An owned read half of a TCP stream
- An owned write half of a TCP stream
- An owned receive half of a udp socket
- An owned send half of a udp socket
- A struct holding both number and message with can be send as an SMS
- Identifies which radios in the nRF9160 should be active
- A borrowed read half of a TCP stream
- A TCP stream that is connected to another endpoint
- A borrowed write half of a TCP stream
- A borrowed receive half of a udp socket
- A borrowed send half of a udp socket
- A socket that sends and receives UDP messages
Enums
- The preference the modem will have for connecting to the mobile network
- The global error type of this crate
- An enum containing all possible GNSS data types
- Use these values to select which power save mode GNSS should use.
- Used to select which sleep timing source GNSS uses.
Functions
- Enable GNSS on the nRF9160-DK (PCA10090NS)
- Get the IP address that corresponds to the given hostname.
- Get the IP address that corresponds to the given hostname.
- Returns true when the runtime has detected that its state may not represent the actual modem state. This means that the modem may remain active while the runtime thinks it has turned it off.
- Start the NRF Modem library
- Start the NRF Modem library with a manually specified memory layout
- IPC code now lives outside
lib_modem
, so call our IPC handler function. - Resets the runtime state by forcing the modem to be turned off and resetting the state back to 0.
- Send an AT command to the modem.
- Sends a blocking AT command. The non-blocking variants should be preferred, but sometimes it’s necessary to call this in e.g. a drop function.
- Same as send_at, but send a byte array (that must contain ascii chars) instead