diff --git a/docs/_images/cellular_tower.svg b/docs/_images/cellular_tower.svg new file mode 100644 index 00000000..1e2f3858 --- /dev/null +++ b/docs/_images/cellular_tower.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_images/walter.png b/docs/_images/walter.png new file mode 100644 index 00000000..5e0451e2 Binary files /dev/null and b/docs/_images/walter.png differ diff --git a/docs/tutorials/index.mdx b/docs/tutorials/index.mdx index bb2dc139..86c7fc79 100644 --- a/docs/tutorials/index.mdx +++ b/docs/tutorials/index.mdx @@ -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 @@ -307,6 +308,18 @@ Connect to a BLE device. ## Network Get to know about how to use the network capabilities of your device. + + + + +Connect to the internet using a cellular modem. + + + + +## 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. diff --git a/tools/package.lock b/tools/package.lock index 200a64f6..8505d2e2 100644 --- a/tools/package.lock +++ b/tools/package.lock @@ -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 @@ -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 diff --git a/tools/package.yaml b/tools/package.yaml index 7d578eb9..0f90137b 100644 --- a/tools/package.yaml +++ b/tools/package.yaml @@ -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 diff --git a/tools/run_snippets.toit b/tools/run_snippets.toit index 99a2e338..75576b59 100644 --- a/tools/run_snippets.toit +++ b/tools/run_snippets.toit @@ -40,6 +40,7 @@ THINGS-THAT-WONT-RUN-ON-SERVER ::= [ "import ble", "import esp32", "import system.containers", + "import net.cellular", ] main args -> none: diff --git a/tutorial_code/cellular/cellular-user.toit b/tutorial_code/cellular/cellular-user.toit new file mode 100644 index 00000000..e834551f --- /dev/null +++ b/tutorial_code/cellular/cellular-user.toit @@ -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. diff --git a/tutorial_code/cellular/cellular.toit b/tutorial_code/cellular/cellular.toit new file mode 100644 index 00000000..10f3afb6 --- /dev/null +++ b/tutorial_code/cellular/cellular.toit @@ -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 diff --git a/tutorial_code/cellular/package.lock b/tutorial_code/cellular/package.lock new file mode 100644 index 00000000..301c9f24 --- /dev/null +++ b/tutorial_code/cellular/package.lock @@ -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 diff --git a/tutorial_code/cellular/package.yaml b/tutorial_code/cellular/package.yaml new file mode 100644 index 00000000..c0cca4a5 --- /dev/null +++ b/tutorial_code/cellular/package.yaml @@ -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 diff --git a/tutorial_code/cellular/walter.toit b/tutorial_code/cellular/walter.toit new file mode 100644 index 00000000..62437e62 --- /dev/null +++ b/tutorial_code/cellular/walter.toit @@ -0,0 +1,43 @@ +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 + +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"]