Skip to content

Commit

Permalink
Add cellular tutorial. (#451)
Browse files Browse the repository at this point in the history
  • Loading branch information
floitsch authored Nov 2, 2023
1 parent c0eb71a commit c943cb8
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/_images/cellular_tower.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_images/walter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions docs/tutorials/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Shushing from "../_images/shushing_face.svg";
import Supabase from "../_images/supabase_logo.svg";
import AwsIotCore from "../_images/aws_iot_core.png";
import Ota from "../_images/ota.png";
import CellTower from "../_images/cellular_tower.svg";

# Tutorials

Expand Down Expand Up @@ -307,6 +308,18 @@ Connect to a BLE device.
## Network
Get to know about how to use the network capabilities of your device.

<Boxes>
<Box title="Cellular" to="network/cellular">
<NonZoomableImage
src={CellTower}
width="70%"
alt="Cellular Tower Logo."
/>

Connect to the internet using a cellular modem.
</Box>
</Boxes>

<Boxes>
<Box title="HTTP" to="network/http">
<NonZoomableImage
Expand Down
211 changes: 211 additions & 0 deletions docs/tutorials/network/cellular.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import Walter from "../../_images/walter.png";

# Cellular Connectivity
In this tutorial we will learn how to use an ESP32 board with a modem
to connect to the internet.

We are using the [Walter](https://www.quickspot.io/) device, which is
an open-hardware ESP32-S3 board with a Sequans GM02SP modem.

<img
src={Walter}
alt="Walter"
style="width: 300px; float: right; margin-left: 20px;"
/>

## Prerequisites
We assume that you have set up your development environment as described
in [the IDE tutorial](../../setup/ide).

We also assume that you have flashed your device with Jaguar and that
you are familiar with running Toit programs on it.
If not, have a look at the [Hello world](../../setup/firstprogram) tutorial.

Note that the Walter device is an ESP32-S3 board, which requires the
`--chip=esp32s3` flag when flashing.

In later sections we will refer to [containers](../containers) and
[services](../containers/services), but these are not strictly necessary.

We will use HTTP to fetch data from the internet. There are
[multiple](./http) [tutorials](./http-server) on this topic, but you
should be able to follow this tutorial without having read them.

## Packages
Cellular functionality is not part of the core libraries and must be
imported as a package. See the [packages](../../setup/packages)
tutorial for details.

As of writing, all drivers for cellular modems are in the
[cellular](https://pkg.toit.io/package/github.com%2Ftoitware%2Fcellular@v2)
package.

To install it, run the following command:

``` shell
jag pkg install github.com/toitware/cellular@v2
```

We will use the
[http](https://pkg.toit.io/package/github.com%2Ftoitlang%2Fpkg-http@v2)
and the [certificate-roots](https://pkg.toit.io/package/github.com%2Ftoitware%2Ftoit-cert-roots@v1)
packages to fetch data from the internet.

``` shell
jag pkg install github.com/toitlang/pkg-http@v2
jag pkg install github.com/toitware/toit-cert-roots@v1
```

## Code

Start a new Toit program `walter.toit` and watch it with Jaguar.

``` toit
import cellular.modules.sequans.monarch
import http
import encoding.json
import net
import net.cellular
import certificate-roots
RX ::= 14
TX ::= 48
RTS ::= 21
CTS ::= 47
RESET ::= 45
POWER ::= 46
BAUD ::= 115200
main:
// Start the monarch driver/provider.
task --background::
monarch.main
// Establish the connection to the network.
network := cellular.open --name="gm02sp" {
cellular.CONFIG-UART-RX: RX,
cellular.CONFIG-UART-TX: TX,
cellular.CONFIG-UART-CTS: CTS,
cellular.CONFIG-UART-RTS: RTS,
cellular.CONFIG-RESET: [RESET, cellular.CONFIG-ACTIVE-LOW],
cellular.CONFIG-POWER: POWER,
cellular.CONFIG-UART-BAUD-RATE: BAUD,
}
try:
do-network-things network
finally:
network.close
```

The constants for the Walter board can be found in its
[datasheet](https://www.quickspot.io/datasheet/walter_datasheet_v0.4.pdf). The
modem constants are specificed in section 4.1.2 ("Internal Pins").

Even though the modem isn't a "Monarch", but a "GM02SP", we can use the `monarch` driver.
Both are manufactured by Sequans, and use similar AT commands. Eventually, there might be
a more specialized driver for the GM02SP.

The `monarch.main` function installs the driver as a provider so that other code
can use it through a service. We happen to use it from the same process, but that's
not a requirement. In fact, we will see later how the provider can be started in
a different container, so that different programs can have access to the internet
at the same time.

Once the provider is running in the background, we simply use the `cellular.open`
function to establish a connection to the network. It will return a `net.Client`
object that we can pass to code that needs to use the network.

For example, the `do-network-things` function could look as follows:

``` toit
do-network-things network/net.Client:
client := http.Client.tls network
--root-certificates=[certificate-roots.GTS-ROOT-R1]
request := client.get --uri="https://official-joke-api.appspot.com/random_joke"
decoded := json.decode-stream request.body
print decoded["setup"]
print decoded["punchline"]
```

## Container
In our first iteration the cellular provider was started in the same
container as the rest of the code. This is not ideal, as the cellular
connection is then not available to other containers.

We can fix this, by installing the cellular provider in its own container.

Create a new file `cellular.toit` with the following content:

``` toit
import net.cellular
import cellular.modules.sequans.monarch
RX ::= 14
TX ::= 48
RTS ::= 21
CTS ::= 47
RESET ::= 45
POWER ::= 46
BAUD ::= 115200
class WalterCellularProvider extends monarch.MonarchService:
connect client/int config/Map? -> List:
if not config or config.is-empty:
config = {
cellular.CONFIG-UART-RX: RX,
cellular.CONFIG-UART-TX: TX,
cellular.CONFIG-UART-CTS: CTS,
cellular.CONFIG-UART-RTS: RTS,
cellular.CONFIG-RESET: [RESET, cellular.CONFIG-ACTIVE-LOW],
cellular.CONFIG-POWER: POWER,
cellular.CONFIG-UART-BAUD-RATE: BAUD,
}
return super client config
main:
provider := WalterCellularProvider
provider.install
```

The `WalterCellularProvider` extends the `MonarchService` (which was
installed as part of the `monarch.main` call in the previous section), and
overrides the `connect` method to use the constants for the Walter board.

Note that the name `MonarchService` is a bit misleading, as it is actually
a provider (extending the `CellularServiceProvider` class).

The `main` function then installs the provider, so that containers
can use it.

We can now install this container on the device:

``` shell
jag container install cellular cellular.toit
```

Other containers can now use the cellular provider.

For example, create, and watch the following `cellular-user.toit` program:

``` toit
import net
import net.cellular
do-network-things network/net.Client:
...
main:
network := cellular.open --name="walter" {:}
try:
do-network-things network
finally:
network.close
```

The `do-network-things` function could be the same as in the previous
section (in which case you will have to add a few more imports).

Note that multiple containers can call `cellular.open` at the same time and
access the internet concurrently.
8 changes: 7 additions & 1 deletion tools/package.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
sdk: ^2.0.0-alpha.91
sdk: ^2.0.0-alpha.108
prefixes:
bme280: bme280-driver
cellular: cellular
certificate_roots: toit-cert-roots
cli: pkg-cli
dhtxx: toit-dhtxx
Expand All @@ -25,6 +26,11 @@ packages:
name: bme280
version: 1.0.0
hash: 65b88ac19a5e2b48627a2dbae6d7757ae45c502c
cellular:
url: github.com/toitware/cellular
name: cellular
version: 2.1.10
hash: a2b641e2da596ac1fd58b5fd5ce5e26d5e501c35
mqtt:
url: github.com/toitware/mqtt
name: mqtt
Expand Down
3 changes: 3 additions & 0 deletions tools/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ dependencies:
bme280:
url: github.com/toitware/bme280-driver
version: ^1.0.0
cellular:
url: github.com/toitware/cellular
version: ^2.1.10
certificate_roots:
url: github.com/toitware/toit-cert-roots
version: ^1.6.1
Expand Down
1 change: 1 addition & 0 deletions tools/run_snippets.toit
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ THINGS-THAT-WONT-RUN-ON-SERVER ::= [
"import ble",
"import esp32",
"import system.containers",
"import net.cellular",
]

main args -> none:
Expand Down
14 changes: 14 additions & 0 deletions tutorial_code/cellular/cellular-user.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import net
import net.cellular

main:
network := cellular.open --name="walter" {:}

try:
do-network-things network
finally:
network.close


do-network-things network/net.Client:
// Use the network.
28 changes: 28 additions & 0 deletions tutorial_code/cellular/cellular.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import net.cellular
import cellular.modules.sequans.monarch

RX ::= 14
TX ::= 48
RTS ::= 21
CTS ::= 47
RESET ::= 45
POWER ::= 46
BAUD ::= 115200

class WalterCellularProvider extends monarch.MonarchService:
connect client/int config/Map? -> List:
if not config or config.is-empty:
config = {
cellular.CONFIG-UART-RX: RX,
cellular.CONFIG-UART-TX: TX,
cellular.CONFIG-UART-CTS: CTS,
cellular.CONFIG-UART-RTS: RTS,
cellular.CONFIG-RESET: [RESET, cellular.CONFIG-ACTIVE-LOW],
cellular.CONFIG-POWER: POWER,
cellular.CONFIG-UART-BAUD-RATE: BAUD,
}
return super client config

main:
provider := WalterCellularProvider
provider.install
21 changes: 21 additions & 0 deletions tutorial_code/cellular/package.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
sdk: ^2.0.0-alpha.108
prefixes:
cellular: cellular
certificate_roots: toit-cert-roots
http: pkg-http
packages:
cellular:
url: github.com/toitware/cellular
name: cellular
version: 2.1.10
hash: a2b641e2da596ac1fd58b5fd5ce5e26d5e501c35
pkg-http:
url: github.com/toitlang/pkg-http
name: http
version: 2.3.4
hash: 39fe52083b4c745cc37420649a48277b45728fd2
toit-cert-roots:
url: github.com/toitware/toit-cert-roots
name: certificate_roots
version: 1.6.1
hash: 55d3be82ed53d8d332338b2de931865cf69fe48b
10 changes: 10 additions & 0 deletions tutorial_code/cellular/package.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
dependencies:
cellular:
url: github.com/toitware/cellular
version: ^2.1.10
certificate_roots:
url: github.com/toitware/toit-cert-roots
version: ^1.6.1
http:
url: github.com/toitlang/pkg-http
version: ^2.3.4
Loading

0 comments on commit c943cb8

Please sign in to comment.