OpenThread API এর সাথে বিকাশ করা হচ্ছে

1। পরিচিতি

26b7f4f6b3ea0700.png

Nest দ্বারা প্রকাশিত OpenThread হল Thread® নেটওয়ার্কিং প্রোটোকলের একটি ওপেন-সোর্স বাস্তবায়ন। সংযুক্ত বাড়ির জন্য পণ্যগুলির বিকাশকে ত্বরান্বিত করতে নেস্ট পণ্যগুলিতে ব্যবহৃত প্রযুক্তি বিকাশকারীদের কাছে বিস্তৃতভাবে উপলব্ধ করার জন্য নেস্ট OpenThread প্রকাশ করেছে৷

থ্রেড স্পেসিফিকেশন হোম অ্যাপ্লিকেশনের জন্য একটি IPv6-ভিত্তিক নির্ভরযোগ্য, নিরাপদ এবং কম-পাওয়ার ওয়্যারলেস ডিভাইস-টু-ডিভাইস যোগাযোগ প্রোটোকল সংজ্ঞায়িত করে। OpenThread সমস্ত থ্রেড নেটওয়ার্কিং স্তর প্রয়োগ করে যার মধ্যে IPv6, 6LoWPAN, IEEE 802.15.4 MAC নিরাপত্তা, Mesh Link Establishment, এবং Mesh Routing সহ।

এই কোডল্যাবে, আপনি একটি থ্রেড নেটওয়ার্ক শুরু করতে ওপেন থ্রেড এপিআই ব্যবহার করবেন, ডিভাইসের ভূমিকার পরিবর্তনের উপর নজর রাখতে এবং প্রতিক্রিয়া জানাতে এবং UDP বার্তা পাঠাতে, সেইসাথে বাস্তব হার্ডওয়্যারে বোতাম এবং LED-এর সাথে এই ক্রিয়াগুলিকে টাই করতে পারেন।

2a6db2e258c32237.png

আপনি কি শিখবেন

  • নর্ডিক nRF52840 ডেভ বোর্ডে বোতাম এবং এলইডি কীভাবে প্রোগ্রাম করবেন
  • কিভাবে সাধারণ OpenThread API এবং otInstance ক্লাস ব্যবহার করবেন
  • কিভাবে ওপেন থ্রেড অবস্থার পরিবর্তনগুলি নিরীক্ষণ এবং প্রতিক্রিয়া জানাতে হয়
  • কিভাবে একটি থ্রেড নেটওয়ার্কের সমস্ত ডিভাইসে UDP বার্তা পাঠাতে হয়
  • মেকফাইলগুলি কীভাবে পরিবর্তন করবেন

আপনি কি প্রয়োজন হবে

হার্ডওয়্যার:

  • 3 নর্ডিক সেমিকন্ডাক্টর nRF52840 ডেভ বোর্ড
  • বোর্ডগুলিকে সংযুক্ত করতে 3 USB থেকে মাইক্রো-USB কেবল
  • কমপক্ষে 3টি ইউএসবি পোর্ট সহ একটি লিনাক্স মেশিন

সফটওয়্যার:

  • GNU টুলচেইন
  • নর্ডিক nRF5x কমান্ড লাইন টুল
  • সেগার জে-লিংক সফটওয়্যার
  • ওপেন থ্রেড
  • গিট

অন্যথায় উল্লেখ করা ছাড়া, এই কোডল্যাবের বিষয়বস্তু ক্রিয়েটিভ কমন্স অ্যাট্রিবিউশন 3.0 লাইসেন্সের অধীনে লাইসেন্সপ্রাপ্ত , এবং কোড নমুনাগুলি Apache 2.0 লাইসেন্সের অধীনে লাইসেন্সপ্রাপ্ত

2. শুরু করা

হার্ডওয়্যার কোডল্যাব সম্পূর্ণ করুন

এই কোডল্যাব শুরু করার আগে, আপনাকে nRF52840 বোর্ড এবং ওপেন থ্রেড কোডল্যাব দিয়ে একটি থ্রেড নেটওয়ার্ক তৈরি করতে হবে, যা:

  • বিল্ডিং এবং ফ্ল্যাশ করার জন্য আপনার প্রয়োজনীয় সমস্ত সফ্টওয়্যার বিশদ বিবরণ
  • আপনাকে শেখায় কিভাবে OpenThread তৈরি করতে হয় এবং Nordic nRF52840 বোর্ডে ফ্ল্যাশ করতে হয়
  • একটি থ্রেড নেটওয়ার্কের বুনিয়াদি প্রদর্শন করে

