OpenThread API के साथ डेवलप करना

1. परिचय

26b7f4f6b3ea0700.png

Nest ने OpenThread को रिलीज़ किया है. यह Thread® नेटवर्किंग प्रोटोकॉल का ओपन-सोर्स वर्शन है. Nest ने OpenThread को रिलीज़ किया है, ताकि Nest के प्रॉडक्ट में इस्तेमाल की जाने वाली टेक्नोलॉजी, डेवलपर के लिए बड़े पैमाने पर उपलब्ध हो सके. इससे कनेक्टेड होम के लिए प्रॉडक्ट बनाने की प्रोसेस को तेज़ किया जा सकेगा.

Thread स्पेसिफ़िकेशन में, होम ऐप्लिकेशन के लिए, IPv6 पर आधारित भरोसेमंद, सुरक्षित, और कम पावर वाले वायरलेस डिवाइस-टू-डिवाइस कम्यूनिकेशन प्रोटोकॉल के बारे में बताया गया है. OpenThread, Thread नेटवर्किंग की सभी लेयर लागू करता है. इनमें एमएसी सुरक्षा, मेश लिंक सेटअप, और मेश रूटिंग के साथ IPv6, 6LoWPAN, और IEEE 802.15.4 शामिल हैं.

इस कोडलैब में, आपको Thread नेटवर्क शुरू करने, डिवाइस की भूमिकाओं में हुए बदलावों को मॉनिटर करने और उन पर कार्रवाई करने के लिए, OpenThread API का इस्तेमाल करना होगा. साथ ही, आपको यूडीपी मैसेज भेजने होंगे. इसके अलावा, आपको इन कार्रवाइयों को रीयल हार्डवेयर पर बटन और एलईडी से जोड़ना होगा.

2a6db2e258c32237.png

आपको क्या सीखने को मिलेगा

  • Nordic nRF52840 डेवलपर बोर्ड पर बटन और एलईडी को प्रोग्राम करने का तरीका
  • सामान्य OpenThread API और otInstance क्लास का इस्तेमाल करने का तरीका
  • OpenThread की स्थिति में होने वाले बदलावों को मॉनिटर करने और उन पर कार्रवाई करने का तरीका
  • Thread नेटवर्क में मौजूद सभी डिवाइसों पर यूडीपी मैसेज भेजने का तरीका
  • Makefiles में बदलाव करने का तरीका

आपको किन चीज़ों की ज़रूरत होगी

हार्डवेयर:

  • तीन Nordic Semiconductor nRF52840 डेवलपर बोर्ड
  • बोर्ड को कनेक्ट करने के लिए, तीन यूएसबी से माइक्रो-यूएसबी केबल
  • कम से कम तीन यूएसबी पोर्ट वाली Linux मशीन

सॉफ़्टवेयर:

  • GNU टूलचेन
  • Nordic nRF5x कमांड-लाइन टूल
  • Segger J-Link सॉफ़्टवेयर
  • OpenThread
  • Git

जब तक कुछ अलग से न बताया जाए, तब तक इस Codelab के कॉन्टेंट को Creative Commons Attribution 3.0 License के तहत लाइसेंस मिला है. साथ ही, कोड सैंपल को Apache 2.0 License के तहत लाइसेंस मिला है.

2. शुरू करना

हार्डवेयर कोडलैब पूरा करना

इस कोडलैब को शुरू करने से पहले, आपको nRF52840 बोर्ड और OpenThread की मदद से Thread नेटवर्क बनाना कोडलैब पूरा करना होगा. इसमें:

  • बिल्ड करने और फ़्लैश करने के लिए ज़रूरी सभी सॉफ़्टवेयर की जानकारी
  • OpenThread बनाने और उसे Nordic nRF52840 बोर्ड पर फ़्लैश करने का तरीका बताता है
  • थ्रेड नेटवर्क की बुनियादी बातों के बारे में जानकारी

इस कोडलैब में, OpenThread को बनाने और बोर्ड को फ़्लैश करने के लिए, ज़रूरी एनवायरमेंट सेट अप करने के बारे में नहीं बताया गया है. इसमें सिर्फ़ बोर्ड को फ़्लैश करने के बुनियादी निर्देश दिए गए हैं. यह माना जाता है कि आपने पहले ही थ्रेड नेटवर्क बनाने का कोडलैब पूरा कर लिया है.

Linux मशीन

इस कोडलैब को, सभी Thread डेवलपमेंट बोर्ड को फ़्लैश करने के लिए, i386 या x86 पर आधारित Linux मशीन का इस्तेमाल करने के मकसद से डिज़ाइन किया गया था. सभी चरणों की जांच Ubuntu 14.04.5 LTS (Trusty Tahr) पर की गई थी.

Nordic Semiconductor nRF52840 बोर्ड

इस कोडलैब में तीन nRF52840 PDK बोर्ड इस्तेमाल किए गए हैं.

a6693da3ce213856.png

सॉफ़्टवेयर इंस्टॉल करना

OpenThread को बनाने और फ़्लैश करने के लिए, आपको SEGGER J-Link, nRF5x कमांड लाइन टूल, ARM GNU टूलचेन, और कई Linux पैकेज इंस्टॉल करने होंगे. अगर आपने 'थ्रेड नेटवर्क बनाएं' कोडलैब को ज़रूरी शर्तों के मुताबिक पूरा कर लिया है, तो आपके पास पहले से ही ज़रूरी सभी चीज़ें इंस्टॉल होंगी. अगर ऐसा नहीं है, तो आगे बढ़ने से पहले उस Codelab को पूरा करें. इससे यह पक्का किया जा सकेगा कि आपके पास nRF52840 डेवलपर बोर्ड पर OpenThread को बनाने और फ़्लैश करने की सुविधा है.

3. डेटा स्टोर करने की जगह को क्लोन करना

