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

1. परिचय

26b7f4f6b3ea0700.png

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

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

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

2a6db2e258c32237.png

आप इन चीज़ों के बारे में जानेंगे

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

आपको इनकी ज़रूरत होगी

हार्डवेयर:

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

सॉफ़्टवेयर:

  • जीएनयू टूलचेन
  • नॉर्डिक nRF5x कमांड लाइन टूल
  • सेगर जे-लिंक सॉफ़्टवेयर
  • OpenThread
  • Git

जैसा यहां बताया गया है, उसे छोड़कर, इस कोडलैब के कॉन्टेंट को क्रिएटिव कॉमंस एट्रिब्यूशन 3.0 लाइसेंस के तहत लाइसेंस मिला है और कोड सैंपल Apache 2.0 लाइसेंस के तहत लाइसेंस मिला है.

2. शुरू करना

हार्डवेयर कोडलैब (कोड बनाना सीखना) पूरा करें

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

  • बिल्डिंग और फ़्लैशिंग के लिए आपकी ज़रूरत के सारे सॉफ़्टवेयर का विवरण
  • इसमें आपको OpenThread बनाना सिखाया गया है और इसे नॉर्डिक nRF52840 बोर्ड पर फ़्लैश किया गया है
  • यह Thread नेटवर्क की बुनियादी जानकारी दिखाता है

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

Linux मशीन

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

नॉर्डिक सेमीकंडक्टर nRF52840 बोर्ड

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

a6693da3ce213856.png

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

OpenThread को बनाने और फ़्लैश करने के लिए, आपको SEGGER J-Link, nRF5x कमांड लाइन टूल, ARM GNU Toolchain, और कई Linux पैकेज इंस्टॉल करने होंगे. अगर आपने ज़रूरत के हिसाब से Build a Thread नेटवर्क कोडलैब पूरा कर लिया है, तो आपके पास वह सब कुछ पहले से इंस्टॉल होगा जिसकी आपको ज़रूरत है. अगर ऐसा नहीं है, तो पहले कोडलैब को पूरा करें, ताकि यह पक्का किया जा सके कि आप OpenThread को nRF52840 डेव बोर्ड पर बना सकते हैं और फ़्लैश कर सकते हैं.

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

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

OpenThread Nordic nRF528xx उदाहरण रेपो का क्लोन बनाएं और 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 इंस्टेंस की जानकारी और कंट्रोल
  • ऐप्लिकेशन की सेवाएं, जैसे कि आईपीवी6, यूडीपी, और CoAP
  • नेटवर्क क्रेडेंशियल मैनेजमेंट के साथ-साथ कमिश्नर और जॉइनर की भूमिकाएं
  • बॉर्डर राऊटर का मैनेजमेंट
  • बच्चों की निगरानी और जाम का पता लगाने जैसी बेहतर सुविधाएं

सभी OpenThread API की पहचान की जानकारी, 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 इंस्टेंस

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

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

उदाहरण के लिए, हम nRF52840 बटन और LED को जोड़ने के लिए जिन GPIO फ़ंक्शन का इस्तेमाल करेंगे उनके बारे में 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 डेव बोर्ड पर बटन और LED ऐक्सेस करने के लिए, आपको nRF52840 प्लैटफ़ॉर्म के लिए उन फ़ंक्शन को लागू करना होगा. इस कोड में, आपको ऐसे फ़ंक्शन जोड़ने होंगे जो:

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

./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 सेमीकंडक्टर इन्फ़ोसेंटर देखें.

कार्रवाई: जोड़ें कि हेडर में कौन-कौनसी चीज़ें शामिल हैं.

इसके बाद, वह हेडर जोड़ें जो आपको 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. एपीआई: एलईडी चालू करने के लिए मल्टीकास्ट का इस्तेमाल करना

हमारे ऐप्लिकेशन में, जब एक बोर्ड पर बटन 1 दबाया जाता है, तो हम नेटवर्क में अन्य सभी डिवाइस पर भी यूडीपी मैसेज भेजना चाहते हैं. मैसेज मिलने की पुष्टि करने के लिए, हम दूसरे बोर्ड पर 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 स्टेटमेंट से पहले, यूडीपी वाले कॉन्सटेंट जोड़ें और तय करें:

#define UDP_PORT 1212

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

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

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

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

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;

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

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

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

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

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

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 नेटवर्क इंटरफ़ेस से बाइंड करता है. नेटवर्क इंटरफ़ेस के अन्य विकल्पों के लिए, यूडीपी एपीआई रेफ़रंस में 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 ब्लॉक पर जाकर गड़बड़ियों को सही तरीके से हैंडल करता है, जहां यह बफ़र को खाली करता है.

यूडीपी को शुरू करने के लिए इस्तेमाल किए जाने वाले फ़ंक्शन के बारे में ज़्यादा जानकारी के लिए, 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 में पहले से तय किए गए नेटवर्क की डिफ़ॉल्ट सेटिंग बदल जाएंगी, जिससे ऐप्लिकेशन ज़्यादा सुरक्षित हो जाएगा. साथ ही, हमारे नेटवर्क में Thread नोड को सिर्फ़ उन ऐप्लिकेशन के लिए सीमित किया जाएगा जो इस ऐप्लिकेशन को चला रहे हैं.

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

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

कार्रवाई: हेडर जोड़ें.

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

#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

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

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

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

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

ध्यान दें: MTD डिवाइस, राऊटर नहीं बनते. साथ ही, MTD बिल्ड में 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

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

कार्रवाई: 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 ड्राइवर फ़ाइल को NordicSemicon उन्हेंor CMakeLists.txt फ़ाइल में जोड़ें, ताकि इसे नॉर्डिक ड्राइवर के लाइब्रेरी बिल्ड में शामिल किया जा सके.

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

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

...

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

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

कोड अपडेट करने के बाद, नॉर्डिक 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 सीएलआई बाइनरी के साथ डायरेक्ट्री पर जाएं और ARM एंबेडेड टूलचेन की मदद से, इसे हेक्स फ़ॉर्मैट में बदलें:

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

बोर्ड फ़्लैश करें

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

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

20a3b4b480356447.png

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

c00d519ebec7e5f0.jpeg

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

$ 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 में से कोई एक लाइट जलेगी. यह भी हो सकता है कि आपको फ़्लैश (डिवाइस की भूमिका बदलने की सुविधा) के तुरंत बाद, लाइट वाला एलईडी स्विच 3 से 2 (या 2 से 1) तक दिख सकता है.

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

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

डिवाइस रोल इंडिकेटर

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

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

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

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

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

203dd094acca1f97.png

9bbd96d9b1c63504.png

13. डेमो: डिवाइस की भूमिका में होने वाले बदलावों पर नज़र रखें

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

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

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

4e1e885861a66570.png

लीडर को हटाएं

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

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

4c57c87adb40e0e3.png

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

5f40 देखने के लिए 2dcc4b5b.png

बोर्ड रीसेट करें

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

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

नेटवर्क विभाजन

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

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

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

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

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

f186a2618fdbe3fd.png

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

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

f5865ccb8ab7aa34.png

नेटवर्क विभाजन

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

15. बधाई हो!

आपने OpenThread API का इस्तेमाल करने वाला ऐप्लिकेशन बनाया है!

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

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

अगले चरण

इस कोडलैब को बनाने के बाद, ये काम करके देखें:

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

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

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

संदर्भ: