Baca artikelnya ...
"Zig pada RISC-V BL602: Mengintip Cepat dengan Apache Nuttx RTOS"
"Bangun aplikasi IoT dengan zig dan lorawan"
Untuk membangun aplikasi hello zig untuk nuttx di 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 succeedBoot nuttx dan masukkan ini di shell nuttx ...
NuttShell (NSH) NuttX-10.3.0-RC2
nsh> hello_zig
Hello, Zig!
Untuk aplikasi Lorawan Zig, lihat ini ...
Untuk mengkompilasi perpustakaan Lora SX1262 di C dengan compiler zig, lihat ini ...
Begini cara kami membuat Zig dan Lorawan berlari di BL602 Nuttx ...
Apache nuttx rtos dibundel dengan aplikasi zig sederhana ... mari kita jalankan ini di 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 ;
}Kami memperbaiki 2 baris terakhir untuk membuat compiler zig senang ...
// 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 ;Versi asli ada di sini: hello_zig_main.zig
Untuk mengaktifkan aplikasi zig di nuttx ...
make menuconfigPilih "Konfigurasi Aplikasi> Contoh> Contoh Hello Zig"
Simpan konfigurasi dan keluar Menuconfig.
Saat kita membangun nuttx ...
makeKami melihat kesalahan ini ...
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'
(Sumber)
Yang terlihat mirip dengan masalah ini ...
Apache/NutTX#6219
Ini tampaknya disebabkan oleh build nuttx yang tidak memanggil kompiler zig.
Tapi jangan khawatir! Mari kita kompilasi aplikasi zig sendiri dan tautkan ke NUTTX.
Begini cara kami mengkompilasi aplikasi zig kami untuk RISC-V BL602 dan menautkannya dengan 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 Mengapa target riscv32-freestanding-none ?
Target zig memiliki formulir <arch><sub>-<os>-<abi> ...
riscv32 : Karena BL602 adalah prosesor RISC-V 32-bit
freestanding : Karena target tertanam tidak membutuhkan OS
none : Karena target tertanam tidak menentukan ABI
Mengapa target CPU sifive_e76 ?
BL602 ditetapkan sebagai RV32IMACF ...
| Penamaan | Arti |
|---|---|
RV32I | 32-bit RISC-V dengan instruksi bilangan bulat basis |
M | Penggandaan Integer + Divisi |
A | Instruksi Atom |
C | Instruksi terkompresi |
F | Titik mengambang presisi tunggal |
(Sumber)
Di antara semua target zig, hanya sifive_e76 yang memiliki penunjukan yang sama ...
$ zig targets
...
" sifive_e76 " : [ " a " , " c " , " f " , " m " ],(Sumber)
Jadi kami menggunakan sifive_e76 sebagai target CPU kami.
Atau kami dapat menggunakan baseline_rv32-d sebagai target CPU kami ...
# # 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.zigKarena...
baseline_rv32 berarti RV32IMACFD
(D untuk titik mengambang presisi ganda)
-d berarti lepaskan titik mengambang presisi ganda (D)
(Tetapi pertahankan titik mengambang presisi tunggal)
(Lebih lanjut tentang bendera fitur RISC-V. Terima kasih Matheus!)
Saat menautkan aplikasi zig yang dikompilasi dengan NUTTX, kami melihat kesalahan ini ...
$ 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 modulesItu karena NUTTX dikompilasi untuk (presisi tunggal) Hardware Floating-Point ABI (Application Binary Interface) ...
# # 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"(Sumber)
(Nuttx dikompilasi dengan bendera GCC -march=rv32imafc -mabi=ilp32f )
Sedangkan Zig Compiler menghasilkan file objek dengan perangkat lunak floating-point 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"(Sumber)
GCC tidak akan mengizinkan kami untuk menautkan file objek dengan titik mengambang perangkat lunak dan perangkat keras mengambang ABIS!
(Mengapa kompiler zig menghasilkan file objek dengan perangkat lunak floating-point ABI, ketika sifive_e76 mendukung titik mengambang perangkat keras? Lihat ini)
Zig Compiler menghasilkan file objek dengan perangkat lunak floating-point ABI (Application Binary Interface) ...
# # Dump the ABI for the compiled app
$ riscv64-unknown-elf-readelf -h -A hello_zig_main.o
...
Flags: 0x1, RVC, soft-float ABIIni tidak akan terhubung dengan NUTTX karena NUTTX dikompilasi dengan perangkat keras ABI floating-point.
Kami memperbaikinya dengan memodifikasi header ELF ...
Edit hello_zig_main.o dalam editor hex
(Seperti editor vscode hex)
Ubah byte 0x24 (flag) dari 0x01 (soft float) ke 0x03 (hard float)
(Lihat ini)
Kami memverifikasi bahwa file objek telah diubah menjadi perangkat keras mengambang ABI ...
# # Dump the ABI for the compiled app
$ riscv64-unknown-elf-readelf -h -A hello_zig_main.o
...
Flags: 0x3, RVC, single-float ABIIni sekarang perangkat keras mengambang ABI dan akan terhubung dengan NUTTX.
Sekarang kami menautkan file objek yang dimodifikasi dengan 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
makeBangunan NUTTX sekarang harus berhasil.
Apakah tidak apa -apa mengubah Abi seperti ini?
Nah secara teknis ABI dihasilkan dengan benar oleh kompiler zig ...
# # 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 "Baris terakhir diterjemahkan menjadi RV32IMACF , yang berarti bahwa set instruksi RISC-V memang ditargetkan untuk titik mengambang perangkat keras .
Kami hanya mengedit header ELF , karena tampaknya tidak mencerminkan ABI yang benar untuk file objek.
Apakah ada perbaikan yang tepat untuk ini?
Di masa depan kompiler zig mungkin memungkinkan kami untuk menentukan titik mengambang ABI sebagai target ...
# # Compile the Zig App for BL602
# # ("ilp32f" means Hardware Floating-Point ABI)
zig build-obj
-target riscv32-freestanding-ilp32f
...(Lihat ini)
Pantau terus!
Bisakah kita menambal header ELF melalui baris perintah?
Ya kita dapat menambal header elf melalui baris perintah ...
xxd -c 1 hello_zig_main.o
| sed ' s/00000024: 01/00000024: 03/ '
| xxd -r -c 1 - hello_zig_main2.oBuild NUTTX berhasil. Zig berjalan OK di NUTTX BL602!
NuttShell (NSH) NuttX-10.3.0-RC2
nsh> hello_zig
Hello, Zig!
Ingatlah bahwa kami menimpa hello.o dengan file objek yang dikompilasi zig kami.
Nuttx build akan gagal kecuali kami menyediakan fungsi 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'
Itulah mengapa kami mendefinisikan hello_main di aplikasi zig kami ...
pub export fn hello_main (
_argc : c_int ,
_argv : [ * ] const [ * ] const u8
) c_int {
_ = _argc ;
_ = _argv ;
_ = printf ( "Hello, Zig! n " );
return 0 ;
}(Sumber)
Yang berarti bahwa aplikasi hello akan menghubungi kode zig kami juga ...
NuttShell (NSH) NuttX-10.3.0-RC2
nsh> hello
Hello, Zig!
Pinecone BL602 Board Pine64 Terhubung ke SEMTECH SX1262 LORA Transceiver (kiri) melalui SPI
Akankah Zig Compiler berfungsi sebagai pengganti drop-in untuk GCC untuk menyusun pustaka NUTTX?
Mari kita mengujinya di perpustakaan Lora SX1262 untuk Apache Nuttx RTOS!
Begini cara NutTX mengkompilasi perpustakaan Lora SX1262 dengan 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.oKami membuat perubahan ini ...
Ubah riscv64-unknown-elf-gcc menjadi zig cc
Tambahkan target -target riscv32-freestanding-none -mcpu=baseline_rv32-d
Hapus -march=rv32imafc
Dan kami menjalankan ini ...
# # 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 menunjukkan kesalahan ini ...
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];
^
Kami memperbaikinya dengan memasukkan file header yang tepat ...
#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__)Ke dalam file sumber ini ...
(Lihat perubahannya)
Kami memasukkan kode ini untuk memberi tahu kami (saat runtime) apakah itu dikompilasi dengan zig compiler atau 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__(Sumber)
Disusun dengan zig cc , perpustakaan Lora SX1262 berjalan OK di 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
(Lihat log lengkap)
Mari kita menyusun perpustakaan Lorawan besar dengan kompiler zig.
Nuttx mengkompilasi perpustakaan Lorawan seperti ini ...
# # 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.oKami beralih ke kompiler zig ...
# # 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
makeKami menyertakan file header yang tepat ke 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__)(Lihat perubahannya)
Loramac.c mengkompilasi OK dengan compiler zig.
TODO: Kompilasi file lain di perpustakaan Lorawan dengan build.zig
https://ziglang.org/documentation/master/#zig-build-system
Todo: Uji Perpustakaan Lorawan
Sekarang kami mengkompilasi aplikasi Lorawan lorawan_test_main.c dengan kompiler zig.
Nuttx mengkompilasi aplikasi Lorawan lorawan_test_main.c seperti ini ...
# # 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.oKami beralih ke kompiler zig ...
# # 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
makeKami menyertakan file header yang tepat ke 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__)(Lihat perubahannya)
Disusun dengan zig cc , aplikasi Lorawan berjalan OK di 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
(Lihat log lengkap)
Kompiler zig dapat mentranslate kode C secara otomatis ke zig. (Lihat ini)
Beginilah cara kami mentranslate aplikasi Lorawan lorawan_test_main.c kami dari C ke zig ...
Ubah zig cc menjadi zig translate-c
Mengelilingi bendera C oleh -cflags ... --
Seperti ini...
# # 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.zigInilah kode C asli: lorawan_test_main.c
Dan translasi otomatis dari c ke zig: diterjemahkan/lorawan_test_main.zig
Ini cuplikan dari kode C asli ...
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 ;
}(Sumber)
Dan kode zig yang diterjemahkan secara otomatis ...
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 ;
}(Sumber)
Kami akan merujuk pada kode zig yang diterjemahkan secara otomatis ini ketika kami secara manual mengonversi aplikasi Lorawan kami lorawan_test_main.c dari C ke zig di bagian berikutnya ...
Pine64 Pinedio Stack BL604 (kiri) berbicara Lorawan ke Rakwireless Wisgate (kanan)
Akhirnya kami mengonversi aplikasi Lorawan Lorawan_test_main.c dari C ke Zig, untuk menunjukkan bahwa kami dapat membangun aplikasi IoT yang kompleks di Zig.
Aplikasi Lorawan berjalan di Pinedio Stack BL604 (RISC-V). Aplikasi ini terhubung ke Gateway Lorawan (seperti ChirpStack atau Things Network) dan mengirim paket data secara berkala.
Inilah kode C asli: lorawan_test_main.c
(700 baris kode C)
Dan aplikasi Lorawan Zig kami yang dikonversi: lorawan_test.zig
(673 baris kode zig)
/// 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 PacketUntuk mengkompilasi aplikasi 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
makeAplikasi Lorawan Zig kami lorawan_test.zig mengkompilasi OK dengan zig compiler setelah membuat perbaikan berikut ...
Beberapa bagian dari aplikasi Lorawan Zig Lorawan_test.zig bisa menjadi rumit untuk dikonversi dari C ke zig, seperti kode C ini ...
// 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
);(Sumber)
Yang memiliki tipe yang bertentangan ( randr ) dan unsigned ( APP_TX_DUTYCYCLE ).
Kami mendapatkan bantuan dengan merujuk pada kode zig yang diterjemahkan secara otomatis: diterjemahkan/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
)
);Yang menyelesaikan tipe yang bertentangan dengan melemparkan hasil yang ditandatangani menjadi tidak ditandatangani.
Ketika kami merujuk LmHandlerCallbacks di aplikasi Lorawan Zig kami lorawan_test.zig ...
_ = & LmHandlerCallbacks ;Zig Compiler akan menunjukkan kesalahan tipe buram ini ...
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,
^
Kesalahan tipe buram dijelaskan di sini ...
"Perluas proyek C/C ++ dengan zig"
"Kegagalan Terjemahan"
Mari kita lacak melalui kesalahan tipe buram kita ...
export fn OnMacMlmeRequest (
status : c.LoRaMacStatus_t ,
mlmeReq : [ * c ] c.MlmeReq_t ,
nextTxIn : c . TimerTime_t
) void {
c . DisplayMacMlmeRequestUpdate ( status , mlmeReq , nextTxIn );
} Fungsi kami OnMacMlmeRequest memiliki parameter tipe MlmeReq_t , secara otomatis diimpor oleh compiler zig sebagai ...
pub const MlmeReq_t = struct_sMlmeReq ;
pub const struct_sMlmeReq = extern struct {
Type : Mlme_t ,
Req : union_uMlmeParam ,
ReqReturn : RequestReturnParam_t ,
}; Yang berisi jenis union_uMlmeParam yang diimpor secara otomatis ...
pub const union_uMlmeParam = extern union {
Join : MlmeReqJoin_t ,
TxCw : MlmeReqTxCw_t ,
PingSlotInfo : MlmeReqPingSlotInfo_t ,
DeriveMcKEKey : MlmeReqDeriveMcKEKey_t ,
DeriveMcSessionKeyPair : MlmeReqDeriveMcSessionKeyPair_t ,
}; Yang berisi MlmeReqPingSlotInfo_t ...
pub const MlmeReqPingSlotInfo_t = struct_sMlmeReqPingSlotInfo ;
pub const struct_sMlmeReqPingSlotInfo = extern struct {
PingSlot : PingSlotInfo_t ,
}; Yang berisi PingSlotInfo_t ...
pub const PingSlotInfo_t = union_uPingSlotInfo ;
pub const union_uPingSlotInfo = extern union {
Value : u8 ,
Fields : struct_sInfoFields ,
}; Yang berisi struct_sInfoFields ...
pub const struct_sInfoFields = opaque {}; Tetapi bidang struct_sInfoFields tidak diketahui oleh kompiler zig!
Jika kami merujuk pada kode C asli ...
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 ;(Sumber)
Kita melihat bahwa sInfoFields berisi bidang bit, bahwa kompiler zig tidak dapat diterjemahkan.
Sebelumnya kami melihat bahwa ini gagal untuk menyusun aplikasi Lorawan Zig kami lorawan_test.zig ...
_ = & LmHandlerCallbacks ; Itu karena LmHandlerCallbacks merujuk tipe MlmeReq_t yang diimpor secara otomatis, yang berisi bidang bit dan tidak dapat diterjemahkan oleh kompiler zig.
Mari kita konversi MlmeReq_t ke tipe buram, karena kita tidak akan mengakses bidangnya ...
/// 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 {};(Sumber)
Kami mengonversi LmHandlerCallbacks untuk menggunakan tipe buram MlmeReq_t kami ...
/// 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 ,
};(Sumber)
Kami mengubah semua referensi MlmeReq_t yang diimpor secara otomatis dari ...
[ * c ] c . MlmeReq_tUntuk tipe buram kami ...
* MlmeReq_t Kami juga mengubah semua referensi LmHandlerCallbacks_t yang diimporsi otomatis dari ...
[ * c ] c . LmHandlerCallbacks_t Ke LmHandlerCallbacks_t kami yang dikonversi ...
* LmHandlerCallbacks_tYang berarti kita perlu mengimpor fungsi Lorawan yang terpengaruh sendiri ...
/// 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 ;(Sumber)
Setelah memperbaiki tipe buram, Zig Compiler berhasil mengkompilasi aplikasi uji Lorawan kami lorawan_test.zig yay!
Saat menyusun aplikasi uji Lorawan kami lorawan_test.zig, kami melihat kesalahan makro ini ...
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
Menurut Zig Docs, ini berarti bahwa kompiler zig gagal menerjemahkan makro C ...
Jadi kita mendefinisikan LL kita sendiri ...
/// Import the LoRaWAN Library from C
const c = @cImport ({
// Workaround for "Unable to translate macro: undefined identifier `LL`"
@cDefine ( "LL" , "" ); ( LL adalah akhiran "panjang panjang" untuk konstanta C, yang mungkin tidak diperlukan ketika kita mengimpor jenis dan fungsi C ke zig)
Kemudian zig compiler memancarkan kesalahan ini ...
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
Yang mengacu pada baris ini di stdint.h ...
#define __int_c_join ( a , b ) a ## b Makro __int_c_join gagal karena akhiran LL sekarang kosong dan operator concatenation ## gagal.
Kami mendefinisikan kembali makro __int_c_join tanpa operator gabungan ## ...
/// 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.hSekarang Zig Compiler berhasil menyusun aplikasi uji Lorawan kami lorawan_test.zig
Zig Compiler macet saat mencoba menginisialisasi struct timer saat startup ...
/// 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(Sumber)
Jadi kami menginisialisasi struct timer di fungsi utama sebagai gantinya ...
/// 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 );(Sumber)
Setelah memperbaiki masalah di atas, kami menguji aplikasi Lorawan Zig di 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
(Lihat log lengkap)
Aplikasi Lorawan Zig Lorawan_test.zig berhasil bergabung dengan Lorawan Network (ChirpStack di Rakwireless Wisgate) dan mengirimkan paket data ke Lorawan Gateway Yay!
Kompiler Zig mengungkapkan wawasan yang menarik ketika mentransokasikan kode C kami ke zig.
Kode C ini menyalin array, byte byte ...
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
}(Sumber)
Inilah kode zig yang diterjemahkan secara otomatis ...
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 ;
}(Sumber)
Perhatikan bahwa pengindeksan array di c ...
// Array Indexing in C...
UnfragmentedData [ addr + i ]Diterjemahkan ke dalam zig ...
// Array Indexing in Zig...
UnfragmentedData [ addr +% i ] + Dalam C menjadi +% dalam zig!
Apa +% dalam zig?
Itulah operator zig untuk penambahan sampul .
Yang berarti bahwa hasilnya membungkus kembali ke 0 (dan seterusnya) jika penambahan meluap integer.
Tapi ini bukan yang kami maksudkan, karena kami tidak mengharapkan penambahan meluap. Itulah mengapa dalam kode zig terakhir yang dikonversi kami, kami kembali +% kembali ke + ...
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
}(Sumber)
Apa yang terjadi jika penambahan meluap?
Kita akan melihat kesalahan runtime ...
panic: integer overflow
(Sumber)
Yang mungkin merupakan hal yang baik, untuk memastikan bahwa nilai -nilai kita masuk akal.
Bagaimana jika indeks array kita keluar dari batas?
Kami akan mendapatkan kesalahan runtime ini ...
panic: index out of bounds
(Sumber)
Berikut daftar pemeriksaan keselamatan yang dilakukan oleh Zig saat runtime ...
Jika kita lebih suka hidup dengan ceroboh, beginilah cara kita menonaktifkan pemeriksaan keselamatan ...
Beberapa fitur debug tampaknya tidak berfungsi? Seperti unreachable , std.debug.assert dan std.debug.panic ?
Itu karena untuk platform tertanam kita perlu menerapkan pawang panik kita sendiri ...
"Menggunakan Zig untuk menyediakan jejak tumpukan pada kernel panik untuk sistem operasi Bare Bones"
Handler panik default: std.debug.default_panic
Dengan penangan panik kami sendiri, kegagalan pernyataan ini ...
// Create a short alias named `assert`
const assert = std . debug . assert ;
// Assertion Failure
assert ( TxPeriodicity != 0 );Akan menunjukkan jejak tumpukan ini ...
!ZIG PANIC!
reached unreachable code
Stack Trace:
0x23016394
0x23016ce0
Menurut pembongkaran RISC-V kami, alamat pertama 23016394 tidak terlihat menarik, karena itu berada di dalam fungsi 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>
Tapi alamat kedua 23016ce0 mengungkapkan pernyataan yang gagal ...
/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
Ini adalah implementasi kami dari 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 ) {}
}(Sumber)
Kami telah menerapkan Debug Logging std.log.debug yang dijelaskan di sini ...
Begini cara kami memanggil std.log.debug untuk mencetak pesan log ...
// 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 .{ ... } Membuat struct anonim dengan sejumlah argumen yang akan diteruskan ke std.log.debug untuk dicetak.
Di bawah ini adalah implementasi std.log.debug kami ...
/// 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 );
}(Sumber)
Panggilan implementasi ini puts() , yang didukung oleh Apache Nuttx RTOS karena sesuai dengan POSIX .
Kode C asli dan kode zig yang dikonversi untuk aplikasi Lorawan kami terlihat sangat mirip.
Inilah fungsi utama dari kode C asli kami ...
/// 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 ;
}(Sumber)
Dan fungsi utama dari kode zig yang dikonversi kami (setelah beberapa menggosok) ...
/// 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 ;
}(Sumber)
TODO: Bersihkan nama jenis, fungsi dan variabel
TODO: Baca sensor suhu internal
TODO: Pengkodean data sensor suhu dengan Tinycbor dan kirim ke jaringan hal -hal
https://lupyuen.github.io/articles/cbor2
TODO: Monitor data sensor dengan Prometheus dan Grafana
https://lupyuen.github.io/articles/prometheus
TODO: Tambahkan kode baru dengan @import()
https://zig.news/mattnite/import-and-packages-23mb
TODO: Apakah kita perlu menyelaraskan buffer dengan 32 bit saat mengekspor ke 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 );Refleksi tipe zig ... dapatkah kita menggunakannya untuk menghasilkan grafik panggilan terstruktur untuk perpustakaan C ... seperti untuk perpustakaan Lorawan? ?
Program zig ini mengimpor Perpustakaan Lorawan dari C dan membuang jenis dan fungsi 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
}(Sumber)
( @typeInfo dijelaskan di sini)
Ketika Zig Compiler mengkompilasi kode di atas, kami melihat ini pada waktu kompilasi ...
$ 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);
^
(Sumber)
Yang merupakan daftar jenis dan fungsi C dari Perpustakaan Lorawan.
Mari kita gunakan ini untuk memvisualisasikan grafik panggilan (dengan modul) untuk perpustakaan Lorawan.
Kami akan membuat grafik panggilan dengan Mermaid.js ...
https://mermaid-js.github.io/mermaid/#/./flowchart?id=flowcharts
Dan kami akan mengelompokkan fungsi Lorawan dalam grafik panggilan oleh Lorawan Module (Subgraph), sehingga kita dapat melihat panggilan di seluruh modul Lorawan.
Dalam kode di atas, mengapa kita menggunakan T2.Struct.decls[i].name bukannya 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 );
}
}Kami berharap kode ini mencetak nama deklarasi ...
@compileLog ( "decl.name: " , decl . name );Seperti ...
"decl.name: ", "LmnStatus_t"
Tapi anehnya mencetak byte ...
"decl.name: ", []const u8{76,109,110,83,116,97,116,117,115,95,116}
Zig Compiler tampaknya menafsirkan nama secara berbeda setelah kami merujuk nama sebelumnya ...
// If the C Declaration starts with "Lm" (LoRaMAC)...
if ( std . mem . startsWith ( u8 , decl . name , "Lm" )) { ...Jadi kami menggunakan solusi ini sebagai gantinya ...
// Get a fresh reference to the Type Info
var T2 = @typeInfo ( c );
// This works OK
@compileLog ( "decl.name: " , T2 . Struct . decls [ i ]. name );Yang menghasilkan hasil yang kita butuhkan ...
"decl.name: ", "LmnStatus_t"
Bisakah kita secara otomatis mengidentifikasi modul Lorawan untuk setiap fungsi Lorawan, dengan menganalisis macro header HEADER_NAME_H__ C?
Mari kita coba ini untuk mencampakkan semua deklarasi C dan makro yang diimpor dari 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(Sumber)
Kami mendapatkan daftar fungsi Lorawan ini dan Lorawan Macro ...
| *"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__"
(Sumber)
Yang tidak berguna. LmHandlerInit sebenarnya dinyatakan di dalam file header C untuk __LORAMAC_HANDLER_H__ . Tapi entah bagaimana refleksi tipe zig bergerak LmHandlerInit ke atas, sebelum __LORAMAC_HANDLER_H__ muncul.
Jadi sepertinya kita perlu mengelompokkan fungsi Lorawan secara manual ke dalam modul Lorawan.
Fungsi Lorawan tampaknya diurutkan sesuai dengan file header C, jadi kita hanya perlu secara manual menandai fungsi Lorawan pertama untuk setiap modul Lorawan. Seperti ini...
LmHandlerInit → __LORAMAC_HANDLER_H__
LoRaMacInitialization → __LORAMAC_H__
RegionCommonValueInRange → __REGIONCOMMON_H__
SX126xInit → __SX126x_H__
SX126xIoInit → __SX126x_BOARD_H__
Aplikasi Zig kami dapat melakukan tipe refleksi pada dirinya sendiri untuk menemukan jenis, konstanta, variabel, dan fungsi ...
// 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" (Sumber)
Kami akan menggunakan ini untuk memplot panggilan fungsi dari fungsi zig kami ke fungsi C di perpustakaan Lorawan.
Sebelumnya kami telah menangkap log panggilan ini: log panggilan ke fungsi C di perpustakaan 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
(Sumber)
Setiap baris log panggilan berisi nama fungsi Lorawan. Kami akan mencocokkan ini dengan info dari refleksi tipe zig untuk memplot grafik panggilan.
Kami mengimpor log panggilan ke aplikasi zig kami seperti ...
/// 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
...
;(Sumber)
Zig Compiler dapat memproses saluran panggilan baris demi baris seperti ...
// 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}(Sumber)
Untuk mengulangi semua baris log panggilan, kami melakukan ini ...
// 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(Sumber)
Mari Cocokkan Log Panggilan Dengan Nama Fungsi dari Perpustakaan Lorawan kami ...
// 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(Sumber)
Kode di atas menghasilkan hasil ini ...
| *"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"
...
(Sumber)
Yang merupakan daftar fungsi Lorawan dan urutan yang mereka sebut.
Satu langkah lebih dekat untuk memberikan grafik panggilan terstruktur kami!
Mari kita perpanjang kode di atas dan render grafik panggilan yang naif ...
Untuk setiap fungsi Lorawan yang kami identifikasi di log panggilan ...
Kami memplot garis antara fungsi Lorawan dan fungsi Lorawan berikutnya dalam log panggilan
Jadi kami hanya merencanakan urutan panggilan fungsi yang terhubung
(Ya itu sangat naif!)
Kami melakukannya seperti ini ...
// 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" , ";" );(Sumber)
Zig Compiler menghasilkan hasil ini pada waktu kompilasi ...
| *"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", *";"
...
(Sumber)
Kami secara manual menghapus pembatas dari log Zig Compiler di atas seperti ini ...
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;
...
Untuk mendapatkan putri duyung ini.js ...
Flowchart TD;
Mulai-> loramacinitialisasi;
Loramacinitialisasi-> 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-> RadioSetPublicNetwork;
RadioSetPublicNetwork-> RadioSleep;
Radiosleep-> RadioSetModem;
RadioSetModem-> RadioSetPublicNetwork;
RadioSetPublicNetwork-> TimerInit;
Timerinit-> timerinit;
Timerinit-> timerinit;
Timerinit-> RadioSetchannel;
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;
TimerSop-> 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-> RadioSetchannel;
RadioSetchannel-> RadiosetRxConfig;
RadiosetrxConfig-> Radiostandby;
Radiostandby-> RadioSetModem;
RadiosetModem-> RadiosetRxConfig;
RadiosetrxConfig-> 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-> TimerSop;
TimerSop-> 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;
TimerSop-> 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-> RadioSetchannel;
RadioSetchannel-> RadiosetRxConfig;
RadiosetrxConfig-> Radiostandby;
Radiostandby-> RadioSetModem;
RadiosetModem-> RadiosetRxConfig;
RadiosetrxConfig-> Radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> irq_rx_tx_timeout;
IRQ_RX_TX_TIMEOUT-> TimerSop;
TimerSop-> 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;
TimerSop-> Radioondioirq;
Radioondioirq-> 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-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> irq_rx_tx_timeout;
IRQ_RX_TX_TIMEOUT-> TimerSop;
TimerSop-> 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;
TimerSop-> 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-> RadioSetchannel;
RadioSetchannel-> RadiosetRxConfig;
RadiosetrxConfig-> Radiostandby;
Radiostandby-> RadioSetModem;
RadiosetModem-> RadiosetRxConfig;
RadiosetrxConfig-> Radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> irq_rx_tx_timeout;
IRQ_RX_TX_TIMEOUT-> TimerSop;
TimerSop-> 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;
TimerSop-> 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-> RadioSetchannel;
RadioSetchannel-> RadiosetRxConfig;
RadiosetrxConfig-> Radiostandby;
Radiostandby-> RadioSetModem;
RadiosetModem-> RadiosetRxConfig;
RadiosetrxConfig-> Radiorx;
Radiorx-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioIRQProcess-> irq_rx_tx_timeout;
IRQ_RX_TX_TIMEOUT-> TimerSop;
TimerSop-> 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;
TimerSop-> Radioondioirq;
Radioondioirq-> RadioirqProcess;
RadioirqProcess-> Radiosleep;
Radiosleep-> TimersetValue;
TimersetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Timerstart-> timersetValue;
TimersetValue-> Timerstart;
Timerstart-> Timerstop;
Timerstop-> Timerstart;
Apa yang salah dengan grafik panggilan super naif yang telah kami hasilkan?
flowchart TD;
Start-->LoRaMacInitialization;
LoRaMacInitialization-->TimerInit;
TimerInit-->TimerInit;
TimerInit-->SX126xIoInit;
SX126xIoInit-->SX126xSetTx;
SX126xSetTx-->SX126xSetPaConfig;
SX126xSetPaConfig-->TimerInit;
TimerInit-->RadioSetModem;
...
(Sumber)
Grafik panggilan kami tidak memiliki struktur . Ingatlah kita hanya merencanakan urutan panggilan fungsi ...
TimerInit → TimerInit tidak masuk akal (karena kami tidak memiliki fungsi rekursif)
TimerInit → RadioSetModem benar-benar salah karena TimerInit adalah fungsi tingkat rendah (perpustakaan multithreading yang gesit), sedangkan RadioSetModem adalah fungsi tingkat tinggi (perpustakaan SX1262)
Bisakah kita menambahkan beberapa struktur untuk meningkatkan grafik panggilan?
Untuk menghasilkan grafik panggilan terstruktur, kami akan mengelompokkan fungsi menjadi modul, dari tingkat tinggi hingga tingkat rendah ...
Aplikasi Zig (level tertinggi)
Perpustakaan Lorawan
Perpustakaan SX1262
Perpustakaan multithreading yang gesit (level terendah)
Dan kami akan memastikan bahwa kami tidak pernah menarik garis dari fungsi tingkat rendah ke fungsi tingkat tinggi.
Ini adalah cuplikan dari apa yang ingin kita capai ...
Flowchart TD;
Subgraph Lorawan;
Awal;
Loramacinitialisasi;
akhir;
Subgraph SX1262;
Sx126xioinit;
SX126XSETTX;
SX126XSetPaconfig;
akhir;
subgraph gesit;
Timerinit;
Timerinit;
akhir;
Mulai-> loramacinitialisasi;
Loramacinitialisasi-> timerinit;
Sx126xioinit-> sx126xsettx;
SX126XSETTX-> SX126XSETPACONFIG;
Sx126xsetPaconfig-> timerinit;
Mari kita tambahkan beberapa struktur ke grafik panggilan kami dengan mengelompokkan fungsi C ke dalam modul.
Beginilah cara kami mendefinisikan modul, dari level tinggi ke level rendah ...
// 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 ,
},
};(Sumber)
Perhatikan bahwa kami hanya menentukan fungsi pertama dan terakhir untuk setiap modul.
Itu karena fungsi dari modul yang sama dikelompokkan bersama dalam refleksi tipe zig.
Lalu kami membuat setiap modul sebagai subgraph putri duyung.js ...
/// 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
}
}(Sumber)
Setiap subgraph berisi daftar fungsi milik modul ...
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;
...
(Sumber)
Ketika kami membuat output dengan Mermaid.js, kami mendapatkan grafik panggilan terstruktur yang terlihat lebih bermakna ...
Flowchart TD;
subgraph lmhandler;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
Lmhandlersend;
akhir;
Subgraph Loramac;
Loramacinitialisasi;
akhir;
radio subgraph;
RadiosetModem;
RadiosetModem;
RadioSetPublicNetwork;
Radiosleep;
RadiosetModem;
RadioSetPublicNetwork;
Radiosetchannel;
RadiosettxConfig;
RadiosettxConfig;
Radiostandby;
RadiosetModem;
Radiosend;
Radiosend;
RadioirqProcess;
RadioirqProcess;
Radiosleep;
Radiostandby;
Radiosetchannel;
RadiosetrxConfig;
Radiostandby;
RadiosetModem;
RadiosetrxConfig;
Radiorx;
RadioirqProcess;
RadioirqProcess;
RadioirqProcess;
RadioirqProcess;
RadioirqProcess;
RadioirqProcess;
RadioirqProcess;
Radiosleep;
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;
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;
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;
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;
RadioIrqProcess;
RadioSetChannel;
RadioSetTxConfig;
RadioSetTxConfig;
RadioStandby;
RadioSetModem;
RadioSend;
RadioSend;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
RadioStandby;
RadioSetChannel;
RadioSetRxConfig;
RadioStandby;
RadioSetModem;
RadioSetRxConfig;
RadioRx;
RadioIrqProcess;
RadioIrqProcess;
RadioIrqProcess;
RadioSleep;
akhir;
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;
akhir;
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;
akhir;
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;
Todo
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
}
}(Sumber)
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
}
}(Sumber)
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; ")