Google is committed to advancing racial equity for Black communities. See how.
Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

OpenThread API'leri ile Geliştirme

26b7f4f6b3ea0700.png

Nest tarafından yayınlanan OpenThread , Thread® ağ protokolünün açık kaynaklı bir uygulamasıdır. Nest, bağlantılı ev için ürünlerin geliştirilmesini hızlandırmak amacıyla Nest ürünlerinde kullanılan teknolojiyi geliştiricilere yaygın olarak sunmak için OpenThread'i piyasaya sürdü.

İş Parçacığı özelliği , ev uygulamaları için IPv6 tabanlı, güvenilir, güvenli ve düşük güç tüketen kablosuz bir aygıttan aygıta iletişim protokolünü tanımlar. OpenThread, IPv6, 6LoWPAN, IEEE 802.15.4, MAC güvenliği, Mesh Link Establishment ve Mesh Routing dahil olmak üzere tüm Thread ağ katmanlarını uygular.

Bu Codelab'de, bir Thread ağı başlatmak, cihaz rollerindeki değişiklikleri izlemek ve bunlara tepki vermek, UDP mesajları göndermek ve bu eylemleri gerçek donanımdaki düğmelere ve LED'lere bağlamak için OpenThread API'leri kullanacaksınız.

2a6db2e258c32237.png

Ne öğreneceksin

  • Nordic nRF52840 geliştirme kartlarında düğmeler ve LED'ler nasıl programlanır
  • Yaygın OpenThread API'leri ve otInstance sınıfı nasıl kullanılır?
  • OpenThread durum değişikliklerini izleme ve bunlara tepki verme
  • Bir Thread ağındaki tüm cihazlara UDP mesajları nasıl gönderilir
  • Makefiles nasıl değiştirilir

Neye ihtiyacın olacak

Donanım:

  • 3 Nordic Semiconductor nRF52840 geliştirme kartı
  • Kartları bağlamak için 3 USB'den Mikro USB'ye kablolar
  • En az 3 USB bağlantı noktasına sahip bir Linux makinesi

Yazılım:

  • GNU Araç Zinciri
  • Nordic nRF5x komut satırı araçları
  • Segger J-Link yazılımı
  • OpenThread
  • Git

Aksi belirtilmedikçe, bu Codelab'in içeriği Creative Commons Attribution 3.0 Lisansı altında, kod örnekleri ise Apache 2.0 Lisansı altında lisanslanmıştır .

Donanım Kod Laboratuarını tamamlayın

Bu Codelab'e başlamadan önce, Build a Thread Network'ü nRF52840 Boards ve OpenThread Codelab ile tamamlamalısınız.

  • Oluşturmak ve yanıp sönmek için ihtiyacınız olan tüm yazılımları detaylandırır
  • OpenThread'i nasıl oluşturacağınızı ve Nordic nRF52840 kartlarında nasıl flash yapacağınızı öğretir
  • Bir Thread ağının temellerini gösterir

OpenThread oluşturmak ve panoları flaşlamak için gerekli ortam kurulumlarından hiçbiri bu Codelab'de ayrıntılı olarak anlatılmamıştır - yalnızca panoların yanıp sönmesi için temel talimatlar. Bir İş Parçacığı Ağı Oluşturma Kod Laboratuvarı'nı zaten tamamlamış olduğunuz varsayılmaktadır.

İş Parçacığı Ağı Oluşturma Kod Laboratuvarı'nı tamamlayın

Linux makinesi

Bu Codelab, tüm İş Parçacığı geliştirme kartlarını flaşlamak için i386 veya x86 tabanlı bir Linux makinesi kullanmak üzere tasarlanmıştır. Tüm adımlar Ubuntu 14.04.5 LTS (Trusty Tahr) üzerinde test edildi.

Nordic Semiconductor nRF52840 panoları

Bu Codelab, üç nRF52840 PDK kartı kullanır.

a6693da3ce213856.png

Yazılımı kur

OpenThread oluşturmak ve flaşlamak için SEGGER J-Link, nRF5x Komut Satırı araçları, ARM GNU Araç Zinciri ve çeşitli Linux paketlerini kurmanız gerekir. Bir İş Parçacığı Ağı Kod Laboratuvarını gerektiği gibi tamamladıysanız, ihtiyacınız olan her şeyi zaten kurmuş olacaksınız. Değilse, OpenThread'i nRF52840 geliştirme kartlarında oluşturup flaş edebileceğinizden emin olmak için devam etmeden önce bu Codelab'i tamamlayın.

İş Parçacığı Ağı Oluşturma Kod Laboratuvarı'nı tamamlayın

OpenThread, bu Codelab için başlangıç ​​noktası olarak kullanabileceğiniz örnek uygulama koduyla birlikte gelir.

OpenThread'i klonlayın ve yükleyin:

$ cd ~
$ git clone --recursive https://github.com/openthread/openthread.git
$ cd openthread
$ ./bootstrap

OpenThread'in genel API'leri OpenThread deposunda include/openthread . Bu API'ler, uygulamalarınızda kullanılmak üzere hem Thread hem de platform düzeyinde çeşitli OpenThread özelliklerine ve işlevlerine erişim sağlar:

  • OpenThread örnek bilgisi ve denetimi
  • IPv6, UDP ve CoAP gibi uygulama hizmetleri
  • Komisyon Üyesi ve Birleştirici rolleriyle birlikte ağ kimlik bilgisi yönetimi
  • Sınır Yönlendirici yönetimi
  • Çocuk Denetimi ve Sıkışma Algılama gibi gelişmiş özellikler

Tüm OpenThread API'lerine ilişkin referans bilgileri openthread.io/reference adresinde mevcuttur .

API kullanma

Bir API kullanmak için, başlık dosyasını uygulama dosyalarınızdan birine ekleyin. Ardından istediğiniz işlevi çağırın.

Örneğin, OpenThread ile birlikte verilen CLI örnek uygulaması aşağıdaki API başlıklarını kullanır:

