nuttx-apps/examples/leds_zig/leds_zig.zig
Matheus Catarino 89dd0c29e2 Zig & D examples clean & refactor
dlang: use importC to get NuttX include
zig: leds_zig added
2024-08-26 10:22:16 +08:00

212 lines
7.4 KiB
Zig

///**************************************************************************
// 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;
}