Zephyr: question: Using OpenThread API in Zephyr application

Created on 14 May 2019  路  11Comments  路  Source: zephyrproject-rtos/zephyr

Hello everyone!
As I understand - currently OpenThread is implemented as L2 layer in Zephyr. The provided OT samples echo_server and echo_client use Zephyr's "standard" network API for sending and receiving packets. OpenThread code and libraries are hidden from the application.
Is it possible to use OpenThread API directly in the application?
For example, I'd like to use otNetworkTimeGet function with the OT instance that is being used in the L2 layer, to check the OpenThread network time.

OpenThread question

All 11 comments

Hi, @szymonnnm! I've been using OT API functions like otThreadSetNetworkName and otLinkSetChannel just by adding

#include <openthread/thread.h>
#include <openthread/link.h>

to my c file.

I believe that including openthread/network_time.h would make it for you

Hi,

you should be able to use OpenThread APIs, the trick is you need to obtain otInstance pointer from the networking stack. The instance pointer is encapsulated within openthread_context structure inside the network interface, I think you should be able to obtain it with a combination of net_if_get_first_by_type and net_if_l2_data.

Just keep in mind, that eventually we aim to have a proper Thread management interface in Zephyr (see https://github.com/zephyrproject-rtos/zephyr/issues/3861), so it should not be needed to use OpenThread API directly - consider it more like a bypass for current limitations.

@rlubos @jcorde Thank you very much for your responses!

Following them, I've been able to obtain the openthread_contex structure and use functions from the OpenThread API such as ex. otThreadGetNetworkName.
Unfortunately, otThreadSetNetworkName didn't work, it returns OT_ERROR_INVALID_STATE so I guess it's because according to this function's docs:

This function succeeds only when Thread protocols are disabled.

I tried to use it at the very beginning of the main function in the echo_server sample, so I guess the Thread protocol initialization happens beforehand.

As for the otNetworkTimeGet - trying to use it results in compilation error:

zephyr/ext_proj/Source/ot/include/openthread/network_time.h:87:70: error: expected ';', ',' or ')' before '&' token
 otNetworkTimeStatus otNetworkTimeGet(otInstance *aInstance, uint64_t &aNetworkTime);

I've tried to add CONFIG_CPLUSPLUS=y to the sample's prj.conf file but it didn't help.

Having Thread management interface sounds like a great feature. Who knows, maybe I would be able to contribute, but obviously I need to learn a lot of stuff related to Zephyr first.

Hi @szymonnnm.
About otThreadSetNetworkName
OpenThread automatically initializes before main. So you should stop it before modifying anything.
In my project, we were able to modify the credentials by stopping the interface first.
You can how we did it at https://github.com/CESARBR/zephyr-knot-sdk/blob/master/core/src/net.c#L115.
Please, notice that we call the functions in this sequence:

  1. ot_config_stop()
  2. ot_config_set()
  3. ot_config_start()
    You can find the implementation of ot_config at https://github.com/CESARBR/zephyr-knot-sdk/blob/master/core/src/ot_config.c

About otNetworkTimeGet
I don't think that you can access c++ code from a c file like that.

@szymonnnm otThreadSetEnabled(instance, false) is the API function you need, it will stop the Thread network and allow reconfiguration. Once you are done, restart the network with otThreadSetEnabled(ot_context->instance, true). The code posted by @jcorde looks like a very good example on how this should be done.

Regarding otNetworkTimeGet, for me, it looks like an obvious issue with OpenThread. To my knowledge, all OT APIs were designed to be callable from C code, yet a reference operator sneaked in. I encourage you to create an OT issue for that.

Thank you very much! Following your comments, I've been able to make it work!
As for the otNetworkTimeGet, I will create an issue in the OT repository as suggested.

Hello again, I've reported the issue with otNetworkTimeGet in the OpenThread repository here - the bug has been fixed and merged into master among many other fixes since then.
I've been trying to use the master branch of the OpenThread repo in my Zephyr application but it turns out that there have been a lot of other changes that cause Zephyr to not be compliant with the fresh version of the OpenThread, one of them (or maybe the only one) being:

/home/build/zephyr/subsys/net/lib/openthread/platform/random.c:10:10: fatal error: openthread/platform/random.h: No such file or directory
 #include <openthread/platform/random.h>

It seems to me that in the master branch of the OpenThread repo this header file has removed and instead, two other header files have been added:

  • <openthread/random_crypto.h>
  • <openthread/random_noncrypto.h>

Is there a simple way to make Zephyr compliant with these changes? Are you planning to bump the OpenThread commit used in Zephyr in the near future?

I've also tried using Zephyr's "default" OpenThread commit but with additional, cherry-picked commit (the one that resolves the otNetworkTimeGet bug) but there seems to be some problem with linking:

/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/8.3.0/../../../../arm-zephyr-eabi/bin/ld: app/libapp.a(udp.c.obj): in function `process_udp':
/home/build/zephyr/samples/net/sockets/echo_server/src/udp.c:79: undefined reference to `otNetworkTimeGet'
collect2: error: ld returned 1 exit status

I think that the source file has been compiled properly because I can see:

CXX      api/libopenthread_ftd_a-network_time_api.o

in the building logs. Perhaps the compiled object file is not being linked to the final executable but I'm struggling to find the place in the build system where I could specify that I want to link it.

Hi @szymonnnm,

Indeed the OpenThread RNG API's were redesigned recently, so in order to update OT version in Zephyr it will need to be reimplemented on the Zephyr side - I do not see a way to avoid that. Especially, that the API update was merged before the change you're interested in. So if you have time, contributions are welcome :)

