Skip to content

Commit

Permalink
zephyr: 05-golioth: update Kconfig and client
Browse files Browse the repository at this point in the history
Update this page to reflect Golioth Firmware SDK

Signed-off-by: Mike Szczys <[email protected]>
  • Loading branch information
szczys committed Feb 20, 2024
1 parent 5f28571 commit 1ff8cdf
Showing 1 changed file with 166 additions and 50 deletions.
216 changes: 166 additions & 50 deletions website/docs/zephyr-training/05_golioth/kconfig_and_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ description:

## Learning objectives

Now that the Golioth Zephyr SDK has been added to your Zephyr installation we
Now that the Golioth Firmware SDK has been added to your Zephyr installation we
are ready to start using it. As with all Zephyr libraries, we need to first
enable Golioth using some Kconfig symbols. Then we create the Golioth System
Client to handle all things Golioth.
enable Golioth using some Kconfig symbols. Then we create the Golioth Client to
handle all things Golioth.

* **Desired outcome(s)**
1. Understand how to enable Kconfig symbols required by the Golioth SDK
Expand All @@ -28,41 +28,79 @@ example.

## Kconfig symbols required by Golioth

There are two Kconfig symbols that are always required to use the Golioth Zephyr
SDK:
There is one Kconfig symbol required to use the Golioth Zephyr SDK:

```kconfig
CONFIG_GOLIOTH=y
CONFIG_GOLIOTH_SYSTEM_CLIENT=y
CONFIG_GOLIOTH_FIRMWARE_SDK=y
```

These will immediately allow you to connect to Golioth to send and receive data
on LightDB Stream and LightDB state. The logging and RPC services are similarly
easy to enable:
These will immediately allow you to connect to Golioth, however each Golioth
service must be individually enabled. This helps conserve device resources by
only including what you need in the firmware build. Here is an example of the
Kconfig symbols used for our services:

```
# Enable remote logging
# Enable OTA firmware update
CONFIG_GOLIOTH_FW_UPDATE=y
# Enable stateful data
CONFIG_GOLIOTH_LIGHTDB_STATE=y
# Enable sending log messages to the Golioth cloud
CONFIG_LOG_BACKEND_GOLIOTH=y
# Enable remote procedure call
CONFIG_GOLIOTH_RPC=y
# Enable fleet-wide device settings
CONFIG_GOLIOTH_SETTINGS=y
# Enable time-series data
CONFIG_GOLIOTH_STREAM=y
```

