อ่านบทความ ...
"zig on RISC-V BL602: Peek Quick กับ Apache Nuttx RTOS"
"สร้างแอพ IoT ด้วย Zig และ Lorawan"
เพื่อสร้างแอพ Hello Zig สำหรับ nuttx บน BL602 ...
# # Enable Zig App in NuttX menuconfig
make menuconfig
# # TODO: Select "Application Configuration > Examples > Hello Zig Example"
# # Save the configuration and exit menuconfig.
# # Build Nuttx
make
# # NuttX Build fails with Undefined Reference to `hello_zig_main`
# # That's OK, here's the fix...
# # Download our modified Zig App for NuttX
git clone --recursive https://github.com/lupyuen/zig-bl602-nuttx
cd zig-bl602-nuttx
# # Compile the Zig App for BL602 (RV32IMACF with Hardware Floating-Point)
zig build-obj
-target riscv32-freestanding-none
-mcpu sifive_e76
hello_zig_main.zig
# # Dump the ABI for the compiled app
riscv64-unknown-elf-readelf -h -A hello_zig_main.o
# # Shows "Flags: 0x1, RVC, soft-float ABI"
# # Which is Software Floating-Point.
# # This won't link with NuttX because NuttX is compiled with Hardware Floating-Point
# # We change Software Floating-Point to Hardware Floating-Point...
# # Edit hello_zig_main.o in a Hex Editor, change byte 0x24 from 0x01 to 0x03
# # (See https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header)
# # Dump the ABI for the compiled app
riscv64-unknown-elf-readelf -h -A hello_zig_main.o
# # Shows "Flags: 0x3, RVC, single-float ABI"
# # Which is Hardware Floating-Point and will link with NuttX
# # Copy the compiled app to NuttX and overwrite `hello.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cp hello_zig_main.o $HOME /nuttx/apps/examples/hello/ * hello.o
# # Build NuttX to link the Zig Object from `hello.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
make
# # NuttX build should now succeedบูต nuttx และป้อนสิ่งนี้ที่เชลล์ nuttx ...
NuttShell (NSH) NuttX-10.3.0-RC2
nsh> hello_zig
Hello, Zig!
สำหรับแอพ Lorawan Zig ดูสิ่งนี้ ...
ในการรวบรวมไลบรารี Lora SX1262 ใน C ด้วย Zig Compiler ดูสิ่งนี้ ...
นี่คือวิธีที่เราทำให้ Zig และ Lorawan ทำงานบน BL602 Nuttx ...
Apache Nuttx RTOS มาพร้อมกับแอพซิกง่าย ๆ ... มาเรียกใช้สิ่งนี้บน BL602: hello_zig_main.zig
// Import the Zig Standard Library
const std = @import ( "std" );
// Import printf() from C
pub extern fn printf (
_format : [ * : 0 ] const u8
) c_int ;
// Main Function
pub export fn hello_zig_main (
_argc : c_int ,
_argv : [ * ] const [ * ] const u8
) c_int {
_ = _argc ;
_ = _argv ;
_ = printf ( "Hello, Zig! n " );
return 0 ;
}เราแก้ไข 2 บรรทัดสุดท้ายเพื่อให้คอมไพเลอร์ Zig มีความสุข ...
// Previously: printf("Hello, Zig!n");
// Zig needs us to use the returned value from printf()...
_ = printf ( "Hello, Zig! n " );
// Previously this was missing.
// Zig needs us to return a value...
return 0 ;เวอร์ชันต้นฉบับอยู่ที่นี่: hello_zig_main.zig
เพื่อเปิดใช้งานแอพ Zig ใน nuttx ...
make menuconfigเลือก "การกำหนดค่าแอปพลิเคชัน> ตัวอย่าง> ตัวอย่างสวัสดีซิก"
บันทึกการกำหนดค่าและออกจาก menuconfig
เมื่อเราสร้าง nuttx ...
makeเราเห็นข้อผิดพลาดนี้ ...
LD: nuttx
riscv64-unknown-elf-ld: nuttx/staging/libapps.a(builtin_list.c.home.user.nuttx.apps.builtin.o):(.rodata.g_builtins+0xbc):
undefined reference to `hello_zig_main'
(แหล่งที่มา)
ซึ่งดูคล้ายกับปัญหานี้ ...
Apache/nuttx#6219
สิ่งนี้ดูเหมือนจะเกิดจากการสร้าง nuttx ไม่เรียกคอมไพเลอร์ซิก
แต่ไม่ต้องกังวล! มารวบรวมแอพ Zig ด้วยตัวเองและเชื่อมโยงไปยัง nuttx
นี่คือวิธีที่เรารวบรวมแอพ ZIG ของเราสำหรับ RISC-V BL602 และเชื่อมโยงกับ nuttx ...
# # Download our modified Zig App for NuttX
git clone --recursive https://github.com/lupyuen/zig-bl602-nuttx
cd zig-bl602-nuttx
# # Compile the Zig App for BL602 (RV32IMACF with Hardware Floating-Point)
zig build-obj
-target riscv32-freestanding-none
-mcpu sifive_e76
hello_zig_main.zig
# # Copy the compiled app to NuttX and overwrite `hello.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cp hello_zig_main.o $HOME /nuttx/apps/examples/hello/ * hello.o
# # Build NuttX to link the Zig Object from `hello.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
make เหตุใดเป้าหมาย riscv32-freestanding-none ?
เป้าหมาย ZIG มีแบบฟอร์ม <arch><sub>-<os>-<abi> ...
riscv32 : เนื่องจาก BL602 เป็นโปรเซสเซอร์ RISC-V 32 บิต
freestanding : เนื่องจากเป้าหมายที่ฝังตัวไม่จำเป็นต้องใช้ระบบปฏิบัติการ
none : เพราะเป้าหมายที่ฝังตัวไม่ได้ระบุ ABI
เหตุใด CPU เป้าหมาย sifive_e76
BL602 ถูกกำหนดให้เป็น RV32IMACF ...
| การกำหนด | ความหมาย |
|---|---|
RV32I | 32 บิต RISC-V พร้อมคำแนะนำพื้นฐานจำนวนเต็ม |
M | การคูณจำนวนเต็ม + การแบ่ง |
A | คำแนะนำปรมาณู |
C | คำแนะนำบีบอัด |
F | จุดลอยตัวเดี่ยว |
(แหล่งที่มา)
ในบรรดาเป้าหมาย ZIG ทั้งหมดมีเพียง sifive_e76 เท่านั้นที่มีการกำหนดเดียวกัน ...
$ zig targets
...
" sifive_e76 " : [ " a " , " c " , " f " , " m " ],(แหล่งที่มา)
ดังนั้นเราจึงใช้ sifive_e76 เป็นเป้าหมาย CPU ของเรา
หรือเราอาจใช้ baseline_rv32-d เป็นเป้าหมาย CPU ของเรา ...
# # Compile the Zig App for BL602 (RV32IMACF with Hardware Floating-Point)
zig build-obj
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
hello_zig_main.zigเพราะ...
baseline_rv32 หมายถึง rv32imacfd
(D สำหรับจุดลอยตัวที่มีความแม่นยำสองเท่า)
-d หมายถึงการลบจุดลอยตัวแบบสองเท่า (D)
(แต่เก็บจุดลอยตัวที่มีความแม่นยำเดียว)
(เพิ่มเติมเกี่ยวกับธงฟีเจอร์ RISC-V ขอบคุณ Matheus!)
เมื่อเชื่อมโยงแอป Zig ที่รวบรวมกับ NUTTX เราจะเห็นข้อผิดพลาดนี้ ...
$ make
...
riscv64-unknown-elf-ld: nuttx/staging/libapps.a(hello_main.c.home.user.nuttx.apps.examples.hello.o):
can ' t link soft-float modules with single-float modulesนั่นเป็นเพราะ Nuttx ถูกรวบรวมสำหรับฮาร์ดแวร์ (ความแม่นยำเดียว) ฮาร์ดแวร์ ABI แบบลอยตัว (อินเตอร์เฟสไบนารีแอปพลิเคชัน) ...
# # Do this BEFORE overwriting hello.o by hello_zig_main.o.
# # "*hello.o" expands to something like "hello_main.c.home.user.nuttx.apps.examples.hello.o"
$ riscv64-unknown-elf-readelf -h -A $HOME /nuttx/apps/examples/hello/ * hello.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2 ' s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 4528 (bytes into file)
Flags: 0x3, RVC, single-float ABI
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 26
Section header string table index: 25
Attribute Section: riscv
File Attributes
Tag_RISCV_stack_align: 16-bytes
Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_c2p0"(แหล่งที่มา)
(nuttx ถูกรวบรวมด้วยธง GCC -march=rv32imafc -mabi=ilp32f )
ในขณะที่ Zig Compiler สร้างไฟล์วัตถุที่มี ซอฟต์แวร์ลอยตัว ABI ...
$ riscv64-unknown-elf-readelf -h -A hello_zig_main.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2 ' s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 11968 (bytes into file)
Flags: 0x1, RVC, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 24
Section header string table index: 22
Attribute Section: riscv
File Attributes
Tag_RISCV_stack_align: 16-bytes
Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_c2p0"(แหล่งที่มา)
GCC จะไม่อนุญาตให้เราเชื่อมโยงไฟล์วัตถุกับซอฟต์แวร์ลอยจุดและฮาร์ดแวร์จุดลอยตัว ABIs!
(ทำไม Zig Compiler สร้างไฟล์วัตถุด้วยซอฟต์แวร์ลอย ABI จุดเมื่อ sifive_e76 รองรับฮาร์ดแวร์จุดลอยตัว? ดูสิ่งนี้)
ZIG Compiler สร้างไฟล์วัตถุด้วย ซอฟต์แวร์ Floating-Point ABI (แอปพลิเคชันไบนารีอินเตอร์เฟส) ...
# # Dump the ABI for the compiled app
$ riscv64-unknown-elf-readelf -h -A hello_zig_main.o
...
Flags: 0x1, RVC, soft-float ABIสิ่งนี้จะไม่เชื่อมโยงกับ nuttx เพราะ Nuttx ถูกรวบรวมด้วยฮาร์ดแวร์จุดลอย ABI
เราแก้ไขสิ่งนี้โดยการแก้ไขส่วนหัวของ ELF ...
แก้ไข hello_zig_main.o ในโปรแกรมแก้ไข hex
(เช่น Vscode hex editor)
เปลี่ยนไบต์ 0x24 (แฟล็ก) จาก 0x01 (ซอฟต์ลอย) เป็น 0x03 (Hard Float)
(ดูสิ่งนี้)
เราตรวจสอบว่าไฟล์วัตถุถูกเปลี่ยนเป็น ฮาร์ดแวร์จุดลอยตัว ABI ...
# # Dump the ABI for the compiled app
$ riscv64-unknown-elf-readelf -h -A hello_zig_main.o
...
Flags: 0x3, RVC, single-float ABIตอนนี้เป็นฮาร์ดแวร์จุดลอยตัว ABI และจะเชื่อมโยงกับ NUTTX
ตอนนี้เราเชื่อมโยงไฟล์วัตถุที่แก้ไขด้วย nuttx ...
# # Copy the compiled app to NuttX and overwrite `hello.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cp hello_zig_main.o $HOME /nuttx/apps/examples/hello/ * hello.o
# # Build NuttX to link the Zig Object from `hello.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
makeตอนนี้บิลด์ nuttx ควรประสบความสำเร็จ
การเปลี่ยน Abi แบบนี้หรือไม่?
ในทางเทคนิคแล้ว ABI นั้นถูกสร้างขึ้นอย่างถูกต้อง โดยคอมไพเลอร์ซิก ...
# # Dump the ABI for the compiled Zig app
$ riscv64-unknown-elf-readelf -h -A hello_zig_main.o
...
Flags: 0x1, RVC, soft-float ABI
Tag_RISCV_arch: " rv32i2p0_m2p0_a2p0_f2p0_c2p0 "บรรทัดสุดท้ายแปลเป็น RV32IMACF ซึ่งหมายความว่าชุดคำสั่ง RISC-V นั้นมีเป้าหมายสำหรับ ฮาร์ดแวร์จุดลอยตัว
เราแค่แก้ไข ส่วนหัวของเอลฟ์ เท่านั้นเพราะดูเหมือนจะไม่สะท้อน ABI ที่ถูกต้องสำหรับไฟล์วัตถุ
มีการแก้ไขที่เหมาะสมสำหรับเรื่องนี้หรือไม่?
ในอนาคตคอมไพเลอร์ซิกอาจช่วยให้เราสามารถระบุ จุดลอยตัว ABI เป็นเป้าหมาย ...
# # Compile the Zig App for BL602
# # ("ilp32f" means Hardware Floating-Point ABI)
zig build-obj
-target riscv32-freestanding-ilp32f
...(ดูสิ่งนี้)
คอยติดตาม!
เราสามารถแก้ไขส่วนหัวของเอลฟ์ผ่านบรรทัดคำสั่งได้หรือไม่?
ใช่เราอาจแก้ไขส่วนหัวของเอลฟ์ผ่าน บรรทัดคำสั่ง ...
xxd -c 1 hello_zig_main.o
| sed ' s/00000024: 01/00000024: 03/ '
| xxd -r -c 1 - hello_zig_main2.oการสร้าง nuttx ประสบความสำเร็จ ZIG ทำงานตกลงบน NUTTX BL602!
NuttShell (NSH) NuttX-10.3.0-RC2
nsh> hello_zig
Hello, Zig!
โปรดจำไว้ว่าเราเขียนทับ hello.o ด้วยไฟล์วัตถุที่รวบรวม ZIG ของเรา
build nuttx จะล้มเหลวเว้นแต่เราจะให้ฟังก์ชั่น hello_main ...
riscv64-unknown-elf-ld: nuttx/staging/libapps.a(builtin_list.c.home.user.nuttx.apps.builtin.o):(.rodata.g_builtins+0xcc):
undefined reference to `hello_main'
นั่นเป็นเหตุผลที่เรากำหนด hello_main ในแอพ Zig ของเรา ...
pub export fn hello_main (
_argc : c_int ,
_argv : [ * ] const [ * ] const u8
) c_int {
_ = _argc ;
_ = _argv ;
_ = printf ( "Hello, Zig! n " );
return 0 ;
}(แหล่งที่มา)
ซึ่งหมายความว่าแอป hello จะโทรหารหัสซิกของเราด้วย ...
NuttShell (NSH) NuttX-10.3.0-RC2
nsh> hello
Hello, Zig!
PINE64 PINECONE BL602 บอร์ด (ขวา) เชื่อมต่อกับ Semtech SX1262 LORA ตัวรับส่งสัญญาณ (ซ้าย) เหนือ SPI
Zig Compiler จะทำงานแทน Drop-in สำหรับ GCC สำหรับการรวบรวมไลบรารี NUTTX หรือไม่?
ลองทดสอบบนไลบรารี Lora SX1262 สำหรับ Apache Nuttx RTOS!
นี่คือวิธีที่ NUTTX รวบรวมไลบรารี LORA SX1262 ด้วย GCC ...
# # LoRa SX1262 Source Directory
cd $HOME /nuttx/nuttx/libs/libsx1262
# # Compile radio.c with GCC
riscv64-unknown-elf-gcc
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-march=rv32imafc
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/radio.c
-o src/radio.o
# # Compile sx126x.c with GCC
riscv64-unknown-elf-gcc
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-march=rv32imafc
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/sx126x.c
-o src/sx126x.o
# # Compile sx126x-nuttx.c with GCC
riscv64-unknown-elf-gcc
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-march=rv32imafc
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/sx126x-nuttx.c
-o src/sx126x-nuttx.oเราทำการเปลี่ยนแปลงเหล่านี้ ...
เปลี่ยน riscv64-unknown-elf-gcc เป็น zig cc
เพิ่มเป้าหมาย -target riscv32-freestanding-none -mcpu=baseline_rv32-d
ลบ -march=rv32imafc
และเราเรียกใช้สิ่งนี้ ...
# # LoRa SX1262 Source Directory
cd $HOME /nuttx/nuttx/libs/libsx1262
# # Compile radio.c with zig cc
zig cc
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/radio.c
-o src/radio.o
# # Compile sx126x.c with zig cc
zig cc
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/sx126x.c
-o src/sx126x.o
# # Compile sx126x-nuttx.c with zig cc
zig cc
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/sx126x-nuttx.c
-o src/sx126x-nuttx.o
# # Link Zig Object Files with NuttX after compiling with `zig cc`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
makeZig Compiler แสดงข้อผิดพลาดเหล่านี้ ...
In file included from src/sx126x-nuttx.c:3:
In file included from nuttx/include/debug.h:39:
In file included from nuttx/include/sys/uio.h:45:
nuttx/include/sys/types.h:119:9: error: unknown type name '_size_t'
typedef _size_t size_t;
^
nuttx/include/sys/types.h:120:9: error: unknown type name '_ssize_t'
typedef _ssize_t ssize_t;
^
nuttx/include/sys/types.h:121:9: error: unknown type name '_size_t'
typedef _size_t rsize_t;
^
nuttx/include/sys/types.h:174:9: error: unknown type name '_wchar_t'
typedef _wchar_t wchar_t;
^
In file included from src/sx126x-nuttx.c:4:
In file included from nuttx/include/stdio.h:34:
nuttx/include/nuttx/fs/fs.h:238:20: error: use of undeclared identifier 'NAME_MAX'
char parent[NAME_MAX + 1];
^
เราแก้ไขสิ่งนี้โดยรวมไฟล์ส่วนหัวที่ถูกต้อง ...
#if defined( __NuttX__ ) && defined( __clang__ ) // Workaround for NuttX with zig cc
#include <arch/types.h>
#include "../../nuttx/include/limits.h"
#endif // defined(__NuttX__) && defined(__clang__)ลงในไฟล์ต้นฉบับเหล่านี้ ...
(ดูการเปลี่ยนแปลง)
เราแทรกรหัสนี้เพื่อบอกเรา (ในรันไทม์) ไม่ว่าจะรวบรวมด้วย Zig Compiler หรือ GCC ...
void SX126xIoInit ( void ) {
#ifdef __clang__
#warning Compiled with zig cc
puts ( "SX126xIoInit: Compiled with zig cc" );
#else
#warning Compiled with gcc
puts ( "SX126xIoInit: Compiled with gcc" );
#endif // __clang__(แหล่งที่มา)
รวบรวมด้วย zig cc ห้องสมุด Lora SX1262 ทำงานได้ดีบน nuttx yay!
nsh> lorawan_test
SX126xIoInit: Compiled with zig cc
...
###### =========== MLME-Confirm ============ ######
STATUS : OK
###### =========== JOINED ============ ######
OTAA
DevAddr : 000E268C
DATA RATE : DR_2
...
###### =========== MCPS-Confirm ============ ######
STATUS : OK
###### ===== UPLINK FRAME 1 ===== ######
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923400000
TX POWER : 0
CHANNEL MASK: 0003
(ดูบันทึกที่สมบูรณ์)
มารวบรวมไลบรารี Lorawan ขนาดใหญ่ด้วยคอมไพเลอร์ซิก
Nuttx รวบรวมไลบรารี Lorawan เช่นนี้ ...
# # LoRaWAN Source Directory
cd $HOME /nuttx/nuttx/libs/liblorawan
# # Compile mac/LoRaMac.c with GCC
riscv64-unknown-elf-gcc
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-march=rv32imafc
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/mac/LoRaMac.c
-o src/mac/LoRaMac.oเราเปลี่ยนไปใช้คอมไพเลอร์ซิก ...
# # LoRaWAN Source Directory
cd $HOME /nuttx/nuttx/libs/liblorawan
# # Compile mac/LoRaMac.c with zig cc
zig cc
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe src/mac/LoRaMac.c
-o src/mac/LoRaMac.o
# # Link Zig Object Files with NuttX after compiling with `zig cc`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
makeเรารวมไฟล์ส่วนหัวที่ถูกต้องไว้ใน loramac.c ...
#if defined( __NuttX__ ) && defined( __clang__ ) // Workaround for NuttX with zig cc
#include <arch/types.h>
#include "../../nuttx/include/limits.h"
#endif // defined(__NuttX__) && defined(__clang__)(ดูการเปลี่ยนแปลง)
Loramac.c รวบรวมตกลงด้วย Zig Compiler
TODO: รวบรวมไฟล์อื่น ๆ ในไลบรารี Lorawan ด้วย build.zig
https://ziglang.org/documentation/master/#zig-build-system
TODO: ทดสอบห้องสมุด Lorawan
ตอนนี้เรารวบรวมแอพ Lorawan lorawan_test_main.c ด้วย Zig Compiler
Nuttx รวบรวมแอพ Lorawan lorawan_test_main.c เช่นนี้ ...
# # App Source Directory
cd $HOME /nuttx/apps/examples/lorawan_test/lorawan_test_main.c
# # Compile lorawan_test_main.c with GCC
riscv64-unknown-elf-gcc
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-march=rv32imafc
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe
-I " $HOME /nuttx/apps/graphics/lvgl "
-I " $HOME /nuttx/apps/graphics/lvgl/lvgl "
-I " $HOME /nuttx/apps/include "
-Dmain=lorawan_test_main lorawan_test_main.c
-o lorawan_test_main.c.home.user.nuttx.apps.examples.lorawan_test.oเราเปลี่ยนไปใช้คอมไพเลอร์ซิก ...
# # App Source Directory
cd $HOME /nuttx/apps/examples/lorawan_test
# # Compile lorawan_test_main.c with zig cc
zig cc
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-c
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-mabi=ilp32f
-mno-relax
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-pipe
-I " $HOME /nuttx/apps/graphics/lvgl "
-I " $HOME /nuttx/apps/graphics/lvgl/lvgl "
-I " $HOME /nuttx/apps/include "
-Dmain=lorawan_test_main lorawan_test_main.c
-o * lorawan_test.o
# # Link Zig Object Files with NuttX after compiling with `zig cc`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
makeเรารวมไฟล์ส่วนหัวที่ถูกต้องไว้ใน lorawan_test_main.c ...
#if defined( __NuttX__ ) && defined( __clang__ ) // Workaround for NuttX with zig cc
#include <arch/types.h>
#include "../../nuttx/include/limits.h"
#endif // defined(__NuttX__) && defined(__clang__)(ดูการเปลี่ยนแปลง)
รวบรวมด้วย zig cc แอพ Lorawan ทำงานได้ดีบน nuttx yay!
nsh> lorawan_test
lorawan_test_main: Compiled with zig cc
...
###### =========== MLME-Confirm ============ ######
STATUS : OK
###### =========== JOINED ============ ######
OTAA
DevAddr : 00DC5ED5
DATA RATE : DR_2
...
###### =========== MCPS-Confirm ============ ######
STATUS : OK
###### ===== UPLINK FRAME 1 ===== ######
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923400000
TX POWER : 0
CHANNEL MASK: 0003
(ดูบันทึกที่สมบูรณ์)
คอมไพเลอร์ ZIG สามารถเปลี่ยนรหัส C อัตโนมัติไปยัง ZIG (ดูสิ่งนี้)
นี่คือวิธีที่เราแปลอัตโนมัติแอพ Lorawan ของเรา lorawan_test_main.c จาก C ถึง Zig ...
เปลี่ยน zig cc เป็น zig translate-c
ล้อมรอบธง c โดย -cflags ... --
แบบนี้...
# # App Source Directory
cd $HOME /nuttx/apps/examples/lorawan_test
# # Auto-translate lorawan_test_main.c from C to Zig
zig translate-c
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-cflags
-fno-common
-Wall
-Wstrict-prototypes
-Wshadow
-Wundef
-Os
-fno-strict-aliasing
-fomit-frame-pointer
-fstack-protector-all
-ffunction-sections
-fdata-sections
-g
-mabi=ilp32f
-mno-relax
--
-isystem " $HOME /nuttx/nuttx/include "
-D__NuttX__
-DNDEBUG
-DARCH_RISCV
-I " $HOME /nuttx/apps/graphics/lvgl "
-I " $HOME /nuttx/apps/graphics/lvgl/lvgl "
-I " $HOME /nuttx/apps/include "
-Dmain=lorawan_test_main
lorawan_test_main.c
> lorawan_test_main.zigนี่คือรหัส C ดั้งเดิม: lorawan_test_main.c
และการแปลอัตโนมัติจาก C ถึง zig: แปล/lorawan_test_main.zig
นี่คือตัวอย่างจากรหัส C ดั้งเดิม ...
int main ( int argc , FAR char * argv []) {
#ifdef __clang__
puts ( "lorawan_test_main: Compiled with zig cc" );
#else
puts ( "lorawan_test_main: Compiled with gcc" );
#endif // __clang__
// If we are using Entropy Pool and the BL602 ADC is available,
// add the Internal Temperature Sensor data to the Entropy Pool
init_entropy_pool ();
// Compute the interval between transmissions based on Duty Cycle
TxPeriodicity = APP_TX_DUTYCYCLE + randr ( - APP_TX_DUTYCYCLE_RND , APP_TX_DUTYCYCLE_RND );
const Version_t appVersion = { . Value = FIRMWARE_VERSION };
const Version_t gitHubVersion = { . Value = GITHUB_VERSION };
DisplayAppInfo ( "lorawan_test" ,
& appVersion ,
& gitHubVersion );
// Init LoRaWAN
if ( LmHandlerInit ( & LmHandlerCallbacks , & LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS )
{
printf ( "LoRaMac wasn't properly initializedn" );
// Fatal error, endless loop.
while ( 1 ) {}
}
// Set system maximum tolerated rx error in milliseconds
LmHandlerSetSystemMaxRxError ( 20 );
// The LoRa-Alliance Compliance protocol package should always be initialized and activated.
LmHandlerPackageRegister ( PACKAGE_ID_COMPLIANCE , & LmhpComplianceParams );
LmHandlerPackageRegister ( PACKAGE_ID_CLOCK_SYNC , NULL );
LmHandlerPackageRegister ( PACKAGE_ID_REMOTE_MCAST_SETUP , NULL );
LmHandlerPackageRegister ( PACKAGE_ID_FRAGMENTATION , & FragmentationParams );
IsClockSynched = false;
IsFileTransferDone = false;
// Join the LoRaWAN Network
LmHandlerJoin ( );
// Set the Transmit Timer
StartTxProcess ( LORAMAC_HANDLER_TX_ON_TIMER );
// Handle LoRaWAN Events
handle_event_queue ( NULL ); // Never returns
return 0 ;
}(แหล่งที่มา)
และรหัสซิกอัตโนมัติที่แปลอัตโนมัติ ...
pub export fn lorawan_test_main ( arg_argc : c_int , arg_argv : [ * c ][ * c ] u8 ) c_int {
var argc = arg_argc ;
_ = argc ;
var argv = arg_argv ;
_ = argv ;
_ = puts ( "lorawan_test_main: Compiled with zig cc" );
init_entropy_pool ();
TxPeriodicity = @bitCast ( u32 , @as ( c_int , 40000 ) + randr ( - @as ( c_int , 5000 ), @as ( c_int , 5000 )));
const appVersion : Version_t = Version_t {
. Value = @bitCast ( u32 , @as ( c_int , 16908288 )),
};
const gitHubVersion : Version_t = Version_t {
. Value = @bitCast ( u32 , @as ( c_int , 83886080 )),
};
DisplayAppInfo ( "lorawan_test" , & appVersion , & gitHubVersion );
if ( LmHandlerInit ( & LmHandlerCallbacks , & LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS ) {
_ = printf ( "LoRaMac wasn't properly initialized n " );
while ( true ) {}
}
_ = LmHandlerSetSystemMaxRxError ( @bitCast ( u32 , @as ( c_int , 20 )));
_ = LmHandlerPackageRegister ( @bitCast ( u8 , @truncate ( i8 , @as ( c_int , 0 ))), @ptrCast ( ? * anyopaque , & LmhpComplianceParams ));
_ = LmHandlerPackageRegister ( @bitCast ( u8 , @truncate ( i8 , @as ( c_int , 1 ))), @intToPtr ( ? * anyopaque , @as ( c_int , 0 )));
_ = LmHandlerPackageRegister ( @bitCast ( u8 , @truncate ( i8 , @as ( c_int , 2 ))), @intToPtr ( ? * anyopaque , @as ( c_int , 0 )));
_ = LmHandlerPackageRegister ( @bitCast ( u8 , @truncate ( i8 , @as ( c_int , 3 ))), @ptrCast ( ? * anyopaque , & FragmentationParams ));
IsClockSynched = @as ( c_int , 0 ) != 0 ;
IsFileTransferDone = @as ( c_int , 0 ) != 0 ;
LmHandlerJoin ();
StartTxProcess ( @bitCast ( c_uint , LORAMAC_HANDLER_TX_ON_TIMER ));
handle_event_queue ( @intToPtr ( ? * anyopaque , @as ( c_int , 0 )));
return 0 ;
}(แหล่งที่มา)
เราจะอ้างถึงรหัสซิกอัตโนมัติที่แปลอัตโนมัตินี้เมื่อเราแปลงแอพ Lorawan Lorawan_Test_Main.c ด้วยตนเองเป็น ZIG ในส่วนถัดไป ...
Pine64 Pinedio Stack BL604 (ซ้าย) พูดคุย Lorawan กับ Rakwireless Wisgate (ขวา)
ในที่สุดเราก็แปลงแอพ Lorawan lorawan_test_main.c จาก C เป็น zig เพื่อแสดงว่าเราสามารถสร้างแอพ IoT ที่ซับซ้อนใน Zig
แอพ Lorawan ทำงานบน Pinedio Stack BL604 (RISC-V) แอพเชื่อมต่อกับเกตเวย์ Lorawan (เช่น Chirpstack หรือเครือข่ายสิ่งต่าง ๆ ) และส่งแพ็คเก็ตข้อมูลเป็นระยะ ๆ
นี่คือรหัส C ดั้งเดิม: lorawan_test_main.c
(รหัส C 700 บรรทัด)
และแอพ Lorawan Zig ที่แปลงแล้วของเรา: lorawan_test.zig
(รหัสซิก 673 บรรทัด)
/// Import the LoRaWAN Library from C
const c = @cImport ({
// NuttX Defines
@cDefine ( "__NuttX__" , "" );
@cDefine ( "NDEBUG" , "" );
@cDefine ( "ARCH_RISCV" , "" );
// Workaround for "Unable to translate macro: undefined identifier `LL`"
@cDefine ( "LL" , "" );
@cDefine ( "__int_c_join(a, b)" , "a" ); // Bypass zig/lib/include/stdint.h
// NuttX Header Files
@cInclude ( "arch/types.h" );
@cInclude ( "../../nuttx/include/limits.h" );
@cInclude ( "stdio.h" );
// LoRaWAN Header Files
@cInclude ( "firmwareVersion.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/githubVersion.h" );
@cInclude ( "../libs/liblorawan/src/boards/utilities.h" );
@cInclude ( "../libs/liblorawan/src/mac/region/RegionCommon.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/Commissioning.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/LmHandler/LmHandler.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/LmHandler/packages/LmhpCompliance.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/LmHandler/packages/LmhpClockSync.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/LmHandler/packages/LmhpRemoteMcastSetup.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/LmHandler/packages/LmhpFragmentation.h" );
@cInclude ( "../libs/liblorawan/src/apps/LoRaMac/common/LmHandlerMsgDisplay.h" );
});
// Main Function that will be called by NuttX
pub export fn lorawan_test_main (
_argc : c_int ,
_argv : [ * ] const [ * ] const u8
) c_int {
// Call the LoRaWAN Library to set system maximum tolerated rx error in milliseconds
_ = c . LmHandlerSetSystemMaxRxError ( 20 );
// TODO: Call the LoRaWAN Library to Join LoRaWAN Network
// and send a Data Packetเพื่อรวบรวมแอพ Lorawan Zig Lorawan_test.zig ...
# # Download our LoRaWAN Zig App for NuttX
git clone --recursive https://github.com/lupyuen/zig-bl602-nuttx
cd zig-bl602-nuttx
# # Compile the Zig App for BL602 (RV32IMACF with Hardware Floating-Point)
zig build-obj
--verbose-cimport
-target riscv32-freestanding-none
-mcpu=baseline_rv32-d
-isystem " $HOME /nuttx/nuttx/include "
-I " $HOME /nuttx/apps/examples/lorawan_test "
lorawan_test.zig
# # Patch the ELF Header of `lorawan_test.o` from Soft-Float ABI to Hard-Float ABI
xxd -c 1 lorawan_test.o
| sed ' s/00000024: 01/00000024: 03/ '
| xxd -r -c 1 - lorawan_test2.o
cp lorawan_test2.o lorawan_test.o
# # Copy the compiled app to NuttX and overwrite `lorawan_test.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cp lorawan_test.o $HOME /nuttx/apps/examples/lorawan_test/ * lorawan_test.o
# # Build NuttX to link the Zig Object from `lorawan_test.o`
# # TODO: Change "$HOME/nuttx" to your NuttX Project Directory
cd $HOME /nuttx/nuttx
makeแอพ Lorawan Zig ของเรา LORAWAN_TEST.ZIG รวบรวมโอเคด้วยคอมไพเลอร์ ZIG หลังจากทำการแก้ไขต่อไปนี้ ...
บางส่วนของแอพ Lorawan Zig Lorawan_test.zig อาจได้รับการแปลงจาก C เป็น Zig เช่นรหัส C นี้ ...
// Original C code...
#define APP_TX_DUTYCYCLE 40000
#define APP_TX_DUTYCYCLE_RND 5000
uint32_t TxPeriodicity =
APP_TX_DUTYCYCLE +
randr (
- APP_TX_DUTYCYCLE_RND ,
APP_TX_DUTYCYCLE_RND
);(แหล่งที่มา)
ซึ่งมีการลงนามที่ขัดแย้งกัน ( randr ) และประเภทที่ไม่ได้ลงชื่อ ( APP_TX_DUTYCYCLE )
เราได้รับความช่วยเหลือโดยอ้างถึงรหัสซิกอัตโนมัติอัตโนมัติ: แปล/lorawan_test_main.zig
// Converted from C to Zig...
const APP_TX_DUTYCYCLE : c_int = 40000 ;
const APP_TX_DUTYCYCLE_RND : c_int = 5000 ;
// Cast to u32 because randr() can be negative
var TxPeriodicity : u32 = @bitCast ( u32 ,
APP_TX_DUTYCYCLE +
c . randr (
- APP_TX_DUTYCYCLE_RND ,
APP_TX_DUTYCYCLE_RND
)
);ซึ่งแก้ไขประเภทที่ขัดแย้งกันโดยการคัดเลือกผลลัพธ์ที่ลงนามให้กลายเป็นที่ไม่ได้ลงชื่อ
เมื่อเราอ้างอิง LmHandlerCallbacks ในแอพ Lorawan Zig ของเรา lorawan_test.zig ...
_ = & LmHandlerCallbacks ;Zig Compiler จะแสดงข้อผิดพลาดประเภททึบแสงนี้ ...
zig-cache/o/d4d456612514c342a153a8d34fbf5970/cimport.zig:1353:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions
Fields: struct_sInfoFields,
^
zig-cache/o/d4d456612514c342a153a8d34fbf5970/cimport.zig:1563:5: note: while checking this field
PingSlot: PingSlotInfo_t,
^
zig-cache/o/d4d456612514c342a153a8d34fbf5970/cimport.zig:1579:5: note: while checking this field
PingSlotInfo: MlmeReqPingSlotInfo_t,
^
zig-cache/o/d4d456612514c342a153a8d34fbf5970/cimport.zig:1585:5: note: while checking this field
Req: union_uMlmeParam,
^
zig-cache/o/d4d456612514c342a153a8d34fbf5970/cimport.zig:2277:5: note: while checking this field
OnMacMlmeRequest: ?fn (LoRaMacStatus_t, [*c]MlmeReq_t, TimerTime_t) callconv(.C) void,
^
ข้อผิดพลาดประเภททึบแสงอธิบายไว้ที่นี่ ...
"ขยายโครงการ C/C ++ ด้วย ZIG"
"การแปลล้มเหลว"
มาติดตามข้อผิดพลาดประเภททึบแสงของเรา ...
export fn OnMacMlmeRequest (
status : c.LoRaMacStatus_t ,
mlmeReq : [ * c ] c.MlmeReq_t ,
nextTxIn : c . TimerTime_t
) void {
c . DisplayMacMlmeRequestUpdate ( status , mlmeReq , nextTxIn );
} ฟังก์ชั่นของเรา OnMacMlmeRequest มีพารามิเตอร์ของประเภท MlmeReq_t , นำเข้าอัตโนมัติโดยคอมไพเลอร์ ZIG เป็น ...
pub const MlmeReq_t = struct_sMlmeReq ;
pub const struct_sMlmeReq = extern struct {
Type : Mlme_t ,
Req : union_uMlmeParam ,
ReqReturn : RequestReturnParam_t ,
}; ซึ่งมีอีกประเภทที่นำเข้าอัตโนมัติ union_uMlmeParam ...
pub const union_uMlmeParam = extern union {
Join : MlmeReqJoin_t ,
TxCw : MlmeReqTxCw_t ,
PingSlotInfo : MlmeReqPingSlotInfo_t ,
DeriveMcKEKey : MlmeReqDeriveMcKEKey_t ,
DeriveMcSessionKeyPair : MlmeReqDeriveMcSessionKeyPair_t ,
}; ซึ่งมี MlmeReqPingSlotInfo_t ...
pub const MlmeReqPingSlotInfo_t = struct_sMlmeReqPingSlotInfo ;
pub const struct_sMlmeReqPingSlotInfo = extern struct {
PingSlot : PingSlotInfo_t ,
}; ซึ่งมี PingSlotInfo_t ...
pub const PingSlotInfo_t = union_uPingSlotInfo ;
pub const union_uPingSlotInfo = extern union {
Value : u8 ,
Fields : struct_sInfoFields ,
}; ซึ่งมี struct_sInfoFields ...
pub const struct_sInfoFields = opaque {}; แต่ฟิลด์ของ struct_sInfoFields ไม่เป็นที่รู้จักโดยคอมไพเลอร์ ZIG!
ถ้าเราอ้างถึงรหัส C ดั้งเดิม ...
typedef union uPingSlotInfo
{
/*!
* Parameter for byte access
*/
uint8_t Value ;
/*!
* Structure containing the parameters for the PingSlotInfoReq
*/
struct sInfoFields
{
/*!
* Periodicity = 0: ping slot every second
* Periodicity = 7: ping slot every 128 seconds
*/
uint8_t Periodicity : 3 ;
/*!
* RFU
*/
uint8_t RFU : 5 ;
} Fields ;
} PingSlotInfo_t ;(แหล่งที่มา)
เราเห็นว่า sInfoFields มีฟิลด์บิตที่คอมไพเลอร์ซิกไม่สามารถแปลได้
ก่อนหน้านี้เราเห็นว่าสิ่งนี้ล้มเหลวในการรวบรวมในแอพ Lorawan Zig ของเรา lorawan_test.zig ...
_ = & LmHandlerCallbacks ; นั่นเป็นเพราะ LmHandlerCallbacks อ้างอิงประเภท MlmeReq_t ประเภทอัตโนมัติซึ่งมีฟิลด์บิตและไม่สามารถแปลได้โดยคอมไพเลอร์ ZIG
มาแปลง MlmeReq_t เป็นประเภททึบแสงเพราะเราจะไม่เข้าถึงฟิลด์ต่อไป ...
/// We use an Opaque Type to represent MLME Request, because it contains Bit Fields that can't be converted by Zig
const MlmeReq_t = opaque {};(แหล่งที่มา)
เราแปลง LmHandlerCallbacks เพื่อใช้ประเภททึบแสงของเรา MlmeReq_t ...
/// Handler Callbacks. Adapted from
/// https://github.com/lupyuen/zig-bl602-nuttx/blob/main/translated/lorawan_test_main.zig#L2818-L2833
pub const LmHandlerCallbacks_t = extern struct {
GetBatteryLevel : ? fn () callconv ( .C ) u8 ,
GetTemperature : ? fn () callconv ( .C ) f32 ,
GetRandomSeed : ? fn () callconv ( .C ) u32 ,
OnMacProcess : ? fn () callconv ( .C ) void ,
OnNvmDataChange : ? fn ( c.LmHandlerNvmContextStates_t , u16 ) callconv ( .C ) void ,
OnNetworkParametersChange : ? fn ([ * c ] c.CommissioningParams_t ) callconv ( .C ) void ,
OnMacMcpsRequest : ? fn ( c.LoRaMacStatus_t , [ * c ] c.McpsReq_t , c.TimerTime_t ) callconv ( .C ) void ,
/// Changed `[*c]c.MlmeReq_t` to `*MlmeReq_t`
OnMacMlmeRequest : ? fn ( c.LoRaMacStatus_t , * MlmeReq_t , c.TimerTime_t ) callconv ( .C ) void ,
OnJoinRequest : ? fn ([ * c ] c.LmHandlerJoinParams_t ) callconv ( .C ) void ,
OnTxData : ? fn ([ * c ] c.LmHandlerTxParams_t ) callconv ( .C ) void ,
OnRxData : ? fn ([ * c ] c.LmHandlerAppData_t , [ * c ] c.LmHandlerRxParams_t ) callconv ( .C ) void ,
OnClassChange : ? fn ( c.DeviceClass_t ) callconv ( .C ) void ,
OnBeaconStatusChange : ? fn ([ * c ] c.LoRaMacHandlerBeaconParams_t ) callconv ( .C ) void ,
OnSysTimeUpdate : ? fn ( bool , i32 ) callconv ( .C ) void ,
};(แหล่งที่มา)
เราเปลี่ยนการอ้างอิง MlmeReq_t อัตโนมัติทั้งหมดจาก ...
[ * c ] c . MlmeReq_tถึงประเภททึบแสงของเรา ...
* MlmeReq_t นอกจากนี้เรายังเปลี่ยนการอ้างอิง LmHandlerCallbacks_t ทั้งหมดจาก ...
[ * c ] c . LmHandlerCallbacks_t ไปยัง LmHandlerCallbacks_t ที่แปลงแล้วของเรา ...
* LmHandlerCallbacks_tซึ่งหมายความว่าเราจำเป็นต้องนำเข้าฟังก์ชั่น Lorawan ที่ได้รับผลกระทบเอง ...
/// Changed `[*c]c.MlmeReq_t` to `*MlmeReq_t`. Adapted from
/// https://github.com/lupyuen/zig-bl602-nuttx/blob/main/translated/lorawan_test_main.zig#L2905
extern fn DisplayMacMlmeRequestUpdate (
status : c.LoRaMacStatus_t ,
mlmeReq : * MlmeReq_t ,
nextTxIn : c . TimerTime_t
) void ;
/// Changed `[*c]c.LmHandlerCallbacks_t` to `*LmHandlerCallbacks_t`. Adapted from
/// https://github.com/lupyuen/zig-bl602-nuttx/blob/main/translated/lorawan_test_main.zig#L2835
extern fn LmHandlerInit (
callbacks : * LmHandlerCallbacks_t ,
handlerParams : [ * c ] c . LmHandlerParams_t
) c.LmHandlerErrorStatus_t ;(แหล่งที่มา)
หลังจากแก้ไขประเภททึบแสง Zig Compiler ประสบความสำเร็จในการรวบรวมแอพทดสอบ Lorawan ของเรา lorawan_test.zig yay!
ในขณะที่รวบรวมแอพทดสอบ Lorawan ของเรา lorawan_test.zig เราเห็นข้อผิดพลาดมาโครนี้ ...
zig-cache/o/23409ceec9a6e6769c416fde1695882f/cimport.zig:2904:32:
error: unable to translate macro: undefined identifier `LL`
pub const __INT64_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `LL`");
// (no file):178:9
ตามเอกสารซิกซึ่งหมายความว่าคอมไพเลอร์ซิกไม่สามารถแปลแมโคร C ...
ดังนั้นเราจึงกำหนด LL เอง ...
/// Import the LoRaWAN Library from C
const c = @cImport ({
// Workaround for "Unable to translate macro: undefined identifier `LL`"
@cDefine ( "LL" , "" ); ( LL คือคำต่อท้าย "ยาวยาว" สำหรับค่าคงที่ C ซึ่งอาจไม่จำเป็นเมื่อเรานำเข้าประเภทและฟังก์ชั่น C ไปยัง ZIG)
จากนั้น Zig Compiler ปล่อยข้อผิดพลาดนี้ ...
zig-cache/o/83fc6cf7a78f5781f258f156f891554b/cimport.zig:2940:26:
error: unable to translate C expr: unexpected token '##'
pub const __int_c_join = @compileError("unable to translate C expr: unexpected token '##'");
// /home/user/zig-linux-x86_64-0.10.0-dev.2351+b64a1d5ab/lib/include/stdint.h:282:9
ซึ่งหมายถึงบรรทัดนี้ใน stdint.h ...
#define __int_c_join ( a , b ) a ## b แมโคร __int_c_join ล้มเหลวเนื่องจากคำต่อท้าย LL นั้นว่างเปล่าและตัวดำเนินการ ## concatenation ล้มเหลว
เรากำหนด macro __int_c_join ใหม่โดยไม่ต้องใช้ตัวดำเนินการ ## concatenation ...
/// Import the LoRaWAN Library from C
const c = @cImport ({
// Workaround for "Unable to translate macro: undefined identifier `LL`"
@cDefine ( "LL" , "" );
@cDefine ( "__int_c_join(a, b)" , "a" ); // Bypass zig/lib/include/stdint.hตอนนี้ Zig Compiler ประสบความสำเร็จในการรวบรวมแอพทดสอบ Lorawan ของเรา lorawan_test.zig ของเรา
Zig Compiler ขัดข้องเมื่อพยายามเริ่มต้นโครงสร้างตัวจับเวลาเมื่อเริ่มต้น ...
/// Timer to handle the application data transmission duty cycle
var TxTimer : c.TimerEvent_t =
std . mem . zeroes ( c . TimerEvent_t );
// Zig Compiler crashes with...
// TODO buf_write_value_bytes maybe typethread 11512 panic:
// Unable to dump stack trace: debug info stripped(แหล่งที่มา)
ดังนั้นเราจึงเริ่มต้นโครงสร้างตัวจับเวลาในฟังก์ชันหลักแทน ...
/// Timer to handle the application data transmission duty cycle.
/// Init the timer in Main Function.
var TxTimer : c.TimerEvent_t = undefined ;
/// Main Function
pub export fn lorawan_test_main (
_argc : c_int ,
_argv : [ * ] const [ * ] const u8
) c_int {
// Init the Timer Struct at startup
TxTimer = std . mem . zeroes ( c . TimerEvent_t );(แหล่งที่มา)
หลังจากแก้ไขปัญหาข้างต้นเราทดสอบแอพ Lorawan Zig บน nuttx: lorawan_test.zig
nsh> lorawan_test
Application name : Zig LoRaWAN Test
...
###### =========== MLME-Confirm ============ ######
STATUS : OK
###### =========== JOINED ============ ######
OTAA
DevAddr : 00D803AB
DATA RATE : DR_2
...
PrepareTxFrame: Transmit to LoRaWAN (9 bytes): Hi NuttX
###### =========== MCPS-Confirm ============ ######
STATUS : OK
###### ===== UPLINK FRAME 1 ===== ######
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923200000
TX POWER : 0
CHANNEL MASK: 0003
(ดูบันทึกที่สมบูรณ์)
แอพ Lorawan Zig Lorawan_test.zig ประสบความสำเร็จในการเข้าร่วมเครือข่าย Lorawan (Chirpstack บน Rakwireless Wisgate) และส่งแพ็คเก็ตข้อมูลไปยัง Lorawan Gateway Yay!
คอมไพเลอร์ ZIG เปิดเผยข้อมูลเชิงลึกที่น่าสนใจเมื่อแปลรหัส C ของเราไปยัง ZIG โดยอัตโนมัติ
รหัส C นี้คัดลอกอาร์เรย์ไบต์โดยไบต์ ...
static int8_t FragDecoderWrite ( uint32_t addr , uint8_t * data , uint32_t size ) {
...
for ( uint32_t i = 0 ; i < size ; i ++ ) {
UnfragmentedData [ addr + i ] = data [ i ];
}
return 0 ; // Success
}(แหล่งที่มา)
นี่คือรหัสซิกอัตโนมัติที่แปลแล้ว ...
pub fn FragDecoderWrite ( arg_addr : u32 , arg_data : [ * c ] u8 , arg_size : u32 ) callconv ( .C ) i8 {
...
var size = arg_size ;
var i : u32 = 0 ;
while ( i < size ) : ( i +%= 1 ) {
UnfragmentedData [ addr +% i ] = data [ i ];
}
return 0 ;
}(แหล่งที่มา)
โปรดทราบว่าการจัดทำดัชนีอาร์เรย์ใน C ...
// Array Indexing in C...
UnfragmentedData [ addr + i ]ได้รับการแปลเป็นสิ่งนี้ในซิก ...
// Array Indexing in Zig...
UnfragmentedData [ addr +% i ] + ใน C กลายเป็น +% ในซิก!
ซิก +% คืออะไร?
นั่นคือตัวดำเนินการ ZIG สำหรับ การเพิ่ม Wraparound
ซึ่งหมายความว่าผลลัพธ์จะกลับมาเป็น 0 (และเกิน) หากการเพิ่มล้นจำนวนเต็ม
แต่นี่ไม่ใช่สิ่งที่เราตั้งใจไว้เนื่องจากเราไม่คาดหวังว่าจะได้รับการเสริมล้น นั่นเป็นเหตุผลว่าทำไมในรหัสซิกสุดท้ายของเราเรากลับไปที่ +% กลับไปที่ + ...
export fn FragDecoderWrite ( addr : u32 , data : [ * c ] u8 , size : u32 ) i8 {
...
var i : u32 = 0 ;
while ( i < size ) : ( i += 1 ) {
UnfragmentedData [ addr + i ] = data [ i ];
}
return 0 ; // Success
}(แหล่งที่มา)
จะเกิดอะไรขึ้นถ้าการเพิ่มล้น?
เราจะเห็นข้อผิดพลาดรันไทม์ ...
panic: integer overflow
(แหล่งที่มา)
ซึ่งอาจเป็นสิ่งที่ดีเพื่อให้แน่ใจว่าคุณค่าของเรามีเหตุผล
จะเกิดอะไรขึ้นถ้าดัชนีอาร์เรย์ของเราหมดลง?
เราจะได้รับข้อผิดพลาดรันไทม์นี้ ...
panic: index out of bounds
(แหล่งที่มา)
นี่คือรายการ ตรวจสอบความปลอดภัย ที่ทำโดย Zig ในเวลาทำงาน ...
หากเราชอบใช้ชีวิตอย่างประมาทนี่คือวิธีที่เราปิดการตรวจสอบความปลอดภัย ...
คุณสมบัติการดีบักบางอย่างดูเหมือนจะไม่ทำงาน? เช่นเดียวกับ unreachable std.debug.assert และ std.debug.panic ?
นั่นเป็นเพราะสำหรับแพลตฟอร์มที่ฝังอยู่เราจำเป็นต้องใช้ตัวจัดการตื่นตระหนกของเราเอง ...
"การใช้ซิกเพื่อให้ร่องรอยสแต็กบนเคอร์เนลตื่นตระหนกสำหรับระบบปฏิบัติการกระดูกเปลือย"
ตัวจัดการความตื่นตระหนกเริ่มต้น: std.debug.default_panic
ด้วยตัวจัดการตื่นตระหนกของเราเองการยืนยันนี้ล้มเหลว ...
// Create a short alias named `assert`
const assert = std . debug . assert ;
// Assertion Failure
assert ( TxPeriodicity != 0 );จะแสดงร่องรอยสแต็กนี้ ...
!ZIG PANIC!
reached unreachable code
Stack Trace:
0x23016394
0x23016ce0
ตามการถอดชิ้นส่วน RISC-V ของเราที่อยู่แรก 23016394 ดูไม่น่าสนใจเพราะมันอยู่ในฟังก์ชั่น assert ...
/home/user/zig-linux-x86_64-0.10.0-dev.2351+b64a1d5ab/lib/std/debug.zig:259
pub fn assert(ok: bool) void {
2301637c: 00b51c63 bne a0,a1,23016394 <std.debug.assert+0x2c>
23016380: a009 j 23016382 <std.debug.assert+0x1a>
23016382: 2307e537 lui a0,0x2307e
23016386: f9850513 addi a0,a0,-104 # 2307df98 <__unnamed_4>
2301638a: 4581 li a1,0
2301638c: 00000097 auipc ra,0x0
23016390: f3c080e7 jalr -196(ra) # 230162c8 <panic>
if (!ok) unreachable; // assertion failure
23016394: a009 j 23016396 <std.debug.assert+0x2e>
แต่ที่อยู่ที่สอง 23016ce0 เปิดเผยการยืนยันที่ล้มเหลว ...
/home/user/nuttx/zig-bl602-nuttx/lorawan_test.zig:95
assert(TxPeriodicity != 0);
23016ccc: 42013537 lui a0,0x42013
23016cd0: fbc52503 lw a0,-68(a0) # 42012fbc <TxPeriodicity>
23016cd4: 00a03533 snez a0,a0
23016cd8: fffff097 auipc ra,0xfffff
23016cdc: 690080e7 jalr 1680(ra) # 23016368 <std.debug.assert>
/home/user/nuttx/zig-bl602-nuttx/lorawan_test.zig:100
TxTimer = std.mem.zeroes(c.TimerEvent_t);
23016ce0: 42016537 lui a0,0x42016
นี่คือการดำเนินการของเราของ Zig Panic Handler ...
/// Called by Zig when it hits a Panic. We print the Panic Message, Stack Trace and halt. See
/// https://andrewkelley.me/post/zig-stack-traces-kernel-panic-bare-bones-os.html
/// https://github.com/ziglang/zig/blob/master/lib/std/builtin.zig#L763-L847
pub fn panic (
message : [] const u8 ,
_stack_trace : ? * std . builtin . StackTrace
) noreturn {
// Print the Panic Message
_ = _stack_trace ;
_ = puts ( " n !ZIG PANIC!" );
_ = puts ( @ptrCast ([ * c ] const u8 , message ));
// Print the Stack Trace
_ = puts ( "Stack Trace:" );
var it = std . debug . StackIterator . init ( @returnAddress (), null );
while ( it . next ()) | return_address | {
_ = printf ( "%p n " , return_address );
}
// Halt
while ( true ) {}
}(แหล่งที่มา)
เราได้ดำเนินการ Debug Logging std.log.debug ที่อธิบายไว้ที่นี่ ...
นี่คือวิธีที่เราเรียก std.log.debug เพื่อพิมพ์ข้อความบันทึก ...
// Create a short alias named `debug`
const debug = std . log . debug ;
// Message with 8 bytes
const msg : [] const u8 = "Hi NuttX" ;
// Print the message
debug ( "Transmit to LoRaWAN ({} bytes): {s}" , .{
msg . len , msg
});
// Prints: Transmit to LoRaWAN (8 bytes): Hi NuttX .{ ... } สร้าง โครงสร้างที่ไม่ระบุชื่อ ด้วยจำนวนอาร์กิวเมนต์ที่จะถูกส่งผ่านไปยัง std.log.debug สำหรับการพิมพ์
ด้านล่างคือการใช้งาน std.log.debug ของเรา ...
/// Called by Zig for `std.log.debug`, `std.log.info`, `std.log.err`, ...
/// https://gist.github.com/leecannon/d6f5d7e5af5881c466161270347ce84d
pub fn log (
comptime _message_level : std.log.Level ,
comptime _scope : @Type ( .EnumLiteral ),
comptime format : [] const u8 ,
args : anytype ,
) void {
_ = _message_level ;
_ = _scope ;
// Format the message
var buf : [ 100 ] u8 = undefined ; // Limit to 100 chars
var slice = std . fmt . bufPrint ( & buf , format , args )
catch { _ = puts ( "*** log error: buf too small" ); return ; };
// Terminate the formatted message with a null
var buf2 : [ buf . len + 1 : 0 ] u8 = undefined ;
std . mem . copy (
u8 ,
buf2 [0 .. slice . len ],
slice [0 .. slice . len ]
);
buf2 [ slice . len ] = 0 ;
// Print the formatted message
_ = puts ( & buf2 );
}(แหล่งที่มา)
การใช้งานการเรียกใช้นี้ puts() ซึ่งได้รับการสนับสนุนโดย Apache Nuttx RTOs เนื่องจากเป็น ไปตาม Posix
รหัส C ดั้งเดิมและรหัส ZIG ที่แปลงแล้วสำหรับแอพ Lorawan ของเรานั้นดูคล้ายกันอย่างมาก
นี่คือฟังก์ชั่นหลักจากรหัส C ดั้งเดิมของเรา ...
/// Main Function that will be called by NuttX. We call the LoRaWAN Library
/// to Join a LoRaWAN Network and send a Data Packet.
int main ( int argc , FAR char * argv []) {
// If we are using Entropy Pool and the BL602 ADC is available,
// add the Internal Temperature Sensor data to the Entropy Pool
init_entropy_pool ();
// Compute the interval between transmissions based on Duty Cycle
TxPeriodicity = APP_TX_DUTYCYCLE + randr ( - APP_TX_DUTYCYCLE_RND , APP_TX_DUTYCYCLE_RND );
const Version_t appVersion = { . Value = FIRMWARE_VERSION };
const Version_t gitHubVersion = { . Value = GITHUB_VERSION };
DisplayAppInfo ( "lorawan_test" ,
& appVersion ,
& gitHubVersion );
// Init LoRaWAN
if ( LmHandlerInit ( & LmHandlerCallbacks , & LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS )
{
printf ( "LoRaMac wasn't properly initializedn" );
// Fatal error, endless loop.
while ( 1 ) {}
}
// Set system maximum tolerated rx error in milliseconds
LmHandlerSetSystemMaxRxError ( 20 );
// The LoRa-Alliance Compliance protocol package should always be initialized and activated.
LmHandlerPackageRegister ( PACKAGE_ID_COMPLIANCE , & LmhpComplianceParams );
LmHandlerPackageRegister ( PACKAGE_ID_CLOCK_SYNC , NULL );
LmHandlerPackageRegister ( PACKAGE_ID_REMOTE_MCAST_SETUP , NULL );
LmHandlerPackageRegister ( PACKAGE_ID_FRAGMENTATION , & FragmentationParams );
IsClockSynched = false;
IsFileTransferDone = false;
// Join the LoRaWAN Network
LmHandlerJoin ( );
// Set the Transmit Timer
StartTxProcess ( LORAMAC_HANDLER_TX_ON_TIMER );
// Handle LoRaWAN Events
handle_event_queue ( NULL ); // Never returns
return 0 ;
}(แหล่งที่มา)
และฟังก์ชั่นหลักจากรหัสซิกที่แปลงแล้วของเรา (หลังจากการขัดถู) ...
/// Main Function that will be called by NuttX. We call the LoRaWAN Library
/// to Join a LoRaWAN Network and send a Data Packet.
pub export fn lorawan_test_main (
_argc : c_int ,
_argv : [ * ] const [ * ] const u8
) c_int {
_ = _argc ;
_ = _argv ;
// Init the Timer Struct at startup
TxTimer = std . mem . zeroes ( c . TimerEvent_t );
// If we are using Entropy Pool and the BL602 ADC is available,
// add the Internal Temperature Sensor data to the Entropy Pool
// TODO: init_entropy_pool();
// Compute the interval between transmissions based on Duty Cycle
TxPeriodicity = @bitCast ( u32 , // Cast to u32 because randr() can be negative
APP_TX_DUTYCYCLE +
c . randr (
- APP_TX_DUTYCYCLE_RND ,
APP_TX_DUTYCYCLE_RND
)
);
// Show the Firmware and GitHub Versions
const appVersion = c.Version_t {
. Value = c . FIRMWARE_VERSION ,
};
const gitHubVersion = c.Version_t {
. Value = c . GITHUB_VERSION ,
};
c . DisplayAppInfo ( "Zig LoRaWAN Test" , & appVersion , & gitHubVersion );
// Init LoRaWAN
if ( LmHandlerInit ( & LmHandlerCallbacks , & LmHandlerParams )
!= c . LORAMAC_HANDLER_SUCCESS ) {
std . log . err ( "LoRaMac wasn't properly initialized" , .{});
// Fatal error, endless loop.
while ( true ) {}
}
// Set system maximum tolerated rx error in milliseconds
_ = c . LmHandlerSetSystemMaxRxError ( 20 );
// The LoRa-Alliance Compliance protocol package should always be initialized and activated.
_ = c . LmHandlerPackageRegister ( c . PACKAGE_ID_COMPLIANCE , & LmhpComplianceParams );
_ = c . LmHandlerPackageRegister ( c . PACKAGE_ID_CLOCK_SYNC , null );
_ = c . LmHandlerPackageRegister ( c . PACKAGE_ID_REMOTE_MCAST_SETUP , null );
_ = c . LmHandlerPackageRegister ( c . PACKAGE_ID_FRAGMENTATION , & FragmentationParams );
// Init the Clock Sync and File Transfer status
IsClockSynched = false ;
IsFileTransferDone = false ;
// Join the LoRaWAN Network
c . LmHandlerJoin ();
// Set the Transmit Timer
StartTxProcess ( LmHandlerTxEvents_t . LORAMAC_HANDLER_TX_ON_TIMER );
// Handle LoRaWAN Events
handle_event_queue (); // Never returns
return 0 ;
}(แหล่งที่มา)
TODO: ทำความสะอาดชื่อประเภทฟังก์ชั่นและตัวแปร
TODO: อ่านเซ็นเซอร์อุณหภูมิภายใน
TODO: เข้ารหัสข้อมูลเซ็นเซอร์อุณหภูมิด้วย tinycbor และส่งไปยังเครือข่ายสิ่งต่าง ๆ
https://lupyuen.github.io/articles/cbor2
TODO: ตรวจสอบข้อมูลเซ็นเซอร์ด้วย Prometheus และ Grafana
https://lupyuen.github.io/articles/prometheus
TODO: เพิ่มรหัสใหม่ด้วย @import()
https://zig.news/mattnite/import-and-packages-23mb
TODO: เราจำเป็นต้องจัดบัฟเฟอร์เป็น 32 บิตเมื่อส่งออกไปยัง C หรือไม่?
/// User application data
/// (Aligned to 32-bit because it's exported to C)
var AppDataBuffer : [ LORAWAN_APP_DATA_BUFFER_MAX_SIZE ] u8 align ( 4 ) =
std . mem . zeroes ([ LORAWAN_APP_DATA_BUFFER_MAX_SIZE ] u8 );การสะท้อนประเภท ZIG ... เราสามารถใช้มันเพื่อสร้างกราฟการโทรที่มีโครงสร้างสำหรับไลบรารี C ... เช่น Lorawan Library ได้หรือไม่? -
โปรแกรม ZIG นี้นำเข้าห้องสมุด Lorawan จาก C และทิ้งประเภทและฟังก์ชั่น Lorawan ...
// Do Type Reflection on the imported C functions
fn reflect () void {
// We run this at Compile-Time (instead of Runtime)...
comptime {
// Allow Zig Compiler to loop up to 100,000 times (Default is 1,000)
@setEvalBranchQuota ( 100_000 );
// Get the Type Info of the C Namespace
const T = @typeInfo ( c );
// Show the Type Info of the C Namespace (Struct)
@compileLog ( "@typeInfo(c): " , T );
// Shows | *"@typeInfo(c): ", std.builtin.Type { .Struct = (struct std.builtin.Type.Struct constant)}
// Show the number of Fields in the C Namespace (0)
@compileLog ( "T.Struct.fields.len: " , T . Struct . fields . len );
// Shows | *"T.Struct.fields.len: ", 0
// Show the number of Declarations in the C Namespace (4743)
@compileLog ( "T.Struct.decls.len: " , T . Struct . decls . len );
// Shows | *"T.Struct.decls.len: ", 4743
// Show the first Declaration in the C Namespace (__builtin_bswap16)
@compileLog ( "T.Struct.decls[0].name: " , T . Struct . decls [ 0 ]. name );
// Shows | *"T.Struct.decls[0].name: ", "__builtin_bswap16"
// For every C Declaration...
for ( T . Struct . decls ) | decl , i | {
// If the C Declaration starts with "Lm" (LoRaMAC)...
if ( std . mem . startsWith ( u8 , decl . name , "Lm" )) {
// Dump the C Declaration
var T2 = @typeInfo ( c );
@compileLog ( "decl.name: " , T2 . Struct . decls [ i ]. name );
// Strangely we can't do this...
// @compileLog("decl.name: ", decl.name);
// Because it shows...
// *"decl.name: ", []const u8{76,109,110,83,116,97,116,117,115,95,116}
}
}
} // End of Compile-Time Code
}(แหล่งที่มา)
( @typeInfo อธิบายไว้ที่นี่)
เมื่อ Zig Compiler รวบรวมรหัสด้านบนเราจะเห็นสิ่งนี้ในเวลาคอมไพล์ ...
$ zig build-obj --verbose-cimport -target riscv32-freestanding-none -mcpu=baseline_rv32-d -isystem /Users/Luppy/pinecone/nuttx/nuttx/include -I /Users/Luppy/pinecone/nuttx/apps/examples/lorawan_test reflect.zig
info(compilation): C import output: zig-cache/o/e979b806463a36dcecc2ef773bd2d2ad/cimport.zig
| *"@typeInfo(c): ", std.builtin.Type { .Struct = (struct std.builtin.Type.Struct constant)}
| *"T.Struct.fields.len: ", 0
| *"T.Struct.decls.len: ", 4744
| *"T.Struct.decls[0].name: ", "__builtin_bswap16"
| *"decl.name: ", "LmnStatus_t"
| *"decl.name: ", "LmHandlerAdrStates_t"
| *"decl.name: ", "LmHandlerFlagStatus_t"
...
| *"decl.name: ", "LmHandlerInit"
| *"decl.name: ", "LmHandlerIsBusy"
| *"decl.name: ", "LmHandlerProcess"
| *"decl.name: ", "LmHandlerGetDutyCycleWaitTime"
| *"decl.name: ", "LmHandlerSend"
| *"decl.name: ", "LmHandlerJoin"
...
./reflect.zig:836:9: error: found compile log statement
@compileLog("@typeInfo(c): ", T);
^
./reflect.zig:840:9: error: found compile log statement
@compileLog("T.Struct.fields.len: ", T.Struct.fields.len);
^
./reflect.zig:844:9: error: found compile log statement
@compileLog("T.Struct.decls.len: ", T.Struct.decls.len);
^
./reflect.zig:848:9: error: found compile log statement
@compileLog("T.Struct.decls[0].name: ", T.Struct.decls[0].name);
^
./reflect.zig:857:17: error: found compile log statement
@compileLog("decl.name: ", T2.Struct.decls[i].name);
^
(แหล่งที่มา)
ซึ่งเป็นรายการประเภท C และฟังก์ชั่นจากไลบรารี Lorawan
ลองใช้สิ่งนี้เพื่อให้เห็นภาพกราฟการโทร (โดยโมดูล) สำหรับไลบรารี Lorawan
เราจะแสดงกราฟการโทรด้วย mermaid.js ...
https://mermaid-js.github.io/mermaid/#/./flowchart?id=flowCharts
และเราจะจัดกลุ่มฟังก์ชั่น Lorawan ในกราฟการโทรโดยโมดูล Lorawan (กราฟย่อย) ดังนั้นเราจึงสามารถเห็นการโทรข้ามโมดูล Lorawan
ในรหัสด้านบนทำไมเราถึงใช้ T2.Struct.decls[i].name แทน decl.name ?
// For every C Declaration...
for ( T . Struct . decls ) | decl , i | {
// If the C Declaration starts with "Lm" (LoRaMAC)...
if ( std . mem . startsWith ( u8 , decl . name , "Lm" )) {
// Dump the C Declaration
var T2 = @typeInfo ( c );
// Can't use decl.name here...
@compileLog ( "decl.name: " , T2 . Struct . decls [ i ]. name );
}
}เราคาดว่ารหัสนี้จะพิมพ์ชื่อของการประกาศ ...
@compileLog ( "decl.name: " , decl . name );ชอบ ...
"decl.name: ", "LmnStatus_t"
แต่แปลกประหลาดพิมพ์ไบต์ ...
"decl.name: ", []const u8{76,109,110,83,116,97,116,117,115,95,116}
Zig Compiler ดูเหมือนจะตีความชื่อแตกต่างกันหลังจากที่เราอ้างอิงชื่อก่อนหน้านี้ ...
// If the C Declaration starts with "Lm" (LoRaMAC)...
if ( std . mem . startsWith ( u8 , decl . name , "Lm" )) { ...ดังนั้นเราจึงใช้วิธีแก้ปัญหานี้แทน ...
// Get a fresh reference to the Type Info
var T2 = @typeInfo ( c );
// This works OK
@compileLog ( "decl.name: " , T2 . Struct . decls [ i ]. name );ซึ่งให้ผลลัพธ์ที่เราต้องการ ...
"decl.name: ", "LmnStatus_t"
เราสามารถระบุโมดูล Lorawan สำหรับฟังก์ชั่น LoRawan ทุกฟังก์ชั่นได้โดยอัตโนมัติโดยการวิเคราะห์ macros ส่วนหัวของส่วนหัว HEADER_NAME_H__ หรือไม่?
ลองทำสิ่งนี้เพื่อทิ้งประกาศ C และมาโครทั้งหมดที่นำเข้าจาก C ...
// Get the Type Info of the C Namespace
const T = @typeInfo ( c );
// Remember the C Header
var header : [] const u8 = "" ;
// For every C Declaration...
for ( T . Struct . decls ) | decl , i | {
var T2 = @typeInfo ( c );
// If the C Declaration ends with "_H"...
if (
std . mem . endsWith ( u8 , decl . name , "_H" ) or
std . mem . endsWith ( u8 , decl . name , "_H_" ) or
std . mem . endsWith ( u8 , decl . name , "_H__" )
) {
// Dump the C Header and remember it
var name = T2 . Struct . decls [ i ]. name ;
@compileLog ( "-----" , name );
header = name ;
} else {
// Dump the C Declaration
var name = T2 . Struct . decls [ i ]. name ;
@compileLog ( "decl.name:" , name );
}
} // End of C Declaration(แหล่งที่มา)
เราได้รับรายการฟังก์ชัน Lorawan และมาโคร Lorawan ...
| *"decl.name:", "LmHandlerInit"
| *"decl.name:", "LmHandlerIsBusy"
| *"decl.name:", "LmHandlerProcess"
| *"decl.name:", "LmHandlerGetDutyCycleWaitTime"
| *"decl.name:", "LmHandlerSend"
| *"decl.name:", "LmHandlerJoin"
...
| *"-----", "__LORAMAC_HANDLER_H__"
| *"-----", "__LORAMAC_HANDLER_TYPES_H__"
| *"decl.name:", "LMH_SYS_TIME_UPDATE_NEW_API"
| *"decl.name:", "__LMHP_COMPLIANCE__"
(แหล่งที่มา)
ซึ่งไม่มีประโยชน์ LmHandlerInit ถูกประกาศจริง ๆ ภายในไฟล์ส่วนหัว C สำหรับ __LORAMAC_HANDLER_H__ แต่อย่างใดการสะท้อนประเภทซิกจะย้าย LmHandlerInit ขึ้นไปด้านบนก่อน __LORAMAC_HANDLER_H__ จะปรากฏขึ้น
ดังนั้นดูเหมือนว่าเราจำเป็นต้องจัดกลุ่มฟังก์ชั่น Lorawan ด้วยตนเองเป็นโมดูล Lorawan
ฟังก์ชั่น Lorawan ดูเหมือนจะถูกจัดลำดับตามไฟล์ส่วนหัว C ดังนั้นเราจึงต้องติดแท็กฟังก์ชัน Lorawan แรกสำหรับแต่ละโมดูล Lorawan เท่านั้น แบบนี้...
LmHandlerInit → __LORAMAC_HANDLER_H__
LoRaMacInitialization → __LORAMAC_H__
RegionCommonValueInRange → __REGIONCOMMON_H__
SX126xInit → __SX126x_H__
SX126xIoInit → __SX126x_BOARD_H__
แอพ Zig ของเราสามารถพิมพ์ภาพสะท้อนได้เองเพื่อค้นหาประเภทค่าคงที่ตัวแปรและฟังก์ชั่น ...
// Show the Type Info for our Zig Namespace
const ThisType = @typeInfo ( @This ());
@compileLog ( "ThisType: " , ThisType );
@compileLog ( "ThisType.Struct.decls.len: " , ThisType . Struct . decls . len );
@compileLog ( "ThisType.Struct.decls[0].name: " , ThisType . Struct . decls [ 0 ]. name );
@compileLog ( "ThisType.Struct.decls[1].name: " , ThisType . Struct . decls [ 1 ]. name );
@compileLog ( "ThisType.Struct.decls[2].name: " , ThisType . Struct . decls [ 2 ]. name );
// Shows...
// | *"ThisType: ", std.builtin.Type { .Struct = (struct std.builtin.Type.Struct constant)}
// | *"ThisType.Struct.decls.len: ", 66
// | *"ThisType.Struct.decls[0].name: ", "std"
// | *"ThisType.Struct.decls[1].name: ", "c"
// | *"ThisType.Struct.decls[2].name: ", "ACTIVE_REGION" (แหล่งที่มา)
เราจะใช้สิ่งนี้เพื่อพล็อตการเรียกใช้ฟังก์ชันจากฟังก์ชั่น ZIG ของเราไปยังฟังก์ชั่น C ในไลบรารี Lorawan
ก่อนหน้านี้เราได้บันทึกบันทึกการโทรนี้: บันทึกการโทรไปยังฟังก์ชัน C ในไลบรารี Lorawan ...
init_event_queue
TimerInit: 0x4201c76c
SX126xIoInit: Compiled with gcc
init_gpio
...
RadioSetChannel: freq=923200000
RadioSetTxConfig: modem=1, power=13, fdev=0, bandwidth=0, datarate=10, coderate=1, preambleLen=8, fixLen=0, crcOn=1, freqHopOn=0, hopPeriod=0, iqInverted=0, timeout=4000
RadioSetTxConfig: SpreadingFactor=10, Bandwidth=4, CodingRate=1, LowDatarateOptimize=0, PreambleLength=8, HeaderType=0, PayloadLength=255, CrcMode=1, InvertIQ=0
RadioStandby
RadioSetModem
SX126xSetTxParams: power=13, rampTime=7
SX126xSetPaConfig: paDutyCycle=4, hpMax=7, deviceSel=0, paLut=1
(แหล่งที่มา)
แต่ละบรรทัดของบันทึกการโทรมีชื่อฟังก์ชัน Lorawan เราจะจับคู่สิ่งนี้กับข้อมูลจาก zig type reflection เพื่อพล็อตกราฟการโทร
เรานำเข้าบันทึกการโทรไปยังแอพ Zig ของเราเช่น ...
/// Call Log captured for this app. From
/// https://gist.github.com/lupyuen/0871ac515b18d9d68d3aacf831fd0f5b
const call_log =
\init_event_queue
\TimerInit: 0x4201c76c
\SX126xIoInit: Compiled with gcc
\init_gpio
...
\RadioSetChannel: freq=923200000
\RadioSetTxConfig: modem=1, power=13, fdev=0, bandwidth=0, datarate=10, coderate=1, preambleLen=8, fixLen=0, crcOn=1, freqHopOn=0, hopPeriod=0, iqInverted=0, timeout=4000
\RadioSetTxConfig: SpreadingFactor=10, Bandwidth=4, CodingRate=1, LowDatarateOptimize=0, PreambleLength=8, HeaderType=0, PayloadLength=255, CrcMode=1, InvertIQ=0
\RadioStandby
\RadioSetModem
\SX126xSetTxParams: power=13, rampTime=7
\SX126xSetPaConfig: paDutyCycle=4, hpMax=7, deviceSel=0, paLut=1
\SecureElementRandomNumber: 0xbc9f21c2
\RadioSend: size=23
\00 00 00 00 00 00 00 00 00 5b b1 7b 37 e7 5e c1 4b c2 21 9c 04 48 1b
\RadioSend: PreambleLength=8, HeaderType=0, PayloadLength=23, CrcMode=1, InvertIQ=0
\TimerStop: 0x4201b86c
\TimerStart2: 0x4201b86c, 4000 ms
\callout_reset: evq=0x420131a8, ev=0x4201b86c
\
\###### =========== MLME-Request ============ ######
\###### MLME_JOIN ######
\###### ===================================== ######
\STATUS : OK
\StartTxProcess
\handle_event_queue
\DIO1 add event
\handle_event_queue: ev=0x4201b894
\RadioOnDioIrq
\RadioIrqProcess
\IRQ_TX_DONE
\TimerStop: 0x4201b86c
\TODO: RtcGetCalendarTime
\TODO: RtcBkupRead
\RadioOnDioIrq
\RadioIrqProcess
\ProcessRadioTxDone: RxWindow1Delay=4988
\RadioSleep
...
;(แหล่งที่มา)
Zig Compiler สามารถประมวลผลบันทึกการโทรทีละบรรทัดเช่นเดียวกับ ...
// Show the first line of the Call Log
var call_log_split = std . mem . split ( u8 , call_log , " n " );
const line = call_log_split . next ();
@compileLog ( "line:" , line );
// Shows | *"line:", []const u8{103,112,108,104,95,101,110,97,98,108,101,58,32,87,65,82,78,73,78,71,58,32,112,105,110,57,58,32,65,108,114,101,97,100,121,32,100,101,116,97,99,104,101,100}(แหล่งที่มา)
เพื่อวนซ้ำทุกบรรทัดของบันทึกการโทรเราทำสิ่งนี้ ...
// For every line in the Call Log...
var call_log_split = std . mem . split ( u8 , call_log , " n " );
while ( call_log_split . next ()) | line | {
// TODO: Process the line
@compileLog ( "line:" , line );
...
} // End of Call Log(แหล่งที่มา)
มาจับคู่บันทึกการโทรกับชื่อฟังก์ชั่นจากไลบรารี Lorawan ของเรา ...
// For every line in the Call Log...
var call_log_split = std . mem . split ( u8 , call_log , " n " );
while ( call_log_split . next ()) | line | {
// For every C Declaration...
for ( T . Struct . decls ) | decl , i | {
if ( std . mem . eql ( u8 , decl . name , "Radio" )) { continue ; } // Skip Radio
var T2 = @typeInfo ( c );
// If the C Declaration matches the Call Log...
if ( std . mem . startsWith ( u8 , line , decl . name )) {
// Dump the C Declaration
var name = T2 . Struct . decls [ i ]. name ;
@compileLog ( "Found call log" , name );
break ;
}
} // End of C Declaration
} // End of Call Log(แหล่งที่มา)
รหัสด้านบนสร้างผลลัพธ์นี้ ...
| *"Found call log", "LoRaMacInitialization"
| *"Found call log", "TimerInit"
| *"Found call log", "SX126xIoInit"
| *"Found call log", "SX126xSetTx"
| *"Found call log", "SX126xSetPaConfig"
| *"Found call log", "TimerInit"
| *"Found call log", "TimerInit"
| *"Found call log", "RadioSetModem"
| *"Found call log", "RadioSetModem"
| *"Found call log", "RadioSetPublicNetwork"
| *"Found call log", "RadioSleep"
| *"Found call log", "RadioSetModem"
| *"Found call log", "RadioSetPublicNetwork"
...
(แหล่งที่มา)
ซึ่งเป็นรายการของฟังก์ชั่น Lorawan และลำดับที่เรียกว่า
หนึ่งก้าวเข้าใกล้กราฟการโทรที่มีโครงสร้างของเรามากขึ้น!
มาขยายรหัสด้านบนและแสดงกราฟการโทรที่ไร้เดียงสา ...
สำหรับทุกฟังก์ชัน Lorawan ที่เราระบุในบันทึกการโทร ...
เราพล็อตบรรทัดระหว่างฟังก์ชัน Lorawan และฟังก์ชัน Lorawan ถัดไปในบันทึกการโทร
ดังนั้นเราแค่พล็อตลำดับการเรียกใช้ฟังก์ชันที่เชื่อมต่อ
(ใช่มันไร้เดียงสามาก!)
เราทำแบบนี้ ...
// Draw the graph for all functions in the Call Log
var call_log_split = std . mem . split ( u8 , call_log , " n " );
var prev_name : [] const u8 = "Start" ;
@compileLog ( "flowchart TD;" ); // Top-Down Flowchart
// For every line in the Call Log...
while ( call_log_split . next ()) | line | {
// For every C Declaration...
for ( T . Struct . decls ) | decl , i | {
if ( std . mem . eql ( u8 , decl . name , "Radio" )) { continue ; } // Skip Radio
var T2 = @typeInfo ( c );
// If the C Declaration matches the Call Log...
if ( std . mem . startsWith ( u8 , line , decl . name )) {
// Draw the graph: [previous function]-->[current function]
var name = T2 . Struct . decls [ i ]. name ;
@compileLog ( " " , prev_name , "-->" , name , ";" );
prev_name = name ;
break ;
}
} // End of C Declaration
} // End of Call Log
@compileLog ( " " , prev_name , "-->" , "End" , ";" );(แหล่งที่มา)
Zig Compiler สร้างผลลัพธ์นี้ในเวลาคอมไพล์ ...
| *"flowchart TD;"
| *" ", "Start", *"-->", "LoRaMacInitialization", *";"
| *" ", "LoRaMacInitialization", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "SX126xIoInit", *";"
| *" ", "SX126xIoInit", *"-->", "SX126xSetTx", *";"
| *" ", "SX126xSetTx", *"-->", "SX126xSetPaConfig", *";"
| *" ", "SX126xSetPaConfig", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "TimerInit", *";"
| *" ", "TimerInit", *"-->", "RadioSetModem", *";"
...
(แหล่งที่มา)
เราลบตัวคั่นจากบันทึกซิกคอมไพเลอร์ด้วยตนเองด้านบนเช่นนี้ ...
flowchart TD;
Start-->LoRaMacInitialization;
LoRaMacInitialization-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->SX126xIoInit;
SX126xIoInit-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->RadioSetModem;
...
เพื่อรับแผนผัง mermaid.js นี้ ...
ผังงาน TD;
เริ่ม-> loramacinitialization;
Loramacinitialization-> Timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> sx126xioinit;
SX126XIOINIT-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Timerinit;
timerinit-> timerinit;
Timerinit-> RadioSetModem;
RadioSetModem-> RadioSetModem;
RadioSetModem-> RadioTpublicNetwork;
RadiosetPublicNetwork-> Radiosleep;
Radiosleep-> RadioSetModem;
RadioSetModem-> RadioTpublicNetwork;
RadiosetPublicNetwork-> Timerinit;
timerinit-> timerinit;
timerinit-> timerinit;
timerinit-> radioTeTnEnel;
Radiosetchannel-> radiosettxConfig;
radiosettxConfig-> radiosettxConfig;
RadiosettxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Radiosend;
Radiosend-> Radiosend;
Radiosend-> Timerstop;
Timerstop-> Timerstart;
timerstart-> timerinit;
Timerinit-> TimersetValue;
TimerSetValue-> Timerstop;
Timerstop-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_tx_done;
irq_tx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> radiostandby;
Radiostandby-> RadioTeTnEntannel;
Radiosetchannel-> RadioTrxConfig;
RadioTrxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> RadioTrxConfig;
RadioTrxConfig-> radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_header_valid;
irq_header_valid-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_rx_done;
irq_rx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> Timerstop;
Timerstop-> lmhandlersend;
lmhandlersend-> radiosetchannel;
Radiosetchannel-> radiosettxConfig;
radiosettxConfig-> radiosettxConfig;
RadiosettxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Radiosend;
Radiosend-> Radiosend;
Radiosend-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_tx_done;
irq_tx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> radiostandby;
Radiostandby-> RadioTeTnEntannel;
Radiosetchannel-> RadioTrxConfig;
RadioTrxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> RadioTrxConfig;
RadioTrxConfig-> radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
RadioirqProcess-> irq_rx_tx_timeout;
irq_rx_tx_timeout-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> lmhandlersend;
lmhandlersend-> radiosetchannel;
Radiosetchannel-> radiosettxConfig;
radiosettxConfig-> radiosettxConfig;
RadiosettxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Radiosend;
Radiosend-> Radiosend;
Radiosend-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_tx_done;
irq_tx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> radiosleep;
Radiosleep-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> radiostandby;
Radiostandby-> RadioTeTnEntannel;
Radiosetchannel-> RadioTrxConfig;
RadioTrxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> RadioTrxConfig;
RadioTrxConfig-> radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
RadioirqProcess-> irq_rx_tx_timeout;
irq_rx_tx_timeout-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> lmhandlersend;
lmhandlersend-> radiosetchannel;
Radiosetchannel-> radiosettxConfig;
radiosettxConfig-> radiosettxConfig;
RadiosettxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Radiosend;
Radiosend-> Radiosend;
Radiosend-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_tx_done;
irq_tx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> radiostandby;
Radiostandby-> RadioTeTnEntannel;
Radiosetchannel-> RadioTrxConfig;
RadioTrxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> RadioTrxConfig;
RadioTrxConfig-> radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
RadioirqProcess-> irq_rx_tx_timeout;
irq_rx_tx_timeout-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> lmhandlersend;
lmhandlersend-> radiosetchannel;
Radiosetchannel-> radiosettxConfig;
radiosettxConfig-> radiosettxConfig;
RadiosettxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Radiosend;
Radiosend-> Radiosend;
Radiosend-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_tx_done;
irq_tx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> radiostandby;
Radiostandby-> RadioTeTnEntannel;
Radiosetchannel-> RadioTrxConfig;
RadioTrxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> RadioTrxConfig;
RadioTrxConfig-> radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
RadioirqProcess-> irq_rx_tx_timeout;
irq_rx_tx_timeout-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> Timerstop;
Timerstop-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> lmhandlersend;
lmhandlersend-> radiosetchannel;
Radiosetchannel-> radiosettxConfig;
radiosettxConfig-> radiosettxConfig;
RadiosettxConfig-> radiostandby;
Radiostandby-> RadioSetModem;
RadioSetModem-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Radiosend;
Radiosend-> Radiosend;
Radiosend-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> irq_tx_done;
irq_tx_done-> timerstop;
Timerstop-> RadioOndioirq;
RadioOndioirq-> Radioirqprocess;
Radioirqprocess-> radiosleep;
Radiosleep-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> TimersetValue;
TimerSetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
มีอะไรผิดปกติกับกราฟการโทรที่ไร้เดียงสาที่เราผลิต?
flowchart TD;
Start-->LoRaMacInitialization;
LoRaMacInitialization-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->SX126xIoInit;
SX126xIoInit-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->TimerInit;
TimerInit-->RadioSetModem;
...
(แหล่งที่มา)
กราฟการโทรของเราขาด โครงสร้าง จำไว้ว่าเราแค่พล็อตลำดับของการเรียกใช้ฟังก์ชัน ...
TimerInit → TimerInit ไม่สมเหตุสมผล (เพราะเราไม่มีฟังก์ชั่นการเรียกซ้ำ)
TimerInit → RadioSetModem นั้นผิดทั้งหมดเนื่องจาก TimerInit เป็นฟังก์ชั่นระดับต่ำ (Library Multithreading Nimble) ในขณะที่ RadioSetModem เป็นฟังก์ชันระดับสูง (Library SX1262)
เราสามารถเพิ่มโครงสร้างบางอย่างเพื่อปรับปรุงกราฟการโทรได้หรือไม่?
ในการสร้างกราฟการโทรที่มีโครงสร้างเราจะจัดกลุ่มฟังก์ชั่นเป็นโมดูลตั้งแต่ระดับสูงถึงระดับต่ำ ...
แอพ Zig (ระดับสูงสุด)
ห้องสมุด Lorawan
ห้องสมุด SX1262
ไลบรารีมัลติเธรดว่องไว (ระดับต่ำสุด)
และเราจะตรวจสอบให้แน่ใจว่าเราไม่เคยวาดเส้นจากฟังก์ชั่นระดับต่ำไปยังฟังก์ชั่นระดับสูง
นี่คือตัวอย่างของสิ่งที่เราต้องการบรรลุ ...
ผังงาน TD;
Subgraph Lorawan;
เริ่ม;
Loramacinitialization;
จบ;
Subgraph SX1262;
SX126xioinit;
SX126XSETTX;
SX126XSetPaconfig;
จบ;
Subgraph ว่องไว;
timerinit;
timerinit;
จบ;
เริ่ม-> loramacinitialization;
Loramacinitialization-> Timerinit;
SX126XIOINIT-> SX126XSETTX;
SX126XSETTX-> SX126XSETPACONFIG;
SX126XSetPaconFig-> Timerinit;
มาเพิ่มโครงสร้างบางอย่างลงในกราฟการโทรของเราโดยจัดกลุ่มฟังก์ชัน C เป็นโมดูล
นี่คือวิธีที่เรากำหนดโมดูลจากระดับสูงถึงระดับต่ำ ...
// Define the Modules and the First / Last Functions in each Module.
// We order the Modules from High-Level to Low-Level.
var all_modules = [ _ ] Module {
// LoRaMAC Handler is the Top Level Module that drives the LoRaWAN Stack
Module {
. name = "LMHandler" ,
. first_function = "LmHandlerInit" ,
. last_function = "DisplayAppInfo" ,
. first_index = undefined ,
. last_index = undefined ,
},
// LoRaMAC Module is the implementation of the LoRaWAN Driver
Module {
. name = "LoRaMAC" ,
. first_function = "LoRaMacInitialization" ,
. last_function = "LoRaMacDeInitialization" ,
. first_index = undefined ,
. last_index = undefined ,
},
// Radio Module is the abstract interface for LoRa Radio Transceivers
Module {
. name = "Radio" ,
. first_function = "RadioInit" ,
. last_function = "RadioAddRegisterToRetentionList" ,
. first_index = undefined ,
. last_index = undefined ,
},
// SX1262 Module is the LoRa Driver for Semtech SX1262 Radio Transceiver
Module {
. name = "SX1262" ,
. first_function = "SX126xInit" ,
. last_function = "SX126xSetOperatingMode" ,
. first_index = undefined ,
. last_index = undefined ,
},
// NimBLE is the Bottom Level Module that contains Multithreading Functions like Timers and Event Queues
Module {
. name = "NimBLE" ,
. first_function = "TimerInit" ,
. last_function = "TimerGetElapsedTime" ,
. first_index = undefined ,
. last_index = undefined ,
},
};(แหล่งที่มา)
โปรดทราบว่าเราระบุเฉพาะฟังก์ชั่นแรกและสุดท้ายสำหรับแต่ละโมดูล
นั่นเป็นเพราะฟังก์ชั่นจากโมดูลเดียวกันจะถูกรวมเข้าด้วยกันในการสะท้อนประเภทซิก
จากนั้นเราแสดงแต่ละโมดูลเป็น mermaid.js subgraph ...
/// Render all Modules and their Functions as Subgraphs
fn render_modules ( all_modules : [] Module ) void {
comptime {
// Render every Module
for ( all_modules ) | module , m | {
@compileLog ( " subgraph " , module . name , ";" );
// For every line in the Call Log...
var call_log_split = std . mem . split ( u8 , call_log , " n " );
while ( call_log_split . next ()) | line | {
var T = @typeInfo ( c );
// If the Call Log matches a C Declaration...
if ( get_decl_by_name_filtered ( all_modules , line )) | decl_index | {
// Get the Module Index for the C Declaration
if ( get_module_by_decl ( all_modules , decl_index )) | m2 | {
// If the C Declaration matches our Module Index...
if ( m == m2 ) {
// Print the Function Name
var name = T . Struct . decls [ decl_index ]. name ;
@compileLog ( " " , name , ";" );
}
} else {
// Missing Declaration
var name = T . Struct . decls [ decl_index ]. name ;
@compileLog ( "Missing Decl:" , name );
}
}
} // End of Call Log
@compileLog ( " end;" );
} // End of Module
}
}(แหล่งที่มา)
แต่ละกราฟย่อยมีรายการฟังก์ชั่นที่เป็นของโมดูล ...
flowchart TD;
subgraph LMHandler;
LmHandlerSend;
end;
subgraph LoRaMAC;
LoRaMacInitialization;
end;
subgraph Radio;
RadioSetModem;
RadioSetPublicNetwork;
RadioSleep;
RadioSetChannel;
RadioSetTxConfig;
RadioStandby;
RadioSend;
RadioIrqProcess;
...
end;
subgraph SX1262;
SX126xIoInit;
SX126xSetTx;
SX126xSetPaConfig;
end;
subgraph NimBLE;
TimerInit;
TimerStop;
TimerStart;
TimerSetValue;
end;
Start-->LoRaMacInitialization;
LoRaMacInitialization-->TimerInit;
TimerInit-->SX126xIoInit;
...
(แหล่งที่มา)
เมื่อเราแสดงผลด้วย mermaid.js เราจะได้รับกราฟการโทรที่มีโครงสร้างซึ่งดูมีความหมายมากขึ้น ...
ผังงาน TD;
subgraph lmhandler;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
lmhandlersend;
จบ;
Subgraph Loramac;
Loramacinitialization;
จบ;
วิทยุกราฟย่อย;
RadioSetModem;
RadioSetModem;
RadiosetPublicNetwork;
Radiosleep;
RadioSetModem;
RadiosetPublicNetwork;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadioSetModem;
วิทยุ;
วิทยุ;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadioSetModem;
RadiosetrxConfig;
Radiorx;
Radioirqprocess;
Radioirqprocess;
Radioirqprocess;
Radiosleep;
Radioirqprocess;
Radiosetchannel;
RadiosettxConfig;
RadioSetTxConfig;
RadioStandby;
RadioSetModem;
RadioSend;
RadioSend;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
RadioStandby;
RadioSetChannel;
RadioSetRxConfig;
RadioStandby;
RadioSetModem;
RadioSetRxConfig;
RadioRx;
RadioIrqProcess;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
RadioIrqProcess;
RadioSetChannel;
RadioSetTxConfig;
RadioSetTxConfig;
RadioStandby;
RadioSetModem;
RadioSend;
RadioSend;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
RadioStandby;
RadioSetChannel;
RadioSetRxConfig;
RadioStandby;
RadioSetModem;
RadioSetRxConfig;
RadioRx;
RadioIrqProcess;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
RadioIrqProcess;
RadioSetChannel;
RadioSetTxConfig;
RadioSetTxConfig;
RadioStandby;
RadioSetModem;
RadioSend;
RadioSend;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
RadioStandby;
RadioSetChannel;
RadioSetRxConfig;
RadioStandby;
RadioSetModem;
RadioSetRxConfig;
RadioRx;
RadioIrqProcess;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
จบ;
subgraph SX1262;
SX126xIoInit;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
SX126xSetTx;
SX126xSetPaConfig;
จบ;
subgraph NimBLE;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerInit;
TimerStop;
TimerStart;
TimerInit;
TimerSetValue;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerSetValue;
TimerStart;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStart;
TimerStop;
TimerStop;
TimerStop;
จบ;
Start-->LoRaMacInitialization;
LoRaMacInitialization-->TimerInit;
TimerInit-->SX126xIoInit;
SX126xIoInit-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->TimerInit;
TimerInit-->RadioSetModem;
RadioSetModem-->RadioSetPublicNetwork;
RadioSetPublicNetwork-->RadioSleep;
RadioSleep-->RadioSetModem;
RadioSetModem-->RadioSetPublicNetwork;
RadioSetPublicNetwork-->TimerInit;
TimerInit-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerInit;
TimerInit-->TimerSetValue;
TimerSetValue-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->LmHandlerSend;
LmHandlerSend-->RadioSetChannel;
RadioSetChannel-->RadioSetTxConfig;
RadioSetTxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->RadioSend;
RadioSend-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerSetValue;
TimerSetValue-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->TimerStop;
TimerStop-->RadioStandby;
RadioStandby-->RadioSetChannel;
RadioSetChannel-->RadioSetRxConfig;
RadioSetRxConfig-->RadioStandby;
RadioStandby-->RadioSetModem;
RadioSetModem-->RadioSetRxConfig;
RadioSetRxConfig-->RadioRx;
RadioRx-->TimerStop;
TimerStop-->TimerStart;
TimerStart-->RadioIrqProcess;
RadioIrqProcess-->TimerStop;
TimerStop-->RadioIrqProcess;
RadioIrqProcess-->RadioSleep;
RadioSleep-->TimerStop;
TimerStop-->End;
สิ่งที่ต้องทำ
Zig Compiler crashes when we run this code to group the C Functions by Module...
zig-bl602-nuttx/reflect.zig
Lines 825 to 1086 in f5a5c82
Here is the Output Log...
https://gist.github.com/lupyuen/5738abefa9d4c138e9d731e22d01500f
On macOS, Zig Compiler consumes over 34 GB of memory and crashes...
(On WSL, Zig Compiler hangs the WSL process when it consumes over 4 GB of memory)
This happens because our code loops repeatedly over 4,700 C Declarations while processing 1,500 lines of Raw Call Logs .
Let's optimise our code.
Our code searches for a C Declaration by looping repeatedly over 4,700 C Declarations like so...
/// Return the C Declaration Index for the Function Name.
/// We match the C Declaration Name against the start of the Function Name.
/// This is the slower, unfiltered version that searches all C Declarations.
fn get_decl_by_name ( name : [] const u8 ) ? usize {
comptime {
const T = @typeInfo ( c );
// For every C Declaration...
for ( T . Struct . decls ) | decl , i | {
if ( std . mem . eql ( u8 , decl . name , "Radio" )) { continue ; } // Skip Radio
// If the C Declaration starts with the Function Name...
if ( std . mem . startsWith ( u8 , name , decl . name )) {
// Return the C Declaration Index
return i ;
}
} // End of C Declaration
return null ; // Not found
}
}(แหล่งที่มา)
Which causes Zig Compiler to crash with Out Of Memory. But we don't actually need to loop through all the C Declarations!
According to our list of Modules, we call only 173 Functions . Let's fix the above function so that we loop over the 173 Functions instead...
/// Return the C Declaration Index for the Function Name.
/// We match the C Declaration Name against the start of the Function Name.
/// This is the faster, filtered version that searches C Declarations by Modules.
fn get_decl_by_name_filtered ( all_modules : [] Module , name : [] const u8 ) ? usize {
comptime {
const T = @typeInfo ( c );
// Search all Modules for the Function Name
for ( all_modules ) | module | {
// For every C Declaration in the Module...
var decl_index = module . first_index ;
while ( decl_index <= module . last_index ) {
// Get the C Declaration
var decl = T . Struct . decls [ decl_index ];
if ( std . mem . eql ( u8 , decl . name , "Radio" )) { continue ; } // Skip Radio
// If the C Declaration starts with the Function Name...
if ( std . mem . startsWith ( u8 , name , decl . name )) {
// Return the C Declaration Index
return decl_index ;
}
decl_index += 1 ;
} // End of C Declaration
} // End of Module
return null ; // Not found
}
}(แหล่งที่มา)
And our code runs OK with Zig Compiler!
(macOS, not WSL though)
Building a Call Graph at Compile-Time with Zig Compiler looks pretty challenging.
I hope that future versions of the Zig Compiler will support the following...
Type Reflection for C Declarations will provide the full path of source files
(Makes it easier to identify the module for each declaration)
@compileLog will emit any kind of strings
(So that @compileLog can generate proper Mermaid.js strings like " Start-->LoRaMacInitialization; ")