2024년 10월 31일 목요일

Thread Router와 Device 이야기

이번 시간에는 Gl-iNet사에서 개발한 GL-S200/S20 Thread Border RouterThread Dev Board를 이용하여 Thread 프로토콜이 어떻게 동작하는지에 관하여 살펴 보고자 한다. 😎  

 

목차
1. Thread Protocol
2. Thread Border Router GL-S200과 Thread Dev Board A0/A1
3. Thread Dev Board 용 Firmware 만들기
4. 또 다른 Thread Border Router GL-S20
5. 아직 못다한 이야기
6. References



OpenWrt(S200 router), FreeRTOS(S20 router), 그리고 Zephyr(TDB 디바이스)의 절묘한 만남~


1. Thread Protocol
Thread(R)는 일반적으로 WPAN(Wireless Personal Area Network)이라고 부르는 IEEE 802.15.4-2006 무선 메쉬 네트워크 상에서, 저전력 IoT 기기 간의 원할한 통신을 위해 설계된 IPv6 기반의 네트워크 프로토콜이다. 유사한 프로토콜로는 ZigBee, Z-Wave, Bluetooth LE(BLE) 등을 생각해 볼 수 있다.

[그림 1.1] Thread 로고 [출처 - https://www.threadgroup.org]

Thread의 주요 특징을 열거해 보면 다음과 같다(느낌을 살리기 위해 일부러 원문을 그대로 유지하였다).

  • Simplicity(단순성/쉬움) — Simple installation, start up, and operation
  • Security(보안성) — All devices in a Thread network are authenticated and all communications are encrypted
  • Reliability(신뢰성) — Self-healing mesh networking, with no single point of failure, and spread-spectrum techniques to provide immunity to interference
  • Efficiency(효율성/저전력) — Low-power Thread devices can sleep and operate on battery power for years
  • Scalability(확장성) — Thread networks can scale up to hundreds of devices


Thread 관련 대표적인 Open source project로는 Google에서 개발한 OpenThread 프로젝트가 있다.

[그림 1.2] OpenThread의 주요 기능 [출처 - 참고문헌 4]

[그림 1.3] OpenThread Architecture [출처 - 참고문헌 4]

Thread는 IPv6를 기반으로 하는 protocol(ip 주소를 이용하여 통신)로써, 아래와 같이 6LoWPAN -> IPv6(IP routing) -> UDP/DTLS의 계층 구조로 구성되어 있다.

[그림 1.4] Thread Stack [출처 - 참고문헌 6]

한편 Thread는 아래 그림과 같이 mesh network을 기반으로 동작한다. Mesh network을 구성하는 각각의 thread node는 상호간의 통신을 통해 router(parent) 혹은 종단 device(child)와 같은 역할을 부여받게 된다. 또한, 이 과정에서 Thread reader(router)를 선출하게 된다.


[그림 1.5] Thread Network Topology [출처 - 참고문헌 5]


[그림 1.6] Thread Node의 역할 - Router와 End Device [출처 - 참고문헌 4]


[그림 1.7] Thread Node의 Type - Full Thread Device와 Minimal Thread Device [출처 - 참고문헌 4]

[그림 1.8] Thread Leader와 Border Router [출처 - 참고문헌 4]


[그림 1.9] Thread Border Router [출처 - 참고문헌 4]

이렇게 Mesh network를 통해 ip 통신이 가능한 환경이 갖추어진 후에는, node 간의 message 전송은 CoAP(Constrained Application Protocol)을 기반으로 진행된다.

[그림 1.10] CoAP 프로토콜#1 [출처 - 참고문헌 11]


[그림 1.11] CoAP 프로토콜#2 [출처 - 참고문헌 11]

또한 CoAP을 통해 전송되는 data를 보호하기 위하여 DTLS protocol이 사용된다. DTLS는 UDP용 TLS protocol을 의미하며, 아래와 같은 방식으로 handshaking(상호 인증 및 키 교환, 이후 안전한 암호 통신)을 한다.

[그림 1.12] DTLS Protocol [출처 - 참고문헌 8]

끝으로, 아래 그림은 (2장에서 소개할) GL-S200 router를 border router(thread network을 ip network으로 연결해 주는 router)로 사용한 경우의 Thread network 구성을 보여준다.
[그림 1.13] GL-S200 기반의 Thread Network 구성[출처 - 참고문헌 3]

지금까지 Thread protocol에 관하여 수박 겉핥기 식으로 대략적인 내용을 살펴 보았다. 부족한 부분은 독자 여러분의 몫(source code를 들여다 보아야 함)으로 남기며, 다음 장으로 넘어가도록 하겠다. 😂

 https://github.com/openthread/openthread


2. Thread Border Router GL-S200과 Thread Dev Board A0/A1

Gl-iNet은 소형 Internet Router로 유명한 회사이다. 개인적으로는 8년 정도 전부터 이 회사에서 나온 여러 제품을 구매하여 사용(심지어는 제품으로 판매하고자 s/w를 개선한 적도 있음)해 오고 있는데, 오늘은 이 중에서 Thread 프로토콜을 지원하는 GL-S200 router model과 A0/A1 Thread Dev Board을 소개해 보고자 한다.

<Gl-iNet Router의 장점>

  • Open source이다. 많은 부분이 공개되어 있긴하나, 최근 들어 full build가 안되는 문제가 있는 점은 아쉬운 부분이다. 😈
  • Router design이 훌륭하다(very cute하다).
  • WebUI가 수려하고, (실험 정신이 느껴질 정도로) 다양한 기능을 제공한다. Original OpenWrt webui도 덤으로 제공된다.
  • Wi-Fi repeater 기능이 탁월하다(wi-fi만을 이용해서 인터넷 연결이 가능함).
  • (필자가 좋아하는) WireGuard가 기본적으로 탑재되어 있다(OpenVPN도 있음).
  • OpenWrt를 기본 OS(배포 형식)로 하고 있으며, ssh 접속이 가능하고, s/w를 심을 수 있다.
  • GL-S200의 경우는 LAN 쪽에 Thread, BLE, Wi-Fi, 유선 ethernet 연결을 지원한다.
  • ...

📌 이 밖에도 모두 열거하기 어려울 정도로 아주 많은 장점을 가지고 있다. 😍


[그림 2.1] GL-S200(우측)과 Thread Device Board(좌측)

앞서 언급한 바와 같이, GL-S200의 장점으로는 LAN 쪽에 Thread, BLE, Wi-Fi 등의 무선 연결이 가능한 다양한 센서를 붙일 수 있다는 점을 꼽을 수 있다.

[그림 2.2] GL-S200 기반의 Thread Network [출처 - 참고문헌 3]
📌 GL-S200은 Thread or BLE(LAN)와 wi-fi or ethernet(WAN) network의 경계를 연결해준다는 의미에서 Border Router(Gateway)라고 부른다.

GL-S200 router의 PCB 구성을 유심히 살펴 보면, 좌측의 Thread module과 우측의 BLE module이 눈에 들어온다.


[그림 2.3] GL-S200의 PCB pinout [출처 - 참고문헌 3]

GL-S200의 H/W spec은 다음과 같다. 👍

[그림 2.4] GL-S200의 H/W spec.


한편, 아래 그림은 GL-S200과 연동가능한 TDB(Thread Device Board)의 외관으로, 좌측의 Base 보드(A0)와 우측의 daughter 보드(온도/습도/조도/압력 센서 등 탑재 - A1)로 구성되어 있다. GL-S200 보드와 연동시키기 위해서는 별도의 pairing 절차를 따라야만 한다.

[그림 2.5] GL Thread Device Board A0, A1

Thread Device Board의 H/W spec은 다음과 같다.
[그림 2.6] GL TDB(Thread Device Board) H/W information
📌 TDB는 MCU로 Nordic NRF52840 SoC를 사용하고 있으며, 온도, 습도, 조도, 압력 및 초전 적외선 센서, 그리고 LED와 3개의 button 등이 장착되어 있다. 캬~ 살 때는 몰랐는데, 있을 건 다 있다. +💯

GL-S200 router와 Thread Device Board를  연결하는 방법과 관련해서는 아래 page에 상세히 설명되어 있다.

따라서, 이 내용을 참조하여 1개의 TDB를 GL-S200 router에 연결해 보면 다음과 같다(TDB EUI-64 값, 온도, 압력, 습도, 조도 정보 등이 출력됨).

[그림 2.7] GL-S200 Thread Network 화면


[그림 2.8] GL-S200과 Thread Device Board 간의 pairing 후 모습(1)


[그림 2.9] GL-S200과 Thread Device Board 간의 pairing 후 모습(2)


참고로, GL-S200 router는 ssh 접속이 가능한데, 아래에 ssh login 모습을 capture해 보았다.
$ ssh root@192.168.8.1

[그림 2.10] GL-S200 router에 ssh login한 모습


재밌게도, (ssh login 후) 아래 명령을 실행할 경우, 앞서 WebUI에 표시되었던 sensor 정보 값 등을 뽑아낼 수가 있다.

root@GL-S200:~# /usr/bin/demo_get_sensor_data
1 dev_id=9483c4624605dbe8 connected=0 temperature=23.655776 humidity=46.076965 brightness=93 pressure=101.217536

[그림 2.11] GL-S200 router에서 TDB 센서 정보 출력
📌 Border Router에서 외부 서버(예: Cloud 서버)로 sensor 정보를 전달하고자 할 때 활용하면 좋을 듯 하다.

끝으로, TDB 장치의 동작 내용은 serial console을 통해 확인 가능하다.

sudo minicom -D /dev/ttyUSB1 -b 460800

[그림 2.12] GL Thread Dev Board Console 출력 모습
📌 Baudrate이 460800으로 다소 특이하다.

이상으로 GL-S200 router와 TDB thread 장치를 간략히 살펴 보고, 둘 간을 Thread protocol을 이용하여 연결시켜 보았다. 다음 장에서는 TDB 장치의 firmware를 직접 build하고 설치(기존 내용 교체)하는 과정을 소개해 보도록 하자. 🔧



3. Thread Dev Board 용 Firmware 만들기
이번 장에서는 Thread Dev Board용 firmware를 새로 build해서 올리는 방법을 소개하고자 한다.

[그림 3.1] GL Thread Dev Board pinout [출처 - https://github.com/gl-inet/gl-thread-dev-board]

TDB의 MCU인 NRF52840 SoC은 ARM Cortex-M4, 1MB flash, 256KB RAM, BLE, Thread, ZigBee 및 다양한 주변장치 controller(UART, i2c, spi ..)등으로 구성되어 있다.

[그림 3.2] nRF52840 SoC [출처 - https://www.nordicsemi.com/Products/nRF52840]

한편, TDB가 Zephyr project를 기반으로 되어 있는 만큼, 관련 내용을 사전에 확인해 볼 필요가 있겠다.




3.1 TDB firmware build 하기
아래 github에 올라가 있는 source code를 살펴 보니, (앞서에 언급한 바와 같이)재밌게도 Zephyr project를 기반으로 하고 있다. 


Zephyr project에 관해서는 좀 오래되기는 했어도, (다음 단계로 넘어가기에 앞서) 필자가 작성한 이전 글을 참조해 보는 것도 좋을 듯 싶다. 😙

<TDB firmware build 하기>
$ cd zephyrproject/
chyi@earth:~$ west init -m https://github.com/gl-inet/gl-nrf-sdk --mr v2.2.0-glinet gl-nrf-sdk
=== Initializing in /home/chyi/gl-nrf-sdk
--- Cloning manifest repository from https://github.com/gl-inet/gl-nrf-sdk, rev. v2.2.0-glinet
'/home/chyi/gl-nrf-sdk/.west/manifest-tmp'에 복제합니다...
remote: Enumerating objects: 203945, done.
remote: Total 203945 (delta 0), reused 0 (delta 0), pack-reused 203945 (from 1)
오브젝트를 받는 중: 100% (203945/203945), 135.86 MiB | 1.09 MiB/s, 완료.
델타를 알아내는 중: 100% (152502/152502), 완료.
--- setting manifest.path to nrf
=== Initialized. Now run "west update" inside /home/chyi/gl-nrf-sdk.

$ cd gl-nrf-sdk/
$ west update

$ cd glinet/gl-dev-board-over-thread
chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread$ ls -la
합계 92
drwxrwxr-x 12 chyi chyi  4096 10월 28 16:32 .
drwxrwxr-x  3 chyi chyi  4096 10월 26 18:21 ..
drwxrwxr-x  8 chyi chyi  4096 10월 26 18:29 .git
drwxrwxr-x  3 chyi chyi  4096 10월 26 18:21 .github
-rwxrwxr-x  1 chyi chyi    13 10월 26 18:21 .gitignore
-rwxrwxr-x  1 chyi chyi  2278 10월 26 18:21 CMakeLists.txt
-rwxrwxr-x  1 chyi chyi  1205 10월 26 18:21 Kconfig
-rwxrwxr-x  1 chyi chyi 11357 10월 26 18:21 LICENSE
-rwxrwxr-x  1 chyi chyi 11174 10월 26 18:21 README.md
drwxrwxr-x  2 chyi chyi  4096 10월 26 18:21 boards
drwxrwxr-x  8 chyi chyi  4096 10월 26 18:34 build
drwxrwxr-x  4 chyi chyi  4096 10월 26 18:21 docs
drwxrwxr-x  4 chyi chyi  4096 10월 26 18:21 drivers
drwxrwxr-x  3 chyi chyi  4096 10월 26 18:21 dts
-rw-rw-r--  1 chyi chyi  1983 10월 26 18:21 guide_to_use.md
drwxrwxr-x  2 chyi chyi  4096 10월 26 18:21 hardware_files
-rwxrwxr-x  1 chyi chyi  2673 10월 26 18:21 prj.conf
drwxrwxr-x  3 chyi chyi  4096 10월 26 18:21 src
drwxrwxr-x  4 chyi chyi  4096 10월 26 18:21 uart_dfu

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread$ west build -b gl_nrf52840_dev_board
📌 zephyr project에서는 west로 build를 한다. -p always option을 주면 pristine(초기 상태로 clean) build를 하게 해 준다.
...
[657/675] Linking CXX executable zephyr/zephyr_pre0.elf

[661/675] Linking CXX executable zephyr/zephyr_pre1.elf

[667/675] Linking CXX executable zephyr/zephyr.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:      440916 B     495104 B     89.06%
             RAM:      115768 B       256 KB     44.16%
        IDT_LIST:          0 GB         2 KB      0.00%
[670/675] Generating ../../zephyr/app_update.bin          #아무래도 update시에는 이 파일을 사용하는 것 같다.
sign the payload
[672/675] Generating ../../zephyr/app_signed.hex
sign the payload
[673/675] Generating ../../zephyr/app_test_update.hex
sign the payload
[675/675] Generating zephyr/merged.hex                      #얘는 jtag/swd 연결 후 사용하는 통합 image로 보임.

OK, 성공적으로 build가 되었으니, 이제 부터는 flash writing을 시도해 보도록 하자.

TDB firmware 설치 방법 3가지
  • 1) JTAG or SWD(Serial Wire Debug) adapter를 이용하는 방법
  • 2) DFU over Serial 방법(ROM code에서 설치 모드 진입 후 진행)
  • 3) DFU over IP 방법(WebUI에서 network으로 설치하는 방법)