The cherry-pick approach should work though, especially that the API fix was pretty simple. I'm not sure if you've noticed, but the Network Time API implementation is conditionally compiled, based on OPENTHREAD_CONFIG_ENABLE_TIME_SYNC config, see: https://github.com/openthread/openthread/blob/787184d4bb5bd6390176fe07cad868dfd4e54365/src/core/api/network_time_api.cpp#L36

Perhaps that's the reason your linker cannot find otNetworkTimeGet? If so, you might want to enable it in https://github.com/zephyrproject-rtos/zephyr/blob/master/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h
Ideally, the API header should be protected with the same config guard, so that the build would crash at the compilation level, but apparently, it was overlooked.

@rlubos Okay, thank you very much, I think it works now.

Besides defining OPENTHREAD_CONFIG_ENABLE_TIME_SYNC in subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h I also had to add the following platform functions to subsys/net/lib/openthread/platform/alarm.c so the OpenThread would be able to use them:

/**
 * Get the current time (64bits width).
 *
 * @returns The current time in microseconds.
 *
 */
uint64_t otPlatTimeGet(void)
{
    return (uint64_t)(k_uptime_get() * 1000);
}

/**
 * Get the device's XTAL accuracy.
 *
 * @returns The device's XTAL accuracy, in ppm.
 *
 */
uint16_t otPlatTimeGetXtalAccuracy(void)
{
    return XTAL_ACCURACY;
}

I defined XTAL_ACCURACY as 40 because (snippet from OpenThread examples):

#define XTAL_ACCURACY       40 // The crystal used on nRF52840PDK has 卤20ppm accuracy.

Anyway, after all this fight it turned out that the otNetworkGetTime is not what I was looking for. Somehow I was hoping that it will let me get current unix epoch time when connected to a border router but it's returning the network uptime.
Maybe there is some method to force the border router (I'm using nRF example - RaspPIoT Border Router Demo) to set the network time to unix epoch and broadcast time sync message to all connected childs from time to time, but I guess that I would need to ask this question in one of the OpenThread support channels.

@szymonnnm If you have internet connectivity (which I assume you have via border router) you can try to use SNTP, there's an API in Zephyr for that, see https://github.com/zephyrproject-rtos/zephyr/blob/master/samples/net/sockets/sntp_client/src/main.c and https://github.com/zephyrproject-rtos/zephyr/blob/22f1a29185bbf6b2547103967c8e725cdb51ffa6/subsys/net/lib/sntp/sntp_simple.c. The latter should allow you to easily retrieve network time from a public server.

@rlubos Thanks you! It works like a charm!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

spoorthik picture spoorthik  路  3Comments

akansal1 picture akansal1  路  4Comments

pdunaj picture pdunaj  路  3Comments

mike-scott picture mike-scott  路  4Comments

Nukersson picture Nukersson  路  4Comments