89dd0c29e2
dlang: use importC to get NuttX include zig: leds_zig added
212 lines
7.4 KiB
Zig
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;
|
|
}
|