More setup is required for the settings service and for OTA firmware updates.
Generally speaking, see [the Golioth Zephyr
samples](https://github.com/golioth/golioth-zephyr-sdk/tree/main/samples) for
information on enabling services.

:::note

Golioth Kconfig symbols are already enabled in the `prj.conf` file of the
`05_golioth` application we're working with in this module. If you're curious,
you may use `menuconfig` and navigate to `modules`&rarr;`golioth` to see the
full configuration for Golioth.

![Golioth menuconfig options](./assets/golioth_menuconfig_options.jpg)
<details>
<summary>Explain the Golioth Kconfig symbols present in the 05_golioth sample code</summary>

Some Golioth Kconfig symbols are already enabled [in the `prj.conf` file of the
`05_golioth`
application](https://github.com/golioth/zephyr-training/blob/main/05_golioth/prj.conf)
we're working with in this module.

* We use the [Golioth common
library](https://github.com/golioth/golioth-firmware-sdk/tree/main/examples/zephyr/common)
for credential and connection management

```
CONFIG_GOLIOTH_SAMPLE_COMMON=y
```
* These symbols enable [Golioth runtime
settings](https://github.com/golioth/golioth-firmware-sdk/blob/main/examples/zephyr/hello/README.md#psk-based-auth---runtime)
so that WiFi and Golioth credentials can be stored in the settings partition
from the shell
```
CONFIG_GOLIOTH_SETTINGS=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_RUNTIME=y
CONFIG_GOLIOTH_SAMPLE_HARDCODED_CREDENTIALS=n
CONFIG_GOLIOTH_SAMPLE_PSK_SETTINGS=y
CONFIG_GOLIOTH_SAMPLE_SETTINGS_AUTOLOAD=y
CONFIG_GOLIOTH_SAMPLE_SETTINGS_SHELL=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SHELL=y
```
:::
</details>
## Exercise: Create a Golioth Client in main.c
Expand All @@ -74,22 +112,28 @@ API calls in our C code.
Add the following code to the `05_golioth/src/main.c` file:
```c
#include <net/golioth/system_client.h>

static struct golioth_client *client = GOLIOTH_SYSTEM_CLIENT_GET();
#include <golioth/client.h>
static struct golioth_client *client;
static K_SEM_DEFINE(connected, 0, 1);
static void golioth_on_connect(struct golioth_client *client)
static void on_client_event(struct golioth_client *client,
enum golioth_client_event event,
void *arg)
{
k_sem_give(&connected);
bool is_connected = (event == GOLIOTH_CLIENT_EVENT_CONNECTED);
if (is_connected) {
k_sem_give(&connected);
}
LOG_INF("Golioth client %s", is_connected ? "connected" : "disconnected");
}
```

Here's what's happening in this block:

1. Include the Golioth System Client at the top of the file
2. Create a pointer to a `golioth_client` singleton
2. Create a pointer to a `golioth_client` instance
3. Create a semaphore to block until a connection with Golioth is established
4. Create a callback that will be used when we connect to Golioth
* This callback will unblock the semaphore, allowing program execution to
Expand All @@ -101,28 +145,88 @@ Finally, add this code in your `main()` function, after the network connection
function calls, but before the loop:

```c
client->on_connect = golioth_on_connect;
golioth_system_client_start();
/* Get golioth_client_config filled with PSK-ID/PSK credentials
* using Golioth common Library */
const struct golioth_client_config *client_config = golioth_sample_credentials_get();

k_sem_take(&connected, K_FOREVER);
/* Use golioth_client_config to create the Golioth client */
client = golioth_client_create(client_config);

/* Register a callback to run when we connect to Golioth */
golioth_client_register_event_callback(client, on_client_event, NULL);

/* Block program flow until connection is ready */
k_sem_take(&connected, K_FOREVER);
```
This block serves the following purpose:
1. Register the callback to be used when the Golioth System Client connects
2. Start the Golioth System Client
3. Block program execution until the connection is established
1. Get the stored credentials
2. Create the Golioth client
3. Register a callback so we can do things when first connected to Golioth
4. Block program execution until the connection is established
:::tip
The Golioth System Client runs on its own thread. Since we cannot send or
receive anything from Golioth until a connection is established it makes sense
for simple demo code to block program flow until that point. In production, you
may want to adopt a different approach that allows other parts of your
application to run while waiting for a connection.
The Golioth client runs on its own thread. Since we cannot send or receive
anything from Golioth until a connection is established, it makes sense for
simple demo code to block program flow until that point. In production, you may
want to adopt a different approach that allows other parts of your application
to run while waiting for a connection.
:::
### More information on credentials
This example uses a helper function to get the runtime credentials and use them
when creating the Golioth client. But the Golioth client is designed to make
this step configurable. You may be using credentials stored in a secure
keystore, or loaded in from a storage location of your choosing. Here are a few
examples of different golioth_client_config structs:
```c
/* Config for Certificate authentication */
struct golioth_client_config client_config = {
.credentials =
{
.auth_type = GOLIOTH_TLS_AUTH_TYPE_PKI,
.pki =
{
.ca_cert = tls_ca_crt,
.ca_cert_len = sizeof(tls_ca_crt),
.public_cert = tls_client_crt,
.public_cert_len = tls_client_crt_len,
.private_key = tls_client_key,
.private_key_len = tls_client_key_len,
},
},
};
/* Config for PSK authentication */
struct golioth_client_config client_config = {
.credentials =
{
.auth_type = GOLIOTH_TLS_AUTH_TYPE_PSK,
.psk =
{
.psk_id = client_psk_id,
.psk_id_len = client_psk_id_len,
.psk = client_psk,
.psk_len = client_psk_len,
},
},
};
/* Config for credential tag authentication */
struct golioth_client_config client_config = {
.credentials =
{
.auth_type = GOLIOTH_TLS_AUTH_TYPE_TAG,
.tag = YOUR_CREDENTIALS_TAG,
},
};
```

## Expected results

You have added Golioth to your application. The code will build and attempt to
Expand All @@ -135,29 +239,39 @@ LightDB Steam.

Here is an excerpt from `main.c` that includes the added code from this section:
```c
#include <net/golioth/system_client.h> /* already included in earlier */

static struct golioth_client *client = GOLIOTH_SYSTEM_CLIENT_GET();
/* There are existing file contents above this line that aren't shown */
/* - additions you should have made are highlighted below */

// highlight-start
#include <golioth/client.h>
static struct golioth_client *client;
static K_SEM_DEFINE(connected, 0, 1);

static void golioth_on_connect(struct golioth_client *client)
static void on_client_event(struct golioth_client *client,
enum golioth_client_event event,
void *arg)
{
k_sem_give(&connected);
bool is_connected = (event == GOLIOTH_CLIENT_EVENT_CONNECTED);

if (is_connected) {
k_sem_give(&connected);
}
LOG_INF("Golioth client %s", is_connected ? "connected" : "disconnected");
}
// highlight-end

/* Main function */
void main(void)
int main(void)
{
int ret;

if (!device_is_ready(led1.port)) {
return;
return -EIO;
}

ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return;
return -EIO;
}

/* Start timer-based LED blinker */
Expand All @@ -167,15 +281,17 @@ void main(void)
#ifdef CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP
wifi_connect();
#else
if (IS_ENABLED(CONFIG_GOLIOTH_SAMPLES_COMMON)) {
if (IS_ENABLED(CONFIG_GOLIOTH_SAMPLE_COMMON)) {
net_connect();
}
#endif

client->on_connect = golioth_on_connect;
golioth_system_client_start();

// highlight-start
const struct golioth_client_config *client_config = golioth_sample_credentials_get();
client = golioth_client_create(client_config);
golioth_client_register_event_callback(client, on_client_event, NULL);
k_sem_take(&connected, K_FOREVER);
// highlight-end

int counter = 0;

Expand Down

0 comments on commit 1ff8cdf

Please sign in to comment.