ওপেন থ্রেড তৈরি করতে এবং বোর্ডগুলি ফ্ল্যাশ করার জন্য প্রয়োজনীয় পরিবেশগুলির কোনওটিই এই কোডল্যাবে বিশদ বিবরণ নেই - বোর্ডগুলি ফ্ল্যাশ করার জন্য শুধুমাত্র প্রাথমিক নির্দেশাবলী। মনে করা হচ্ছে আপনি ইতিমধ্যেই বিল্ড একটি থ্রেড নেটওয়ার্ক কোডল্যাব সম্পূর্ণ করেছেন।

লিনাক্স মেশিন

এই কোডল্যাবটিকে একটি i386- বা x86-ভিত্তিক লিনাক্স মেশিন ব্যবহার করার জন্য ডিজাইন করা হয়েছে যাতে সমস্ত থ্রেড ডেভেলপমেন্ট বোর্ড ফ্ল্যাশ করা যায়। সমস্ত পদক্ষেপ উবুন্টু 14.04.5 LTS (বিশ্বস্ত তাহর) এ পরীক্ষা করা হয়েছিল।

নর্ডিক সেমিকন্ডাক্টর nRF52840 বোর্ড

এই কোডল্যাব তিনটি nRF52840 PDK বোর্ড ব্যবহার করে।

a6693da3ce213856.png

সফটওয়্যার ইনস্টল

OpenThread তৈরি এবং ফ্ল্যাশ করতে, আপনাকে SEGGER J-Link, nRF5x কমান্ড লাইন টুলস, ARM GNU টুলচেইন এবং বিভিন্ন লিনাক্স প্যাকেজ ইনস্টল করতে হবে। আপনি যদি প্রয়োজন অনুসারে একটি থ্রেড নেটওয়ার্ক কোডল্যাব তৈরি করে থাকেন তবে আপনার কাছে ইতিমধ্যেই আপনার প্রয়োজনীয় সমস্ত কিছু ইনস্টল করা থাকবে। যদি তা না হয়, তাহলে আপনি nRF52840 ডেভ বোর্ডে OpenThread তৈরি এবং ফ্ল্যাশ করতে পারেন তা নিশ্চিত করার আগে কোডল্যাবটি সম্পূর্ণ করুন।

3. ভান্ডার ক্লোন করুন

OpenThread উদাহরণ অ্যাপ্লিকেশন কোড সহ আসে যা আপনি এই কোডল্যাবের জন্য একটি সূচনা পয়েন্ট হিসাবে ব্যবহার করতে পারেন।

OpenThread নর্ডিক nRF528xx উদাহরণ রেপো ক্লোন করুন এবং OpenThread তৈরি করুন:

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

4. OpenThread API বেসিক

OpenThread-এর সর্বজনীন API গুলি OpenThread সংগ্রহস্থলে ./openthread/include/openthread এ অবস্থিত। এই APIগুলি আপনার অ্যাপ্লিকেশানগুলিতে ব্যবহারের জন্য একটি থ্রেড- এবং প্ল্যাটফর্ম-স্তরে উভয়েরই বিভিন্ন OpenThread বৈশিষ্ট্য এবং কার্যকারিতাগুলিতে অ্যাক্সেস প্রদান করে:

  • OpenThread ইনস্ট্যান্স তথ্য এবং নিয়ন্ত্রণ
  • অ্যাপ্লিকেশন পরিষেবাগুলি যেমন IPv6, UDP, এবং CoAP৷
  • কমিশনার এবং যোগদানকারীর ভূমিকা সহ নেটওয়ার্ক শংসাপত্র ব্যবস্থাপনা
  • বর্ডার রাউটার ব্যবস্থাপনা
  • উন্নত বৈশিষ্ট্য যেমন শিশু তত্ত্বাবধান এবং জ্যাম সনাক্তকরণ

সমস্ত OpenThread API-এর রেফারেন্স তথ্য openthread.io/reference- এ উপলব্ধ।

একটি API ব্যবহার করে

একটি API ব্যবহার করতে, আপনার অ্যাপ্লিকেশন ফাইলগুলির একটিতে এর শিরোনাম ফাইল অন্তর্ভুক্ত করুন। তারপর পছন্দসই ফাংশন কল করুন।

উদাহরণস্বরূপ, OpenThread এর সাথে অন্তর্ভুক্ত CLI উদাহরণ অ্যাপটি নিম্নলিখিত API হেডার ব্যবহার করে:

./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 উদাহরণটি 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 বোতাম এবং 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 বোতাম এবং LED সম্পর্কে আরও তথ্যের জন্য, নর্ডিক সেমিকন্ডাক্টর ইনফোসেন্টার দেখুন।

অ্যাকশন: শিরোনাম যোগ করুন অন্তর্ভুক্ত.

এরপরে, 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;
}