OpenThread में, ऐप्लिकेशन कोड का उदाहरण दिया गया है. इसका इस्तेमाल, इस कोडलैब (कोड बनाना सीखने के लिए ट्यूटोरियल) के लिए शुरुआती बिंदु के तौर पर किया जा सकता है.

OpenThread Nordic nRF528xx के उदाहरणों वाले repo को क्लोन करें और OpenThread बनाएं:

$ git clone --recursive https://github.com/openthread/ot-nrf528xx
$ cd ot-nrf528xx
$ ./script/bootstrap

4. OpenThread API के बुनियादी बातें

OpenThread के सार्वजनिक एपीआई, OpenThread के रिपॉज़िटरी में ./openthread/include/openthread पर मौजूद हैं. ये एपीआई, आपके ऐप्लिकेशन में इस्तेमाल करने के लिए, Thread और प्लैटफ़ॉर्म, दोनों लेवल पर OpenThread की कई सुविधाओं और फ़ंक्शन का ऐक्सेस देते हैं:

  • OpenThread इंस्टेंस की जानकारी और कंट्रोल
  • IPv6, UDP, और CoAP जैसी ऐप्लिकेशन सेवाएं
  • कमिश्नर और जॉइनर की भूमिकाओं के साथ-साथ, नेटवर्क क्रेडेंशियल मैनेजमेंट
  • बॉर्डर राऊटर मैनेजमेंट
  • बेहतर सुविधाएं, जैसे कि बच्चों की निगरानी और रुकावट का पता लगाना

OpenThread के सभी एपीआई के बारे में रेफ़रंस जानकारी, openthread.io/reference पर उपलब्ध है.

एपीआई का इस्तेमाल करना

किसी एपीआई का इस्तेमाल करने के लिए, उसकी हेडर फ़ाइल को अपनी किसी ऐप्लिकेशन फ़ाइल में शामिल करें. इसके बाद, अपनी पसंद का फ़ंक्शन कॉल करें.

उदाहरण के लिए, OpenThread के साथ शामिल सीएलआई उदाहरण ऐप्लिकेशन, इन एपीआई हेडर का इस्तेमाल करता है:

./openthread/examples/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 इंस्टेंस

OpenThread API के साथ काम करते समय, otInstance स्ट्रक्चर का इस्तेमाल अक्सर किया जाता है. शुरू होने के बाद, यह स्ट्रक्चर OpenThread लाइब्रेरी के स्टैटिक इंस्टेंस को दिखाता है. साथ ही, उपयोगकर्ता को OpenThread API कॉल करने की अनुमति देता है.

उदाहरण के लिए, OpenThread इंस्टेंस को CLI के उदाहरण वाले ऐप्लिकेशन के main() फ़ंक्शन में शुरू किया जाता है:

./openthread/examples/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;
}

प्लैटफ़ॉर्म के हिसाब से फ़ंक्शन

अगर आपको OpenThread के साथ दिए गए उदाहरण के तौर पर मौजूद किसी ऐप्लिकेशन में, प्लैटफ़ॉर्म के हिसाब से फ़ंक्शन जोड़ने हैं, तो सबसे पहले उन्हें ./openthread/examples/platforms/openthread-system.h हेडर में एलान करें. इसके लिए, सभी फ़ंक्शन के लिए otSys नेमस्पेस का इस्तेमाल करें. इसके बाद, उन्हें प्लैटफ़ॉर्म के हिसाब से बनाई गई सोर्स फ़ाइल में लागू करें. इस तरह से एब्स्ट्रैक्ट करने पर, उदाहरण के तौर पर दिए गए अन्य प्लैटफ़ॉर्म के लिए, एक ही फ़ंक्शन हेडर का इस्तेमाल किया जा सकता है.

उदाहरण के लिए, nRF52840 बटन और एलईडी में जोड़ने के लिए इस्तेमाल किए जाने वाले जीपीआईओ फ़ंक्शन, openthread-system.h में बताए जाने चाहिए.

./openthread/examples/platforms/openthread-system.h फ़ाइल को अपने पसंदीदा टेक्स्ट एडिटर में खोलें.

./openthread/examples/platforms/openthread-system.h

कार्रवाई: प्लैटफ़ॉर्म के हिसाब से GPIO फ़ंक्शन के एलान जोड़ें.

openthread/instance.h हेडर के लिए, #include के बाद ये फ़ंक्शन एलान जोड़ें:

/**
 * 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);

हम अगले चरण में इन बदलावों को लागू कर देंगे.

ध्यान दें कि otSysButtonProcess फ़ंक्शन के एलान में otInstance का इस्तेमाल किया जाता है. इस तरह, ज़रूरत पड़ने पर ऐप्लिकेशन, बटन दबाने पर OpenThread इंस्टेंस की जानकारी ऐक्सेस कर सकता है. यह आपके ऐप्लिकेशन की ज़रूरतों पर निर्भर करता है. अगर आपको फ़ंक्शन को लागू करने के लिए, इसकी ज़रूरत नहीं है, तो कुछ टूलचेन के लिए, इस्तेमाल न किए गए वैरिएबल से जुड़ी बिल्ड गड़बड़ियों को रोकने के लिए, OpenThread API के OT_UNUSED_VARIABLE मैक्रो का इस्तेमाल किया जा सकता है. हम इसके उदाहरण बाद में देखेंगे.

5. GPIO प्लैटफ़ॉर्म ऐब्स्ट्रैक्शन लागू करना

पिछले चरण में, हमने ./openthread/examples/platforms/openthread-system.h में प्लैटफ़ॉर्म के हिसाब से फ़ंक्शन के एलान के बारे में बताया था. इनका इस्तेमाल GPIO के लिए किया जा सकता है. nRF52840 डेवलपर बोर्ड पर बटन और एलईडी ऐक्सेस करने के लिए, आपको nRF52840 प्लैटफ़ॉर्म के लिए उन फ़ंक्शन को लागू करना होगा. इस कोड में, आपको ऐसे फ़ंक्शन जोड़ने होंगे जो:

  • जीपीआईओ पिन और मोड को शुरू करना
  • किसी पिन पर वोल्टेज कंट्रोल करना
  • जीपीआईओ इंटरप्ट चालू करना और कॉलबैक रजिस्टर करना

./src/src डायरेक्ट्री में, gpio.c नाम की एक नई फ़ाइल बनाएं. इस नई फ़ाइल में, यह कॉन्टेंट जोड़ें.

./src/src/gpio.c (नई फ़ाइल)

कार्रवाई: डेफ़ाइन जोड़ें.

ये परिभाषाएं, nRF52840 की खास वैल्यू और OpenThread ऐप्लिकेशन लेवल पर इस्तेमाल किए जाने वाले वैरिएबल के बीच के एब्स्ट्रैक्शन के तौर पर काम करती हैं.

/**
 * @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 बटन और एलईडी के बारे में ज़्यादा जानकारी के लिए, Nordic Semiconductor Infocenter देखें.

कार्रवाई: हेडर में शामिल करें.

इसके बाद, GPIO फ़ंक्शन के लिए ज़रूरी हेडर शामिल करें.

/* 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"

कार्रवाई: बटन 1 के लिए कॉलबैक और इंटरप्ट फ़ंक्शन जोड़ें.

इसके बाद, यह कोड जोड़ें. in_pin1_handler फ़ंक्शन एक कॉलबैक है, जो बटन दबाने की सुविधा शुरू होने पर रजिस्टर होता है. इस फ़ंक्शन के बारे में इस फ़ाइल में आगे बताया गया है.

ध्यान दें कि यह कॉलबैक, OT_UNUSED_VARIABLE मैक्रो का इस्तेमाल कैसे करता है. इसकी वजह यह है कि in_pin1_handler फ़ंक्शन में पास किए गए वैरिएबल का इस्तेमाल, फ़ंक्शन में असल में नहीं किया जाता.

/* 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;
}

कार्रवाई: एलईडी को कॉन्फ़िगर करने के लिए कोई फ़ंक्शन जोड़ें.

शुरू करने के दौरान सभी एलईडी के मोड और स्टेटस को कॉन्फ़िगर करने के लिए, यह कोड जोड़ें.

/**
 * @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);
}

कार्रवाई: एलईडी का मोड सेट करने के लिए कोई फ़ंक्शन जोड़ें.

इस फ़ंक्शन का इस्तेमाल तब किया जाएगा, जब डिवाइस की भूमिका बदलेगी.

/**
 * @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;
    }
}

कार्रवाई: एलईडी के मोड को टॉगल करने के लिए कोई फ़ंक्शन जोड़ें.

इस फ़ंक्शन का इस्तेमाल, मल्टीकास्ट यूडीपी मैसेज मिलने पर LED4 को टॉगल करने के लिए किया जाएगा.

/**
 * @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;
    }
}

कार्रवाई: बटन दबाने की प्रोसेस शुरू करने और उसे प्रोसेस करने के लिए फ़ंक्शन जोड़ें.

पहला फ़ंक्शन, बटन दबाने पर बोर्ड को शुरू करता है और दूसरा फ़ंक्शन, बटन 1 दबाने पर मल्टीकास्ट यूडीपी मैसेज भेजता है.

/**
 * @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);
    }
}

कार्रवाई: gpio.c फ़ाइल को सेव करें और बंद करें.

6. एपीआई: डिवाइस की भूमिका में हुए बदलावों पर प्रतिक्रिया देना

हमें अपने ऐप्लिकेशन में, डिवाइस की भूमिका के आधार पर अलग-अलग एलईडी जलाना है. आइए, इन भूमिकाओं को ट्रैक करते हैं: लीडर, राउटर, और आखिरी डिवाइस. हम इन्हें एलईडी के लिए इस तरह असाइन कर सकते हैं:

  • LED1 = लीडर
  • LED2 = राऊटर
  • LED3 = आखिरी डिवाइस

इस सुविधा को चालू करने के लिए, ऐप्लिकेशन को यह पता होना चाहिए कि डिवाइस की भूमिका कब बदली है और जवाब में सही एलईडी को कैसे चालू किया जाए. हम पहले हिस्से के लिए OpenThread इंस्टेंस और दूसरे हिस्से के लिए GPIO प्लैटफ़ॉर्म एब्स्ट्रैक्शन का इस्तेमाल करेंगे.

./openthread/examples/apps/cli/main.c फ़ाइल को अपने पसंदीदा टेक्स्ट एडिटर में खोलें.

./openthread/examples/apps/cli/main.c

कार्रवाई: हेडर में शामिल करें.

main.c फ़ाइल के 'शामिल है' सेक्शन में, एपीआई हेडर फ़ाइलें जोड़ें. आपको भूमिका बदलने की सुविधा के लिए इन फ़ाइलों की ज़रूरत होगी.

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

कार्रवाई: OpenThread इंस्टेंस की स्थिति में बदलाव होने पर, हैंडलर फ़ंक्शन का एलान जोड़ें.

इस एलान को main.c में जोड़ें. यह एलान, हेडर के बाद और #if स्टेटमेंट से पहले जोड़ा जाना चाहिए. इस फ़ंक्शन को मुख्य ऐप्लिकेशन के बाद तय किया जाएगा.

void handleNetifStateChanged(uint32_t aFlags, void *aContext);

कार्रवाई: स्टेटस में बदलाव करने वाले हैंडलर फ़ंक्शन के लिए कॉलबैक रजिस्ट्रेशन जोड़ें.

main.c में, otAppCliInit कॉल के बाद main() फ़ंक्शन में यह फ़ंक्शन जोड़ें. यह कॉलबैक रजिस्ट्रेशन, OpenThread को बताता है कि जब भी OpenThread इंस्टेंस की स्थिति में बदलाव हो, तो handleNetifStateChange फ़ंक्शन को कॉल करें.

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

कार्रवाई: स्टेटस में बदलाव लागू करने की सुविधा जोड़ें.

main.c में, main() फ़ंक्शन के बाद handleNetifStateChanged फ़ंक्शन लागू करें. यह फ़ंक्शन, OpenThread इंस्टेंस के OT_CHANGED_THREAD_ROLE फ़्लैग की जांच करता है. अगर इसमें कोई बदलाव होता है, तो ज़रूरत के हिसाब से एलईडी को चालू/बंद करता है.

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;
        }
    }
}

7. एपीआई: एलईडी चालू करने के लिए मल्टीकास्ट का इस्तेमाल करना

हमारे ऐप्लिकेशन में, हम एक बोर्ड पर Button1 दबाने पर, नेटवर्क के सभी अन्य डिवाइसों को भी UDP मैसेज भेजना चाहते हैं. मैसेज मिलने की पुष्टि करने के लिए, हम दूसरे बोर्ड पर LED4 को टॉगल करेंगे.

इस सुविधा को चालू करने के लिए, ऐप्लिकेशन को:

  • स्टार्ट अप होने पर यूडीपी कनेक्शन शुरू करना
  • मेश-लोकल मल्टीकास्ट पते पर यूडीपी मैसेज भेजने की सुविधा
  • आने वाले यूडीपी मैसेज मैनेज करना
  • आने वाले यूडीपी मैसेज के जवाब में LED4 को टॉगल करना

./openthread/examples/apps/cli/main.c फ़ाइल को अपने पसंदीदा टेक्स्ट एडिटर में खोलें.

./openthread/examples/apps/cli/main.c

कार्रवाई: हेडर में शामिल करें.

main.c फ़ाइल में सबसे ऊपर मौजूद 'शामिल है' सेक्शन में, मल्टीकास्ट यूडीपी सुविधा के लिए ज़रूरी एपीआई हेडर फ़ाइलें जोड़ें.

#include <string.h>

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

#include "utils/code_utils.h"

code_utils.h हेडर का इस्तेमाल, otEXPECT और otEXPECT_ACTION मैक्रो के लिए किया जाता है. ये मैक्रो, रन-टाइम की शर्तों की पुष्टि करते हैं और गड़बड़ियों को आसानी से मैनेज करते हैं.

कार्रवाई: डेफ़ाइन और कॉन्सटेंट जोड़ें:

main.c फ़ाइल में, 'शामिल है' सेक्शन के बाद और किसी भी #if स्टेटमेंट से पहले, UDP के हिसाब से कॉन्स्टेंट और डेफ़ाइन जोड़ें:

#define UDP_PORT 1212

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

ff03::1, मेश-लोकल मल्टीकास्ट पता है. इस पते पर भेजे गए सभी मैसेज, नेटवर्क में मौजूद फ़ुल थ्रेड डिवाइसों पर भेजे जाएंगे. OpenThread में मल्टीकास्ट की सुविधा के बारे में ज़्यादा जानकारी के लिए, openthread.io पर मल्टीकास्ट देखें.

कार्रवाई: फ़ंक्शन के एलान जोड़ें.

main.c फ़ाइल में, otTaskletsSignalPending परिभाषा के बाद और main() फ़ंक्शन से पहले, UDP से जुड़े फ़ंक्शन जोड़ें. साथ ही, UDP सॉकेट को दिखाने के लिए स्टैटिक वैरिएबल जोड़ें:

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;

कार्रवाई: जीपीआईओ एलईडी और बटन को शुरू करने के लिए कॉल जोड़ें.

main.c में, otSetStateChangedCallback कॉल के बाद main() फ़ंक्शन में ये फ़ंक्शन कॉल जोड़ें. ये फ़ंक्शन, GPIO और GPIOTE पिन को शुरू करते हैं. साथ ही, बटन पुश इवेंट को हैंडल करने के लिए, बटन हैंडलर सेट करते हैं.

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

कार्रवाई: यूडीपी शुरू करने का कॉल जोड़ें.

main.c में, अभी जोड़े गए otSysButtonInit कॉल के बाद, main() फ़ंक्शन में यह फ़ंक्शन जोड़ें:

initUdp(instance);

इस कॉल से यह पक्का होता है कि ऐप्लिकेशन के शुरू होने पर, यूडीपी सॉकेट को शुरू किया गया है. इसके बिना, डिवाइस यूडीपी मैसेज भेज या पा नहीं सकता.

कार्रवाई: GPIO बटन इवेंट को प्रोसेस करने के लिए कॉल जोड़ें.

main.c में, while लूप में otSysProcessDrivers कॉल के बाद, main() फ़ंक्शन में यह फ़ंक्शन कॉल जोड़ें. gpio.c में बताया गया यह फ़ंक्शन, यह जांच करता है कि बटन दबाया गया है या नहीं. अगर बटन दबाया गया है, तो ऊपर दिए गए चरण में सेट किए गए हैंडलर (handleButtonInterrupt) को कॉल करता है.

otSysButtonProcess(instance);

कार्रवाई: बटन इंटरप्ट हैंडलर लागू करें.

main.c में, पिछले चरण में जोड़े गए handleNetifStateChanged फ़ंक्शन के बाद, handleButtonInterrupt फ़ंक्शन को लागू करने का तरीका जोड़ें:

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

कार्रवाई: यूडीपी को शुरू करने की सुविधा लागू करें.

main.c में, अभी जोड़े गए handleButtonInterrupt फ़ंक्शन के बाद, initUdp फ़ंक्शन को लागू करें:

/**
 * 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, OT_NETIF_THREAD);
}

UDP_PORT वह पोर्ट है जिसे आपने पहले से तय किया है (1212). otUdpOpen फ़ंक्शन, यूडीपी मैसेज मिलने पर कॉलबैक फ़ंक्शन (handleUdpReceive) को रजिस्टर करता है और सॉकेट खोलता है. otUdpBind, OT_NETIF_THREAD को पास करके, सॉकेट को Thread नेटवर्क इंटरफ़ेस से बांधता है. नेटवर्क इंटरफ़ेस के अन्य विकल्पों के लिए, UDP API रेफ़रंस में otNetifIdentifier एनोटेशन देखें.

कार्रवाई: यूडीपी मैसेजिंग लागू करें.

main.c में, अभी जोड़े गए initUdp फ़ंक्शन के बाद, sendUdp फ़ंक्शन को लागू करें:

/**
 * 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 और otEXPECT_ACTION मैक्रो पर ध्यान दें. इनसे यह पक्का होता है कि यूडीपी मैसेज मान्य है और बफ़र में सही तरीके से असाइन किया गया है. अगर ऐसा नहीं है, तो फ़ंक्शन exit ब्लॉक पर जाकर गड़बड़ियों को आसानी से मैनेज करता है. यहां यह बफ़र खाली कर देता है.

UDP को शुरू करने के लिए इस्तेमाल किए जाने वाले फ़ंक्शन के बारे में ज़्यादा जानने के लिए, openthread.io पर IPv6 और UDP रेफ़रंस देखें.

कार्रवाई: यूडीपी मैसेज मैनेज करने की सुविधा लागू करें.

main.c में, अभी जोड़े गए sendUdp फ़ंक्शन के बाद, handleUdpReceive फ़ंक्शन को लागू करें. यह फ़ंक्शन, LED4 को टॉगल करता है.

/**
 * 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);
}

8. एपीआई: Thread नेटवर्क को कॉन्फ़िगर करना

आसानी से डेमो दिखाने के लिए, हम चाहते हैं कि हमारे डिवाइस चालू होने पर, Thread तुरंत शुरू हो जाए और वे एक नेटवर्क में शामिल हो जाएं. इसके लिए, हम otOperationalDataset स्ट्रक्चर का इस्तेमाल करेंगे. इस स्ट्रक्चर में, किसी डिवाइस पर Thread नेटवर्क के क्रेडेंशियल भेजने के लिए ज़रूरी सभी पैरामीटर होते हैं.

इस स्ट्रक्चर का इस्तेमाल करने से, OpenThread में पहले से मौजूद नेटवर्क डिफ़ॉल्ट सेटिंग बदल जाएंगी. इससे, हमारा ऐप्लिकेशन ज़्यादा सुरक्षित हो जाएगा और हमारे नेटवर्क में सिर्फ़ उन थ्रेड नोड को सीमित किया जा सकेगा जो ऐप्लिकेशन चला रहे हैं.

फिर से, अपने पसंदीदा टेक्स्ट एडिटर में ./openthread/examples/apps/cli/main.c फ़ाइल खोलें.

./openthread/examples/apps/cli/main.c

कार्रवाई: हेडर शामिल करें.

main.c फ़ाइल में सबसे ऊपर मौजूद 'शामिल है' सेक्शन में, वह एपीआई हेडर फ़ाइल जोड़ें जिसकी ज़रूरत आपको थ्रेड नेटवर्क को कॉन्फ़िगर करने के लिए होगी:

#include <openthread/dataset_ftd.h>

कार्रवाई: नेटवर्क कॉन्फ़िगरेशन सेट करने के लिए, फ़ंक्शन का एलान जोड़ें.

इस एलान को main.c में जोड़ें. यह एलान, हेडर के बाद और #if स्टेटमेंट से पहले जोड़ा जाना चाहिए. इस फ़ंक्शन को ऐप्लिकेशन के मुख्य फ़ंक्शन के बाद तय किया जाएगा.

static void setNetworkConfiguration(otInstance *aInstance);

कार्रवाई: नेटवर्क कॉन्फ़िगरेशन कॉल जोड़ें.

main.c में, otSetStateChangedCallback कॉल के बाद main() फ़ंक्शन में यह फ़ंक्शन कॉल जोड़ें. यह फ़ंक्शन, Thread नेटवर्क डेटासेट को कॉन्फ़िगर करता है.

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

कार्रवाई: Thread नेटवर्क इंटरफ़ेस और स्टैक को चालू करने के लिए कॉल जोड़ें.

main.c में, otSysButtonInit कॉल के बाद main() फ़ंक्शन में ये फ़ंक्शन कॉल जोड़ें.

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

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

कार्रवाई: Thread नेटवर्क कॉन्फ़िगरेशन लागू करें.

main.c में, main() फ़ंक्शन के बाद setNetworkConfiguration फ़ंक्शन को लागू करें:

/**
 * 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 Key, PSKc, Security Policy
     */
    aDataset.mActiveTimestamp.mSeconds             = 1;
    aDataset.mActiveTimestamp.mTicks               = 0;
    aDataset.mActiveTimestamp.mAuthoritative       = false;
    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 network key to 1234C0DE1AB51234C0DE1AB51234C0DE */
    uint8_t key[OT_NETWORK_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE};
    memcpy(aDataset.mNetworkKey.m8, key, sizeof(aDataset.mNetworkKey));
    aDataset.mComponents.mIsNetworkKeyPresent = 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;

    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);
}

फ़ंक्शन में बताए गए अनुसार, इस ऐप्लिकेशन के लिए Thread नेटवर्क के पैरामीटर ये हैं:

  • चैनल = 15
  • पैन आईडी = 0x2222
  • बड़ा पैन आईडी = C0DE1AB5C0DE1AB5
  • नेटवर्क पासकोड = 1234C0DE1AB51234C0DE1AB51234C0DE
  • नेटवर्क का नाम = OTCodelab

इसके अलावा, हम रूटर चुनने में लगने वाले समय को कम करते हैं, ताकि हमारे डिवाइसों को डेमो के लिए, भूमिकाएं बदलने में कम समय लगे. ध्यान दें कि ऐसा सिर्फ़ तब किया जाता है, जब नोड एक एफ़टीडी (फ़ुल थ्रेड डिवाइस) हो. इसके बारे में अगले चरण में ज़्यादा जानकारी दी गई है.

9. एपीआई: पाबंदी वाले फ़ंक्शन

OpenThread के कुछ एपीआई, ऐसी सेटिंग में बदलाव करते हैं जिनमें सिर्फ़ डेमो या जांच के लिए बदलाव किया जाना चाहिए. इन एपीआई का इस्तेमाल, OpenThread का इस्तेमाल करने वाले ऐप्लिकेशन के प्रोडक्शन डिप्लॉयमेंट में नहीं किया जाना चाहिए.

उदाहरण के लिए, otThreadSetRouterSelectionJitter फ़ंक्शन, उस समय (सेकंड में) में बदलाव करता है जो किसी एंड डिवाइस को राउटर के तौर पर प्रमोट करने में लगता है. थ्रेड स्पेसिफ़िकेशन के मुताबिक, इस वैल्यू की डिफ़ॉल्ट वैल्यू 120 है. इस कोडलैब में आसानी से इस्तेमाल करने के लिए, हम इसे 20 पर सेट कर रहे हैं. इससे आपको थ्रेड नोड की भूमिकाएं बदलने के लिए, बहुत देर तक इंतज़ार नहीं करना पड़ेगा.

ध्यान दें: एमटीडी डिवाइस, राउटर नहीं बनते. साथ ही, otThreadSetRouterSelectionJitter जैसे फ़ंक्शन के लिए, एमटीडी बिल्ड में सहायता शामिल नहीं होती. इसके बाद, हमें CMake विकल्प -DOT_MTD=OFF तय करना होगा. ऐसा न करने पर, हमें बिल्ड करने में समस्या आ सकती है.

otThreadSetRouterSelectionJitter फ़ंक्शन की परिभाषा देखकर इस बात की पुष्टि की जा सकती है. यह परिभाषा, OPENTHREAD_FTD के प्रीप्रोसेसर डायरेक्टिव में शामिल होती है:

./openthread/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

10. CMake से जुड़े अपडेट

अपना ऐप्लिकेशन बनाने से पहले, तीन CMake फ़ाइलों के लिए कुछ छोटे अपडेट ज़रूरी हैं. बिल्ड सिस्टम, आपके ऐप्लिकेशन को कंपाइल और लिंक करने के लिए इनका इस्तेमाल करता है.

./third_party/NordicSemiconductor/CMakeLists.txt

अब NordicSemiconductor CMakeLists.txt में कुछ फ़्लैग जोड़ें, ताकि यह पक्का किया जा सके कि ऐप्लिकेशन में GPIO फ़ंक्शन तय किए गए हैं.

कार्रवाई: CMakeLists.txt फ़ाइल में फ़्लैग जोड़ें.

अपने पसंदीदा टेक्स्ट एडिटर में ./third_party/NordicSemiconductor/CMakeLists.txt खोलें और COMMON_FLAG सेक्शन में ये लाइनें जोड़ें.

...
set(COMMON_FLAG
    -DSPIS_ENABLED=1
    -DSPIS0_ENABLED=1
    -DNRFX_SPIS_ENABLED=1
    -DNRFX_SPIS0_ENABLED=1
    ...

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

...

./src/CMakeLists.txt

नई gpio.c सोर्स फ़ाइल जोड़ने के लिए, ./src/CMakeLists.txt फ़ाइल में बदलाव करें:

कार्रवाई: ./src/CMakeLists.txt फ़ाइल में gpio सोर्स जोड़ें.

अपने पसंदीदा टेक्स्ट एडिटर में ./src/CMakeLists.txt खोलें और फ़ाइल को NRF_COMM_SOURCES सेक्शन में जोड़ें.

...

set(NRF_COMM_SOURCES
  ...
  src/gpio.c
  ...
)

...

./third_party/NordicSemiconductor/CMakeLists.txt

आखिर में, nrfx_gpiote.c ड्राइवर फ़ाइल को NordicSemiconductor CMakeLists.txt फ़ाइल में जोड़ें, ताकि इसे Nordic ड्राइवरों की लाइब्रेरी बिल्ड में शामिल किया जा सके.

कार्रवाई: NordicSemiconductor CMakeLists.txt फ़ाइल में gpio ड्राइवर जोड़ें.

अपने पसंदीदा टेक्स्ट एडिटर में ./third_party/NordicSemiconductor/CMakeLists.txt खोलें और फ़ाइल को COMMON_SOURCES सेक्शन में जोड़ें.

...

set(COMMON_SOURCES
  ...
  nrfx/drivers/src/nrfx_gpiote.c
  ...
)
...

11. डिवाइसों को सेट अप करना

कोड के सभी अपडेट हो जाने के बाद, तीनों Nordic nRF52840 डेवलपर बोर्ड पर ऐप्लिकेशन को बिल्ड और फ़्लैश किया जा सकता है. हर डिवाइस, फ़ुल थ्रेड डिवाइस (एफ़टीडी) के तौर पर काम करेगा.

OpenThread बनाना

nRF52840 प्लैटफ़ॉर्म के लिए, OpenThread FTD बाइनरी बनाएं.

$ cd ~/ot-nrf528xx
$ ./script/build nrf52840 UART_trans -DOT_MTD=OFF -DOT_APP_RCP=OFF -DOT_RCP=OFF

OpenThread FTD CLI बाइनरी वाली डायरेक्ट्री पर जाएं और ARM एम्बेडेड टूलचेन की मदद से, उसे हेक्स फ़ॉर्मैट में बदलें:

$ cd build/bin
$ arm-none-eabi-objcopy -O ihex ot-cli-ftd ot-cli-ftd.hex

बोर्ड फ़्लैश करना

हर nRF52840 बोर्ड में ot-cli-ftd.hex फ़ाइल को फ़्लैश करें.

यूएसबी केबल को nRF52840 बोर्ड पर, बाहरी पावर पिन के बगल में मौजूद माइक्रो-यूएसबी डीबग पोर्ट से जोड़ें. इसके बाद, उसे अपनी Linux मशीन में प्लग करें. सही तरीके से सेट करें, LED5 चालू है.

20a3b4b480356447.png

पहले की तरह, nRF52840 बोर्ड का सीरियल नंबर नोट करें:

c00d519ebec7e5f0.jpeg

nRFx कमांड लाइन टूल की जगह पर जाएं और बोर्ड के सीरियल नंबर का इस्तेमाल करके, nRF52840 बोर्ड पर OpenThread CLI FTD हेक्स फ़ाइल को फ़्लैश करें:

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

फ़्लैश करने के दौरान, LED5 कुछ समय के लिए बंद हो जाएगा. सफल होने पर, यह आउटपुट जनरेट होता है:

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.

दूसरे दो बोर्ड के लिए, "बोर्ड फ़्लैश करें" वाला यह चरण दोहराएं. हर बोर्ड को Linux मशीन से एक ही तरह से कनेक्ट किया जाना चाहिए. साथ ही, बोर्ड के सीरियल नंबर को छोड़कर, फ़्लैश करने का निर्देश एक ही होना चाहिए. पक्का करें कि आपने

nrfjprog फ़्लैश करने का निर्देश.

अगर ऐसा हो जाता है, तो हर बोर्ड पर LED1, LED2 या LED3 जल जाएगा. आपको फ़्लैश होने के तुरंत बाद, रोशनी वाली एलईडी को तीन से दो (या दो से एक) पर स्विच करते हुए भी दिख सकता है. यह डिवाइस की भूमिका बदलने की सुविधा है.

12. ऐप्लिकेशन की मुख्य सुविधाओं और उनके काम करने के तरीके के लिए

अब तीनों nRF52840 बोर्ड चालू हो जाने चाहिए और उन पर OpenThread ऐप्लिकेशन चल रहा होगा. जैसा कि पहले बताया गया है, इस ऐप्लिकेशन में दो मुख्य सुविधाएं हैं.

डिवाइस की भूमिका के इंडिकेटर

हर बोर्ड पर जलने वाली एलईडी, थ्रेड नोड की मौजूदा भूमिका दिखाती है:

  • LED1 = लीडर
  • LED2 = राऊटर
  • LED3 = आखिरी डिवाइस

भूमिका बदलने पर, एलईडी की रोशनी भी बदल जाती है. आपको हर डिवाइस के चालू होने के 20 सेकंड के अंदर, एक या दो बोर्ड पर ये बदलाव दिखने चाहिए.

यूडीपी मल्टीकास्ट

जब किसी बोर्ड पर Button1 को दबाया जाता है, तो मेश-लोकल मल्टीकास्ट पते पर एक यूडीपी मैसेज भेजा जाता है. इसमें Thread नेटवर्क के सभी अन्य नोड शामिल होते हैं. इस मैसेज को मिलने पर, अन्य सभी बोर्ड पर LED4 टॉगल करके चालू या बंद हो जाता है. LED4 तब तक चालू या बंद रहता है, जब तक उसे कोई दूसरा यूडीपी मैसेज नहीं मिलता.

203dd094acca1f97.png

9bbd96d9b1c63504.png

13. डेमो: डिवाइस की भूमिका में हुए बदलावों को देखना

आपने जिन डिवाइसों को फ़्लैश किया है वे एक खास तरह के फ़ुल थ्रेड डिवाइस (एफ़टीडी) हैं. इन्हें राऊटर के साथ काम करने वाले एंड डिवाइस (आरईईडी) कहा जाता है. इसका मतलब है कि वे राउटर या एंड डिवाइस, दोनों के तौर पर काम कर सकते हैं. साथ ही, वे खुद को एंड डिवाइस से राउटर में बदल सकते हैं.

थ्रेड में ज़्यादा से ज़्यादा 32 राउटर जोड़े जा सकते हैं. हालांकि, राउटर की संख्या 16 से 23 के बीच रखने की कोशिश की जाती है. अगर कोई आरईईडी, एंड डिवाइस के तौर पर जुड़ता है और राउटर की संख्या 16 से कम है, तो वह अपने-आप राउटर में बदल जाता है. यह बदलाव, ऐप्लिकेशन में otThreadSetRouterSelectionJitter वैल्यू को सेट किए गए सेकंड (20 सेकंड) के अंदर, किसी भी समय हो सकता है.

हर Thread नेटवर्क में एक लीडर भी होता है. यह एक राऊटर होता है, जो Thread नेटवर्क में राऊटर के सेट को मैनेज करने की ज़िम्मेदारी रखता है. सभी डिवाइसों के चालू होने के 20 सेकंड बाद, उनमें से एक डिवाइस लीडर (LED1 चालू) और दो डिवाइस राउटर (LED2 चालू) होने चाहिए.

4e1e885861a66570.png

लीडर को हटाना

अगर लीडर को थ्रेड नेटवर्क से हटा दिया जाता है, तो कोई दूसरा राऊटर खुद को लीडर के तौर पर प्रमोट कर लेता है. इससे यह पक्का होता है कि नेटवर्क में अब भी कोई लीडर मौजूद है.

पावर स्विच का इस्तेमाल करके, लीडर बोर्ड (LED1 जलने वाला) बंद करें. करीब 20 सेकंड इंतज़ार करें. बाकी बचे दो बोर्ड में से किसी एक पर, LED2 (राऊटर) बंद हो जाएगा और LED1 (लीडर) चालू हो जाएगा. यह डिवाइस अब Thread नेटवर्क का लीडर है.

4c57c87adb40e0e3.png

ओरिजनल लीडर बोर्ड को फिर से चालू करें. यह डिवाइस, एंड डिवाइस (LED3 जलाया गया है) के तौर पर, Thread नेटवर्क से अपने-आप फिर से जुड़ जाएगा. 20 सेकंड (राउटर चुनने में लगने वाला समय) के अंदर, यह अपने-आप राउटर (LED2 जल जाता है) बन जाता है.

5f40afca2dcc4b5b.png

बोर्ड रीसेट करना

तीनों बोर्ड बंद करें. इसके बाद, उन्हें फिर से चालू करें और एलईडी देखें. सबसे पहले चालू किया गया बोर्ड, लीडर की भूमिका में शुरू होना चाहिए (LED1 जलाया गया है)—थ्रेड नेटवर्क में पहला राउटर अपने-आप लीडर बन जाता है.

शुरुआत में, अन्य दो बोर्ड नेटवर्क से एंड डिवाइस (LED3 जलता है) के तौर पर कनेक्ट होते हैं. हालांकि, 20 सेकंड के अंदर उन्हें अपने-आप राउटर (LED2 जलता है) के तौर पर प्रमोट होना चाहिए.

नेटवर्क के सेगमेंट

अगर आपके बोर्ड को ज़रूरत के मुताबिक पावर नहीं मिल रही है या उनके बीच रेडियो कनेक्शन खराब है, तो Thread नेटवर्क अलग-अलग हिस्सों में बंट सकता है. साथ ही, हो सकता है कि आपके एक से ज़्यादा डिवाइस, लीडर के तौर पर दिखें.

थ्रेड अपने-आप ठीक हो जाती है. इसलिए, आखिर में सभी सेगमेंट एक ही सेगमेंट में मर्ज हो जाते हैं और एक लीडर बन जाता है.

14. डेमो: यूडीपी मल्टीकास्ट भेजना

अगर पिछले एक्सरसाइज़ से जारी रखा जा रहा है, तो किसी भी डिवाइस पर LED4 नहीं जलना चाहिए.

कोई भी बोर्ड चुनें और Button1 दबाएं. ऐप्लिकेशन चला रहे Thread नेटवर्क के अन्य सभी बोर्ड पर मौजूद LED4 की स्थिति टॉगल हो जानी चाहिए. अगर पिछली कसरत से जारी रखा जा रहा है, तो अब ये चालू होने चाहिए.

f186a2618fdbe3fd.png

उसी बोर्ड को फिर से देखने के लिए, Button1 दबाएं. अन्य सभी बोर्ड पर LED4 फिर से टॉगल हो जाना चाहिए.

किसी दूसरे बोर्ड पर Button1 दबाएं और देखें कि दूसरे बोर्ड पर LED4 कैसे टॉगल होती है. उस बोर्ड पर Button1 दबाएं जिस पर फ़िलहाल LED4 चालू है. LED4 उस बोर्ड के लिए चालू रहता है, लेकिन अन्य बोर्ड के लिए टॉगल हो जाता है.

f5865ccb8ab7aa34.png

नेटवर्क के सेगमेंट

अगर आपके बोर्ड को अलग-अलग हिस्सों में बांटा गया है और उनमें एक से ज़्यादा लीडर हैं, तो मल्टीकास्ट मैसेज का नतीजा बोर्ड के हिसाब से अलग-अलग होगा. अगर आपने किसी ऐसे बोर्ड पर Button1 दबाया है जिसे अलग किया गया है (इसलिए, वह अलग किए गए Thread नेटवर्क का एकमात्र सदस्य है), तो दूसरे बोर्ड पर LED4 नहीं जलेगा. अगर ऐसा होता है, तो बोर्ड रीसेट करें. ऐसा करने पर, वे एक थ्रेड नेटवर्क बना देंगे और यूडीपी मैसेजिंग ठीक से काम करेगी.

15. बधाई हो!

आपने ऐसा ऐप्लिकेशन बनाया है जो OpenThread एपीआई का इस्तेमाल करता है!

अब आपको पता है कि:

  • Nordic nRF52840 डेवलपर बोर्ड पर बटन और एलईडी को प्रोग्राम करने का तरीका
  • सामान्य OpenThread API और otInstance क्लास का इस्तेमाल करने का तरीका
  • OpenThread की स्थिति में होने वाले बदलावों को मॉनिटर करने और उन पर कार्रवाई करने का तरीका
  • Thread नेटवर्क में मौजूद सभी डिवाइसों पर यूडीपी मैसेज भेजने का तरीका
  • Makefiles में बदलाव करने का तरीका

अगले चरण

इस कोडलैब के आधार पर, ये एक्सरसाइज़ आज़माएं:

  • बोर्ड पर मौजूद एलईडी के बजाय, जीपीआईओ पिन का इस्तेमाल करने के लिए जीपीआईओ मॉड्यूल में बदलाव करें. साथ ही, राऊटर की भूमिका के आधार पर रंग बदलने वाले बाहरी आरजीबी एलईडी कनेक्ट करें
  • किसी दूसरे उदाहरण प्लैटफ़ॉर्म के लिए, जीपीआईओ की सुविधा जोड़ना
  • बटन दबाकर सभी डिवाइसों को पिंग करने के लिए मल्टीकास्ट का इस्तेमाल करने के बजाय, किसी एक डिवाइस को ढूंढने और उसे पिंग करने के लिए Router/Leader API का इस्तेमाल करें
  • OpenThread बॉर्डर राऊटर का इस्तेमाल करके, अपने मेश नेटवर्क को इंटरनेट से कनेक्ट करें. साथ ही, एलईडी को रोशन करने के लिए, उन्हें Thread नेटवर्क के बाहर से मल्टीकास्ट करें

इसके बारे में और पढ़ें

OpenThread के अलग-अलग संसाधनों के लिए, openthread.io और GitHub पर जाएं. इनमें ये शामिल हैं:

रेफ़रंस: