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