이 중 처음 2가지 방법을 시도해보도록 하겠다.

<1. SWD debugger를 이용한 방법>
원래대로라면, 정품 J-link adapter를 이용하여 flash writing을 시도하는 것이 답이겠지만, 개인적으로 (값비싼) J-link adapter를 보유하지 못한 관계로, 아래와 같이 SWD 호환 debugger(디바이스 마트에서 5000원에 구매 😝)를 이용해 보기로 한다.

[그림 3.3] J-Link OB(On Board) V8 micro USB ARM용 SWD 호환 디버거 [SZH-EK205] [출처 - 참고문헌 12]

먼저, 아래와 같은 구성으로 pin 연결을 한 후, USB cable을 PC(notebook)에 연결한다.
[그림 3.4] J-Link OB V8 micro USB ARM용 SWD 호환 디버거 연결 개요도

<TDB>                             <SWD debugger>
VCC(3.3V)    ---------         VCC
GND              ---------         GND
SWDIO          ---------         SWDIO
SWDCLK       ---------         SWDCLK

[그림 3.5] J-Link OB V8 micro USB ARM용 SWD 호환 디버거 연결 모습

다음으로, dmesg 명령으로 SWD debugger가 USB 장치로 제대로 인식되는지 확인한다.
$ sudo dmesg
[ 1396.261536] usb 1-9: new full-speed USB device number 8 using xhci_hcd
[ 1396.388703] usb 1-9: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice=81.34
[ 1396.388713] usb 1-9: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 1396.388717] usb 1-9: Product: USB Serial
[ 1396.391179] ch341 1-9:1.0: ch341-uart converter detected
[ 1396.391715] usb 1-9: ch341-uart converter now attached to ttyUSB1
[ 8708.931035] usb 1-9: USB disconnect, device number 8
[ 8708.931388] ch341-uart ttyUSB1: ch341-uart converter now disconnected from ttyUSB1
[ 8708.931419] ch341 1-9:1.0: device disconnected
[ 9267.124593] usb 1-7.1: new full-speed USB device number 9 using xhci_hcd
[ 9267.203694] usb 1-7.1: New USB device found, idVendor=1366, idProduct=0101, bcdDevice= 1.00
[ 9267.203706] usb 1-7.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 9267.203710] usb 1-7.1: Product: J-Link
[ 9267.203713] usb 1-7.1: Manufacturer: SEGGER
[ 9267.203716] usb 1-7.1: SerialNumber: 000000123456

그 다음, 아래 site에서 nrfjprog tool을 내려 받아 설치하도록 한다(west flash 명령을 시도해 보면, nrfjprog가 없다고 나옴).

sudo dpkg -i ./nrf-command-line-tools_10.24.2_amd64.deb
$ sudo apt install /opt/nrf-command-line-tools/share/JLink_Linux_V794e_x86_64.deb --fix-broken
📌 nrfjprog은 SEGGER J-Link programmer & debugger를 사용하여 노르딕 SoC에 flash writing(or debugging)을 할 때 사용하는 명령 도구이다. Openocd와 유사한 녀석으로 생각하면 될 듯하다.

자, 준비가 끝났으니, flash writing을 해 보자.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread$ west flash --erase
-- west flash: rebuilding
[0/5] Performing build step for 'mcuboot_subimage'
ninja: no work to do.
[2/2] cd /home/chyi/gl-nrf-sdk/glinet/gl-dev-boar...-sdk/modules/lib/openthread/etc/cmake/print.cmake
OPENTHREAD_CONFIG_ASSERT_ENABLE=0
OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE=0
OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE=0
OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE=0
OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE=0
OPENTHREAD_CONFIG_CHANNEL_MONITOR_ENABLE=0
OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE=0
OPENTHREAD_CONFIG_COAP_API_ENABLE=1
OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE=0
OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE=0
OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE=0
OPENTHREAD_CONFIG_COMMISSIONER_ENABLE=0
OPENTHREAD_CONFIG_MAC_CSL_AUTO_SYNC_ENABLE=0
OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE=0
OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE=0
OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE=0
OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE=0
OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE=0
OPENTHREAD_CONFIG_DIAG_ENABLE=0
OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE=0
OPENTHREAD_CONFIG_DNS_DSO_ENABLE=0
OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE=0
OPENTHREAD_CONFIG_DUA_ENABLE=0
OPENTHREAD_CONFIG_ECDSA_ENABLE=1
OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE=0
OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE=0
OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE=0
OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE=0
OPENTHREAD_CONFIG_JOINER_ENABLE=1
OPENTHREAD_CONFIG_LEGACY_ENABLE=1
OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE=0
OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE=0
OPENTHREAD_CONFIG_LINK_RAW_ENABLE=0
OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE=0
OPENTHREAD_CONFIG_MAC_FILTER_ENABLE=0
OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE=0
OPENTHREAD_CONFIG_MLR_ENABLE=0
OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE=0
OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE=0
OPENTHREAD_CONFIG_NEIGHBOR_DISCOVERY_AGENT_ENABLE=0
OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE=0
OPENTHREAD_CONFIG_OTNS_ENABLE=0
OPENTHREAD_CONFIG_PING_SENDER_ENABLE=1
OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE=0
OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE=0
OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE=0
OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE=0
OPENTHREAD_SETTINGS_RAM=0
OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE=1
OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE=0
OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE=1
OPENTHREAD_CONFIG_SRP_SERVER_ENABLE=0
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE=0
OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE=0
OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE=0
OPENTHREAD_CONFIG_UPTIME_ENABLE=0
OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT=0
OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS=0
OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS_MANAGEMENT=0
PACKAGE_NAME=OPENTHREAD
OPENTHREAD_CONFIG_THREAD_VERSION=OT_THREAD_VERSION_1_3
OPENTHREAD_CONFIG_NCP_HDLC_ENABLE=1
KERNEL
__ZEPHYR__=1
_FORTIFY_SOURCE=1
_ANSI_SOURCE
__LINUX_ERRNO_EXTENSIONS__
USE_PARTITION_MANAGER=1
__PROGRAM_START
NRF52840_XXAA
NRF_802154_CCA_CORR_LIMIT_DEFAULT=2
NRF_802154_CCA_CORR_THRESHOLD_DEFAULT=45
NRF_802154_CCA_ED_THRESHOLD_DEFAULT=45
NRF_802154_CCA_MODE_DEFAULT=NRF_RADIO_CCA_MODE_ED
NRF_802154_USE_RAW_API=1
NRF_802154_PENDING_SHORT_ADDRESSES=16
NRF_802154_PENDING_EXTENDED_ADDRESSES=16
NRF_802154_RX_BUFFERS=16
NRF_802154_TX_STARTED_NOTIFY_ENABLED=1
NRF_802154_ACK_TIMEOUT_ENABLED=1
NRF_802154_ENCRYPTION_ENABLED=1
NRF_802154_SECURITY_WRITER_ENABLED=1
NRF_802154_IE_WRITER_ENABLED=1
NRF_802154_INTERNAL_RADIO_IRQ_HANDLING=0
NRF_802154_ECB_PRIORITY=-1
NRF_802154_SWI_PRIORITY=1
MBEDTLS_CONFIG_FILE=nrf-config.h
MBEDTLS_USER_CONFIG_FILE=nrf-config-user.h
-- west flash: using runner nrfjprog
-- runners.nrfjprog: mass erase requested
Using board 123456
-- runners.nrfjprog: Flashing file: /home/chyi/gl-nrf-sdk/glinet/gl-dev-board-over-thread/build/zephyr/merged.hex
ERROR: Serial number of connected device (20090928) does not match the expected serial number 123456.
ERROR: There is no debugger connected to the PC with the given serial number.
NOTE: For additional output, try running again with logging enabled (--log).
NOTE: Any generated log error messages will be displayed.
FATAL ERROR: command exited with status 40: nrfjprog --program /home/chyi/gl-nrf-sdk/glinet/gl-dev-board-over-thread/build/zephyr/merged.hex --chiperase --verify -f NRF52 --snr 123456

예상대로, 에러가 발생한다. (겁먹지 말고) 위의 마지막 명령에서 --snr 부분만 제거하고 실행해 본다.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread$ nrfjprog --program /home/chyi/gl-nrf-sdk/glinet/gl-dev-board-over-thread/build/zephyr/merged.hex --sectoranduicrerase --verify -f NRF52






















OK, 정상적으로 설치가 되었다. 이후 minicom으로 확인해 보니 제대로 올라온다. 😎
📌 J-Link OB V8 micro USB ARM용 SWD 호환 디버거를 이용해서 거창한(?) debugging을 할 것이 아니라면, 가격대비 나쁘지 않은 선택인 듯 보인다.

<2. mcumgr tool로 firmware 올리기 - DFU over Serial 방법>
다음으로, Gl-iNet에서 제공하는 mcumgr이라는 DFU(Development Firmware Upgrade) 도구를 활용하기로 한다.
📌 DFU over serial 이라고 함은, 부팅 시 강제로 ROM code로 진입한 후, serial port(UART)를 통해 firmware를 download 받는 방식을 말한다.


먼저 현재 설치되어 있는 image 정보를 확인한다.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB1,baud=460800 image list
Images:
 image=0 slot=0
    version: 1.1.5
    bootable: true
    flags: active confirmed
    hash: 4d8548e6910e7214d8325a7d1a49a8390fb25cce983bdb0b15bfecc657f7860b
Split status: N/A (0)

다음으로, github에 release되어 있는 firmware 파일(bin file)로 1차 설치 테스트를 진행해 본다.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB2,baud=460800 image upload /home/chyi/gl-nrf-sdk/glinet/mydownload/GL-Dev-Board-Thread-MTD-OTA-v1.1.11.bin
 379.04 KiB / 379.04 KiB [==================================================] 100.00% 16.90 KiB/s 22s
Done

정상적으로 firmware writing이 진행되는 것을 확인하였으니, 이번에는 앞서 build해 두었던 app_update.bin 파일을 이용해서 flash writing을 다시 시도하도록 하자.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB2,baud=460800 image upload ../../../build/zephyr/app_update.bin
 431.23 KiB / 431.23 KiB [======================================================] 100.00% 61.12 KiB/s 7s
Done

역시, 정상 설치가 된 듯 보이니, 이 상태에서 현재 설치되어 있는 image 정보를 확인해 보자.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB2,baud=460800 image list
Images:
 image=0 slot=0
    version: 1.1.5
    bootable: true
    flags: active confirmed
    hash: 4d8548e6910e7214d8325a7d1a49a8390fb25cce983bdb0b15bfecc657f7860b
 image=0 slot=1
    version: 1.1.11
    bootable: true
    flags: 
    hash: dab4c5f561debfb3064da2277d72aa3fc89c15fe838f395b18c4479eca310de9
Split status: N/A (0)

확인 결과, 기존 것 외에 새로 설치된 것이 함께 보인다. 다음번 booting시, 새로 설치한 image가 반영되도록 하기 위해 hash 값을 입력해 준다.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB2,baud=460800 image test dab4c5f561debfb3064da2277d72aa3fc89c15fe838f395b18c4479eca310de9
Images:
 image=0 slot=0
    version: 1.1.5
    bootable: true
    flags: active confirmed
    hash: 4d8548e6910e7214d8325a7d1a49a8390fb25cce983bdb0b15bfecc657f7860b
 image=0 slot=1
    version: 1.1.11
    bootable: true
    flags: pending
    hash: dab4c5f561debfb3064da2277d72aa3fc89c15fe838f395b18c4479eca310de9
Split status: N/A (0)

자, 모든 것이 준비되었으니, Thread Dev Board를 reset 하도록 한다.

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB2,baud=460800 reset
Done

부팅 후, image list를 재 확인해 보니, 새로 설치한 버젼이 구동되었음을 알 수 있다. 😎

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread/uart_dfu/mcumgr/ubuntu22.04$ sudo ./mcumgr --conntype serial --connstring=/dev/ttyUSB2,baud=460800 image list
Images:
 image=0 slot=0
    version: 1.1.11
    bootable: true
    flags: active confirmed
    hash: dab4c5f561debfb3064da2277d72aa3fc89c15fe838f395b18c4479eca310de9
 image=0 slot=1
    version: 1.1.5
    bootable: true
    flags: 
    hash: 4d8548e6910e7214d8325a7d1a49a8390fb25cce983bdb0b15bfecc657f7860b
Split status: N/A (0)
_____________________________________________________________

마지막으로, TDB를 pairing한 후, GL-S200 WebUI에서 확인해 보니 모두 정상적으로 동작되고 있다.

[그림 3.6] Firmware를 교체한 Thread Device Board(TDB2)를 GL-S200에 연결한 모습


3.2 TDB firmware source code 살펴 보기
<TBD> 코드를 살펴 보도록 하자. 💢

chyi@earth:~/gl-nrf-sdk/glinet/gl-dev-board-over-thread$ ls -la
합계 92
drwxrwxr-x 12 chyi chyi  4096 10월 28 16:33 .
drwxrwxr-x  4 chyi chyi  4096 10월 29 13:12 ..
drwxrwxr-x  8 chyi chyi  4096 10월 26 18:29 .git
drwxrwxr-x  3 chyi chyi  4096 10월 26 18:21 .github
-rwxrwxr-x  1 chyi chyi    13 10월 26 18:21 .gitignore
-rwxrwxr-x  1 chyi chyi  2278 10월 26 18:21 CMakeLists.txt
-rwxrwxr-x  1 chyi chyi  1205 10월 26 18:21 Kconfig
-rwxrwxr-x  1 chyi chyi 11357 10월 26 18:21 LICENSE
-rwxrwxr-x  1 chyi chyi 11174 10월 26 18:21 README.md
drwxrwxr-x  2 chyi chyi  4096 10월 29 13:12 boards
drwxrwxr-x  8 chyi chyi  4096 10월 26 18:34 build
drwxrwxr-x  4 chyi chyi  4096 10월 26 18:21 docs
drwxrwxr-x  4 chyi chyi  4096 10월 26 18:21 drivers
drwxrwxr-x  3 chyi chyi  4096 10월 26 18:21 dts
-rw-rw-r--  1 chyi chyi  1983 10월 26 18:21 guide_to_use.md
drwxrwxr-x  2 chyi chyi  4096 10월 26 18:21 hardware_files
-rwxrwxr-x  1 chyi chyi  2673 10월 26 18:21 prj.conf
drwxrwxr-x  3 chyi chyi  4096 10월 28 20:34 src
drwxrwxr-x  4 chyi chyi  4096 10월 26 18:21 uart_dfu
___________________________________________

지금까지 Thread Dev Board에 zephyr로 구현된 firmware를 올리는 과정을 정리해 보았다. (커피 한잔 마신 후)이어지는 장에서는 또 다른 Thread Border Router인 GL-S20을 살펴 보도록 하자. ☕


4. 또 다른 Thread Border Router GL-S20
이 장에서는 또 다른 Thread Border Router(Compact Thread Border Router for IoT)GL-S20 model을 (빠른 속도로) 소개하고자 한다. GL-S20에는 ESP32 chip이 장착되어 있고, OS도 Linux가 아니라  FreeRTOS가 올라가 있다.


[그림 4.1] Thread Device Board + GL-S20 + GL-S200

ESP32 및 FreeRTOS와 관련해서는 필자의 이전 글을 참조해 볼 것을 권한다. 😃

4.1 GL-S20 Router Overview
GL-S20 router의 대략적인 개요는 몇장의 그림으로 충분할 듯 하다(외관이 이쁘장하게 생겼다 😍).

[그림 4.2] GL-S20 Thread Border Router(1) [출처 - https://www.gl-inet.com/products/gl-s20/]

[그림 4.3] GL-S20 Thread Border Router(2)


[그림 4.4] GL-S20 주요 기능


[그림 4.5] GL-S20 Board pinout [출처 - 참고문헌 7]


[그림 4.6] GL-S20 Thread Border Router를 이용한 Network 구성


[그림 4.7] GL-S20 H/W Spec.
📌 GL-S20은 MCU로 ESP32-S3(CPU: Dual-core Xtensa® LX7 @ 240MHz)을 사용하며, OS로는 FreeRTOS를 사용한다.

4.2 GL-S20 Router 연결하기
GL-S20을 시험하기 위한 네트워크 구성은 다음과 같다.

<Testbed 구성>

Internet
^
|
GL-MT1300 Router (LAN: 192.168.8.1, WAN: 172.30.x.x)
^
|
GL-S200 (LAN: 192.168.7.1, WAN: 192.168.8.179), port forward(8080 -> 80)
^
|
GL-S20 (WAN: 192.168.7.175)
^
|
Thread Dev Boards

GL-S20도 (간단한 기능만 제공하기는 하지만) webui를 제공한다. 하지만 ssh는 당연히 안된다.

[그림 4.8] GL-S20 WebUI(1) - 인터넷 연결 화면


[그림 4.9] GL-S20 WebUI(2) - Thread Network 화면

4.3 GL-S20 firmware build 하기
GL-S20 firmware는 Espressif 사의 ESP-IDF를 기초로 하고 있다. 지금부터는 아래 3개의 site 내용을 참조하여 GL-S20용 firmware image를 만드는 과정을 소개해 보고자 한다.

📌 보다 보니, 위의 link(3)에 자세한 설명이 나와 있다.

[그림 4.10] ESP32 Thread Border Router Architecture

(Espressif에서 제조한) ESP Thread Border Router는 아래와 같이 2개의 SoC로 구성되어 있다.
  • The host Wi-Fi SoC, which can be ESP32, ESP32-S and ESP32-C series SoC.

  • The radio co-processor (RCP), which is an ESP32-H series SoC. The RCP enables the Border Router to access the 802.15.4 physical and MAC layer.

[그림 4.11] ESP32 Thread Border Router [출처 - 참고문헌 9]

2개의 SoC 간은 아래 그림 처럼, 다양한 h/w interface를 통해 연결되어 있다.
  • UART and SPI for serial communication
  • RESET and BOOT pins for RCP Update
  • 3-Wires PTA for RF coexistence
[그림 4.12] ESP32 Thread Border Router 2개의 SoC간 통신 Interface[출처 - 참고문헌 10]
📌 Firmware build를 시도해 보면 자연히 알게 되겠지만, 2개의 SoC가 있기 때문에 관련 firmware도 총 2개가 필요(최종 결과물은 2개를 하나로 묶어서 출력하게됨)하다. 단, 설치는 main SoC(ESP32-S3) -> UART -> ESP32-H2 형태로 알아서 진행되게 된다.

<esp-idf 환경 구축하기>
$ git clone -b v5.1.2 --recursive https://github.com/espressif/esp-idf.git
$ cd esp-idf/
$ ./install.sh 
$ .  ./export.sh 
$ cd ..

<Thread Border Router firmware build 하기>
$ git clone -b v1.0 --recursive https://github.com/espressif/esp-thread-br.git
$ cd esp-thread-br/examples/basic_thread_border_router
$ idf.py menuconfig
-> 아래 page의 내용을 참조하여 menuconfig 설정을 한다(설정 사항이 너무 많이 link로 대신함).

$ cd ..
$ cd esp-idf/
$ cd examples/openthread/ot_rcp/
$ idf.py set-target esp32h2
$ idf.py build
  -> 여기서 만든 image는 esp32s3 soc image를 설치하면서 자동으로 UART를 통해 esp32h2 soc에 전달된다.
$ cd ..
$ cd esp-thread-br/
$ cd examples/
$ cd basic_thread_border_router/
$ idf.py set-target esp32s3
$ idf.py build
  -> esp32s3 soc용 firmware image를 build 한다.

OK, 여기까지 정상적으로 build가 진행되었다. 이제 flash writing을 해 보도록 하자.

$ idf.py -p /dev/ttyUSB1 flash monitor


이상으로 GL-S20 thread border router를 (다소 빠른 속도로) 살펴 보았다.


5. 아직 못다한 이야기
지금까지 Gl-iNet 사에서 판매하는 Thread 관련 3개의 제품 즉, GL-S200, GL-S20, Thread Dev Board의 주요 특징을 간략히 살펴 보았다. 늘 그렇지만 정리를 하다 보면, 아쉬운 점이 항상 남게 되는데, 앞으로 해야 할 일을 정리하는 것으로 이번 posting을 마무리하고자 한다. 🏁

1) OpenThread source code에 대한 면밀한 분석이 필요해 보인다.
2) Thread 기능 설정 관련하여 추가 테스트가 필요해 보인다.
3) BLE sensor를 붙여 보는 실험을 하지 못했다.
4) Thread Dev Board용 Zephyr code에 대한 상세 분석이 필요하다.
5) GL-S20 ESP-IDF code에 대한 상세 분석이 필요하다.
6) 이 3개의 제품(s/w)을 가공하여 또 다른 제품 형태로 만들 수 있을지 고민해 보자.

제품을 단순히 사용해 보는 것은 크게 의미가 없으며, 각 제품을 구성하는 주요 코드의 동작 원리를 정확히 파악해 보는 것이 개발자의 자세(?)가 아닐까? ㅋㅋ 😋

Good luck~


6. References
[1] https://www.gl-inet.com/products/gl-s200/#specs
[2] https://docs.gl-inet.com/iot/en/thread_board_router/gl-s200/openthread_border_router_codelabs/
[3] s200_datasheet_EN_20230602, GL Technologies (Hong Kong) Limited.
[4] https://openthread.io
[5] https://www.threadgroup.org/Portals/0/documents/support/Thread%20Network%20Fundamentals_v3.pdf
[6] https://webthesis.biblio.polito.it/27126/1/tesi.pdf
[7] https://docs.gl-inet.com/iot/en/thread_board_router/gl-s20/user_manual/web_admin_panel_guide/
[8] Analysis of DTLS Implementations Using Protocol State Fuzzing, Paul Fiterau-Brostean
[9] https://www.espressif.com/en/news/Thread_Border_Router_Certification
[10] https://dl.espressif.com/dl/schematics/esp_thread_br_zigbee_gw_sub_ethernet_schematiccs_v1.0.pdf
[11] https://velog.io/@gs0351/CoAPConstrained-Application-Protocol
[12] https://www.devicemart.co.kr/goods/view?no=1360841&srsltid=AfmBOopMYhHHctSmebkqCsFrnyQIV4qp0h87Yfs1nBU5dAeDcBaODbJb
[13] https://docs.nordicsemi.com/bundle/ug_nrf_cltools/page/UG/cltools/nrf_nrfjprogexe.html
[14] And, Google~


Slowboot