Skip to main content

osal_rs/freertos/
ffi.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***************************************************************************/
19
20//! Foreign Function Interface (FFI) bindings for FreeRTOS.
21//!
22//! This module provides raw FFI declarations for FreeRTOS kernel functions and types.
23//! It directly interfaces with the FreeRTOS C API, providing the foundation for
24//! the safe Rust wrappers in other modules.
25//!
26//! # Contents
27//!
28//! - **Type definitions**: Handles for tasks, queues, semaphores, etc.
29//! - **Constants**: FreeRTOS constants (pdTRUE, pdFALSE, etc.)
30//! - **Function declarations**: Direct bindings to FreeRTOS C functions
31//! - **Utility macros**: Rust macros wrapping common FreeRTOS patterns
32//!
33//! # Safety
34//!
35//! All functions in this module are `unsafe` and require careful handling:
36//! - Null pointer checks
37//! - Proper synchronization
38//! - Correct memory management
39//! - Valid handle usage
40//!
41//! Use the safe wrappers in parent modules instead of calling these directly.
42//!
43//! # Examples
44//!
45//! ```ignore
46//! // Don't use FFI directly - use safe wrappers instead:
47//! use osal_rs::os::{Thread, ThreadFn};
48//! 
49//! // This is safe:
50//! let thread = Thread::new("task", 1024, 5);
51//! 
52//! // This is unsafe and should be avoided:
53//! // unsafe { xTaskCreate(...) }
54//! ```
55
56#![allow(non_upper_case_globals)]
57#![allow(non_snake_case)]
58
59use core::ffi::{c_char, c_uint, c_void};
60use core::ptr;
61
62use super::types::{BaseType, StackType, UBaseType, TickType, EventBits};
63
64/// Opaque handle to a FreeRTOS task/thread
65pub type ThreadHandle = *const c_void;
66/// Opaque handle to a FreeRTOS queue
67pub type QueueHandle = *const c_void;
68/// Opaque handle to a FreeRTOS semaphore
69pub type SemaphoreHandle = *const c_void;
70/// Opaque handle to a FreeRTOS event group
71pub type EventGroupHandle = *const c_void;
72/// Opaque handle to a FreeRTOS timer
73pub type TimerHandle = *const c_void;
74/// Opaque handle to a FreeRTOS mutex
75pub type MutexHandle = *const c_void;
76/// Callback function type for timers
77pub type TimerCallback = unsafe extern "C" fn(timer: TimerHandle);
78/// Task state enumeration
79pub type TaskState = c_uint;
80
81// Task states
82pub const RUNNING: TaskState = 0;
83pub const READY: TaskState = 1;
84pub const BLOCKED: TaskState = 2;
85pub const SUSPENDED: TaskState = 3;
86pub const DELETED: TaskState = 4;
87pub const INVALID: TaskState = 5;
88
89// Boolean/status constants
90pub const pdFALSE: BaseType = 0;
91
92pub const pdTRUE: BaseType = 1;
93
94pub const pdPASS: BaseType = pdTRUE;
95
96pub const pdFAIL: BaseType = pdFALSE;
97
98// Task notification constants
99pub const tskDEFAULT_INDEX_TO_NOTIFY: UBaseType = 0;
100
101// Semaphore constants
102pub const semBINARY_SEMAPHORE_QUEUE_LENGTH: u8 = 1;
103
104pub const semSEMAPHORE_QUEUE_ITEM_LENGTH: u8 = 0;
105
106pub const semGIVE_BLOCK_TIME: TickType = 0;
107
108// Queue constants
109pub const queueSEND_TO_BACK: BaseType = 0;
110
111pub const queueSEND_TO_FRONT: BaseType = 1;
112
113pub const queueOVERWRITE: BaseType = 2;
114
115// Queue type constants
116pub const queueQUEUE_TYPE_BASE: u8 = 0;
117
118pub const queueQUEUE_TYPE_MUTEX: u8 = 1;
119
120pub const queueQUEUE_TYPE_COUNTING_SEMAPHORE: u8 = 2;
121
122pub const queueQUEUE_TYPE_BINARY_SEMAPHORE: u8 = 3;
123
124pub const queueQUEUE_TYPE_RECURSIVE_MUTEX: u8 = 4;
125
126pub const queueQUEUE_TYPE_SET: u8 = 5;
127
128
129
130/// Task status information structure.
131///
132/// Contains detailed information about a task's state, priority, stack usage, etc.
133#[repr(C)]
134#[derive(Debug, Copy, Clone)]
135pub struct TaskStatus {
136    /// Task handle
137    pub xHandle: ThreadHandle,
138    /// Task name (null-terminated C string)
139    pub pcTaskName: *const c_char,
140    /// Task number (unique ID)
141    pub xTaskNumber: UBaseType,
142    /// Current task state
143    pub eCurrentState: TaskState,
144    /// Current priority
145    pub uxCurrentPriority: UBaseType,
146    /// Base priority (before priority inheritance)
147    pub uxBasePriority: UBaseType,
148    /// Total runtime counter
149    pub ulRunTimeCounter: u32,
150    /// Stack base address
151    pub pxStackBase: *mut StackType,
152    /// Stack high water mark (minimum free stack)
153    pub usStackHighWaterMark: StackType
154}
155
156impl Default for TaskStatus {
157    fn default() -> Self {
158        TaskStatus {
159            xHandle: ptr::null(),
160            pcTaskName: ptr::null(),
161            xTaskNumber: 0,
162            eCurrentState: INVALID,
163            uxCurrentPriority: 0,
164            uxBasePriority: 0,
165            ulRunTimeCounter: 0,
166            pxStackBase: ptr::null_mut(),
167            usStackHighWaterMark: 0,
168        }
169    }
170}
171
172pub type TaskFunction = Option<unsafe extern "C" fn(arg: *mut c_void)>;
173
174unsafe extern "C" {
175    
176
177    /// Allocate memory from the  heap
178    /// 
179    /// # Arguments
180    /// * `size` - The number of bytes to allocate
181    /// 
182    /// # Returns
183    /// A pointer to the allocated memory, or null if allocation fails
184    pub fn pvPortMalloc(size: usize) -> *mut c_void;
185
186    /// Free memory previously allocated by pvPortMalloc
187    /// 
188    /// # Arguments
189    /// * `pv` - Pointer to the memory to free
190    pub fn vPortFree(pv: *mut c_void);
191
192    pub fn vTaskDelay(xTicksToDelay: TickType);
193
194    pub fn xTaskDelayUntil(
195        pxPreviousWakeTime: *mut TickType,
196        xTimeIncrement: TickType,
197    ) -> BaseType;
198
199
200    pub fn xTaskGetTickCount() -> TickType;
201
202    pub fn vTaskStartScheduler();
203
204    pub fn vTaskEndScheduler();
205
206    pub fn vTaskSuspendAll();
207
208    pub fn xTaskResumeAll() -> BaseType;
209
210    pub fn xTaskGetCurrentTaskHandle() -> ThreadHandle;
211
212    pub fn eTaskGetState(xTask: ThreadHandle) -> TaskState;
213
214    pub fn uxTaskGetNumberOfTasks() -> UBaseType;
215
216    pub fn uxTaskGetSystemState(
217        pxTaskStatusArray: *mut TaskStatus,
218        uxArraySize: UBaseType,
219        pulTotalRunTime: *mut u32,
220    ) -> UBaseType;
221
222    pub fn osal_rs_task_enter_critical();
223    pub fn osal_rs_task_exit_critical();
224
225    pub fn osal_rs_task_enter_critical_from_isr() -> UBaseType;
226    pub fn osal_rs_task_exit_critical_from_isr(uxSavedInterruptStatus: UBaseType);
227
228
229    pub fn xTaskCreate(
230        pxTaskCode: TaskFunction,
231        pcName: *const c_char,
232        uxStackDepth: StackType,
233        pvParameters: *mut c_void,
234        uxPriority: UBaseType,
235        pxCreatedTask: *mut ThreadHandle,
236    ) -> BaseType;
237
238    pub fn vTaskDelete(xTaskToDelete: ThreadHandle);
239
240    pub fn vTaskSuspend(xTaskToSuspend: ThreadHandle);
241
242    pub fn vTaskResume(xTaskToResume: ThreadHandle);
243
244    pub fn vTaskGetInfo(
245        xTask: ThreadHandle,
246        pxTaskStatus: *mut TaskStatus,
247        xGetFreeStackSpace: BaseType,
248        eState: TaskState,
249    );
250
251    pub fn ulTaskGenericNotifyTake(uxIndexToWaitOn: UBaseType, xClearCountOnExit: BaseType, xTicksToWait: TickType) -> u32;
252
253
254    pub fn xTaskGenericNotifyWait(
255        uxIndexToWaitOn: UBaseType,
256        ulBitsToClearOnEntry: u32,
257        ulBitsToClearOnExit: u32,
258        pulNotificationValue: *mut u32,
259        xTicksToWait: TickType,
260    ) -> BaseType;
261
262
263    pub fn xTaskGenericNotify(
264        xTaskToNotify: ThreadHandle,
265        uxIndexToNotify: UBaseType,
266        ulValue: u32,
267        eAction: u32,
268        pulPreviousNotificationValue: *mut u32,
269    ) -> BaseType;
270
271
272    pub fn xTaskGenericNotifyFromISR(
273        xTaskToNotify: ThreadHandle,
274        uxIndexToNotify: UBaseType,
275        ulValue: u32,
276        eAction: u32,
277        pulPreviousNotificationValue: *mut u32,
278        pxHigherPriorityTaskWoken: *mut BaseType,
279    ) -> BaseType;
280    
281    pub fn xEventGroupWaitBits(
282        xEventGroup: EventGroupHandle,
283        uxBitsToWaitFor: EventBits,
284        xClearOnExit: BaseType,
285        xWaitForAllBits: BaseType,
286        xTicksToWait: TickType,
287    ) -> EventBits;
288
289    pub fn xEventGroupClearBits(
290        xEventGroup: EventGroupHandle,
291        uxBitsToClear: EventBits,
292    ) -> EventBits;
293
294    pub fn xEventGroupClearBitsFromISR(
295        xEventGroup: EventGroupHandle,
296        uxBitsToClear: EventBits,
297    ) -> BaseType;
298
299        pub fn xEventGroupSetBits(
300        xEventGroup: EventGroupHandle,
301        uxBitsToSet: EventBits,
302    ) -> EventBits;
303
304
305    pub fn xEventGroupSetBitsFromISR(
306        xEventGroup: EventGroupHandle,
307        uxBitsToSet: EventBits,
308        pxHigherPriorityTaskWoken: *mut BaseType,
309    ) -> BaseType;
310
311    pub fn xEventGroupGetBitsFromISR(xEventGroup: EventGroupHandle) -> EventBits;
312
313    pub fn vEventGroupDelete(xEventGroup: EventGroupHandle);
314
315    pub fn xEventGroupCreate() -> EventGroupHandle;
316
317    pub fn osal_rs_critical_section_enter();
318
319    pub fn osal_rs_critical_section_exit();
320
321    pub fn osal_rs_port_yield_from_isr(pxHigherPriorityTaskWoken: BaseType);
322
323    pub fn osal_rs_port_end_switching_isr( xSwitchRequired: BaseType );
324
325    pub fn xQueueCreateMutex(ucQueueType: u8) -> QueueHandle;
326    
327    pub fn xQueueCreateCountingSemaphore(
328        uxMaxCount: UBaseType,
329        uxInitialCount: UBaseType,
330    ) -> QueueHandle;
331
332    pub fn xQueueSemaphoreTake(xQueue: QueueHandle, xTicksToWait: TickType) -> BaseType;
333
334    pub fn xQueueReceiveFromISR(
335        xQueue: QueueHandle,
336        pvBuffer: *mut c_void,
337        pxHigherPriorityTaskWoken: *mut BaseType,
338    ) -> BaseType;
339
340    pub fn xQueueGenericSend(
341        xQueue: QueueHandle,
342        pvItemToQueue: *const c_void,
343        xTicksToWait: TickType,
344        xCopyPosition: BaseType,
345    ) -> BaseType;
346
347    pub fn xQueueGiveFromISR(
348        xQueue: QueueHandle,
349        pxHigherPriorityTaskWoken: *mut BaseType,
350    ) -> BaseType;
351
352     pub fn vQueueDelete(xQueue: QueueHandle);
353
354    pub fn xQueueGenericCreate(
355        uxQueueLength: UBaseType,
356        uxItemSize: UBaseType,
357        ucQueueType: u8,
358    ) -> QueueHandle;
359
360    pub fn xQueueReceive(
361        xQueue: QueueHandle,
362        pvBuffer: *mut c_void,
363        xTicksToWait: TickType,
364    ) -> BaseType;
365
366    pub fn xQueueGenericSendFromISR(
367        xQueue: QueueHandle,
368        pvItemToQueue: *const c_void,
369        pxHigherPriorityTaskWoken: *mut BaseType,
370        xCopyPosition: BaseType,
371    ) -> BaseType;
372
373    pub fn xQueueTakeMutexRecursive(xMutex: QueueHandle, xTicksToWait: TickType) -> BaseType;
374
375    pub fn xQueueGiveMutexRecursive(xMutex: QueueHandle) -> BaseType;
376
377    pub fn xPortGetFreeHeapSize() -> usize;
378
379    pub fn xTimerCreateTimerTask() -> BaseType;
380
381    pub fn xTimerCreate(
382        pcTimerName: *const c_char,
383        xTimerPeriodInTicks: TickType,
384        xAutoReload: BaseType,
385        pvTimerID: *mut c_void,
386        pxCallbackFunction: Option<TimerCallback>,
387    ) -> TimerHandle;
388
389    pub fn osal_rs_timer_start(xTimer: TimerHandle, xTicksToWait: TickType) -> BaseType;
390
391    pub fn osal_rs_timer_stop(xTimer: TimerHandle, xTicksToWait: TickType) -> BaseType;
392
393    pub fn osal_rs_timer_reset(xTimer: TimerHandle, xTicksToWait: TickType) -> BaseType;
394
395    pub fn osal_rs_timer_change_period(
396        xTimer: TimerHandle,
397        xNewPeriodInTicks: TickType,
398        xTicksToWait: TickType,
399    ) -> BaseType;
400
401    pub fn osal_rs_timer_delete(xTimer: TimerHandle, xTicksToWait: TickType) -> BaseType;
402
403    pub fn pvTimerGetTimerID(xTimer: TimerHandle) -> *mut c_void;
404
405    pub fn printf(fmt: *const u8, ...) -> i32; 
406}
407
408
409macro_rules! xTaskNotifyWait {
410    ($ulBitsToClearOnEntry:expr, $ulBitsToClearOnExit:expr, $pulNotificationValue:expr, $xTicksToWait:expr) => {
411        unsafe {
412            $crate::freertos::ffi::xTaskGenericNotifyWait(
413                $crate::freertos::ffi::tskDEFAULT_INDEX_TO_NOTIFY,
414                $ulBitsToClearOnEntry,
415                $ulBitsToClearOnExit,
416                $pulNotificationValue,
417                $xTicksToWait
418            )
419        }
420    };
421}
422
423macro_rules! xTaskNotify {
424    ($xTaskToNotify:expr, $ulValue:expr, $eAction:expr) => {
425        unsafe {
426            $crate::freertos::ffi::xTaskGenericNotify(
427                $xTaskToNotify,
428                $crate::freertos::ffi::tskDEFAULT_INDEX_TO_NOTIFY,
429                $ulValue,
430                $eAction,
431                core::ptr::null_mut()
432            )
433        }
434    };
435}
436
437macro_rules! xTaskNotifyFromISR {
438    ($xTaskToNotify:expr, $ulValue:expr, $eAction:expr, $pxHigherPriorityTaskWoken:expr) => {
439        unsafe {
440            $crate::freertos::ffi::xTaskGenericNotifyFromISR(
441                $xTaskToNotify,
442                $crate::freertos::ffi::tskDEFAULT_INDEX_TO_NOTIFY,
443                $ulValue,
444                $eAction,
445                core::ptr::null_mut(),
446                $pxHigherPriorityTaskWoken
447            )
448        }
449    };
450}
451
452
453macro_rules! xEventGroupGetBits {
454    ($xEventGroup:expr) => {
455        unsafe {
456            $crate::freertos::ffi::xEventGroupClearBits($xEventGroup, 0)
457        }
458    };
459}
460
461macro_rules! xSemaphoreCreateCounting {
462    ($uxMaxCount:expr, $uxInitialCount:expr) => {
463        unsafe {
464            $crate::freertos::ffi::xQueueCreateCountingSemaphore(
465                $uxMaxCount,
466                $uxInitialCount
467            )
468        }
469    };
470}
471
472macro_rules! xSemaphoreTake {
473    ($xSemaphore:expr, $xBlockTime:expr) => {
474        unsafe {
475            $crate::freertos::ffi::xQueueSemaphoreTake(
476                $xSemaphore,
477                $xBlockTime
478            )
479        }
480    };
481}
482
483macro_rules! xSemaphoreTakeFromISR {
484    ($xSemaphore:expr, $pxHigherPriorityTaskWoken:expr) => {
485        unsafe {
486            $crate::freertos::ffi::xQueueReceiveFromISR(
487                $xSemaphore,
488                core::ptr::null_mut(),
489                $pxHigherPriorityTaskWoken
490            )
491        }
492    };
493}
494
495macro_rules! xSemaphoreGive {
496    ($xSemaphore:expr) => {
497        unsafe {
498            $crate::freertos::ffi::xQueueGenericSend(
499                $xSemaphore,
500                core::ptr::null(),
501                $crate::freertos::ffi::semGIVE_BLOCK_TIME,
502                $crate::freertos::ffi::queueSEND_TO_BACK
503            )
504        }
505    };
506}
507
508macro_rules! xSemaphoreGiveFromISR {
509    ($xSemaphore:expr, $pxHigherPriorityTaskWoken:expr) => {
510        unsafe {
511            $crate::freertos::ffi::xQueueGiveFromISR(
512                $xSemaphore,
513                $pxHigherPriorityTaskWoken
514            )
515        }
516    };
517}
518
519macro_rules! vSemaphoreDelete {
520    ($xSemaphore:expr) => {
521        unsafe {
522            $crate::freertos::ffi::vQueueDelete($xSemaphore)
523        }
524    };
525}
526
527macro_rules! xQueueSendToBackFromISR {
528    ($xQueue:expr, $pvItemToQueue:expr, $pxHigherPriorityTaskWoken:expr) => {
529        unsafe {
530            $crate::freertos::ffi::xQueueGenericSendFromISR(
531                $xQueue,
532                $pvItemToQueue,
533                $pxHigherPriorityTaskWoken,
534                $crate::freertos::ffi::queueSEND_TO_BACK
535            )
536        }
537    };
538}
539
540macro_rules! xQueueSendToBack {
541    ($xQueue:expr, $pvItemToQueue:expr, $xTicksToWait:expr) => {
542        unsafe {
543            $crate::freertos::ffi::xQueueGenericSend(
544                $xQueue,
545                $pvItemToQueue,
546                $xTicksToWait,
547                $crate::freertos::ffi::queueSEND_TO_BACK
548            )
549        }
550    };
551}
552
553macro_rules! xSemaphoreCreateRecursiveMutex {
554    () => {
555        unsafe {
556            $crate::freertos::ffi::xQueueCreateMutex(
557                $crate::freertos::ffi::queueQUEUE_TYPE_RECURSIVE_MUTEX
558            )
559        }
560    };
561}
562
563macro_rules! xSemaphoreTakeRecursive {
564    ($xMutex:expr, $xBlockTime:expr) => {
565        unsafe {
566            $crate::freertos::ffi::xQueueTakeMutexRecursive(
567                $xMutex,
568                $xBlockTime
569            )
570        }
571    };
572}
573
574macro_rules! xSemaphoreGiveRecursive {
575    ($xMutex:expr) => {
576        unsafe {
577            $crate::freertos::ffi::xQueueGiveMutexRecursive($xMutex)
578        }
579    };
580}