Skip to content

Commit 7a7a7d1

Browse files
authored
esp: RTOS work (#907)
- yield when a higher priority task wakes in sync primitives - fix priority inheritance in `Mutex` - refactor sync primitive timeouts - add `Signal` sync primitive (alternative to direct to task notifications) - remove `Condition` (as well as the event waiting system from wifi which seemed a bit hacky) - foundation libc: implement `strnlen`
1 parent 7c1b479 commit 7a7a7d1

11 files changed

Lines changed: 424 additions & 503 deletions

File tree

examples/espressif/esp/src/lwip/exports.zig

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,13 @@ export fn sys_mbox_set_invalid(ptr: *c.sys_mbox_t) void {
113113

114114
export fn sys_mbox_post(ptr: *c.sys_mbox_t, element: MailboxElement) void {
115115
const mailbox: *Mailbox = @ptrCast(@alignCast(ptr.*));
116-
mailbox.put_one(element, null) catch unreachable;
116+
mailbox.put_one(element, .never) catch unreachable;
117117
}
118118

119119
export fn sys_mbox_trypost(ptr: *c.sys_mbox_t, element: MailboxElement) c.err_t {
120120
const mailbox: *Mailbox = @ptrCast(@alignCast(ptr.*));
121-
if (mailbox.put_one_non_blocking(element)) {
122-
return c.ERR_OK;
123-
} else {
124-
return c.ERR_MEM;
125-
}
121+
mailbox.put_one(element, .non_blocking) catch return c.ERR_MEM;
122+
return c.ERR_OK;
126123
}
127124

128125
comptime {
@@ -132,7 +129,7 @@ comptime {
132129
export fn sys_arch_mbox_fetch(ptr: *c.sys_mbox_t, element_ptr: *MailboxElement, timeout: u32) u32 {
133130
const mailbox: *Mailbox = @ptrCast(@alignCast(ptr.*));
134131
const now = esp.time.get_time_since_boot();
135-
element_ptr.* = mailbox.get_one(if (timeout != 0) .from_ms(timeout) else null) catch {
132+
element_ptr.* = mailbox.get_one(if (timeout != 0) .{ .after = .from_ms(timeout) } else .never) catch {
136133
return c.SYS_ARCH_TIMEOUT;
137134
};
138135
// returns waiting time in ms
@@ -141,12 +138,9 @@ export fn sys_arch_mbox_fetch(ptr: *c.sys_mbox_t, element_ptr: *MailboxElement,
141138

142139
export fn sys_arch_mbox_tryfetch(ptr: *c.sys_mbox_t, element_ptr: *MailboxElement) u32 {
143140
const mailbox: *Mailbox = @ptrCast(@alignCast(ptr.*));
144-
if (mailbox.get_one_non_blocking()) |element| {
145-
element_ptr.* = element;
146-
return 0;
147-
} else {
148-
return c.SYS_MBOX_EMPTY;
149-
}
141+
const element = mailbox.get_one(.non_blocking) catch return c.SYS_MBOX_EMPTY;
142+
element_ptr.* = element;
143+
return 0;
150144
}
151145

152146
export fn sys_sem_new(ptr: *c.sys_sem_t, count: u8) c.err_t {
@@ -172,7 +166,7 @@ export fn sys_sem_signal(ptr: *c.sys_sem_t) void {
172166
export fn sys_arch_sem_wait(ptr: *c.sys_sem_t, timeout: u32) u32 {
173167
const sem: *rtos.Semaphore = @ptrCast(@alignCast(ptr.*));
174168
const now = esp.time.get_time_since_boot();
175-
sem.take_with_timeout(if (timeout != 0) .from_ms(timeout) else null) catch {
169+
sem.take_with_timeout(if (timeout != 0) .{ .after = .from_ms(timeout) } else .never) catch {
176170
return c.SYS_ARCH_TIMEOUT;
177171
};
178172
// returns waiting time in ms

examples/espressif/esp/src/rtos.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const rtos = esp.rtos;
88
pub const microzig_options: microzig.Options = .{
99
.logFn = usb_serial_jtag.logger.log,
1010
.interrupts = .{
11-
.interrupt31 = rtos.tick_interrupt_handler,
11+
.interrupt31 = rtos.interrupt_handler,
1212
},
1313
.log_level = .debug,
1414
.cpu = .{
@@ -26,7 +26,7 @@ pub const microzig_options: microzig.Options = .{
2626

2727
fn task1(queue: *rtos.Queue(u32)) void {
2828
for (0..5) |i| {
29-
queue.put_one(i, null) catch unreachable;
29+
queue.put_one(i, .never) catch unreachable;
3030
rtos.sleep(.from_ms(500));
3131
}
3232
}
@@ -44,7 +44,7 @@ pub fn main() !void {
4444
defer rtos.wait_and_free(gpa, task);
4545

4646
while (true) {
47-
const item = try queue.get_one(.from_ms(1000));
47+
const item = try queue.get_one(.{ .after = .from_ms(1000) });
4848
std.log.info("got item: {}", .{item});
4949
}
5050
}

examples/espressif/esp/src/tcp_server.zig

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub const microzig_options: microzig.Options = .{
2424
.logFn = usb_serial_jtag.logger.log,
2525
.interrupts = .{
2626
.interrupt30 = radio.interrupt_handler,
27-
.interrupt31 = rtos.tick_interrupt_handler,
27+
.interrupt31 = rtos.interrupt_handler,
2828
},
2929
.cpu = .{
3030
.interrupt_stack = .{
@@ -52,8 +52,7 @@ const SERVER_PORT = 3333;
5252

5353
var maybe_netif: ?*lwip.c.netif = null;
5454

55-
var ip_ready_semaphore: rtos.Semaphore = .init(0, 1);
56-
var ip: lwip.c.ip_addr_t = undefined;
55+
var wifi_ready_signal: rtos.Signal(void) = .{};
5756

5857
extern fn netconn_new_with_proto_and_callback(t: lwip.c.enum_netconn_type, proto: lwip.c.u8_t, callback: ?*const anyopaque) [*c]lwip.c.struct_netconn;
5958
pub fn main() !void {
@@ -86,7 +85,11 @@ pub fn main() !void {
8685
.auth_method = AUTH_METHOD,
8786
},
8887
});
89-
try radio.wifi.start_blocking();
88+
89+
try radio.wifi.start();
90+
while (!radio.wifi.get_sta_state().is_started()) {
91+
rtos.sleep(.from_ms(100));
92+
}
9093

9194
{
9295
std.log.info("Scanning for access points...", .{});
@@ -102,10 +105,14 @@ pub fn main() !void {
102105
}
103106
}
104107

105-
try radio.wifi.connect_blocking();
106-
try lwip.c_err(lwip.c.netifapi_netif_common(&netif, lwip.c.netif_set_link_up, null));
108+
try radio.wifi.connect();
109+
while (radio.wifi.get_sta_state() != .connected) {
110+
rtos.sleep(.from_ms(100));
111+
}
112+
_ = lwip.c.netifapi_netif_common(maybe_netif.?, lwip.c.netif_set_link_up, null);
113+
114+
wifi_ready_signal.wait();
107115

108-
ip_ready_semaphore.take();
109116
std.log.info("Listening on {f}:{}", .{ IP_Formatter.init(netif.ip_addr), SERVER_PORT });
110117

111118
const server_conn = netconn_new_with_proto_and_callback(lwip.c.NETCONN_TCP, 0, null) orelse {
@@ -164,6 +171,13 @@ fn handle_client(conn: ?*lwip.c.netconn) !void {
164171
}
165172
}
166173

174+
fn netif_status_callback(netif_ptr: [*c]lwip.c.netif) callconv(.c) void {
175+
const netif = &netif_ptr[0];
176+
if (netif.ip_addr.u_addr.ip4.addr != 0) {
177+
wifi_ready_signal.put({});
178+
}
179+
}
180+
167181
fn on_packet_received(comptime _: radio.wifi.Interface, data: []const u8) void {
168182
const pbuf: *lwip.c.struct_pbuf = lwip.c.pbuf_alloc(lwip.c.PBUF_RAW, @intCast(data.len), lwip.c.PBUF_POOL) orelse {
169183
std.log.err("failed to allocate receive pbuf", .{});
@@ -197,14 +211,6 @@ fn netif_init(netif_ptr: [*c]lwip.c.struct_netif) callconv(.c) lwip.c.err_t {
197211
return lwip.c.ERR_OK;
198212
}
199213

200-
fn netif_status_callback(netif_ptr: [*c]lwip.c.netif) callconv(.c) void {
201-
const netif = &netif_ptr[0];
202-
if (netif.ip_addr.u_addr.ip4.addr != 0) {
203-
ip = netif.ip_addr;
204-
ip_ready_semaphore.give();
205-
}
206-
}
207-
208214
var packet_buf: [1600]u8 = undefined;
209215

210216
fn netif_output(_: [*c]lwip.c.struct_netif, pbuf_c: [*c]lwip.c.struct_pbuf) callconv(.c) lwip.c.err_t {

modules/foundation-libc/include/string.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ char * strcpy(char * restrict s1, char const * restrict s2);
1515
size_t strcspn(char const * s1, char const * s2);
1616
char * strerror(int errnum);
1717
size_t strlen(char const * str);
18+
size_t strnlen(char const * str, size_t n);
1819
char * strncat(char * restrict s1, char const * restrict s2, size_t n);
1920
int strncmp(char const * lhs, char const * rhs, size_t count);
2021
char * strncpy(char * restrict s1, char const * restrict s2, size_t n);

modules/foundation-libc/src/modules/string.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ export fn strlen(str: ?[*:0]const c_char) usize {
4444
return std.mem.len(s);
4545
}
4646

47+
export fn strnlen(str: ?[*:0]const u8, n: usize) usize {
48+
const s = str orelse return 0;
49+
return if (std.mem.indexOfScalar(u8, s[0..n], 0)) |index| index else n;
50+
}
51+
4752
/// https://en.cppreference.com/w/c/string/byte/strncmp
4853
export fn strncmp(lhs: ?[*:0]const c_char, rhs: ?[*:0]const c_char, count: usize) c_int {
4954
const lhs_s: [*:0]const u8 = @ptrCast(lhs orelse return if (rhs != null) 1 else 0);

port/espressif/esp/src/hal.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,5 @@ fn str(comptime l: usize, comptime s: []const u8) [l]u8 {
116116

117117
test {
118118
_ = rtos;
119+
_ = radio;
119120
}

port/espressif/esp/src/hal/radio.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,7 @@ pub const interrupt_handler: microzig.cpu.InterruptHandler = .{
166166
}
167167
}.handler_fn,
168168
};
169+
170+
test {
171+
_ = osi;
172+
}

port/espressif/esp/src/hal/radio/osi.zig

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ pub fn strlen(str: ?[*:0]const u8) callconv(.c) usize {
4444
return std.mem.len(s);
4545
}
4646

47-
pub fn strnlen(str: ?[*:0]const u8, _: usize) callconv(.c) usize {
48-
// const s = str orelse return 0;
49-
// return if (std.mem.indexOfScalar(u8, s[0..n], 0)) |index| index + 1 else n;
47+
pub fn strnlen(str: ?[*:0]const u8, n: usize) callconv(.c) usize {
5048
const s = str orelse return 0;
49+
return if (std.mem.indexOfScalar(u8, s[0..n], 0)) |index| index else n;
50+
}
5151

52-
return std.mem.len(s);
52+
test "strnlen" {
53+
try std.testing.expect(strnlen(&.{ 10, 20, 30, 0 }, 4) == 3);
54+
try std.testing.expect(strnlen(&.{ 10, 20, 30, 0, 10, 20, 30 }, 7) == 3);
5355
}
5456

5557
pub fn strrchr(str: ?[*:0]const u8, chr: u32) callconv(.c) ?[*:0]const u8 {
@@ -319,11 +321,12 @@ pub fn semphr_take(ptr: ?*anyopaque, tick: u32) callconv(.c) i32 {
319321
log.debug("semphr_take {?} {}", .{ ptr, tick });
320322

321323
const sem: *rtos.Semaphore = @ptrCast(@alignCast(ptr));
322-
const maybe_timeout: ?rtos.Duration = if (tick == c.OSI_FUNCS_TIME_BLOCKING)
323-
.from_ticks(tick)
324-
else
325-
null;
326-
sem.take_with_timeout(maybe_timeout) catch {
324+
const timeout: rtos.Timeout = switch (tick) {
325+
0 => .non_blocking,
326+
c.OSI_FUNCS_TIME_BLOCKING => .never,
327+
else => |ticks| .{ .after = .from_ticks(ticks) },
328+
};
329+
sem.take_with_timeout(timeout) catch {
327330
log.debug(">>>> return from semaphore take with timeout: {*}", .{sem});
328331
return 1;
329332
};
@@ -368,10 +371,11 @@ const RecursiveMutex = struct {
368371
if (@intFromEnum(current_task.priority) > @intFromEnum(owning_task.priority)) {
369372
mutex.prev_priority = owning_task.priority;
370373
owning_task.priority = current_task.priority;
371-
rtos.make_ready(owning_task);
374+
var _hptw = false;
375+
rtos.make_ready(owning_task, &_hptw);
372376
}
373377

374-
mutex.wait_queue.wait(current_task, null);
378+
mutex.wait_queue.wait(null);
375379
}
376380

377381
assert(mutex.value == 0);
@@ -395,8 +399,13 @@ const RecursiveMutex = struct {
395399
owning_task.priority = prev_priority;
396400
mutex.prev_priority = null;
397401
}
402+
398403
mutex.owning_task = null;
399-
mutex.wait_queue.wake_one();
404+
405+
var hptw = false;
406+
mutex.wait_queue.wake_one(&hptw);
407+
if (hptw) rtos.yield_from_cs(.reschedule);
408+
400409
return true;
401410
} else {
402411
return false;
@@ -505,17 +514,12 @@ pub fn queue_send(ptr: ?*anyopaque, item_ptr: ?*anyopaque, block_time_tick: u32)
505514
const queue: *QueueWrapper = @ptrCast(@alignCast(ptr));
506515
const item: [*]const u8 = @ptrCast(@alignCast(item_ptr));
507516

508-
const size = switch (block_time_tick) {
509-
0 => queue.inner.put_non_blocking(item[0..queue.item_len]),
510-
else => queue.inner.put(
511-
item[0..queue.item_len],
512-
1,
513-
if (block_time_tick != c.OSI_FUNCS_TIME_BLOCKING)
514-
.from_ticks(block_time_tick)
515-
else
516-
null,
517-
),
517+
const timeout: rtos.Timeout = switch (block_time_tick) {
518+
0 => .non_blocking,
519+
c.OSI_FUNCS_TIME_BLOCKING => .never,
520+
else => |ticks| .{ .after = .from_ticks(ticks) },
518521
};
522+
const size = queue.inner.put(item[0..queue.item_len], 1, timeout);
519523
if (size == 0) return -1;
520524
return 1;
521525
}
@@ -525,9 +529,11 @@ pub fn queue_send_from_isr(ptr: ?*anyopaque, item_ptr: ?*anyopaque, _hptw: ?*any
525529

526530
const queue: *QueueWrapper = @ptrCast(@alignCast(ptr));
527531
const item: [*]const u8 = @ptrCast(@alignCast(item_ptr));
528-
const n = @divExact(queue.inner.put_non_blocking(item[0..queue.item_len]), queue.item_len);
529532

530-
@as(*u32, @ptrCast(@alignCast(_hptw))).* = @intFromBool(rtos.is_a_higher_priority_task_ready());
533+
var hptw = false;
534+
const n = @divExact(queue.inner.put_from_isr(item[0..queue.item_len], &hptw), queue.item_len);
535+
536+
@as(*u32, @ptrCast(@alignCast(_hptw))).* |= @intFromBool(hptw);
531537

532538
return @intCast(n);
533539
}
@@ -546,17 +552,12 @@ pub fn queue_recv(ptr: ?*anyopaque, item_ptr: ?*anyopaque, block_time_tick: u32)
546552
const queue: *QueueWrapper = @ptrCast(@alignCast(ptr));
547553
const item: [*]u8 = @ptrCast(@alignCast(item_ptr));
548554

549-
const size = switch (block_time_tick) {
550-
0 => queue.inner.get_non_blocking(item[0..queue.item_len]),
551-
else => queue.inner.get(
552-
item[0..queue.item_len],
553-
queue.item_len,
554-
if (block_time_tick != c.OSI_FUNCS_TIME_BLOCKING)
555-
.from_ticks(block_time_tick)
556-
else
557-
null,
558-
),
555+
const timeout: rtos.Timeout = switch (block_time_tick) {
556+
0 => .non_blocking,
557+
c.OSI_FUNCS_TIME_BLOCKING => .never,
558+
else => |ticks| .{ .after = .from_ticks(ticks) },
559559
};
560+
const size = queue.inner.get(item[0..queue.item_len], 1, timeout);
560561
if (size == 0) return -1;
561562
return 1;
562563
}

port/espressif/esp/src/hal/radio/timer.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,16 @@ fn task_fn() void {
150150
callback(arg);
151151
}
152152

153-
const sleep_duration: ?rtos.Duration = blk: {
153+
const timeout: rtos.Timeout = blk: {
154154
mutex.lock();
155155
defer mutex.unlock();
156156
break :blk if (find_next_wake_absolute()) |next_wake_absolute|
157-
.from_us(@truncate(next_wake_absolute.diff(now).to_us()))
157+
.{ .after = .from_us(@truncate(next_wake_absolute.diff(now).to_us())) }
158158
else
159-
null;
159+
.never;
160160
};
161161

162-
reload_semaphore.take_with_timeout(sleep_duration) catch {};
162+
reload_semaphore.take_with_timeout(timeout) catch {};
163163
}
164164
}
165165

0 commit comments

Comments
 (0)