অ্যাকশন: এলইডি কনফিগার করতে একটি ফাংশন যোগ করুন।

আরম্ভ করার সময় সমস্ত LED-এর মোড এবং অবস্থা কনফিগার করতে এই কোড যোগ করুন।

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

অ্যাকশন: একটি LED এর মোড সেট করতে একটি ফাংশন যোগ করুন।

ডিভাইসের ভূমিকা পরিবর্তন হলে এই ফাংশনটি ব্যবহার করা হবে।

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

অ্যাকশন: একটি LED এর মোড টগল করতে একটি ফাংশন যোগ করুন।

যখন ডিভাইসটি একটি মাল্টিকাস্ট UDP বার্তা পায় তখন এই ফাংশনটি 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;
    }
}

অ্যাকশন: বোতাম টিপে শুরু এবং প্রক্রিয়া করার জন্য ফাংশন যোগ করুন।

প্রথম ফাংশনটি একটি বোতাম প্রেসের জন্য বোর্ডকে আরম্ভ করে, এবং দ্বিতীয়টি মাল্টিকাস্ট UDP বার্তা পাঠায় যখন বোতাম 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. API: ডিভাইসের ভূমিকা পরিবর্তনের প্রতিক্রিয়া

আমাদের অ্যাপ্লিকেশনে, আমরা চাই ডিভাইসের ভূমিকার উপর নির্ভর করে বিভিন্ন LED আলোকিত হোক। আসুন নিম্নলিখিত ভূমিকাগুলি ট্র্যাক করি: লিডার, রাউটার, এন্ড ডিভাইস। আমরা সেগুলিকে এলইডিতে বরাদ্দ করতে পারি এভাবে:

  • LED1 = নেতা
  • LED2 = রাউটার
  • LED3 = শেষ ডিভাইস

এই কার্যকারিতা সক্ষম করার জন্য, অ্যাপ্লিকেশনটিকে জানতে হবে কখন ডিভাইসের ভূমিকা পরিবর্তিত হয়েছে এবং প্রতিক্রিয়াতে কীভাবে সঠিক LED চালু করতে হবে। আমরা প্রথম অংশের জন্য OpenThread উদাহরণ এবং দ্বিতীয় অংশের জন্য GPIO প্ল্যাটফর্ম বিমূর্ততা ব্যবহার করব।

আপনার পছন্দের টেক্সট এডিটরে ./openthread/examples/apps/cli/main.c ফাইলটি খুলুন।

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

অ্যাকশন: শিরোনাম যোগ করুন অন্তর্ভুক্ত.

main.c ফাইলের অন্তর্ভুক্ত বিভাগে, ভূমিকা পরিবর্তন বৈশিষ্ট্যের জন্য আপনার প্রয়োজন হবে এমন API শিরোনাম ফাইল যোগ করুন।

#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 কে handleNetifStateChange ফাংশন কল করতে বলে যখনই OpenThread ইনস্ট্যান্সের অবস্থা পরিবর্তন হয়।

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

অ্যাকশন: রাষ্ট্র পরিবর্তন বাস্তবায়ন যোগ করুন.

main.c এ, main() ফাংশনের পরে, handleNetifStateChanged ফাংশনটি প্রয়োগ করুন। এই ফাংশনটি OpenThread ইনস্ট্যান্সের OT_CHANGED_THREAD_ROLE পতাকা পরীক্ষা করে এবং যদি এটি পরিবর্তিত হয়ে থাকে, প্রয়োজন অনুযায়ী LED চালু/বন্ধ করে।

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. API: একটি LED চালু করতে মাল্টিকাস্ট ব্যবহার করুন

আমাদের অ্যাপ্লিকেশনে, যখন একটি বোর্ডে বোতাম 1 টিপানো হয় তখন আমরা নেটওয়ার্কের অন্যান্য সমস্ত ডিভাইসে UDP বার্তা পাঠাতে চাই। বার্তার প্রাপ্তি নিশ্চিত করতে, আমরা প্রতিক্রিয়া হিসাবে অন্যান্য বোর্ডগুলিতে LED4 টগল করব৷

এই কার্যকারিতা সক্ষম করতে, অ্যাপ্লিকেশনটির প্রয়োজন:

  • শুরু করার পরে একটি UDP সংযোগ শুরু করুন
  • মেশ-স্থানীয় মাল্টিকাস্ট ঠিকানায় একটি UDP বার্তা পাঠাতে সক্ষম হন
  • ইনকামিং UDP বার্তা পরিচালনা করুন
  • আগত UDP বার্তাগুলির প্রতিক্রিয়া হিসাবে LED4 টগল করুন

আপনার পছন্দের টেক্সট এডিটরে ./openthread/examples/apps/cli/main.c ফাইলটি খুলুন।

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

অ্যাকশন: শিরোনাম যোগ করুন অন্তর্ভুক্ত.

main.c ফাইলের শীর্ষে অন্তর্ভুক্ত বিভাগে, মাল্টিকাস্ট UDP বৈশিষ্ট্যের জন্য আপনার প্রয়োজনীয় API শিরোনাম ফাইলগুলি যোগ করুন।

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

অ্যাকশন: GPIO LEDs এবং বোতাম চালু করতে কল যোগ করুন।

main.c এ, otSetStateChangedCallback কলের পরে main() ফাংশনে এই ফাংশন কলগুলি যোগ করুন। এই ফাংশনগুলি GPIO এবং GPIOTE পিনগুলি শুরু করে এবং বোতাম পুশ ইভেন্টগুলি পরিচালনা করার জন্য একটি বোতাম হ্যান্ডলার সেট করে।

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

অ্যাকশন: UDP ইনিশিয়ালাইজেশন কল যোগ করুন।

main.c এ, এই ফাংশনটি main() ফাংশনে যোগ করুন otSysButtonInit কলের পরে আপনি এইমাত্র যোগ করেছেন:

initUdp(instance);

এই কলটি নিশ্চিত করে যে অ্যাপ্লিকেশন শুরু হওয়ার পরে একটি UDP সকেট শুরু হয়েছে। এটি ছাড়া, ডিভাইসটি UDP বার্তা পাঠাতে বা গ্রহণ করতে পারে না।

অ্যাকশন: GPIO বোতাম ইভেন্ট প্রক্রিয়া করতে কল যোগ করুন।

main.c এ, এই ফাংশন কলটি main() ফাংশনে যুক্ত করুন otSysProcessDrivers কলের পরে, while লুপে। এই ফাংশনটি, gpio.c এ ঘোষিত, বোতাম টিপছে কিনা তা পরীক্ষা করে, এবং যদি তাই হয়, হ্যান্ডলারকে কল করে ( handleButtonInterrupt ) যা উপরের ধাপে সেট করা হয়েছিল।

otSysButtonProcess(instance);

অ্যাকশন: বোতাম ইন্টারাপ্ট হ্যান্ডলার প্রয়োগ করুন।

main.c তে, আপনি আগের ধাপে যোগ করা handleNetifStateChanged ফাংশনের পরে handleButtonInterrupt ফাংশনের বাস্তবায়ন যোগ করুন:

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

অ্যাকশন: UDP প্রারম্ভিকতা বাস্তবায়ন করুন।

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 ফাংশন সকেটটি খোলে এবং একটি UDP বার্তা প্রাপ্ত হওয়ার জন্য একটি কলব্যাক ফাংশন ( handleUdpReceive ) নিবন্ধন করে। otUdpBind OT_NETIF_THREAD পাস করে থ্রেড নেটওয়ার্ক ইন্টারফেসের সাথে সকেটকে আবদ্ধ করে। অন্যান্য নেটওয়ার্ক ইন্টারফেস বিকল্পের জন্য, UDP API রেফারেন্সে otNetifIdentifier গণনা পড়ুন।

অ্যাকশন: UDP মেসেজিং প্রয়োগ করুন।

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 ম্যাক্রো নোট করুন। এগুলি নিশ্চিত করে যে UDP বার্তাটি বৈধ এবং বাফারে সঠিকভাবে বরাদ্দ করা হয়েছে, এবং যদি তা না হয়, ফাংশনটি exit ব্লকে ঝাঁপ দিয়ে ত্রুটিগুলি সুন্দরভাবে পরিচালনা করে, যেখানে এটি বাফারকে মুক্ত করে।

UDP আরম্ভ করার জন্য ব্যবহৃত ফাংশন সম্পর্কে আরও তথ্যের জন্য openthread.io-তে IPv6 এবং UDP রেফারেন্স দেখুন।

অ্যাকশন: 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. API: থ্রেড নেটওয়ার্ক কনফিগার করুন

প্রদর্শনের স্বাচ্ছন্দ্যের জন্য, আমরা চাই আমাদের ডিভাইসগুলি অবিলম্বে থ্রেড শুরু করুক এবং একটি নেটওয়ার্কে একসাথে যোগদান করুক যখন সেগুলি চালু থাকবে। এটি করার জন্য, আমরা otOperationalDataset কাঠামো ব্যবহার করব। এই কাঠামোটি একটি ডিভাইসে থ্রেড নেটওয়ার্ক শংসাপত্র প্রেরণের জন্য প্রয়োজনীয় সমস্ত পরামিতি ধারণ করে।

