From 89dd0c29e2e3c5dba42240b08ff4ca407b5848c6 Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Fri, 23 Aug 2024 14:57:27 -0300 Subject: [PATCH] Zig & D examples clean & refactor dlang: use importC to get NuttX include zig: leds_zig added --- examples/hello_d/Makefile | 8 +- examples/hello_d/hello_d_main.d | 130 ++++++++++------ examples/hello_d/nuttx_std.c | 39 +++++ examples/hello_zig/Makefile | 2 +- examples/hello_zig/hello_zig.zig | 30 +++- examples/hello_zig/hello_zig_main.zig | 40 ----- examples/leds_zig/Kconfig | 30 ++++ examples/leds_zig/Make.defs | 23 +++ examples/leds_zig/Makefile | 34 +++++ examples/leds_zig/leds_zig.zig | 211 ++++++++++++++++++++++++++ 10 files changed, 453 insertions(+), 94 deletions(-) create mode 100644 examples/hello_d/nuttx_std.c delete mode 100644 examples/hello_zig/hello_zig_main.zig create mode 100644 examples/leds_zig/Kconfig create mode 100644 examples/leds_zig/Make.defs create mode 100644 examples/leds_zig/Makefile create mode 100644 examples/leds_zig/leds_zig.zig diff --git a/examples/hello_d/Makefile b/examples/hello_d/Makefile index a66e165c671..805edea851a 100644 --- a/examples/hello_d/Makefile +++ b/examples/hello_d/Makefile @@ -26,7 +26,13 @@ MAINSRC = hello_d_main.d # hello_d built-in application info -DFLAGS += -oq -betterC +# no garbage collection +DFLAGS += -betterC +# better informations +DFLAGS += -vtls -verrors=context +# like #ifdef/#define NuttX_ImportC +# importC: need $(CC) to compile C file and -P-I to import C includes +DFLAGS += -P-I$(TOPDIR)/include --d-version=NuttX_ImportC --gcc=$(CC) PROGNAME = $(CONFIG_EXAMPLES_HELLO_D_PROGNAME) PRIORITY = $(CONFIG_EXAMPLES_HELLO_D_PRIORITY) STACKSIZE = $(CONFIG_EXAMPLES_HELLO_D_STACKSIZE) diff --git a/examples/hello_d/hello_d_main.d b/examples/hello_d/hello_d_main.d index b679c4b306f..47dd4e88541 100644 --- a/examples/hello_d/hello_d_main.d +++ b/examples/hello_d/hello_d_main.d @@ -26,16 +26,39 @@ module examples.hello_d_main; // import core.stdc.stdio : printf; // import core.stdc.stdlib : malloc, free; -/// -pragma(printf) -extern (C) int printf(scope const(char)* fmt, scope...) @nogc nothrow @trusted; -/// -extern (C) void* malloc(size_t size) @nogc nothrow @trusted; -/// -extern (C) void free(void* ptr) @nogc nothrow @trusted; +version (D_BetterC) // no DRT +{ + /// if betterC and LDC, disable moduleinfo and typeinfo + version (LDC) + { + pragma(LDC_no_moduleinfo); + pragma(LDC_no_typeinfo); + } +} + +/// use --d-version=NuttX_ImportC to define +version (NuttX_ImportC) +{ + /// D compiler will not import C++ symbols + /// so we need to import them manually + /// @nogc, @trusted, @safe, nothrow - not allowed + /// https://issues.dlang.org/show_bug.cgi?id=23812 + import nuttx_std : malloc, free, printf; // by default: @system (unsafe) +} +else +{ + /// Correctly FFI-import C/C++ symbols (@safe compatibility) + /// + pragma(printf) + extern (C) int printf(scope const(char)* fmt, scope...) @nogc nothrow @trusted; + /// + extern (C) void* malloc(size_t size) @nogc nothrow @trusted; + /// + extern (C) void free(scope void* ptr) @nogc nothrow @trusted; +} //*************************************************************************** -// Private module content +// Private module content (default is public) //*************************************************************************** private: @@ -43,62 +66,76 @@ private: extern (C++,class) struct DHelloWorld { -@nogc nothrow: - @disable this(); @disable this(this); - this(int secret) @safe pure - { - mSecret = secret; - debug printf("Constructor\n"); - } - ~this() @safe pure + /// use --d-version=NuttX_ImportC to define + version (NuttX_ImportC) { - debug printf("Destructor\n"); - } - - bool HelloWorld() @safe - { - debug printf("HelloWorld: mSecret=%d\n", mSecret); + this(int secret) + { + mSecret = secret; + printf("Constructor\n"); + } - if (mSecret != 42) + ~this() { - printf("DHelloWorld.HelloWorld: CONSTRUCTION FAILED!\n"); - return false; + printf("Destructor\n"); } - else + + bool HelloWorld() { - printf("DHelloWorld.HelloWorld: Hello, World!!\n"); - return true; + printf("HelloWorld: mSecret=%d\n", mSecret); + + if (mSecret != 42) + { + printf("DHelloWorld.HelloWorld: CONSTRUCTION FAILED!\n"); + return false; + } + else + { + printf("DHelloWorld.HelloWorld: Hello, World!!\n"); + return true; + } } } + else + { + this(int secret) @safe nothrow @nogc + { + mSecret = secret; + printf("Constructor\n"); + } - private int mSecret; -} - -//*************************************************************************** -// Private Data -//*************************************************************************** + ~this() @safe nothrow @nogc + { + printf("Destructor\n"); + } -// Define a statically constructed DHellowWorld instance if D static -// initializers are supported by the platform -// --d-version=D_Initialize -version (D_Initialize) -{ - static DHelloWorld g_HelloWorld; + bool HelloWorld() @safe nothrow @nogc + { + printf("HelloWorld: mSecret=%d\n", mSecret); + + if (mSecret != 42) + { + printf("DHelloWorld.HelloWorld: CONSTRUCTION FAILED!\n"); + return false; + } + else + { + printf("DHelloWorld.HelloWorld: Hello, World!!\n"); + return true; + } + } + } + private int mSecret = 0; } -//*************************************************************************** -// Public Functions -//*************************************************************************** - /**************************************************************************** * Name: hello_d_main ****************************************************************************/ // betterC need main function no-mangle. -extern (C) -int hello_d_main(int argc, char*[] argv) nothrow @nogc +extern (C) int hello_d_main(int argc, char*[] argv) { version (LDC) { @@ -118,5 +155,6 @@ int hello_d_main(int argc, char*[] argv) nothrow @nogc printf("hello_d_main: Saying hello from the instance constructed on the stack\n"); HelloWorld.HelloWorld(); + return 0; } diff --git a/examples/hello_d/nuttx_std.c b/examples/hello_d/nuttx_std.c new file mode 100644 index 00000000000..f8585c47f5c --- /dev/null +++ b/examples/hello_d/nuttx_std.c @@ -0,0 +1,39 @@ +/**************************************************************************** + * apps/examples/hello_d/nuttx_std.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * This is imported to d source using importC + * https://dlang.org/spec/importc.html + ****************************************************************************/ +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * hello_d_main + ****************************************************************************/ \ No newline at end of file diff --git a/examples/hello_zig/Makefile b/examples/hello_zig/Makefile index 5413dc5800a..90b9de59011 100644 --- a/examples/hello_zig/Makefile +++ b/examples/hello_zig/Makefile @@ -25,7 +25,7 @@ include $(APPDIR)/Make.defs MAINSRC = hello_zig.zig # Hello, Zig! built-in application info - +ZIGFLAGS += -lc -I$(TOPDIR)/include PROGNAME = $(CONFIG_EXAMPLES_HELLO_ZIG_PROGNAME) PRIORITY = $(CONFIG_EXAMPLES_HELLO_ZIG_PRIORITY) STACKSIZE = $(CONFIG_EXAMPLES_HELLO_ZIG_STACKSIZE) diff --git a/examples/hello_zig/hello_zig.zig b/examples/hello_zig/hello_zig.zig index 6d7f271eb5d..4c8fbcbcadb 100644 --- a/examples/hello_zig/hello_zig.zig +++ b/examples/hello_zig/hello_zig.zig @@ -24,17 +24,35 @@ const std = @import("std"); //**************************************************************************** -//* Externs +//* C API - need libc linking (freestanding libc is stubs only) //**************************************************************************** +// NuttX namespace +const NuttX = struct { + pub const c = @cImport({ + @cInclude("nuttx/config.h"); + @cInclude("stdio.h"); + }); + pub fn print(comptime fmt: [*:0]const u8, args: anytype) void { + _ = printf(std.fmt.comptimePrint(std.mem.span(fmt), args)); + } +}; -pub extern fn printf(_format: [*:0]const u8) c_int; +// or (optional) const c = std.c; // from std library (non-full libc) +// typedef alias +const printf = NuttX.c.printf; //**************************************************************************** //* hello_zig_main //**************************************************************************** -pub export fn main(_argc: c_int, _argv: [*]const [*]const u8) u8 { - _ = _argc; - _ = _argv; - _ = printf("Hello, Zig!\n"); +comptime { + // rename to hello_zig_main entry point for nuttx + @export(hello_zig, .{ + .name = "hello_zig_main", + .linkage = .weak, + }); +} + +fn hello_zig(_: c_int, _: ?[*]const [*]const u8) callconv(.C) c_int { + NuttX.print("[{s}]: Hello, Zig!\n", .{NuttX.c.CONFIG_ARCH_BOARD}); return 0; } diff --git a/examples/hello_zig/hello_zig_main.zig b/examples/hello_zig/hello_zig_main.zig deleted file mode 100644 index 146e2668a47..00000000000 --- a/examples/hello_zig/hello_zig_main.zig +++ /dev/null @@ -1,40 +0,0 @@ -//*************************************************************************** -// examples/hello_zig/hello_zig_main.zig -// -// Licensed to the Apache Software Foundation (ASF) under one or more -// contributor license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright ownership. The -// ASF licenses this file to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance with the -// License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -//*************************************************************************** - -//*************************************************************************** -// Included Files -//*************************************************************************** -const std = @import("std"); - -//**************************************************************************** -//* Externs -//**************************************************************************** - -pub extern fn printf(_format: [*:0]const u8) c_int; - -//**************************************************************************** -//* hello_zig_main -//**************************************************************************** -pub export fn hello_zig_main(_argc: c_int, _argv: [*]const [*]const u8) c_int { - _ = _argc; - _ = _argv; - _ = printf("Hello, Zig!\n"); - return 0; -} diff --git a/examples/leds_zig/Kconfig b/examples/leds_zig/Kconfig new file mode 100644 index 00000000000..59ea600ca4e --- /dev/null +++ b/examples/leds_zig/Kconfig @@ -0,0 +1,30 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_LEDS_ZIG + tristate "\"LEDs Zig\" example" + default n + depends on USERLED + ---help--- + Enable the \"LEDs Zig\" example + +if EXAMPLES_LEDS_ZIG + +config EXAMPLES_LEDS_ZIG_PROGNAME + string "Program name" + default "leds_zig" + ---help--- + This is the name of the program that will be used when the + program is installed. + +config EXAMPLES_LEDS_ZIG_PRIORITY + int "LEDs Zig task priority" + default 100 + +config EXAMPLES_LEDS_ZIG_STACKSIZE + int "LEDs Zig stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/examples/leds_zig/Make.defs b/examples/leds_zig/Make.defs new file mode 100644 index 00000000000..9f5fb809e02 --- /dev/null +++ b/examples/leds_zig/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/leds_zig/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_LEDS_ZIG),) +CONFIGURED_APPS += $(APPDIR)/examples/leds_zig +endif diff --git a/examples/leds_zig/Makefile b/examples/leds_zig/Makefile new file mode 100644 index 00000000000..4da5a89084d --- /dev/null +++ b/examples/leds_zig/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/examples/leds_zig/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# LEDS in Zig Example + +MAINSRC = leds_zig.zig + +# LEDS_zig built-in application info +ZIGFLAGS += -O ReleaseSmall -lc -I$(TOPDIR)/include +PROGNAME = $(CONFIG_EXAMPLES_LEDS_ZIG_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_LEDS_ZIG_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_LEDS_ZIG_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_LEDS_ZIG) + +include $(APPDIR)/Application.mk diff --git a/examples/leds_zig/leds_zig.zig b/examples/leds_zig/leds_zig.zig new file mode 100644 index 00000000000..ad1b3f435d4 --- /dev/null +++ b/examples/leds_zig/leds_zig.zig @@ -0,0 +1,211 @@ +///************************************************************************** +// examples/leds_zig/leds_zig.zig +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. The +// ASF licenses this file to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance with the +// License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +///************************************************************************** +///************************************************************************** +// Included Files +///************************************************************************** +const std = @import("std"); + +// C types not working with Zig comptime, need allocation +const Allocator = std.mem.Allocator; + +/// NuttX namespace +const NuttX = struct { + // public constant + pub const c = @cImport({ + @cInclude("nuttx/config.h"); + @cInclude("sys/ioctl.h"); + @cInclude("stdbool.h"); + @cInclude("stdlib.h"); + @cInclude("stdio.h"); + @cInclude("fcntl.h"); + @cInclude("sched.h"); + @cInclude("errno.h"); + @cInclude("signal.h"); + @cInclude("unistd.h"); + + @cInclude("nuttx/leds/userled.h"); + }); + + var g_led_daemon_started: bool = false; + + pub fn print(allocator: Allocator, comptime fmt: [*:0]const u8, args: anytype) void { + // comptime buffer[count(fmt, args)] or runtime allocation + const output = if (isComptime(args)) + std.fmt.comptimePrint(std.mem.span(fmt), args) + else + std.fmt.allocPrintZ(allocator, std.mem.span(fmt), args) catch @panic("Out of Memory!!"); + + _ = c.printf(output); + } + + pub const exit_t = enum(c_int) { + success = c.EXIT_SUCCESS, + failure = c.EXIT_FAILURE, + }; + + // private function + + // check if value is comptime + inline fn isComptime(val: anytype) bool { + return @typeInfo(@TypeOf(.{val})).Struct.fields[0].is_comptime; + } + + export fn led_daemon(_: c_int, _: [*c][*c]u8) callconv(.C) c_int { + var supported: NuttX.c.userled_set_t = 0; + var ledset: NuttX.c.userled_set_t = 0; + var incrementing: bool = true; + + // SIGTERM handler + const sigaction_t = NuttX.c.struct_sigaction; + var act: sigaction_t = .{ + .sa_flags = NuttX.c.SA_SIGINFO, + .sa_u = .{ + ._sa_sigaction = sigterm_action, + }, + }; + + _ = NuttX.c.sigemptyset(&act.sa_mask); + _ = NuttX.c.sigaddset(&act.sa_mask, NuttX.c.SIGTERM); + + const sig = NuttX.c.sigaction(NuttX.c.SIGTERM, &act, null); + if (sig != 0) { + NuttX.print(global_allocator, "Failed to install SIGTERM handler, errno={}\n", .{sig}); + return @intFromEnum(NuttX.exit_t.failure); + } + + // Indicate that we are running + const mypid = NuttX.c.getpid(); + g_led_daemon_started = true; + NuttX.print(global_allocator, "\nled_daemon (pid# {}): Running\n", .{mypid}); + + // Open the LED driver + NuttX.print(global_allocator, "led_daemon: Opening {s}\n", .{NuttX.c.CONFIG_EXAMPLES_LEDS_DEVPATH}); + const fd = NuttX.c.open(NuttX.c.CONFIG_EXAMPLES_LEDS_DEVPATH, NuttX.c.O_WRONLY); + if (fd < 0) { + NuttX.print(global_allocator, "led_daemon: ERROR: Failed to open {s}: {}\n", .{ + NuttX.c.CONFIG_EXAMPLES_LEDS_DEVPATH, + fd, + }); + g_led_daemon_started = false; + return @intFromEnum(NuttX.exit_t.failure); + } + + // Get the set of LEDs supported + var ret = NuttX.c.ioctl(fd, NuttX.c.ULEDIOC_SUPPORTED, &supported); + if (ret < 0) { + NuttX.print(global_allocator, "led_daemon: ERROR: ioctl(ULEDIOC_SUPPORTED) failed: {}\n", .{ret}); + _ = NuttX.c.close(fd); + g_led_daemon_started = false; + return @intFromEnum(NuttX.exit_t.failure); + } + + NuttX.print(global_allocator, "led_daemon: Supported LEDs {x}\n", .{supported}); + supported &= NuttX.c.CONFIG_EXAMPLES_LEDS_LEDSET; + + // Main loop + while (g_led_daemon_started) { + var newset: NuttX.c.userled_set_t = 0; + var tmp: NuttX.c.userled_set_t = 0; + + if (incrementing) { + tmp = ledset; + while (newset == ledset) { + tmp += 1; + newset = tmp & supported; + } + + if (newset == 0) { + incrementing = false; + continue; + } + } else { + if (ledset == 0) { + incrementing = true; + continue; + } + + tmp = ledset; + while (newset == ledset) { + tmp -= 1; + newset = tmp & supported; + } + } + + ledset = newset; + NuttX.print(global_allocator, "led_daemon: LED set {x}\n", .{ledset}); + + ret = NuttX.c.ioctl(fd, NuttX.c.ULEDIOC_SETALL, ledset); + if (ret < 0) { + NuttX.print(global_allocator, "led_daemon: ERROR: ioctl(ULEDIOC_SETALL) failed: {}\n", .{ret}); + _ = NuttX.c.close(fd); + g_led_daemon_started = false; + return @intFromEnum(NuttX.exit_t.failure); + } + + _ = NuttX.c.usleep(500 * 1000); + } + + _ = NuttX.c.close(fd); + return @intFromEnum(NuttX.exit_t.success); + } + + export fn sigterm_action(signo: c_int, siginfo: [*c]NuttX.c.siginfo_t, arg: ?*anyopaque) void { + if (signo == NuttX.c.SIGTERM) { + NuttX.print(global_allocator, "SIGTERM received\n", .{}); + g_led_daemon_started = false; + NuttX.print(global_allocator, "led_daemon: Terminated.\n", .{}); + } else { + NuttX.print(global_allocator, "\nsigterm_action: Received signo={} siginfo={*} arg={*}\n", .{ + signo, + siginfo, + arg, + }); + } + } +}; + +// Global allocator +var arena = std.heap.ArenaAllocator.init(std.heap.raw_c_allocator); +const global_allocator = arena.allocator(); + +export fn leds_zig_main(_: c_int, _: [*][*:0]u8) NuttX.exit_t { + defer arena.deinit(); + + NuttX.print(global_allocator, "leds_main: Starting the led_daemon\n", .{}); + if (NuttX.g_led_daemon_started) { + NuttX.print(global_allocator, "leds_main: led_daemon already running\n", .{}); + return .success; + } + + const ret = NuttX.c.task_create( + "led_daemon", + NuttX.c.CONFIG_EXAMPLES_LEDS_PRIORITY, + NuttX.c.CONFIG_EXAMPLES_LEDS_STACKSIZE, + NuttX.led_daemon, + null, + ); + if (ret < 0) { + NuttX.print(global_allocator, "leds_main: ERROR: Failed to start led_daemon: {}\n", .{ret}); + return .failure; + } + + NuttX.print(global_allocator, "leds_main: led_daemon started\n", .{}); + return .success; +}