örnekler / apps / cli / main.c

#include <openthread/config.h>
#include <openthread/cli.h>
#include <openthread/diag.h>
#include <openthread/tasklet.h>
#include <openthread/platform/logging.h>

OpenThread örneği

otInstance yapısı, OpenThread API'leri ile çalışırken sıklıkla kullanacağınız bir şeydir. Bir kez başlatıldığında, bu yapı OpenThread kitaplığının statik bir örneğini temsil eder ve kullanıcının OpenThread API çağrıları yapmasına izin verir.

Örneğin, OpenThread örneği, CLI örnek uygulamasının main() işlevinde başlatılır:

örnekler / apps / cli / main.c

int main(int argc, char *argv[])
{
    otInstance *instance

...

#if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
    // Call to query the buffer size
    (void)otInstanceInit(NULL, &otInstanceBufferLength);

    // Call to allocate the buffer
    otInstanceBuffer = (uint8_t *)malloc(otInstanceBufferLength);
    assert(otInstanceBuffer);

    // Initialize OpenThread with the buffer
    instance = otInstanceInit(otInstanceBuffer, &otInstanceBufferLength);
#else
    instance = otInstanceInitSingle();
#endif

...

    return 0;
}

Platforma özel işlevler

OpenThread ile birlikte verilen örnek uygulamalardan birine platforma özgü işlevler eklemek istiyorsanız, önce tüm işlevler için otSys ad alanını kullanarak bunları examples/platforms/openthread-system.h başlığında otSys . Ardından bunları platforma özgü bir kaynak dosyada uygulayın. Bu şekilde özetlendiğinde, diğer örnek platformlar için aynı işlev başlıklarını kullanabilirsiniz.

Örneğin, nRF52840 düğmelerine ve LED'lere bağlanmak için kullanacağımız GPIO işlevleri openthread-system.h bildirilmelidir.

examples/platforms/openthread-system.h dosyasını tercih ettiğiniz metin düzenleyicide açın.

örnekler / platformlar / openthread-system.h

EYLEM: Platforma özgü GPIO işlevi bildirimleri ekleyin

Bu işlev bildirimlerini dosyanın herhangi bir yerine ekleyin:

/**
 * Init LED module.
 *
 */
void otSysLedInit(void);
void otSysLedSet(uint8_t aLed, bool aOn);
void otSysLedToggle(uint8_t aLed);

/**
* A callback will be called when GPIO interrupts occur.
*
*/
typedef void (*otSysButtonCallback)(otInstance *aInstance);
void otSysButtonInit(otSysButtonCallback aCallback);
void otSysButtonProcess(otInstance *aInstance);

Bunları sonraki adımda uygulayacağız.

otSysButtonProcess işlev bildiriminin bir otInstance kullandığını otInstance . Bu şekilde uygulama, gerekirse bir düğmeye basıldığında OpenThread örneği hakkındaki bilgilere erişebilir. Her şey uygulamanızın ihtiyaçlarına bağlıdır. İşlev uygulamanızda buna ihtiyacınız yoksa, bazı araç zincirleri için kullanılmayan değişkenler etrafındaki derleme hatalarını bastırmak için OpenThread API'den OT_UNUSED_VARIABLE makrosunu kullanabilirsiniz. Bunun örneklerini daha sonra göreceğiz.

Bir önceki adımda, examples/platforms/openthread-system.h içinde GPIO için kullanılabilecek examples/platforms/openthread-system.h özgü işlev bildirimlerinin üzerinden examples/platforms/openthread-system.h . NRF52840 geliştirme kartlarındaki düğmelere ve LED'lere erişmek için, bu işlevleri nRF52840 platformunda uygulamanız gerekir. Bu kodda, şunları yapan işlevler ekleyeceksiniz:

  • GPIO pinlerini ve modlarını başlatın
  • Bir pim üzerindeki voltajı kontrol edin
  • GPIO kesintilerini etkinleştirin ve bir geri aramayı kaydedin

examples/platforms/nrf528xx/src dizininde, gpio.c adında bir dosya oluşturun. Bu yeni dosyaya aşağıdaki içeriği ekleyin.

örnekler / platformlar / nrf528xx / src / gpio.c (YENİ DOSYA)

EYLEM: Tanımlar ekle

Bu tanımlar, nRF52840'a özgü değerler ve OpenThread uygulama düzeyinde kullanılan değişkenler arasında soyutlama görevi görür.

/**
 * @file
 *   This file implements the system abstraction for GPIO and GPIOTE.
 *
 */

#define BUTTON_GPIO_PORT 0x50000300UL
#define BUTTON_PIN 11 // button #1

#define GPIO_LOGIC_HI 0
#define GPIO_LOGIC_LOW 1

#define LED_GPIO_PORT 0x50000300UL
#define LED_1_PIN 13 // turn on to indicate leader role
#define LED_2_PIN 14 // turn on to indicate router role
#define LED_3_PIN 15 // turn on to indicate child role
#define LED_4_PIN 16 // turn on to indicate UDP receive

NRF52840 düğmeleri ve LED'leri hakkında daha fazla bilgi için Nordic Semiconductor Infocenter'a bakın .

EYLEM: Başlık şunları içerir:

Ardından, GPIO işlevselliği için ihtiyaç duyacağınız başlıkları ekleyin.

/* Header for the functions defined here */
#include "openthread-system.h"

#include <string.h>

/* Header to access an OpenThread instance */
#include <openthread/instance.h>

/* Headers for lower-level nRF52840 functions */
#include "platform-nrf5.h"
#include "hal/nrf_gpio.h"
#include "hal/nrf_gpiote.h"
#include "nrfx/drivers/include/nrfx_gpiote.h"

EYLEM: Düğme 1 için geri arama ve kesme işlevleri ekleyin

Sonra bu kodu ekleyin. in_pin1_handler işlevi, düğmeye basma işlevi başlatıldığında (bu dosyanın ileriki bölümlerinde) kaydedilen geri in_pin1_handler .

OT_UNUSED_VARIABLE iletilen değişkenler aslında in_pin1_handler kullanılmadığından, bu geri OT_UNUSED_VARIABLE makrosunu nasıl kullandığına dikkat edin.

/* Declaring callback function for button 1. */
static otSysButtonCallback sButtonHandler;
static bool                sButtonPressed;

/**
 * @brief Function to receive interrupt and call back function
 * set by the application for button 1.
 *
 */
static void in_pin1_handler(uint32_t pin, nrf_gpiote_polarity_t action)
{
    OT_UNUSED_VARIABLE(pin);
    OT_UNUSED_VARIABLE(action);
    sButtonPressed = true;
}

EYLEM: LED'leri yapılandırmak için bir işlev ekleyin

Başlatma sırasında tüm LED'lerin modunu ve durumunu yapılandırmak için bu kodu ekleyin.

/**
 * @brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output,
 * and configures GPIOTE to give an interrupt on pin change.
 */

void otSysLedInit(void)
{
    /* Configure GPIO mode: output */
    nrf_gpio_cfg_output(LED_1_PIN);
    nrf_gpio_cfg_output(LED_2_PIN);
    nrf_gpio_cfg_output(LED_3_PIN);
    nrf_gpio_cfg_output(LED_4_PIN);

    /* Clear all output first */
    nrf_gpio_pin_write(LED_1_PIN, GPIO_LOGIC_LOW);
    nrf_gpio_pin_write(LED_2_PIN, GPIO_LOGIC_LOW);
    nrf_gpio_pin_write(LED_3_PIN, GPIO_LOGIC_LOW);
    nrf_gpio_pin_write(LED_4_PIN, GPIO_LOGIC_LOW);

    /* Initialize gpiote for button(s) input.
     Button event handlers are set in the application (main.c) */
    ret_code_t err_code;
    err_code = nrfx_gpiote_init();
    APP_ERROR_CHECK(err_code);
}

EYLEM: Bir LED'in modunu ayarlamak için bir işlev ekleyin.

Bu işlev, aygıtın rolü değiştiğinde kullanılacaktır.

/**
 * @brief Function to set the mode of an LED.
 */

void otSysLedSet(uint8_t aLed, bool aOn)
{
    switch (aLed)
    {
    case 1:
        nrf_gpio_pin_write(LED_1_PIN, (aOn == GPIO_LOGIC_HI));
        break;
    case 2:
        nrf_gpio_pin_write(LED_2_PIN, (aOn == GPIO_LOGIC_HI));
        break;
    case 3:
        nrf_gpio_pin_write(LED_3_PIN, (aOn == GPIO_LOGIC_HI));
        break;
    case 4:
        nrf_gpio_pin_write(LED_4_PIN, (aOn == GPIO_LOGIC_HI));
        break;
    }
}

EYLEM: Bir LED'in modunu değiştirmek için bir işlev ekleyin.

Bu işlev, cihaz bir multicast UDP mesajı aldığında LED4'ü değiştirmek için kullanılacaktır.

/**
 * @brief Function to toggle the mode of an LED.
 */
void otSysLedToggle(uint8_t aLed)
{
    switch (aLed)
    {
    case 1:
        nrf_gpio_pin_toggle(LED_1_PIN);
        break;
    case 2:
        nrf_gpio_pin_toggle(LED_2_PIN);
        break;
    case 3:
        nrf_gpio_pin_toggle(LED_3_PIN);
        break;
    case 4:
        nrf_gpio_pin_toggle(LED_4_PIN);
        break;
    }
}

EYLEM: Düğme basışlarını başlatmak ve işlemek için işlevler ekleyin.

Birinci işlev, bir düğmeye basılması için kartı başlatır ve ikincisi, Düğme 1'e basıldığında çok noktaya yayın UDP mesajını gönderir.

/**
 * @brief Function to initialize the button.
 */
void otSysButtonInit(otSysButtonCallback aCallback)
{
    nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    in_config.pull                    = NRF_GPIO_PIN_PULLUP;

    ret_code_t err_code;
    err_code = nrfx_gpiote_in_init(BUTTON_PIN, &in_config, in_pin1_handler);
    APP_ERROR_CHECK(err_code);

    sButtonHandler = aCallback;
    sButtonPressed = false;

    nrfx_gpiote_in_event_enable(BUTTON_PIN, true);
}

void otSysButtonProcess(otInstance *aInstance)
{
    if (sButtonPressed)
    {
        sButtonPressed = false;
        sButtonHandler(aInstance);
    }
}

EYLEM: Kaydedip kapatın

gpio.c dosyası.

Uygulamamızda, cihaz rolüne bağlı olarak farklı LED'lerin yanmasını istiyoruz. Şu rolleri takip edelim: Lider, Yönlendirici, Son Cihaz. Bunları şu şekilde LED'lere atayabiliriz:

  • LED1 = Lider
  • LED2 = Yönlendirici
  • LED3 = Cihazı Sonlandır

Bu işlevi etkinleştirmek için uygulamanın, aygıt rolünün ne zaman değiştiğini ve yanıt olarak doğru LED'in nasıl açılacağını bilmesi gerekir. İlk kısım için OpenThread örneğini ve ikinci kısım için GPIO platformu soyutlamasını kullanacağız.

examples/apps/cli/main.c dosyasını tercih ettiğiniz metin düzenleyicide açın.

örnekler / apps / cli / main.c

EYLEM: Başlık şunları içerir:

main.c dosyasının içerir bölümünde, rol değişikliği özelliği için ihtiyaç duyacağınız API başlık dosyalarını ekleyin.

#include <openthread/instance.h>
#include <openthread/thread.h>
#include <openthread/thread_ftd.h>

EYLEM: OpenThread örnek durum değişikliği için işleyici işlevi bildirimi ekleyin

Bu bildirimi, başlık main.c sonra ve herhangi bir #if deyiminden önce main.c ekleyin. Bu fonksiyon, ana uygulamadan sonra tanımlanacaktır.

void handleNetifStateChanged(uint32_t aFlags, void *aContext);

EYLEM: Durum değişikliği işleyici işlevi için bir geri arama kaydı ekleyin

In main.c , bu işlev eklemek main() sonra işlevi otCliUartInit çağrı. Bu geri arama kaydı, OpenThread'e, OpenThread örnek durumu her handleNetifStateChange işlevini çağırmasını söyler.

/* Register Thread state change handler */
otSetStateChangedCallback(instance, handleNetifStateChanged, instance);

EYLEM: Durum değişikliği uygulamasını ekleyin

In main.c , sonra main() fonksiyonu uygulamak handleNetifStateChanged işlevi. Bu işlev, OpenThread örneğinin OT_CHANGED_THREAD_ROLE bayrağını kontrol eder ve eğer değişmişse, gerektiğinde LED'leri açar / kapatır.

void handleNetifStateChanged(uint32_t aFlags, void *aContext)
{
   if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
   {
       otDeviceRole changedRole = otThreadGetDeviceRole(aContext);

       switch (changedRole)
       {
       case OT_DEVICE_ROLE_LEADER:
           otSysLedSet(1, true);
           otSysLedSet(2, false);
           otSysLedSet(3, false);
           break;

       case OT_DEVICE_ROLE_ROUTER:
           otSysLedSet(1, false);
           otSysLedSet(2, true);
           otSysLedSet(3, false);
           break;

       case OT_DEVICE_ROLE_CHILD:
           otSysLedSet(1, false);
           otSysLedSet(2, false);
           otSysLedSet(3, true);
           break;

       case OT_DEVICE_ROLE_DETACHED:
       case OT_DEVICE_ROLE_DISABLED:
           /* Clear LED4 if Thread is not enabled. */
           otSysLedSet(4, false);
           break;
        }
    }
}

Uygulamamızda ayrıca bir panoda Button1'e basıldığında ağdaki diğer tüm cihazlara UDP mesajları göndermek istiyoruz. Mesajın alındığını onaylamak için, yanıt olarak diğer kartlarda LED4'ü değiştireceğiz.

Bu işlevi etkinleştirmek için uygulamanın şunları yapması gerekir:

  • Başladıktan sonra bir UDP bağlantısını başlatın
  • Örgü yerel çok noktaya yayın adresine bir UDP mesajı gönderebilme
  • Gelen UDP mesajlarını yönetin
  • Gelen UDP mesajlarına yanıt olarak LED4'ü değiştirin

examples/apps/cli/main.c dosyasını tercih ettiğiniz metin düzenleyicide açın.

örnekler / apps / cli / main.c

EYLEM: Başlık şunları içerir:

main.c dosyasının en üstündeki içerir bölümünde, çok noktaya yayın UDP özelliği için ihtiyaç duyacağınız API başlık dosyalarını ekleyin.

#include <string.h>

#include <openthread/message.h>
#include <openthread/udp.h>

#include "utils/code_utils.h"

code_utils.h başlığı, çalışma zamanı koşullarını doğrulayan ve hataları incelikle işleyen otEXPECT ve otEXPECT_ACTION makroları için kullanılır.

EYLEM: Tanımları ve sabitleri ekleyin:

main.c dosyasında, içerir bölümünden sonra ve tüm #if ifadelerinden önce, UDP'ye özgü sabitleri ekleyin ve şunları tanımlar:

#define UDP_PORT 1212

static const char UDP_DEST_ADDR[] = "ff03::1";
static const char UDP_PAYLOAD[]   = "Hello OpenThread World!";

ff03::1 , örgü yerel çok noktaya yayın adresidir. Bu adrese gönderilen tüm mesajlar, ağdaki tüm Tam İş Parçacığı Cihazlarına gönderilecektir. OpenThread'de çok noktaya yayın desteği hakkında daha fazla bilgi için openthread.io'da Çok Noktaya Yayın'a bakın.

EYLEM: İşlev bildirimleri ekleyin

In main.c dosyası, sonra otTaskletsSignalPending tanımı ve önce main() fonksiyonu, UDP özgün fonksiyonları yanı sıra UDP soketi temsil edecek bir statik değişkeni ekleyin:

static void initUdp(otInstance *aInstance);
static void sendUdp(otInstance *aInstance);

static void handleButtonInterrupt(otInstance *aInstance);

void handleUdpReceive(void *aContext, otMessage *aMessage, 
                      const otMessageInfo *aMessageInfo);

static otUdpSocket sUdpSocket;

EYLEM: GPIO LED'lerini ve düğmeyi başlatmak için çağrı ekleyin

In main.c , bu işlev çağrıları ekleyin main() sonra işlevi otSetStateChangedCallback çağrı. Bu işlevler, GPIO ve GPIOTE pinlerini başlatır ve düğmeye basma olaylarını işlemek için bir düğme işleyici ayarlar.

/* init GPIO LEDs and button */
otSysLedInit();
otSysButtonInit(handleButtonInterrupt);

EYLEM: UDP başlatma çağrısını ekleyin

In main.c , bu işlev eklemek main() sonra işlevi otSysButtonInit yeni eklediğiniz çağrı:

initUdp(instance);

Bu çağrı, uygulama başlatıldığında bir UDP soketinin başlatılmasını sağlar. Bu olmadan, cihaz UDP mesajları gönderemez veya alamaz.

EYLEM: GPIO düğmesi etkinliğini işlemek için çağrı ekleyin

In main.c , bu işlev çağrısı eklemek main() sonra işlevi otSysProcessDrivers çağrı içinde, while döngü. gpio.c açıklanan bu işlev, düğmeye gpio.c kontrol eder ve öyleyse yukarıdaki adımda ayarlanan işleyiciyi ( handleButtonInterrupt ) çağırır.