এই কাঠামোর ব্যবহার OpenThread-এ নির্মিত নেটওয়ার্ক ডিফল্টগুলিকে ওভাররাইড করবে, আমাদের অ্যাপ্লিকেশনকে আরও সুরক্ষিত করতে এবং আমাদের নেটওয়ার্কে থ্রেড নোডগুলিকে শুধুমাত্র যারা অ্যাপ্লিকেশন চালাচ্ছে তাদের মধ্যে সীমাবদ্ধ করবে।

আবার, আপনার পছন্দের টেক্সট এডিটরে ./openthread/examples/apps/cli/main.c ফাইলটি খুলুন।

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

কর্ম: শিরোনাম যোগ করুন অন্তর্ভুক্ত.

main.c ফাইলের শীর্ষে থাকা অন্তর্ভুক্ত বিভাগের মধ্যে, থ্রেড নেটওয়ার্ক কনফিগার করতে আপনার প্রয়োজন হবে এমন API হেডার ফাইল যোগ করুন:

#include <openthread/dataset_ftd.h>

অ্যাকশন: নেটওয়ার্ক কনফিগারেশন সেট করার জন্য ফাংশন ঘোষণা যোগ করুন।

এই ঘোষণাটি main.c এ যুক্ত করুন, শিরোনামটি অন্তর্ভুক্ত করার পরে এবং যেকোনো #if বিবৃতির আগে। এই ফাংশন প্রধান অ্যাপ্লিকেশন ফাংশন পরে সংজ্ঞায়িত করা হবে.

static void setNetworkConfiguration(otInstance *aInstance);

অ্যাকশন: নেটওয়ার্ক কনফিগারেশন কল যোগ করুন।

main.c এ, otSetStateChangedCallback কলের পরে main() ফাংশনে এই ফাংশন কল যোগ করুন। এই ফাংশনটি থ্রেড নেটওয়ার্ক ডেটাসেট কনফিগার করে।

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

অ্যাকশন: থ্রেড নেটওয়ার্ক ইন্টারফেস এবং স্ট্যাক সক্ষম করতে কল যোগ করুন।

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

অ্যাকশন: থ্রেড নেটওয়ার্ক কনফিগারেশন বাস্তবায়ন করুন।

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

ফাংশনে বিশদ হিসাবে, আমরা এই অ্যাপ্লিকেশনটির জন্য যে থ্রেড নেটওয়ার্ক প্যারামিটারগুলি ব্যবহার করছি তা হল:

  • চ্যানেল = 15
  • প্যান আইডি = 0x2222
  • বর্ধিত প্যান আইডি = C0DE1AB5C0DE1AB5
  • নেটওয়ার্ক কী = 1234C0DE1AB51234C0DE1AB51234C0DE
  • নেটওয়ার্কের নাম = OTCodelab

উপরন্তু, এখানেই আমরা রাউটার সিলেকশন জিটার কমিয়ে ফেলি, তাই ডেমো উদ্দেশ্যে আমাদের ডিভাইসগুলি দ্রুত ভূমিকা পরিবর্তন করে। মনে রাখবেন যে নোডটি একটি FTD (ফুল থ্রেড ডিভাইস) হলেই এটি করা হয়। পরবর্তী ধাপে যে সম্পর্কে আরো.

9. API: সীমাবদ্ধ ফাংশন

OpenThread এর কিছু API সেটিংস পরিবর্তন করে যা শুধুমাত্র ডেমো বা পরীক্ষার উদ্দেশ্যে পরিবর্তন করা উচিত। এই API গুলি OpenThread ব্যবহার করে একটি অ্যাপ্লিকেশনের উৎপাদন স্থাপনায় ব্যবহার করা উচিত নয়।

উদাহরণস্বরূপ, otThreadSetRouterSelectionJitter ফাংশন রাউটারে নিজেকে উন্নীত করতে একটি এন্ড ডিভাইসের জন্য যে সময় লাগে (সেকেন্ডে) তা সামঞ্জস্য করে। থ্রেড স্পেসিফিকেশন অনুযায়ী এই মানের জন্য ডিফল্ট হল 120। এই কোডল্যাবে ব্যবহারের সুবিধার জন্য, আমরা এটিকে 20 এ পরিবর্তন করতে যাচ্ছি, যাতে ভূমিকা পরিবর্তন করার জন্য আপনাকে থ্রেড নোডের জন্য খুব বেশি অপেক্ষা করতে হবে না।

দ্রষ্টব্য: MTD ডিভাইস রাউটারে পরিণত হয় না, এবং otThreadSetRouterSelectionJitter এর মতো একটি ফাংশনের জন্য সমর্থন একটি MTD বিল্ডে অন্তর্ভুক্ত নয়। পরে আমাদের 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

এখন নর্ডিক সেমিকন্ডাক্টর 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

সবশেষে, NordicSemiconductor CMakeLists.txt ফাইলে nrfx_gpiote.c ড্রাইভার ফাইল যোগ করুন, যাতে এটি নর্ডিক ড্রাইভারের লাইব্রেরি বিল্ডের সাথে অন্তর্ভুক্ত করা হয়।

অ্যাকশন: NordicSemiconductor CMakeLists.txt ফাইলে gpio ড্রাইভার যোগ করুন।

আপনার পছন্দের পাঠ্য সম্পাদকে ./third_party/NordicSemiconductor/CMakeLists.txt খুলুন এবং COMMON_SOURCES বিভাগে ফাইলটি যুক্ত করুন৷

...

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

11. ডিভাইসগুলি সেট আপ করুন৷

সমস্ত কোড আপডেট হয়ে গেলে, আপনি তিনটি নর্ডিক nRF52840 ডেভ বোর্ডে অ্যাপ্লিকেশনটি তৈরি এবং ফ্ল্যাশ করতে প্রস্তুত। প্রতিটি ডিভাইস ফুল থ্রেড ডিভাইস (FTD) হিসেবে কাজ করবে।

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 বোর্ডে বাহ্যিক পাওয়ার পিনের পাশে মাইক্রো-ইউএসবি ডিবাগ পোর্টে USB কেবলটি সংযুক্ত করুন এবং তারপরে এটি আপনার লিনাক্স মেশিনে প্লাগ করুন। সঠিকভাবে সেট করুন, 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.

অন্য দুটি বোর্ডের জন্য এই "বোর্ডগুলি ফ্ল্যাশ করুন" পদক্ষেপটি পুনরাবৃত্তি করুন৷ প্রতিটি বোর্ড একইভাবে লিনাক্স মেশিনের সাথে সংযুক্ত হওয়া উচিত এবং বোর্ডের ক্রমিক নম্বর ব্যতীত ফ্ল্যাশ করার কমান্ড একই। তে প্রতিটি বোর্ডের অনন্য সিরিয়াল নম্বর ব্যবহার করা নিশ্চিত করুন৷

nrfjprog ফ্ল্যাশিং কমান্ড।

সফল হলে, প্রতিটি বোর্ডে LED1, LED2 বা LED3 আলোকিত হবে। এমনকি ফ্ল্যাশ করার পরেই আপনি 3 থেকে 2 (বা 2 থেকে 1) পর্যন্ত আলোকিত LED সুইচ দেখতে পাবেন (ডিভাইসের ভূমিকা পরিবর্তন বৈশিষ্ট্য)।

12. অ্যাপ্লিকেশন কার্যকারিতা

তিনটি nRF52840 বোর্ডই এখন চালিত হওয়া উচিত এবং আমাদের OpenThread অ্যাপ্লিকেশনটি চালানো উচিত। পূর্বে বিস্তারিত হিসাবে, এই অ্যাপ্লিকেশন দুটি প্রাথমিক বৈশিষ্ট্য আছে.

ডিভাইস ভূমিকা সূচক

প্রতিটি বোর্ডে আলোকিত LED থ্রেড নোডের বর্তমান ভূমিকা প্রতিফলিত করে:

  • LED1 = নেতা
  • LED2 = রাউটার
  • LED3 = শেষ ডিভাইস

ভূমিকা যেমন পরিবর্তিত হয়, তেমনি আলোকিত LEDও হয়। প্রতিটি ডিভাইস পাওয়ার আপ হওয়ার 20 সেকেন্ডের মধ্যে একটি বা দুটি বোর্ডে এই পরিবর্তনগুলি আপনার ইতিমধ্যেই দেখা উচিত।

ইউডিপি মাল্টিকাস্ট

যখন একটি বোর্ডে Button1 চাপানো হয়, তখন একটি UDP বার্তা মেশ-স্থানীয় মাল্টিকাস্ট ঠিকানায় পাঠানো হয়, যা থ্রেড নেটওয়ার্কের অন্যান্য সমস্ত নোড অন্তর্ভুক্ত করে। এই বার্তাটি পাওয়ার প্রতিক্রিয়া হিসাবে, অন্যান্য সমস্ত বোর্ডে LED4 চালু বা বন্ধ টগল করে । প্রতিটি বোর্ডের জন্য LED4 চালু বা বন্ধ থাকে যতক্ষণ না এটি অন্য UDP বার্তা না পায়।

203dd094acca1f97.png

9bbd96d9b1c63504.png

13. ডেমো: ডিভাইসের ভূমিকা পরিবর্তন পর্যবেক্ষণ করুন

আপনি যে ডিভাইসগুলি ফ্ল্যাশ করেছেন তা হল একটি নির্দিষ্ট ধরণের ফুল থ্রেড ডিভাইস (এফটিডি) যাকে রাউটার এলিজিবল এন্ড ডিভাইস (REED) বলা হয়। এর অর্থ হল তারা একটি রাউটার বা এন্ড ডিভাইস হিসাবে কাজ করতে পারে এবং একটি এন্ড ডিভাইস থেকে রাউটারে নিজেদের প্রচার করতে পারে।

থ্রেড 32টি রাউটার পর্যন্ত সমর্থন করতে পারে, কিন্তু রাউটারের সংখ্যা 16 থেকে 23 এর মধ্যে রাখার চেষ্টা করে। যদি একটি REED একটি এন্ড ডিভাইস হিসাবে সংযুক্ত করে এবং রাউটারের সংখ্যা 16-এর নিচে হয়, তাহলে এটি স্বয়ংক্রিয়ভাবে একটি রাউটারে নিজেকে উন্নীত করে। আপনি অ্যাপ্লিকেশনে (20 সেকেন্ড) otThreadSetRouterSelectionJitter মান সেট করেছেন এমন সেকেন্ডের মধ্যে এই পরিবর্তনটি র্যান্ডম সময়ে হওয়া উচিত।

প্রতিটি থ্রেড নেটওয়ার্কেরও একটি লিডার থাকে, যা একটি রাউটার যা একটি থ্রেড নেটওয়ার্কে রাউটারের সেট পরিচালনার জন্য দায়ী। সমস্ত ডিভাইস চালু থাকলে, 20 সেকেন্ড পরে তাদের মধ্যে একটি লিডার (LED1 চালু) এবং অন্য দুটি রাউটার (LED2 চালু) হওয়া উচিত।

4e1e885861a66570.png

নেতাকে সরান

যদি থ্রেড নেটওয়ার্ক থেকে লিডারকে সরিয়ে দেওয়া হয়, তাহলে একটি ভিন্ন রাউটার নিজেকে একজন লিডারে উন্নীত করে, যাতে নিশ্চিত করা যায় যে নেটওয়ার্কটিতে এখনও একজন লিডার আছে।

পাওয়ার সুইচ ব্যবহার করে লিডার বোর্ড (যেটিতে LED1 আলো আছে) বন্ধ করুন। প্রায় 20 সেকেন্ড অপেক্ষা করুন। বাকি দুটি বোর্ডের একটিতে, LED2 (রাউটার) বন্ধ হয়ে যাবে এবং LED1 (লিডার) চালু হবে। এই ডিভাইসটি এখন থ্রেড নেটওয়ার্কের নেতা।

4c57c87adb40e0e3.png

আসল লিডার বোর্ড আবার চালু করুন। এটি স্বয়ংক্রিয়ভাবে থ্রেড নেটওয়ার্কে একটি শেষ ডিভাইস হিসাবে পুনরায় যোগদান করা উচিত (LED3 জ্বলছে)। 20 সেকেন্ডের মধ্যে (রাউটার নির্বাচন জিটার) এটি নিজেকে একটি রাউটারে উন্নীত করে (LED2 আলোকিত)।

5f40afca2dcc4b5b.png

বোর্ডগুলি পুনরায় সেট করুন

তিনটি বোর্ডই বন্ধ করুন, তারপরে তাদের আবার চালু করুন এবং LED গুলি পর্যবেক্ষণ করুন। চালিত প্রথম বোর্ডটি লিডার রোলে শুরু হওয়া উচিত (LED1 জ্বলছে)—থ্রেড নেটওয়ার্কের প্রথম রাউটারটি স্বয়ংক্রিয়ভাবে লিডার হয়ে যায়।

অন্য দুটি বোর্ড প্রাথমিকভাবে এন্ড ডিভাইস (LED3 আলোকিত) হিসাবে নেটওয়ার্কের সাথে সংযুক্ত হয় কিন্তু 20 সেকেন্ডের মধ্যে নিজেদের রাউটারে (LED2 আলোকিত) প্রচার করা উচিত।

নেটওয়ার্ক পার্টিশন

যদি আপনার বোর্ডগুলি পর্যাপ্ত শক্তি না পায়, বা তাদের মধ্যে রেডিও সংযোগ দুর্বল হয়, তাহলে থ্রেড নেটওয়ার্কটি পার্টিশনে বিভক্ত হতে পারে এবং আপনার কাছে একাধিক ডিভাইস থাকতে পারে যা লিডার হিসাবে প্রদর্শিত হতে পারে।

থ্রেড স্ব-নিরাময় হয়, তাই পার্টিশনগুলি শেষ পর্যন্ত একটি নেতার সাথে একটি একক পার্টিশনে আবার একত্রিত হওয়া উচিত।

14. ডেমো: UDP মাল্টিকাস্ট পাঠান

পূর্ববর্তী অনুশীলন থেকে অব্যাহত থাকলে, LED4 কোনো ডিভাইসে আলো দেওয়া উচিত নয়।

যেকোনো বোর্ড বেছে নিন এবং বোতাম 1 টিপুন। অ্যাপ্লিকেশানটি চলমান থ্রেড নেটওয়ার্কের অন্যান্য সমস্ত বোর্ডে LED4 তাদের অবস্থা টগল করা উচিত। আগের ব্যায়াম থেকে অব্যাহত থাকলে, সেগুলি এখন চালু হওয়া উচিত।

f186a2618fdbe3fd.png

একই বোর্ডের জন্য আবার বোতাম 1 টিপুন। অন্য সব বোর্ডে LED4 আবার টগল করা উচিত।

একটি ভিন্ন বোর্ডে বোতাম 1 টিপুন এবং অন্যান্য বোর্ডে কীভাবে LED4 টগল হয় তা পর্যবেক্ষণ করুন। LED4 বর্তমানে চালু আছে এমন একটি বোর্ডে বোতাম 1 টিপুন। LED4 সেই বোর্ডের জন্য চালু থাকে কিন্তু অন্যগুলিতে টগল করে।

f5865ccb8ab7aa34.png

নেটওয়ার্ক পার্টিশন

যদি আপনার বোর্ডগুলি বিভক্ত হয়ে থাকে এবং তাদের মধ্যে একাধিক নেতা থাকে, তাহলে মাল্টিকাস্ট বার্তার ফলাফল বোর্ডগুলির মধ্যে আলাদা হবে৷ আপনি যদি পার্টিশন করা একটি বোর্ডে বোতাম 1 টিপুন (এবং এইভাবে বিভাজিত থ্রেড নেটওয়ার্কের একমাত্র সদস্য), অন্য বোর্ডগুলিতে LED4 প্রতিক্রিয়াতে আলোকিত হবে না। যদি এটি ঘটে, বোর্ডগুলি পুনরায় সেট করুন - আদর্শভাবে তারা একটি একক থ্রেড নেটওয়ার্ক সংস্কার করবে এবং UDP মেসেজিং সঠিকভাবে কাজ করবে৷

15. অভিনন্দন!

আপনি একটি অ্যাপ্লিকেশন তৈরি করেছেন যা OpenThread API ব্যবহার করে!

আপনি এখন জানেন:

  • নর্ডিক nRF52840 ডেভ বোর্ডে বোতাম এবং এলইডি কীভাবে প্রোগ্রাম করবেন
  • কিভাবে সাধারণ OpenThread API এবং otInstance ক্লাস ব্যবহার করবেন
  • কিভাবে ওপেন থ্রেড অবস্থার পরিবর্তনগুলি নিরীক্ষণ এবং প্রতিক্রিয়া জানাতে হয়
  • কিভাবে একটি থ্রেড নেটওয়ার্কের সমস্ত ডিভাইসে UDP বার্তা পাঠাতে হয়
  • মেকফাইলগুলি কীভাবে পরিবর্তন করবেন

পরবর্তী পদক্ষেপ

এই কোডল্যাবটি তৈরি করে, নিম্নলিখিত অনুশীলনগুলি চেষ্টা করুন:

  • অনবোর্ড এলইডির পরিবর্তে জিপিআইও পিন ব্যবহার করতে জিপিআইও মডিউলটি পরিবর্তন করুন এবং রাউটারের ভূমিকার উপর ভিত্তি করে রঙ পরিবর্তন করে বহিরাগত আরজিবি এলইডি সংযুক্ত করুন
  • একটি ভিন্ন উদাহরণ প্ল্যাটফর্মের জন্য GPIO সমর্থন যোগ করুন
  • একটি বোতাম প্রেস থেকে সমস্ত ডিভাইসে পিং করার জন্য মাল্টিকাস্ট ব্যবহার করার পরিবর্তে, একটি পৃথক ডিভাইস সনাক্ত করতে এবং পিং করতে রাউটার/লিডার API ব্যবহার করুন
  • একটি ওপেন থ্রেড বর্ডার রাউটার ব্যবহার করে আপনার মেশ নেটওয়ার্ককে ইন্টারনেটে সংযুক্ত করুন এবং LED গুলিকে আলোকিত করতে থ্রেড নেটওয়ার্কের বাইরে থেকে মাল্টিকাস্ট করুন

আরও পড়া

Openthread.io এবং GitHub বিভিন্ন OpenThread সম্পদের জন্য দেখুন, যার মধ্যে রয়েছে:

তথ্যসূত্র: