# nRF-Modem
[![crates.io](https://img.shields.io/crates/v/nrf-modem.svg)](https://crates.io/crates/nrf-modem) [![Documentation](https://docs.rs/nrf-modem/badge.svg)](https://docs.rs/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](https://github.com/rust-embedded-community/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.
```rust,ignore
// 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:
```rust,ignore
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
```rust,ignore
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
```rust,ignore
let google_ip = nrf_modem::get_host_by_name("www.google.com").await.unwrap();
```
## Tcp connection
```rust,ignore
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
```rust,ignore
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);
```