otSysButtonProcess(instance);

EYLEM: Düğme Kesme İşleyiciyi Uygulama

In main.c , uygulanmasını eklemek handleButtonInterrupt sonra fonksiyonu handleNetifStateChanged önceki adımda eklenen fonksiyonu:

/**
 * Function to handle button push event
 */
void handleButtonInterrupt(otInstance *aInstance)
{
    sendUdp(aInstance);
}

EYLEM: UDP başlatmayı uygulayın

In main.c , uygulanmasını eklemek initUdp sonra fonksiyonu handleButtonInterrupt eklediğiniz fonksiyonun:

/**
 * Initialize UDP socket
 */
void initUdp(otInstance *aInstance)
{
    otSockAddr  listenSockAddr;

    memset(&sUdpSocket, 0, sizeof(sUdpSocket));
    memset(&listenSockAddr, 0, sizeof(listenSockAddr));

    listenSockAddr.mPort    = UDP_PORT;

    otUdpOpen(aInstance, &sUdpSocket, handleUdpReceive, aInstance);
    otUdpBind(aInstance, &sUdpSocket, &listenSockAddr);
}

UDP_PORT , daha önce tanımladığınız bağlantı noktasıdır (1212). otUdpOpen işlevi soketi açar ve bir UDP mesajı alındığında bir geri arama işlevi ( handleUdpReceive ) kaydeder.

EYLEM: UDP mesajlaşmasını uygulayın

In main.c , uygulanmasını eklemek sendUdp sonra fonksiyonu initUdp eklediğiniz fonksiyonun:

/**
 * Send a UDP datagram
 */
void sendUdp(otInstance *aInstance)
{
    otError       error = OT_ERROR_NONE;
    otMessage *   message;
    otMessageInfo messageInfo;
    otIp6Address  destinationAddr;

    memset(&messageInfo, 0, sizeof(messageInfo));

    otIp6AddressFromString(UDP_DEST_ADDR, &destinationAddr);
    messageInfo.mPeerAddr    = destinationAddr;
    messageInfo.mPeerPort    = UDP_PORT;

    message = otUdpNewMessage(aInstance, NULL);
    otEXPECT_ACTION(message != NULL, error = OT_ERROR_NO_BUFS);

    error = otMessageAppend(message, UDP_PAYLOAD, sizeof(UDP_PAYLOAD));
    otEXPECT(error == OT_ERROR_NONE);

    error = otUdpSend(aInstance, &sUdpSocket, message, &messageInfo);

 exit:
    if (error != OT_ERROR_NONE && message != NULL)
    {
        otMessageFree(message);
    }
}

otEXPECT ve otEXPECT_ACTION makrolarına dikkat edin. Bunlar, UDP mesajının geçerli olduğundan ve arabellekte doğru bir şekilde tahsis edildiğinden emin olur ve değilse, işlev, arabelleği boşalttığı exit bloğuna atlayarak hataları incelikle işler.

UDP'yi başlatmak için kullanılan işlevler hakkında daha fazla bilgi için openthread.io adresindeki IPv6 ve UDP Referanslarına bakın.

EYLEM: UDP mesaj işlemeyi uygulayın

In main.c , uygulanmasını eklemek handleUdpReceive sonra fonksiyonu sendUdp eklediğiniz fonksiyonun. Bu işlev sadece LED4'ü değiştirir.

/**
 * Function to handle UDP datagrams received on the listening socket
 */
void handleUdpReceive(void *aContext, otMessage *aMessage,
                      const otMessageInfo *aMessageInfo)
{
    OT_UNUSED_VARIABLE(aContext);
    OT_UNUSED_VARIABLE(aMessage);
    OT_UNUSED_VARIABLE(aMessageInfo);

    otSysLedToggle(4);
}

Gösterim kolaylığı için, cihazlarımızın derhal Thread'i başlatmasını ve açıldığında bir ağa katılmasını istiyoruz. Bunu yapmak için otOperationalDataset yapısını kullanacağız. Bu yapı, Thread ağ kimlik bilgilerini bir cihaza iletmek için gereken tüm parametreleri tutar.

Bu yapının kullanılması, uygulamamızı daha güvenli hale getirmek ve ağımızdaki Thread düğümlerini yalnızca uygulamayı çalıştıranlarla sınırlamak için OpenThread'de yerleşik ağ varsayılanlarını geçersiz kılacaktır.

Yine, tercih ettiğiniz metin düzenleyicide examples/apps/cli/main.c dosyasını açın.

örnekler / apps / cli / main.c

İŞLEM: Başlık ekle ekle

main.c dosyasının en üstündeki main.c bölümünde, Thread ağını yapılandırmak için ihtiyaç duyacağınız API başlık dosyasını ekleyin:

#include <openthread/dataset_ftd.h>

EYLEM: Ağ yapılandırmasını ayarlamak için işlev bildirimi ekleyin

Bu bildirimi, başlık main.c sonra ve herhangi bir #if deyiminden önce main.c ekleyin. Bu işlev, ana uygulama işlevinden sonra tanımlanacaktır.

static void setNetworkConfiguration(otInstance *aInstance);

EYLEM: Ağ yapılandırma çağrısını ekleyin

In main.c , bu işlev çağrısı eklemek main() sonra işlevi otSetStateChangedCallback çağrı. Bu işlev, Thread ağ veri setini yapılandırır.

/* Override default network credentials */
setNetworkConfiguration(instance);

EYLEM: Thread ağ arayüzünü ve yığını etkinleştirmek için çağrı ekleyin

In main.c , bu işlev çağrıları ekleyin main() sonra işlevi otSysButtonInit çağrı.

/* Start the Thread network interface (CLI cmd > ifconfig up) */
otIp6SetEnabled(instance, true);

/* Start the Thread stack (CLI cmd > thread start) */
otThreadSetEnabled(instance, true);

EYLEM: İş Parçacığı ağ yapılandırmasını uygulayın

In main.c , uygulanmasını eklemek setNetworkConfiguration sonra fonksiyonu main() fonksiyonu:

/**
 * Override default network settings, such as panid, so the devices can join a
 network
 */
void setNetworkConfiguration(otInstance *aInstance)
{
    static char          aNetworkName[] = "OTCodelab";
    otOperationalDataset aDataset;

    memset(&aDataset, 0, sizeof(otOperationalDataset));

    /*
     * Fields that can be configured in otOperationDataset to override defaults:
     *     Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
     *     Channel, Channel Mask Page 0, Network Master Key, PSKc, Security Policy
     */
    aDataset.mActiveTimestamp                      = 1;
    aDataset.mComponents.mIsActiveTimestampPresent = true;

    /* Set Channel to 15 */
    aDataset.mChannel                      = 15;
    aDataset.mComponents.mIsChannelPresent = true;

    /* Set Pan ID to 2222 */
    aDataset.mPanId                      = (otPanId)0x2222;
    aDataset.mComponents.mIsPanIdPresent = true;

    /* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
    uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xC0, 0xDE, 0x1A, 0xB5, 0xC0, 0xDE, 0x1A, 0xB5};
    memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
    aDataset.mComponents.mIsExtendedPanIdPresent = true;

    /* Set master key to 1234C0DE1AB51234C0DE1AB51234C0DE */
    uint8_t key[OT_MASTER_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE};
    memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
    aDataset.mComponents.mIsMasterKeyPresent = true;

    /* Set Network Name to OTCodelab */
    size_t length = strlen(aNetworkName);
    assert(length <= OT_NETWORK_NAME_MAX_SIZE);
    memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
    aDataset.mComponents.mIsNetworkNamePresent = true;

#if OPENTHREAD_FTD
    otDatasetSetActive(aInstance, &aDataset);

    /* Set the router selection jitter to override the 2 minute default.
       CLI cmd > routerselectionjitter 20
       Warning: For demo purposes only - not to be used in a real product */
    uint8_t jitterValue = 20;
    otThreadSetRouterSelectionJitter(aInstance, jitterValue);
#else
    OT_UNUSED_VARIABLE(aInstance);
#endif
}

Fonksiyonda detaylandırıldığı üzere, bu uygulama için kullandığımız Thread ağ parametreleri şunlardır:

  • Kanal = 15
  • PAN Kimliği = 0x2222
  • Genişletilmiş PAN Kimliği = C0DE1AB5C0DE1AB5
  • Ağ Ana Anahtarı = 1234C0DE1AB51234C0DE1AB51234C0DE
  • Ağ Adı = OTCodelab

Ek olarak, Yönlendirici Seçim Jitterini düşürdüğümüz yer burasıdır, böylece cihazlarımız demo amacıyla rolleri daha hızlı değiştirir. Bunun yalnızca düğüm bir FTD (Tam İş Parçacığı Aygıtı) ise yapıldığına dikkat edin. Sonraki adımda bunun hakkında daha fazla bilgi.

OpenThread'in API'lerinden bazıları, yalnızca demo veya test amacıyla değiştirilmesi gereken ayarları değiştirir. Bu API'ler, OpenThread kullanan bir uygulamanın üretim dağıtımında kullanılmamalıdır.

Örneğin, otThreadSetRouterSelectionJitter işlevi, bir Son Cihazın kendisini bir Yönlendiriciye yükseltmesi için geçen süreyi (saniye cinsinden) ayarlar. Bu değer için varsayılan, Diş Belirtimi başına 120'dir. Bu Codelab'de kullanım kolaylığı için onu 20 olarak değiştireceğiz, böylece bir Thread düğümünün rolleri değiştirmesi için çok uzun süre beklemenize gerek kalmayacak.

Ancak, bu işlevin bir önişlemci yönergesi içinde çağrıldığını fark etmiş olabilirsiniz:

#if OPENTHREAD_FTD
    otDatasetSetActive(aInstance, &aDataset);

    /* Set the router selection jitter to override the 2 minute default.
       CLI cmd >routerselectionjitter 20
       Warning: For demo purposes only - not to be used in a real product */
    uint8_t jitterValue = 20;
    otThreadSetRouterSelectionJitter(aInstance, jitterValue);
#else
    OT_UNUSED_VARIABLE(aInstance);
#endif

Bu, bir MTD (Minimal Thread Device) yapısına eklenmesini engellemek içindir. MTD aygıtları yönlendiriciler haline gelmez ve otThreadSetRouterSelectionJitter gibi bir işlevi desteklemek MTD otThreadSetRouterSelectionJitter dahil edilmez.

Sen bakarak bunu teyit edebilir otThreadSetRouterSelectionJitter da bir önişlemci direktifi içinde yer alan fonksiyon tanımı, OPENTHREAD_FTD :

src / core / api / thread_ftd_api.cpp

#if OPENTHREAD_FTD

#include <openthread/thread_ftd.h>

...

void otThreadSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter)
{
    Instance &instance = *static_cast<Instance *>(aInstance);

    instance.GetThreadNetif().GetMle().SetRouterSelectionJitter(aRouterJitter);
}

...

#endif // OPENTHREAD_FTD

Uygulamanızı oluşturmadan önce, üç Makefile için gerekli birkaç küçük güncelleme vardır. Bunlar, uygulamanızı derlemek ve bağlamak için yapı sistemi tarafından kullanılır.

örnekler / Makefile-nrf52840

Şimdi GPIO işlevlerinin uygulamada tanımlandığından emin olmak için nrf52840 Makefile'a bazı bayraklar ekleyin.

EYLEM: nrf52840 Makefile dosyasına bayrak ekleyin

examples/Makefile-nrf52840 tercih ettiğiniz metin düzenleyicide COMMONCFLAGS ve include ... common-switches.mk satırından sonra aşağıdaki COMMONCFLAGS ekleyin:

...

include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/common-switches.mk

# Defined in third_party/NordicSemiconductor/nrfx/templates/nRF52840/nrfx_config.h
COMMONCFLAGS += -DGPIOTE_ENABLED=1
COMMONCFLAGS += -DGPIOTE_CONFIG_IRQ_PRIORITY=7
COMMONCFLAGS += -DGPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS=1

...

örnekler / platformlar / nrf528xx / nrf52840 / Makefile.am

Şimdi yeni gpio.c dosyasını platform nrf52840 Makefile.am dosyasına ekleyin.

EYLEM: gpio kaynağını nrf52840 platformu Makefile'a ekleyin

examples/platforms/nrf528xx/nrf52840/Makefile.am tercih ettiğiniz metin düzenleyicide açın ve dosyayı PLATFORM_COMMON_SOURCES bölümünün sonuna, $(NULL) ifadesinin hemen önüne ekleyin. Satırın sonuna ters eğik çizgi koymayı unutmayın!

...

PLATFORM_COMMON_SOURCES
...
src/gpio.c             \
$(NULL)

...

third_party / NordicSemiconductor / Makefile.am

Son olarak, nrfx_gpiote.c sürücü dosyasını NordicSemiconductor üçüncü taraf Makefile'a ekleyin, böylece Nordic sürücülerinin kitaplık yapısına dahil edilir.

EYLEM: gpio sürücüsünü nrf52840 platformu Makefile'a ekleyin

Tercih ettiğiniz metin düzenleyicide third_party/NordicSemiconductor/Makefile.am dosyasını açın ve dosyayı NORDICSEMI_COMMON_SOURCES bölümünün sonuna, $(NULL) ifadesinin hemen önüne ekleyin. Satırın sonuna ters eğik çizgi koymayı unutmayın!

...

NORDICSEMI_COMMON_SOURCES
...
nrfx/drivers/src/nrfx_gpiote.c             \

$(NULL)

...

Yapılan tüm kod güncellemeleri ile, uygulamayı oluşturmaya ve üç Nordic nRF52840 geliştirme kartının hepsinde flash yapmaya hazırsınız. Her cihaz bir Tam İplik Aygıtı (FTD) olarak işlev görür.

OpenThread oluşturun

NRF52840 örnek platformunu oluşturun. Makefile dosyaları önceki adımda değiştirildiğinden, oluşturmadan önce bootstrap komut dosyasını çalıştırmanız gerekir:

$ cd ~/openthread
$ ./bootstrap
$ make -f examples/Makefile-nrf52840

OpenThread FTD CLI ikili dosyasıyla dizine gidin ve onu ARM Gömülü Araç Zinciri ile onaltılık biçime dönüştürün:

$ cd ~/openthread/output/nrf52840/bin
$ arm-none-eabi-objcopy -O ihex ot-cli-ftd ot-cli-ftd.hex

Panoları flaşla

ot-cli-ftd.hex dosyasını her nRF52840 kartına gönderin.

USB kablosunu, nRF52840 kartındaki harici güç pininin yanındaki Mikro-USB hata ayıklama bağlantı noktasına takın ve ardından Linux makinenize takın. Doğru şekilde ayarlayın, LED5 açık.

20a3b4b480356447.png

Daha önce olduğu gibi, nRF52840 kartının seri numarasını not edin:

c00d519ebec7e5f0.jpeg

NRFx Komut Satırı Araçlarının konumuna gidin ve kartın seri numarasını kullanarak OpenThread CLI FTD onaltılık dosyayı nRF52840 kartına yazın:

$ cd ~/nrfjprog
$ ./nrfjprog -f nrf52 -s 683704924 --chiperase --program \
       ~/openthread/output/nrf52840/bin/ot-cli-ftd.hex --reset

Yanıp sönme sırasında LED5 kısa süreliğine kapanacaktır. Başarı üzerine aşağıdaki çıktı üretilir:

Parsing hex file.
Erasing user available code and UICR flash areas.
Applying system reset.
Checking that the area to write is not protected.
Programing device.
Applying system reset.
Run.

Diğer iki kart için bu "Kartları Flash" adımını tekrarlayın. Her bir kart, Linux makinesine aynı şekilde bağlanmalıdır ve kartın seri numarası dışında flash komutu aynıdır. Her panonun benzersiz seri numarasını

nrfjprog yanıp sönen komut.

Başarılı olursa, her kartta LED1, LED2 veya LED3 yanacaktır. Yanıp söndükten hemen sonra 3'ten 2'ye (veya 2'den 1'e) yanan LED anahtarını bile görebilirsiniz (cihaz rolü değiştirme özelliği).

Üç nRF52840 kartının tümü artık güçlendirilmiş olmalı ve OpenThread uygulamamızı çalıştırmalıdır. Daha önce detaylandırıldığı gibi, bu uygulamanın iki temel özelliği vardır.

Cihaz rolü göstergeleri

Her panodaki yanan LED, Thread düğümünün mevcut rolünü yansıtır:

  • LED1 = Lider
  • LED2 = Yönlendirici
  • LED3 = Cihazı Sonlandır

Rol değiştikçe yanan LED de değişir. Bu değişiklikleri, her aygıtın açılışından sonraki 20 saniye içinde bir veya iki panoda görmüş olmalısınız.

UDP Çok Noktaya Yayın

Bir panoda Button1'e basıldığında, Thread ağındaki tüm diğer düğümleri içeren yerel çok noktaya yayın adresine bir UDP mesajı gönderilir. Bu mesajı aldıktan sonra , diğer tüm kartlardaki LED4 açılır veya kapanır . LED4, başka bir UDP mesajı alana kadar her kart için açık veya kapalı kalır.

203dd094acca1f97.png

9bbd96d9b1c63504.png

Parlattığınız cihazlar, Yönlendiriciye Uygun Son Cihaz (REED) adı verilen belirli bir Tam İş Parçacığı Aygıtıdır (FTD). Bu, bir Yönlendirici veya Son Cihaz olarak çalışabilecekleri ve kendilerini bir Son Cihazdan bir Yönlendiriciye yükseltebilecekleri anlamına gelir.

Thread 32 Yönlendiriciye kadar destekleyebilir, ancak Yönlendirici sayısını 16 ile 23 arasında tutmaya çalışır. Bir REED, bir Son Cihaz olarak bağlanırsa ve Yönlendirici sayısı 16'nın altındaysa, kendisini otomatik olarak bir Yönlendiriciye yükseltir. Bu değişiklik, uygulamada otThreadSetRouterSelectionJitter değerini ayarladığınız saniye sayısı içinde (20 saniye) rastgele bir zamanda gerçekleşmelidir.

Her İş Parçacığı ağının, bir İş Parçacığı ağındaki Yönlendirici kümesini yönetmekten sorumlu bir Yönlendirici olan bir Lider de vardır. Tüm cihazlar açıkken, 20 saniye sonra bunlardan biri Lider (LED1 açık) ve diğer ikisi Yönlendiriciler (LED2 açık) olmalıdır.

4e1e885861a66570.png

Lideri Kaldır

Lider, Thread ağından çıkarılırsa, ağın hala bir Lideri olduğundan emin olmak için, farklı bir Yönlendirici kendisini Liderliğe yükseltir.

Güç anahtarını kullanarak Lider panosunu (LED1 yanan) kapatın. Yaklaşık 20 saniye bekleyin. Kalan iki panodan birinde LED2 (Yönlendirici) kapanacak ve LED1 (Lider) yanacaktır. Bu cihaz artık Thread ağının Lideridir.

4c57c87adb40e0e3.png

Orijinal Lider panosunu tekrar açın. İplik ağına bir Son Cihaz olarak otomatik olarak yeniden katılmalıdır (LED3 yanar). 20 saniye içinde (Yönlendirici Seçimi Değişimi) kendisini bir Yönlendiriciye yükseltir (LED2 yanar).

5f40afca2dcc4b5b.png

Panoları sıfırlayın

Üç kartı da kapatın, ardından tekrar açın ve LED'leri izleyin. Güç verilen ilk kart Lider rolünde başlamalıdır (LED1 yanar) — bir İplik ağındaki ilk Yönlendirici otomatik olarak Lider olur.

Diğer iki kart başlangıçta ağa Son Cihazlar olarak bağlanır (LED3 yanar) ancak kendilerini 20 saniye içinde Yönlendiricilere (LED2 yanar) tanıtmalıdır.

Ağ bölümleri

Panolarınız yeterli güç almıyorsa veya aralarındaki radyo bağlantısı zayıfsa, Thread ağı bölümlere ayrılabilir ve Lider olarak görünen birden fazla cihazınız olabilir.

İş parçacığı kendi kendini iyileştirir, bu nedenle bölümler sonunda bir Lider ile tek bir bölüme geri birleşmelidir.

Önceki alıştırmadan devam ediliyorsa, LED4 hiçbir cihazda yanmamalıdır.

Herhangi bir kartı seçin ve Button1'e basın. Uygulamayı çalıştıran Thread ağındaki diğer tüm kartlardaki LED4 durumlarını değiştirmelidir. Önceki alıştırmadan devam ediyorsanız, şimdi devam etmeleri gerekir.

f186a2618fdbe3fd.png

Aynı kart için tekrar Button1'e basın. Diğer tüm kartlardaki LED4 tekrar geçiş yapmalıdır.

Farklı bir panoda Button1'e basın ve LED4'ün diğer kartlarda nasıl değiştiğini gözlemleyin. LED4'ün o anda açık olduğu kartlardan birinde Button1'e basın. Bu kart için LED4 açık kalır ancak diğerlerinde geçiş yapar.

f5865ccb8ab7aa34.png

Ağ bölümleri

Panolarınız bölümlenmişse ve aralarında birden fazla Lider varsa, çok noktaya yayın mesajının sonucu panolar arasında farklılık gösterecektir. Bölümlenmiş bir kart üzerinde Button1'e basarsanız (ve böylelikle bölümlenmiş Thread ağının tek üyesi olur), diğer kartlardaki LED4 yanıt olarak yanmayacaktır. Böyle bir durumda, panoları sıfırlayın - ideal olarak tek bir Thread ağını yeniden oluştururlar ve UDP mesajlaşması doğru şekilde çalışmalıdır.

OpenThread API'leri kullanan bir uygulama oluşturdunuz!

Artık biliyorsun:

  • Nordic nRF52840 geliştirme kartlarında düğmeler ve LED'ler nasıl programlanır
  • Yaygın OpenThread API'leri ve otInstance sınıfı nasıl kullanılır?
  • OpenThread durum değişikliklerini izleme ve bunlara tepki verme
  • Bir Thread ağındaki tüm cihazlara UDP mesajları nasıl gönderilir
  • Makefiles nasıl değiştirilir

Sonraki adımlar

Bu Codelab'den yola çıkarak aşağıdaki alıştırmaları deneyin:

  • GPIO modülünü yerleşik LED'ler yerine GPIO pinlerini kullanacak şekilde değiştirin ve Yönlendirici rolüne göre renk değiştiren harici RGB LED'leri bağlayın
  • Farklı bir örnek platform için GPIO desteği ekleyin
  • Tek bir düğmeye basarak tüm cihazlara ping göndermek için çok noktaya yayın kullanmak yerine, tek bir cihazı bulmak ve ping atmak için Yönlendirici / Lider API'sini kullanın
  • Bir OpenThread Sınır Yönlendiricisi kullanarak örgü ağınızı internete bağlayın ve LED'leri yakmak için bunları Thread ağının dışından çok noktaya yayınlayın

daha fazla okuma

Check out openthread.io ve GitHub OpenThread dahil kaynakları çeşitli:

Referans: