ZenOS Logo
BUSL-1.1 ARM Cortex-M C++11 100μs Tick Zero Heap Priority Bitmap + Ready Queues Configurable IEC Target Profiles — not a certification claim IEC 62304 Reference IEC 61508 Reference Safety Mechanisms

Real-Time operating system for ARM Cortex-M — written in C++11.

سیستم‌عامل بلادرنگ برای ARM Cortex-M — نوشته‌شده با C++11.

🔗 View on GitHub Back to Home

🚀 Quick Start Guideراهنمای شروع سریع

Target MCU: All examples use STM32F103C8T6 (Blue Pill, Cortex-M3, 72MHz, 64KB Flash, 20KB RAM). Code is portable to other STM32 families — just adjust pins and peripherals. میکروکنترلر هدف: مثال شروع سریع برای STM32F103C8T6 (بلو پیل، Cortex-M3، 72MHz، 64KB فلش، 20KB RAM) هستند. کد قابل حمل به خانواده‌های دیگر STM32 است.

1. Prerequisitesپیش‌نیازها

1.1 Hardware You Needسخت‌افزار مورد نیاز

ItemقطعهSpecificationمشخصاتWhere to Buyخرید
STM32F103C8T6"Blue Pill" boardAliExpress, Amazon
ST-Link V2Debugger/ProgrammerAliExpress, Amazon
USB CableMicro-USBAny electronics shop
Jumper WiresMale-to-female, 10+ pcsAny electronics shop
LED + Resistor220Ω–1kΩAny electronics shop

Use your actual hardware and development-tool costs; no fixed project cost is specified.هزینه سخت‌افزار و ابزارها به برد و تجهیزات انتخابی شما بستگی دارد.

1.2 Software You Needنرم‌افزار مورد نیاز

Softwareنرم‌افزارPurposeکاربردLinkلینک
STM32CubeIDEIDE + CubeMXمحیط توسعهst.com
ST-Link DriverDebugger connectionاتصال دیباگرIncluded with IDEشامل IDE

1.3 What You Should Knowچیزهایی که باید بدانید

TopicموضوعLevelسطح
C/C++ programmingBasicمبتدی
What is an RTOS?RTOS چیست؟Basicمبتدی
ARM Cortex-MOptional (helpful)اختیاری (مفید)

2. Installationنصب

2.1 Install STM32CubeIDEنصب STM32CubeIDE

  1. Go to st.com and download STM32CubeIDE (free, ~2GB)به st.com بروید و STM32CubeIDE را دانلود کنید (رایگان، حدود ۲ گیگابایت)
  2. Create a free ST account if promptedدر صورت درخواست، یک حساب کاربری رایگان ST بسازید
  3. Install the IDE (includes ST-Link drivers)IDE را نصب کنید (شامل درایورهای ST-Link)

2.2 Download ZenOSدانلود ZenOS

git clone https://github.com/Raymon-Research-Team/ZenOS-RTOS.git

2.3 Copy Files to Your Projectکپی فایل‌ها به پروژه شما

Copy these files from ZenOS/ to your CubeMX project:این فایل‌ها را از ZenOS/ به پروژه CubeMX خود کپی کنید:

Source Fileفایل مبداDestinationمقصد
ZenOS.hppInc/
ZenOS_c.hInc/
ZenOS_Config.hppInc/
ZenOS_Internal.hppInc/
ZenOS_Port.hppInc/
ZenOS.cppSrc/
ZenOS_Scheduler.cppSrc/
ZenOS_IPC.cppSrc/
ZenOS_Safety.cppSrc/
ZenOS_Monitor.cppSrc/

2.4 Configure Compilerپیکربندی کامپایلر

In STM32CubeIDE: Project → Properties → C/C++ Build → Settingsدر STM32CubeIDE: Project → Properties → C/C++ Build → Settings

3. Your First ZenOS Projectاولین پروژه ZenOS شما

Critical Step 1: Configure LED Pin in CubeMX (Pinout & Configuration → Click on PC13 → Set as GPIO_Output). This is the built-in LED on Blue Pill boards. مرحله حیاتی ۱: پین LED را در CubeMX پیکربندی کنید (Pinout & Configuration → روی PC13 کلیک کنید → GPIO_Output تنظیم شود). این LED داخلی بردهای بلو پیل است.
Critical Step 2: Set HAL Timebase to TIM1 in CubeMX (System Core → SYS → Timebase Source = TIM1). This prevents SysTick conflict with ZenOS. مرحله حیاتی ۲: تایمر HAL را در CubeMX روی TIM1 تنظیم کنید (System Core → SYS → Timebase Source = TIM1). این کار از تداخل SysTick با ZenOS جلوگیری می‌کند.
Critical Step 3: Add os_tick() to SysTick_Handler in Src/stm32fxxx_it.c: مرحله حیاتی ۳: os_tick() را به SysTick_Handler در فایل Src/stm32fxxx_it.c اضافه کنید:
// In Src/stm32fxxx_it.c
#include "ZenOS.hpp"  // Add at top of file

void SysTick_Handler(void) {
    os_tick();  // ZenOS receives its tick interrupt here
}
Critical Step 4: CubeMX generates main.c, but ZenOS requires C++11. You must rename Src/main.c to Src/main.cpp. Right-click the file in your IDE → Rename → change .c to .cpp. Also ensure all .cpp files are compiled as C++ (not C) in your project settings. مرحله حیاتی ۴: CubeMX فایل main.c را تولید می‌کند، اما ZenOS به C++11 نیاز دارد. باید فایل Src/main.c را به Src/main.cpp تغییر نام دهید. روی فایل در IDE راست کلیک کنید → Rename → .c را به .cpp تغییر دهید. همچنین مطمئن شوید تمام فایل‌های .cpp به عنوان C++ (نه C) کامپایل می‌شوند.

3.1 Complete main.cppفایل کامل main.cpp

#include "ZenOS.hpp"

/* ─── Task: Blink LED ─── */
void task_blink(void) {
    while (1) {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);  // Toggle LED
        os_delay_ms(500);                          // Wait 500ms
    }
}

/* ─── Main ─── */
int main(void) {
    HAL_Init();
    SystemClock_Config();  // Generated by CubeMX
    MX_GPIO_Init();        // Generated by CubeMX
    MX_TIM1_Init();        // Generated by CubeMX

    os_init();                          // Initialize ZenOS kernel
    os_task_create(task_blink, 5);      // Create task with priority 5
    os_start();                         // Start scheduler (never returns!)

    while (1) {}  // Never reached
}
That's it! The kernel takes over from os_start() and never returns. The task blocks for 500ms between LED toggles, and you don't write scheduling code. همین! هسته سیستم‌عامل از os_start() کنترل را به دست می‌گیرد و هرگز برنمی‌گردد. تسک شما هر ۵۰۰ میلی‌ثانیه اجرا می‌شود، LED چشمک می‌زند، و شما حتی یک خط کد زمان‌بندی هم ننوشتید.

4. Build & Flashبیلد و فلش

  1. Click Build (hammer icon) — should compile with 0 errorsروی Build (آیکون چکش) کلیک کنید — باید بدون خطا کامپایل شود
  2. Connect Blue Pill via ST-Link debuggerبلو پیل را از طریق دیباگر ST-Link وصل کنید
  3. Click Run (play icon) — flash to Blue Pillروی Run (آیکون پخش) کلیک کنید — به بلو پیل فلش شود
  4. The built-in LED (PC13) should toggle every 500ms while the task sleeps! 🎉LED داخلی (PC13) باید هر ۵۰۰ میلی‌ثانیه چشمک بزند! 🎉
Note: If LED doesn't blink, check that PC13 is set as GPIO_Output in CubeMX and that the pin names in code match your board. توجه: اگر LED چشمک نمی‌زند، بررسی کنید که PC13 در CubeMX به عنوان GPIO_Output تنظیم شده و نام پین‌ها در کد با برد شما مطابقت دارد.

4.1 Common Beginner Mistakesاشتباهات رایج مبتدیان

MistakeاشتباهSymptomعلائمSolutionراه‌حل
Task has no while(1)System crashesسیستم کرش می‌کندAlways use while(1) {}همیشه از while(1) {} استفاده کنید
Task never yieldsتسک هرگز واگذاری نمی‌کندWatchdog resetریست تایمرAdd os_delay_ms()
Forgot os_tick()os_tick() را فراموش کردهTick counter stuck at 0شمارنده تیک روی ۰ گیر کردهAdd to SysTick_Handlerبه SysTick_Handler اضافه کنید
C++ not enabledC++ فعال نیستCompilation errorsخطاهای کامپایلAdd -std=c++11
Task created after os_start()تسک بعد از os_start() ایجاد شدهReturns -1Create tasks before os_start()تسک‌ها را قبل از os_start() بسازید

📘 API Referenceمرجع API

1. Task Managementمدیریت تسک‌ها

What is a Task? A task is an independent function that runs forever in its own context. Think of it as a separate program that runs simultaneously with other tasks. Each task has its own stack (memory for local variables), its own priority (determines execution order), and can be periodic (runs at fixed intervals) or aperiodic (runs whenever scheduled).تسک چیست؟ تسک یک تابع مستقل است که برای همیشه در بافت خودش اجرا می‌شود. آن را به عنوان یک برنامه مستقل در نظر بگیرید که همزمان با تسک‌های دیگر اجرا می‌شود. هر تسک پشته خودش (حافظه برای متغیرهای محلی)، اولویت خودش (ترتیب اجرا) را دارد و می‌تواند دوره‌ای (در فواصل ثابت اجرا می‌شود) یا غیردوره‌ای (هر وقت زمان‌بندی شود اجرا می‌شود) باشد.

How it works: When you call os_task_create(), ZenOS allocates a Task Control Block (TCB) and a stack for the task. The TCB stores the task's state, priority, and context. When os_start() is called, the scheduler begins running the highest-priority ready task. Tasks can block (sleep) using delays or IPC, allowing lower-priority tasks to run.نحوه کار: وقتی os_task_create() را فراخوانی می‌کنید، ZenOS یک بلوک کنترل تسک (TCB) و یک پشته برای تسک تخصیص می‌دهد. TCB وضعیت تسک، اولویت و زمینه را ذخیره می‌کند. وقتی os_start() فراخوانی می‌شود، زمان‌بند شروع به اجرای تسک آماده با بالاترین اولویت می‌کند. تسک‌ها می‌توانند با استفاده از تاخیرها یا IPC بلاک (بخوابند) که به تسک‌های با اولویت پایین‌تر اجازه اجرا می‌دهد.

// Create tasks (call BEFORE os_start())
os_task_create(task_function, priority);              // Default stack (128 bytes, 256-byte effective floor)
os_task_create(task_function, priority, period_ms);   // + Periodic
os_task_create_st(task_function, priority, period_ms, stack_bytes); // Custom stack

// Control tasks (call AFTER os_start())
os_task_start(task_function);    // Activate a stopped task
os_task_stop(task_function);     // Deactivate a task
bool running = os_task_isActive(task_function);       // Check state

What happens: os_task_create(task_blink, 5) creates a task named "task_blink" with priority 5. The task will be scheduled to run when os_start() is called. os_task_create(task_sensor, 3, 100) creates a periodic task with a 100ms release interval. os_task_create_st(task_ui, 8, 0, 1024) creates a task with a custom 1KB stack (useful for tasks that use printf or deep function calls).چه اتفاقی می‌افتد: os_task_create(task_blink, 5) یک تسک به نام "task_blink" با اولویت ۵ ایجاد می‌کند. این تسک وقتی os_start() فراخوانی شود زمان‌بندی می‌شود. os_task_create(task_sensor, 3, 100) یک تسک دوره‌ای ایجاد می‌کند که هر ۱۰۰ میلی‌ثانیه اجرا می‌شود. os_task_create_st(task_ui, 8, 0, 1024) یک تسک با پشته سفارشی ۱ کیلوبایت ایجاد می‌کند (برای تسک‌هایی که از printf یا فراخوانی‌های عمیق تابع استفاده می‌کنند مفید است).

Priority Guidelinesراهنمای اولویت

PriorityاولویتUsageکاربرد
1Lowest application priorityپایین‌ترین اولویت
2–4Background tasks (sensors, logging)تسک‌های پس‌زمینه
5–10Normal tasks (UI, communication)تسک‌های عادی
11–20High-priority tasks (safety)تسک‌های با اولویت بالا
21+ISR-like tasks (time-critical)تسک‌های حساس به زمان

Stack Sizing Guideراهنمای اندازه پشته

Task Typeنوع تسکRecommended Stackپشته پیشنهادی
LED blink128–256 bytes
Sensor reading (HAL)256–512 bytes
UART communication512–1024 bytes
SPI/I2C + protocol512–1024 bytes
printf / float formatting1024–2048 bytes

2. Timing & Delaysزمان‌بندی و تاخیرها

What is Timing? Timing is how ZenOS keeps track of time and manages task execution intervals. The kernel tick (default 100μs) is the heartbeat of the system — every tick, the scheduler checks which tasks should run. Delays allow tasks to sleep for a specified time, giving other tasks a chance to execute.زمان‌بندی چیست؟ زمان‌بندی نحوه ردیابی زمان و مدیریت فواصل اجرای تسک توسط ZenOS است. تیک هسته (پیش‌فرض ۱۰۰ میکروثانیه) ضربان قلب سیستم است — در هر تیک، زمان‌بند بررسی می‌کند کدام تسک‌ها باید اجرا شوند. تاخیرها به تسک‌ها اجازه می‌دهند برای مدت زمان مشخصی بخوابند و به تسک‌های دیگر فرصت اجرا بدهند.

os_delay_ms(100);  // Sleep ~100ms, yield CPU to other tasks
os_delay_ms(0);    // No implicit yield; use os_yield() to yield

os_delay_us(10);   // Busy-wait ~10µs (blocks CPU — no other task runs!)

uint32_t ms = os_get_ms();    // Milliseconds since boot
uint32_t us = os_get_us();    // Microseconds since boot (DWT counter)
uint32_t tick = os_get_tick(); // Raw tick count

What happens: os_delay_ms(100) puts the current task to sleep for 100ms. During this time, the scheduler runs other ready tasks. When 100ms passes, the task wakes up and continues. os_delay_ms(0) returns immediately without yielding; use os_yield() to yield — useful when you want to give other tasks a chance to run without actually sleeping. os_delay_us(10) busy-waits for 10μs — the CPU does nothing else during this time (use only for sub-millisecond delays).چه اتفاقی می‌افتد: os_delay_ms(100) تسک فعلی را به مدت ۱۰۰ میلی‌ثانیه می‌خواباند. در این مدت، زمان‌بند تسک‌های آماده دیگر را اجرا می‌کند. وقتی ۱۰۰ میلی‌ثانیه بگذرد، تسک بیدار شده و ادامه می‌دهد. os_delay_ms(0) فوراً برمی‌گردد بدون واگذاری؛ از os_yield() برای واگذاری استفاده کنید — مفید وقتی می‌خواهید به تسک‌های دیگر فرصت اجرا بدهید بدون اینکه واقعاً بخوابید. os_delay_us(10) به مدت ۱۰ میکروثانیه انتظار مشغول می‌کشد — CPU در این مدت کار دیگری انجام نمی‌دهد (فقط برای تاخیرهای زیر میلی‌ثانیه استفاده کنید).

os_delay_us() uses DWT cycle counter for busy-waiting. It does NOT yield the CPU. Use only for very short delays (<1ms).os_delay_us() از شمارنده DWT برای انتظار مشغول استفاده می‌کند و CPU را واگذار نمی‌کند. فقط برای تاخیرهای بسیار کوتاه استفاده کنید.

Elapsed Time Measurementاندازه‌گیری زمان سپری شده

uint32_t t0 = os_get_ms();
// ... do work ...
uint32_t elapsed = os_get_ms() - t0;  // Works even if ms wraps (~49 days)

3. Critical Sections (OS_SAFE)بخش‌های بحرانی (OS_SAFE)

What is a Critical Section? A critical section is a piece of code that accesses shared data that might also be accessed by an interrupt service routine (ISR). Without protection, an interrupt could happen in the middle of updating a variable, leaving it in an inconsistent state. OS_SAFE disables all interrupts for the duration of the block, ensuring atomic access to shared data.بخش بحرانی چیست؟ بخش بحرانی قطعه‌ای از کد است که به داده مشترکی دسترسی دارد که ممکن است توسط یک روتین سرویس وقفه (ISR) نیز دسترسی داشته باشد. بدون محافظت، یک وقفه می‌تواند در وسط به‌روزرسانی یک متغیر رخ دهد و آن را در وضعیت ناسازگار باقی بگذارد. OS_SAFE تمام وقفه‌ها را برای مدت بلوک غیرفعال می‌کند و دسترسی اتمی به داده مشترک را تضمین می‌کند.

volatile uint32_t shared_counter = 0;

OS_SAFE {
    shared_counter++;  // Interrupts disabled here
}
// Interrupts re-enabled here

What happens: When the task enters OS_SAFE { ... }, all interrupts are immediately disabled (CPSID I instruction). The code inside the block executes without any interrupt interference. When the block ends, interrupts are re-enabled (CPSIE I). This is implemented using C++ RAII — even if an exception occurs, interrupts are always re-enabled. Keep critical sections short! Long critical sections increase interrupt latency.چه اتفاقی می‌افتد: وقتی تسک وارد OS_SAFE { ... } می‌شود، تمام وقفه‌ها فوراً غیرفعال می‌شوند (دستورالعمل CPSID I). کد داخل بلوک بدون هیچ تداخل وقفه‌ای اجرا می‌شود. وقتی بلوک تمام می‌شود، وقفه‌ها دوباره فعال می‌شوند (دستورالعمل CPSIE I). این با استفاده از RAII C++ پیاده‌سازی می‌شود — حتی اگر خطایی رخ دهد، وقفه‌ها همیشه دوباره فعال می‌شوند. بخش‌های بحرانی را کوتاه نگه دارید! بخش‌های بحرانی طولانی تاخیر وقفه را افزایش می‌دهند.

FeatureویژگیOS_SAFEOS_LOCK
Disables interruptsغیرفعال کردن وقفه‌ها✅❌
Allows blocking callsاجازه فراخوانی بلاک‌کننده❌✅
Protects from ISRsمحافظت از ISRs✅❌
Protects from other tasksمحافظت از تسک‌های دیگر✅✅
Use caseمورد استفادهShare data with ISRsاشتراک داده با ISRsProtect shared resourcesمحافظت از منابع مشترک

4. Events (OS_EVENT)رویدادها (OS_EVENT)

What is an Event? An event is a synchronization primitive used for inter-task signaling. Think of it as a "flag" that one task can raise (signal) and another task can wait for. Events use an internal counter — each signal() increments the counter, and each wait() decrements it (if > 0) or blocks until signaled or timeout. This makes events perfect for ISR-to-task communication and simple synchronization.رویداد چیست؟ رویداد یک اولیه همگام‌سازی برای سیگنال‌دهی بین تسک‌ها است. آن را به عنوان یک "پرچم" در نظر بگیرید که یک تسک می‌تواند آن را بالا ببرد (سیگنال) و تسک دیگری منتظر آن باشد. رویدادها از یک شمارنده داخلی استفاده می‌کنند — هر signal() شمارنده را افزایش می‌دهد و هر wait() آن را کاهش می‌دهد (اگر > ۰ باشد) یا تا سیگنال یا تایم‌اوت بلاک می‌شود. این رویدادها را برای ارتباط ISR-to-task و همگام‌سازی ساده عالی می‌کند.

OS_EVENT sensor_ready;  // Create an event

// Waiter task (waits for the event):
if (sensor_ready.wait(1000)) {  // Wait up to 1000ms
    process_sensor_data();      // Event was signaled!
} else {
    handle_timeout();           // Timeout — no signal received
}

// Signaler task (signals the event):
read_sensor();
sensor_ready.signal();  // Wake up the waiter

// ISR-safe signaling (use in interrupt handlers):
sensor_ready.signal_from_isr();

What happens: Task A calls sensor_ready.wait(1000) and blocks (sleeps). Task B reads a sensor, then calls sensor_ready.signal(). This wakes up Task A, which then processes the data. If Task B doesn't signal within 1000ms, Task A wakes up with false (timeout). Important: Always use signal_from_isr() in interrupt handlers — calling signal() from an ISR is undefined behavior.چه اتفاقی می‌افتد: تسک A فراخوانی sensor_ready.wait(1000) می‌کند و بلاک (می‌خوابد). تسک B یک حسگر می‌خواند، سپس sensor_ready.signal() را فراخوانی می‌کند. این تسک A را بیدار می‌کند که سپس داده را پردازش می‌کند. اگر تسک B ظرف ۱۰۰۰ میلی‌ثانیه سیگنال ندهد، تسک A با false (تایم‌اوت) بیدار می‌شود. مهم: همیشه از signal_from_isr() در روتین‌های وقفه استفاده کنید — فراخوانی signal() از ISR رفتار تعریف نشده است.

Signal Accumulationتجمع سیگنال

OS_EVENT evt;

evt.signal();  // count = 1
evt.signal();  // count = 2
evt.signal();  // count = 3

evt.wait();    // count = 2 (returns 1)
evt.wait();    // count = 1 (returns 1)
evt.wait();    // count = 0 (returns 1)
evt.wait();    // returns 0 (timeout — count was already 0)

What happens: Multiple signals accumulate in the counter. Each wait() consumes one signal. If 3 signals are sent before any wait, the first 3 waits return immediately (count > 0). The 4th wait blocks until a new signal arrives or timeout. Use case: Multiple ISRs can signal the same event, and the task processes all pending signals one by one.چه اتفاقی می‌افتد: سیگنال‌های متعدد در شمارنده تجمع می‌یابند. هر wait() یک سیگنال مصرف می‌کند. اگر ۳ سیگنال قبل از هر wait ارسال شود، ۳ wait اول فوراً برمی‌گردند (count > ۰). wait چهارم تا رسیدن سیگنال جدید یا تایم‌اوت بلاک می‌شود. مورد استفاده: ISR‌های متعدد می‌توانند به یک رویداد سیگنال بدهند و تسک تمام سیگنال‌های معلق را یکی یکی پردازش می‌کند.

5. Mutexes (OS_MUTEX)قفل‌ها (OS_MUTEX)

What is a Mutex? A mutex (mutual exclusion) is a lock that ensures only one task can access a shared resource at a time. Think of it as a key to a room — only the task holding the key (locked mutex) can enter the room (use the resource). When the task leaves, it returns the key (unlocks), allowing another task to enter. ZenOS mutexes support recursive locking (same task can lock multiple times) and IPC priority ceiling (prevents priority inversion).Mutex چیست؟ mutex (حذف متقابل) یک قفل است که تضمین می‌کند فقط یک تسک در هر زمان بتواند به یک منبع مشترک دسترسی داشته باشد. آن را به عنوان کلید یک اتاق در نظر بگیرید — فقط تسکی که کلید (قفل mutex) را در اختیار دارد می‌تواند وارد اتاق (منبع را استفاده کند) شود. وقتی تسک خارج می‌شود، کلید را برمی‌گرداند (قفل را باز می‌کند) و به تسک دیگری اجازه ورود می‌دهد. mutex‌های ZenOS از قفل بازگشتی (همین تسک می‌تواند چندین بار قفل کند) و سقف IPC (جلوگیری از وارونگی اولویت) پشتیبانی می‌کنند.

OS_MUTEX uart_mtx;  // Create a mutex for UART

// RAII lock guard (auto-unlocked when block ends)
OS_LOCK(uart_mtx) {  // Acquire mutex
    HAL_UART_Transmit(&huart1, data, len, 100);  // Use resource
}  // Auto-released when block ends

// Manual lock/unlock
if (mtx.lock(1000)) {  // Wait up to 1000ms
    do_work();
    mtx.unlock();
}

// With IPC priority ceiling (IPC priority ceiling)
OS_MUTEX shared_data_mtx(8);  // Ceiling priority = 8

What happens: When Task A enters OS_LOCK(uart_mtx), it acquires the mutex. If Task B tries to enter while Task A holds it, Task B blocks until Task A exits. OS_LOCK is an RAII guard — it automatically releases the mutex when the block ends. IPC Ceiling: When you pass a ceiling priority (e.g., OS_MUTEX mtx(8)), the task's priority is temporarily boosted to that level while holding the mutex, preventing priority inversion.چه اتفاقی می‌افتد: وقتی تسک A وارد OS_LOCK(uart_mtx) می‌شود، mutex را به دست می‌آورد. اگر تسک B سعی کند وارد شود در حالی که تسک A آن را نگه داشته، تسک B بلاک می‌شود تا تسک A خارج شود. OS_LOCK یک محافظ RAII است — به طور خودکار mutex را آزاد می‌کند. سقف IPC: اولویت تسک به طور موقت به سطح سقف افزایش می‌یابد و از وارونگی اولویت جلوگیری می‌کند.

6. Queues (OS_QUEUE)صفوف (OS_QUEUE)

What is a Queue? A queue is a FIFO (First-In-First-Out) data structure for passing data between tasks or from ISRs to tasks. Think of it as a pipe — one task puts data in one end, and another task takes it out the other end. Queues are type-safe (using C++ templates), thread-safe, and can hold a fixed number of items. If the queue is full, the producer can wait or drop the data. If empty, the consumer can wait or timeout.صف چیست؟ صف یک ساختمان داده FIFO (اول وارد شده، اول خارج شده) برای انتقال داده بین تسک‌ها یا از ISRs به تسک‌هاست. آن را به عنوان یک لوله در نظر بگیرید — یک تسک داده را در یک انتها می‌گذارد و تسک دیگر آن را از انتهای دیگر بیرون می‌آورد. صف‌ها ایمن از نظر نوع (با الگوهای C++), ایمن از نظر رشته‌ای هستند و تعداد ثابتی آیتم نگه می‌دارند. اگر صف پر باشد، تولیدکننده می‌تواند منتظر بماند یا داده را رها کند.

How it works: When you declare OS_QUEUE<int, 8> sensor_queue;, ZenOS reserves space for 8 integers in a circular buffer. put() adds an item to the tail, get() removes from the head. If the queue is full and you call put() with a timeout, the task blocks until space is available. If the queue is empty and you call get(), the task blocks until data arrives.نحوه کار: وقتی OS_QUEUE<int, 8> sensor_queue; را اعلام می‌کنید، ZenOS فضایی برای ۸ عدد در بافر دایره‌ای رزرو می‌کند. put() آیتمی به انتها اضافه می‌کند، get() از سر حذف می‌کند. اگر صف پر باشد و put() را با تایم‌اوت فراخوانی کنید، تسک تا فراهم شدن فضا بلاک می‌شود.

OS_QUEUE<int, 8> sensor_queue;  // Capacity: 8 items of type int

// Producer — puts data into the queue:
sensor_queue.put(42);              // Non-blocking: add 42 to queue
sensor_queue.put(100, 100);        // Blocking: wait up to 100ms if full

// Consumer — gets data from the queue:
int value;
if (sensor_queue.get(value, 1000)) {  // Wait up to 1000ms
    process(value);                    // Got data!
} else {
    handle_timeout();                  // No data within 1000ms
}

// ISR-safe (use in interrupt handlers):
sensor_queue.put_from_isr(val);    // Signal from ISR to task

// Check queue status:
bool empty = sensor_queue.is_empty();
bool full  = sensor_queue.is_full();
uint8_t count = sensor_queue.count();  // Items waiting

Example output: If the sensor task puts values 10, 20, 30 into the queue, and the consumer calls get() three times, it receives 10, then 20, then 30 (FIFO order). If the consumer calls get() when the queue is empty, it blocks until data arrives or timeout.مثال: اگر تسک حسگر مقادیر ۱۰، ۲۰، ۳۰ را در صف بگذارد و مصرف‌کننده سه بار get() فراخوانی کند، به ترتیب ۱۰، سپس ۲۰، سپس ۳۰ دریافت می‌کند (ترتیب FIFO). اگر مصرف‌کننده وقتی صف خالی است get() فراخوانی کند، تا رسیدن داده یا تایم‌اوت بلاک می‌شود.

Queue for Sensor Data Pipelineصف برای خط لوله داده حسگر

struct SensorData {
    uint16_t temperature;
    uint16_t humidity;
    uint32_t timestamp;
};

OS_QUEUE<SensorData, 16> data_queue;  // Queue of 16 SensorData structs

// Task 1: Read sensor every 100ms
void task_reader(void) {
    while (1) {
        SensorData d;
        d.temperature = ADC_ReadTemp();
        d.humidity = ADC_ReadHumidity();
        d.timestamp = os_get_ms();
        data_queue.put(d, 50);  // Wait max 50ms if full
        os_delay_ms(100);
    }
}

// Task 2: Send data to UART
void task_sender(void) {
    while (1) {
        SensorData d;
        if (data_queue.get(d, 1000)) {
            printf("T=%u H=%u\n", d.temperature, d.humidity);
        }
    }
}

What happens: Task 1 reads sensor data every 100ms and puts it into the queue. Task 2 waits for data and sends it over UART. If Task 2 is slower than Task 1, the queue fills up and Task 1 waits. If Task 2 is faster, it waits for new data. The queue acts as a buffer between the two tasks, decoupling their speeds.چه اتفاقی می‌افتد: تسک ۱ هر ۱۰۰ میلی‌ثانیه داده حسگر را می‌خواند و در صف می‌گذارد. تسک ۲ منتظر داده می‌ماند و آن را از UART ارسال می‌کند. اگر تسک ۲ کندتر از تسک ۱ باشد، صف پر شده و تسک ۱ منتظر می‌ماند. صف به عنوان بافر بین دو تسک عمل می‌کند و سرعت آن‌ها را از هم جدا می‌کند.

7. Semaphores (OS_SEMAPHORE)سمافورها (OS_SEMAPHORE)

What is a Semaphore? A semaphore is a counter-based synchronization primitive. Think of it as a pool of resources — the counter represents the number of available resources. wait() decrements the counter (takes a resource), and signal() increments it (returns a resource). If the counter is 0, wait() blocks until someone signals. Semaphores are perfect for limiting concurrent access to a resource pool (e.g., 5 available buffers, 3 UART ports).سمافور چیست؟ سمافور یک اولیه همگام‌سازی مبتنی بر شمارنده است. آن را به عنوان مجموعه‌ای از منابع در نظر بگیرید — شمارنده تعداد منابع موجود را نشان می‌دهد. wait() شمارنده را کاهش می‌دهد (منبعی برمی‌دارد) و signal() آن را افزایش می‌دهد (منبعی برمی‌گرداند). اگر شمارنده ۰ باشد، wait() تا سیگنال کسی بلاک می‌شود. سمافورها برای محدود کردن دسترسی همزمان به مجموعه منابع عالی هستند.

OS_SEMAPHORE(5) resource_sem;  // Max 5 concurrent users

// Task that uses a shared resource:
if (resource_sem.wait(1000)) {  // Wait for available resource
    use_resource();              // Use the resource
    resource_sem.signal();       // Return the resource
}

What happens: Imagine you have 5 buffer slots. Each task calls resource_sem.wait() before using a buffer (counter decrements: 5→4→3→...). When all 5 are in use, the next task blocks. When a task calls resource_sem.signal(), the counter increments and the next waiting task wakes up.چه اتفاقی می‌افتد: فرض کنید ۵ اسلات بافر دارید. هر تسک قبل از استفاده از بافر resource_sem.wait() فراخوانی می‌کند (شمارنده کاهش: ۵→۴→۳→...). وقتی همه ۵ در حال استفاده باشند، تسک بعدی بلاک می‌شود. وقتی تسکی resource_sem.signal() فراخوانی می‌کند، شمارنده افزایش یافته و تسک منتظر بیدار می‌شود.

// Example: Limit UART access to 1 task at a time
OS_SEMAPHORE(1) uart_sem;  // Binary semaphore (max=1)

void task_send(const char* msg) {
    if (uart_sem.wait(500)) {
        HAL_UART_Transmit(&huart1, msg, strlen(msg), 100);
        uart_sem.signal();
    }
}

8. Periodic Tasksتسک‌های دوره‌ای

Periodic task model: ZenOS stores the third argument of os_task_create() as period_ticks and uses next_run_time as a scheduler release gate. A periodic task becomes eligible only when the current tick reaches its next release time. After the task runs, the kernel advances the next release according to the configured period. A period of 0 means no periodic release gate.مدل تسک دوره‌ای: ZenOS آرگومان سوم os_task_create() را به‌صورت period_ticks نگهداری می‌کند و از next_run_time به‌عنوان دروازه آزادسازی در زمان‌بند استفاده می‌کند. تسک دوره‌ای فقط وقتی واجد شرایط اجراست که تیک جاری به زمان آزادسازی بعدی برسد. پس از اجرای تسک، هسته زمان آزادسازی بعدی را بر اساس دوره تنظیم می‌کند. دوره 0 یعنی هیچ دروازه آزادسازی دوره‌ای وجود ندارد.

void task_sensor(void) {
    while (1) {
        uint16_t val = ADC_Read();
        sensor_queue.put(val, 100);

        // Give the scheduler a chance to run another ready task.
        os_yield();
    }
}

// The period is recorded in the TCB.
// Do not describe it as an enforced wake-up interval
// until the scheduler's period gate is enabled.
os_task_create(task_sensor, 3, 100);

Why os_yield() here? A periodic-task example should use os_yield(), not an arbitrary os_delay_ms() value, when the intention is to demonstrate cooperative rescheduling. os_delay_ms() is a real blocking delay and should be documented separately as a sleep primitive.چرا اینجا os_yield()؟ در مثال یک تسک دوره‌ای، وقتی هدف نشان‌دادن واگذاری اجرای CPU است، باید از os_yield() استفاده شود، نه یک مقدار دلخواه برای os_delay_ms(). تابع os_delay_ms() یک تأخیر واقعی و مسدودکننده است و باید جداگانه به‌عنوان primitive خواب‌دادن تسک توضیح داده شود.

Periodic release: The scheduler checks next_run_time before selecting a periodic task. The task should call os_yield() after its work; os_delay_ms() remains a separate blocking sleep primitive.اجرای دوره‌ای: زمان‌بند پیش از انتخاب تسک دوره‌ای، next_run_time را بررسی می‌کند. تسک باید پس از انجام کار از os_yield() استفاده کند؛ os_delay_ms() همچنان یک primitive برای خواب و تأخیر مسدودکننده است.

Periodic vs One-Shot Tasksدوره‌ای در مقابل یکبار اجرا

// Periodic: released every 50ms
os_task_create(task_blink, 5, 50);  // 3rd param = period

// Aperiodic task: period = 0 means no release gate
os_task_create(task_handler, 5, 0);
// Stop/start explicitly when event-driven control is required:
os_task_stop(task_handler);
os_task_start(task_handler);

What happens: A task with period 50 becomes eligible at each 50-tick release boundary (50 ms when the kernel tick is 1 ms). A period of 0 means the task has no periodic release gate; it remains schedulable until it is blocked, stopped, or otherwise made ineligible.چه اتفاقی می‌افتد: تسک با دوره ۵۰ در هر مرز آزادسازی ۵۰ تیکی واجد شرایط اجرا می‌شود (اگر تیک هسته ۱ میلی‌ثانیه باشد، یعنی هر ۵۰ میلی‌ثانیه). دوره ۰ یعنی تسک دروازه آزادسازی دوره‌ای ندارد و تا زمانی که بلاک یا متوقف نشده باشد، قابل زمان‌بندی است.

Complete Example: Sensor + LED Systemمثال کامل: سیستم حسگر + LED

OS_QUEUE<uint16_t, 8> temp_queue;
OS_EVENT temp_ready;

// Periodic sensor task (200ms release interval)
void task_sensor(void) {
    while (1) {
        uint16_t temp = read_temperature();
        temp_queue.put(temp, 50);
        temp_ready.signal();           // Notify processing task
        os_yield();                    // Yield to the scheduler
    }
}

// Processing task (waits for sensor data)
void task_process(void) {
    while (1) {
        if (temp_ready.wait(500)) {
            uint16_t temp;
            if (temp_queue.get(temp, 100)) {
                if (temp > 3000) {     // > 30°C
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);  // LED ON
                } else {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1);  // LED OFF
                }
            }
        }
    }
}

int main(void) {
    // ... HAL init ...
    os_init();
    os_task_create(task_sensor, 3, 200);   // 200ms period
    os_task_create(task_process, 5, 0);    // Event-driven
    os_start();
}

What happens: At each 200ms release boundary, task_sensor becomes eligible, reads the temperature and signals task_process. task_process waits for the signal, reads the temperature from the queue, and turns the LED on/off based on the value. This demonstrates periodic tasks, queues, and events working together.چه اتفاقی می‌افتد: هر ۲۰۰ میلی‌ثانیه، task_sensor دما را می‌خواند و task_process را سیگنال می‌دهد. task_process منتظر سیگنال می‌ماند، دما را از صف می‌خواند و LED را بر اساس مقدار روشن/خاموش می‌کند. این نشان می‌دهد تسک‌های دوره‌ای، صف‌ها و رویدادها چگونه با هم کار می‌کنند.

9. Monitoring & Debuggingپایش و دیباگ

Why Monitor? In embedded systems, debugging is hard — you often can't attach a debugger to production devices. ZenOS provides built-in monitoring tools that help you track stack usage, CPU load, deadline compliance, and errors. These tools run in the background with minimal overhead, giving you visibility into your system's health without affecting real-time performance.چرا پایش؟ در سیستم‌های توکار، دیباگ سخت است — اغلب نمی‌توانید به دستگاه‌های تولیدی دیباگر وصل کنید. ZenOS ابزارهای پایش داخلی ارائه می‌دهد که به ردیابی مصرف پشته، بار CPU، رعایت ددلاین و خطاها کمک می‌کنند. این ابزارها در پس‌زمینه با حداقل سربار اجرا می‌شوند.

#if OS_MONITORING_EN
    // Per-task stack usage — how many bytes the task has used
    uint32_t bytes = os_get_stack_usage(task_function);
    printf("Task stack usage: %u bytes\n", bytes);

    // Full stack report — shows all tasks at once
    uint8_t count = os_get_stack_report_count();
    for (uint8_t i = 0; i < count; i++) {
        os_stack_report_entry_t rep;
        os_get_stack_report(i, &rep);
        printf("%s: %u/%u bytes used\n", rep.name, rep.peak_bytes, rep.size_bytes);
    }

    // CPU usage — percentage of time each task runs
    uint8_t total_cpu = os_get_cpu_usage_total();   // Total CPU usage %
    uint8_t task_cpu  = os_get_task_cpu_usage(task_function);  // Per-task %
    printf("Total CPU: %u%%, Task: %u%%\n", total_cpu, task_cpu);
#endif

// Deadline monitoring — detect if tasks miss their deadlines
#if OS_MONITORING_EN
    os_task_set_deadline(task_safety, 50);  // Set 50ms deadline
    uint32_t misses = os_get_deadline_miss_count(task_safety);
    if (misses > 0) {
        printf("WARNING: Task missed deadline %u times!\n", misses);
    }
#endif

// Error reporting — log errors with severity levels
os_log_error(OSError::SENSOR_TIMEOUT, (uint8_t)ErrorSeverity::WARNING);
uint32_t total_errors = os_get_error_count();
OSError last = os_get_last_error();
printf("Total errors: %u, Last: %d\n", total_errors, (int)last);

// Suppress expected errors during testing (won't trigger watchdog)
os_error_expect_begin();
    /* intentionally trigger and verify the expected error */
    os_event_signal(-1);
    os_error_expect_end();
    os_event_signal(-1);  // Deliberately invalid — expected error
    os_error_expect_end();

What happens: os_get_stack_usage() returns how many bytes of stack a task has used (peak watermark). If a task has a 512-byte stack and uses 480 bytes, you're close to overflow — increase the stack size. os_get_cpu_usage_total() returns total CPU utilization (0-100%). If it's above 80%, your system is overloaded. os_get_task_cpu_usage() shows which task is consuming the most CPU.چه اتفاقی می‌افتد: os_get_stack_usage() تعداد بایت‌های استفاده‌شده از پشته تسک را برمی‌گرداند. اگر تسکی پشته ۵۱۲ بایتی دارد و ۴۸۰ بایت استفاده کرده، نزدیک به سرریز هستید — پشته را بزرگ‌تر کنید. os_get_cpu_usage_total() کل استفاده CPU را برمی‌گرداند (۰-۱۰۰٪). اگر بالای ۸۰٪ باشد، سیستم بیش از حد بارگذاری شده است.

Monitoring Dashboard Exampleمثال داشبورد پایش

void task_monitor(void) {
    while (1) {
        printf("\n=== System Status ===\n");
        printf("Uptime: %u ms\n", os_get_ms());
        printf("CPU Usage: %u%%\n", os_get_cpu_usage_total());
        
        // Stack report
        uint8_t count = os_get_stack_report_count();
        for (uint8_t i = 0; i < count; i++) {
            os_stack_report_entry_t rep;
            os_get_stack_report(i, &rep);
            printf("  %s: %u/%u bytes (%u%% used)\n",
                   rep.name, rep.peak_bytes, rep.size_bytes,
                   (rep.peak_bytes * 100) / rep.size_bytes);
        }
        
        os_delay_ms(5000);  // Print status every 5 seconds
    }
}

os_task_create(task_monitor, 1, 0);  // Low priority, aperiodic

Example output:خروجی مثال:

=== System Status ===
Uptime: 15230 ms
CPU Usage: 45%
  task_blink: 48/256 bytes (18% used)
  task_sensor: 128/512 bytes (25% used)
  task_uart: 256/1024 bytes (25% used)

🛡️ Safety Featuresویژگی‌های ایمنی

1. Safety Mechanismsمکانیسم‌های ایمنی

Safety mechanisms are configurable and not all are enabled by default; they can be individually toggled in ZenOS_Config.hpp.مکانیسم‌های ایمنی قابل پیکربندی هستند و همه به طور پیش‌فرض فعال نیستند؛ هر کدام را می‌توان به طور جداگانه در ZenOS_Config.hpp تنظیم کرد.

MechanismمکانیسمConfig MacroماکروWhat it doesعملکرد
🔍 Stack CanaryAlways activeهمیشه فعالCanary + SP bounds checking (runs every 16 ticks)بررسی کاناری + محدوده SP (هر ۱۶ تیک)
🔐 TCB IntegrityOS_MONITORING_ENMagic number validationاعتبارسنجی عدد جادو
⏱️ Deadline MonitorOS_MONITORING_ENDetects deadline missesتشخیص از دست رفتن ددلاین
📋 Error LogOS_MONITORING_ENRing buffer with timestampبافر حلقه‌ای با زمان
🐕 HW WatchdogOS_SAFETY_HW_WATCHDOG_ENSTM32 IWDG integrationادغام IWDG STM32
💤 SW WatchdogOS_SAFETY_SOFT_WATCHDOG_ENDetects stuck tasksتشخیص تسک‌های گیر کرده
🧪 RAM TestOS_SAFETY_RAM_TEST_ENBounded SRAM integrity test (background)آزمون یکپارچگی SRAM محدود (پس‌زمینه)
✅ CRC CheckOS_SAFETY_CRC_ENFlash integrity via CRCیکپارچگی فلش از طریق CRC
🛡️ MPUOS_SAFETY_MPU_ENPer-task memory protectionحفاظت حافظه هر تسک

Safety Features APIAPI ویژگی‌های ایمنی

#if OS_SAFETY_HW_WATCHDOG_EN
    // Hardware watchdog feed (call from dedicated task)
    void task_wdg_feeder(void) {
        while (1) {
            os_hw_watchdog_feed();  // Unconditional feed
            os_delay_ms(1000);     // Feed every 1s; timeout depends on the target IWDG configuration
        }
    }
    // Or conditional feed (skip if unhealthy)
    os_hw_watchdog_check();  // Only feeds if error_count < 10
#endif

#if OS_SAFETY_RAM_TEST_EN
    // Background RAM test (call from idle or low-priority task)
    os_ram_test_step();  // Test one word per call
    if (os_ram_test_complete() && os_get_ram_test_error_count() > 0) {
        // SRAM fault detected!
    }
#endif

#if OS_SAFETY_CRC_EN
    // ROM integrity check
    // os_crc_init() is called automatically inside os_init()
    os_crc_check_step();  // In background task / idle
    if (os_crc_check_complete() && os_get_crc_error_count() > 0) {
        // ROM corruption detected!
    }
#endif

#if OS_SAFETY_MPU_EN
    // MPU protection setup
    os_mpu_init();
    os_mpu_enable();
    os_mpu_add_region(&task_tcb, 0x20001000, 4096, 3);  // Per-task region
#endif

3. IEC 62304/61508 Target Profilesپروفایل‌های هدف

Certification disclaimer: These compiler profiles enable ZenOS safety mechanisms and compile-time checks. They do not make ZenOS certified or make an application compliant by themselves. Certification and system-level compliance remain the integrator's responsibility.توضیح مهم درباره گواهی: این پروفایل‌های کامپایل، مکانیسم‌های ایمنی ZenOS و بررسی‌های زمان کامپایل را فعال می‌کنند. این تنظیمات به‌تنهایی به معنی گواهی‌شدن ZenOS یا منطبق‌شدن محصول با یک استاندارد نیستند؛ مسئولیت انطباق و فرایند گواهی در سطح محصول بر عهده یکپارچه‌ساز است.
Build with -DOS_TARGET_MEDICAL_CLASS=3 for IEC 62304 Class C or -DOS_TARGET_INDUSTRIAL_SIL=3 for IEC 61508 SIL 3. The build will fail if any required feature is disabled. با -DOS_TARGET_MEDICAL_CLASS=3 برای کلاس C یا -DOS_TARGET_INDUSTRIAL_SIL=3 برای SIL 3 بسازید. اگر هر ویژگی الزامی غیرفعال باشد، build شکست می‌خورد.

IEC 62304 Medical Classesکلاس‌های پزشکی IEC 62304

Note: Use -DOS_TARGET_MEDICAL_CLASS=X compiler flag where X is 1 (Class A), 2 (Class B), or 3 (Class C). The build will fail with #error if required features are disabled. توجه: از پرچم کامپایلر -DOS_TARGET_MEDICAL_CLASS=X استفاده کنید که X برابر ۱ (کلاس A)، ۲ (کلاس B) یا ۳ (کلاس C) است. اگر ویژگی‌های الزامی غیرفعال باشند، build با #error شکست می‌خورد.
ClassRisk Levelسطح ریسکRequired Featuresویژگی‌های الزامی
ANo injury possibleآسیب غیرممکنNone (all optional)هیچ (همه اختیاری)
BNon-serious injuryآسیب غیرجدیOS_MONITORING_EN (deadline + error log), SOFT_WATCHDOG, OS_MONITORING_DEADLINE_ACTION ≥ 1OS_MONITORING_EN (ددلاین + ثبت خطا)، SOFT_WATCHDOG، OS_MONITORING_DEADLINE_ACTION ≥ ۱
CDeath/serious injuryمرگ/آسیب جدیAll features required (HW_WATCHDOG, TCB_INTEGRITY, MPU, CRC, RAM_TEST)تمام ویژگی‌ها الزامی

IEC 61508 SIL Levelsسطوح SIL

Note: Use -DOS_TARGET_INDUSTRIAL_SIL=X compiler flag where X is 1 (SIL 1), 2 (SIL 2), 3 (SIL 3), or 4 (SIL 4). توجه: از پرچم کامپایلر -DOS_TARGET_INDUSTRIAL_SIL=X استفاده کنید که X برابر ۱ (SIL 1)، ۲ (SIL 2)، ۳ (SIL 3) یا ۴ (SIL 4) است.
SILRisk Levelسطح ریسکRequired Featuresویژگی‌های الزامی
1LowپایینSOFT_WATCHDOG, OS_MONITORING_EN (event recording)SOFT_WATCHDOG، OS_MONITORING_EN (ثبت رخداد)
2Mediumمتوسط+ OS_IPC_TOOLS_EN (mutual exclusion), HW_WATCHDOG, OS_MONITORING_DEADLINE_ACTION ≥ 1+ OS_IPC_TOOLS_EN (قطع‌سازی متقابل)، HW_WATCHDOG، OS_MONITORING_DEADLINE_ACTION ≥ ۱
3Highبالا+ MPU, RAM_TEST, CRC+ MPU، RAM_TEST، CRC

🔌 Serial Output (printf)خروجی سریال (printf)

Why Serial Output? In embedded development, you can't use a graphical debugger in production. Serial output (via UART) is your window into the system — it lets you print debug messages, sensor values, and system status. ZenOS provides a simple way to redirect printf() to UART so you can see what's happening in real-time.چرا خروجی سریال؟ در توسعه توکار، نمی‌توانید از دیباگر گرافیکی در تولید استفاده کنید. خروجی سریال (از طریق UART) پنجره شما به سیستم است — به شما اجازه می‌دهد پیام‌های دیباگ، مقادیر حسگر و وضعیت سیستم را چاپ کنید.

Step-by-Step Setupتنظیم گام به گام

  1. Enable USART1 in CubeMX (Pinout & Configuration → Connectivity → USART1)USART1 را در CubeMX فعال کنید (Pinout & Configuration → Connectivity → USART1)
  2. Set pins: PA9 = USART1_TX, PA10 = USART1_RXپین‌ها را تنظیم کنید: PA9 = USART1_TX, PA10 = USART1_RX
  3. Set Baud rate: 115200, Data Bits: 8, Stop Bits: 1, Parity: Noneنرخ بیت: ۱۱۵۲۰۰, بیت‌های داده: ۸, بیت‌های توقف: ۱, بیت زوجیت: بدون
  4. Connect a USB-to-Serial adapter (e.g., CH340, CP2102) to PA9/PA10آداپتور USB به سریال (مثلاً CH340, CP2102) را به PA9/PA10 وصل کنید
  5. Add the printf redirect in main.cpp:redirect printf را به main.cpp اضافه کنید:
#include <cstdio>

// Redirect printf() to UART1
extern "C" int _write(int fd, char* ptr, int len) {
    HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);
    return len;
}

// Now you can use printf() anywhere!
printf("ZenOS %s\n", os_get_version_string());
printf("Tasks: %d\n", os_get_task_count());
printf("Uptime: %u ms\n", os_get_ms());

What happens: The _write() function is called by printf() internally. By overriding it, we redirect all output to UART1. The extern "C" is needed because printf is a C function. HAL_MAX_DELAY means wait forever for the UART to be ready. Now anywhere in your code you call printf(), the output appears on the serial terminal.چه اتفاقی می‌افتد: تابع _write() توسط printf() به طور داخلی فراخوانی می‌شود. با بازنویسی آن، تمام خروجی را به UART1 هدایت می‌کنیم. extern "C" لازم است زیرا printf یک تابع C است. حالا هر جای کد printf() فراخوانی کنید، خروجی در ترمینال سریال ظاهر می‌شود.

Using a Terminal Programاستفاده از برنامه ترمینال

Softwareنرم‌افزارPlatformپلتفرمLinkلینک
PuTTYWindowsputty.org
Tera TermWindowsttssh2.osdn.jp
minicomLinuxBuilt-inداخلی
screenmacOS/LinuxBuilt-inداخلی
# Linux/macOS:
screen /dev/ttyUSB0 115200

# Windows (PuTTY):
# Serial line: COM3 (check Device Manager)
# Speed: 115200

🚨 Error Handling & Monitoringمدیریت خطاها و پایش

Why Error Handling? In safety-critical systems, you need to know when something goes wrong. ZenOS provides a built-in error reporting system with severity levels, timestamps, and error logs. You can report errors from any task, and the system tracks them for you. These mechanisms can contribute evidence to a project-specific IEC 62304/61508 process, but they do not establish compliance by themselves.چرا مدیریت خطا؟ در سیستم‌های حیاتی ایمنی، باید بدانید کی چیزی اشتباه می‌شود. ZenOS یک سیستم گزارش‌دهی خطا داخلی با سطوح شدت، زمان و لاگ خطا ارائه می‌دهد.

// Report a custom error with severity level
os_log_error(OSError::SENSOR_TIMEOUT, (uint8_t)ErrorSeverity::WARNING);
os_log_error(OSError::STACK_OVERFLOW, (uint8_t)ErrorSeverity::CRITICAL);

// Check error counts
uint32_t total       = os_get_error_count();          // Total errors logged
uint32_t unexpected  = os_get_unexpected_error_count(); // Unexpected errors
uint32_t expected    = os_get_expected_error_count();   // Expected errors (suppressed)
OSError last         = os_get_last_error();             // Last error code
printf("Errors: %u total, %u unexpected\n", total, unexpected);

// Suppress expected errors during testing
// Use this when you intentionally trigger errors for testing
os_error_expect_begin();
    /* intentionally trigger and verify the expected error */
    os_event_signal(-1);
    os_error_expect_end();
    os_event_signal(-1);  // Deliberately invalid — expected error
    os_error_expect_end();
// os_get_unexpected_error_count() does NOT increase
// os_get_expected_error_count() DOES increase

// Read error log (if OS_MONITORING_EN is enabled)
#if OS_MONITORING_EN
    uint32_t count = os_get_error_log_count();
    for (uint32_t i = 0; i < count; i++) {
        OSErrorEntry entry = os_get_error_log_entry(i);
        printf("[%u] Error %d in task %d (severity %d)\n",
               entry.timestamp_tick, entry.code, entry.task_id, entry.severity);
    }
#endif

What happens: os_log_error() records an error with a code and severity level. The error is stored in a ring buffer (circular log) with a timestamp. os_error_expect_begin(); /* intentionally trigger and verify the expected error */ os_event_signal(-1); os_error_expect_end(); ... } marks a block where errors are expected — they won't trigger the watchdog or count as unexpected errors. This is useful during testing when you intentionally test error paths.چه اتفاقی می‌افتد: os_log_error() خطایی را با کد و سطح شدت ثبت می‌کند. خطا در بافر حلقه‌ای (لاگ دایره‌ای) با زمان ذخیره می‌شود. os_error_expect_begin(); /* intentionally trigger and verify the expected error */ os_event_signal(-1); os_error_expect_end(); ... } بلوکی را علامت‌گذاری می‌کند که در آن خطاها مورد انتظار هستند.

Error Severity Levelsسطوح شدت خطا

LevelسطحMeaningمعنیActionاقدام
INFOInformational messageپیام اطلاعاتیLog onlyفقط ثبت
WARNINGSomething unusual happenedچیز غیرعادی رخ دادهLog + alertثبت + هشدار
ERRORFunction failed but system OKتابع ناموفق اما سیستم OKLog + recoverثبت + بازیابی
CRITICALSystem integrity at riskیکپارچگی سیستم در خطرReset / safe stateریست / حالت ایمن
Important: Always check os_get_error_count() in your monitoring task. If unexpected errors are increasing, investigate immediately — it indicates a bug or hardware fault.مهم: همیشه os_get_error_count() را در تسک پایش خود بررسی کنید. اگر خطاهای غیرمنتظره در حال افزایش هستند، فوراً بررسی کنید.

🎓 Advanced Tips & Tricksنکات پیشرفته

Task Lifecycle Managementمدیریت چرخه حیات تسک

Why Control Task Lifecycle? In many systems, you don't want all tasks running all the time. For example, a heater task should only run when temperature is low. ZenOS lets you start and stop tasks dynamically at runtime, saving CPU and power.چرا کنترل چرخه حیات تسک؟ در بسیاری از سیستم‌ها، نمی‌خواهید تمام تسک‌ها همیشه اجرا شوند. مثلاً تسک هیتر فقط وقتی دما پایین است باید اجرا شود.

// Pre-create all tasks, start/stop as needed
os_task_create(task_heater, 5);
os_task_create(task_cooler, 5);
os_task_stop(task_heater);   // Start inactive
os_task_stop(task_cooler);   // Start inactive

// Runtime control
if (temperature > 70) {
    os_task_start(task_cooler);    // Activate cooler
    os_task_stop(task_heater);     // Deactivate heater
} else if (temperature < 20) {
    os_task_start(task_heater);    // Activate heater
    os_task_stop(task_cooler);     // Deactivate cooler
}

What happens: Tasks are created but immediately stopped (dormant). They don't use CPU until os_task_start() is called. This is more efficient than creating/destroying tasks repeatedly. The task's stack and TCB remain allocated but the scheduler ignores stopped tasks.چه اتفاقی می‌افتد: تسک‌ها ایجاد اما فوراً متوقف می‌شوند (غیرفعال). تا فراخوانی os_task_start() از CPU استفاده نمی‌کنند.

Power Management with Tickless Idleمدیریت مصرف با حالت idle بدون تیک

What is Tickless Idle? In normal mode, the SysTick interrupt fires every 100μs even when nothing is happening — wasting power. Tickless idle disables SysTick during long delays and uses a hardware timer to wake up exactly when the next task is due. This dramatically reduces power consumption in battery-powered devices.idle بدون تیک چیست؟ در حالت عادی، وقفه SysTick هر ۱۰۰ میکروثانیه حتی وقتی هیچ اتفاقی نمی‌افتد فعال می‌شود — مصرف بیهوده انرژی. idle بدون تیک SysTick را در تاخیرهای طولانی غیرفعال کرده و از تایمر سخت‌افزاری برای بیدار کردن دقیقاً وقتی تسک بعدی لازم است استفاده می‌کند.

// Enable OS_KERNEL_TICKLESS_IDLE_EN in config
// The OS will use WFI (Wait For Interrupt) when no tasks are ready
// This puts the CPU into low-power mode automatically

// Design tips for low power:
// 1. Use os_delay_ms() instead of busy-wait loops
// 2. Long delays → deep sleep (CPU stops)
// 3. Short delays → partial sleep (CPU slows)
// 4. The scheduler releases periodic tasks at their next release time

Debugging Tipsنکات دیباگ

// 1. Print task count at startup
printf("Tasks: %d\n", os_get_task_count());

// 2. Monitor stack usage periodically
uint32_t peak = os_get_stack_usage(task_function);
printf("Stack peak: %d bytes\n", peak);

// 3. Check CPU usage
uint8_t cpu = os_get_task_cpu_usage(task_function);
printf("Task CPU: %d%%\n", cpu);

// 4. Print version
printf("ZenOS %s\n", os_get_version_string());

// 5. Check for unexpected errors
if (os_get_unexpected_error_count() > 0) {
    printf("UNEXPECTED ERRORS: %d\n", os_get_unexpected_error_count());
}

Memory Mapنقشه حافظه

Understanding Memory Usage: ZenOS uses zero heap allocation — all memory is statically allocated at compile time. This means you know exactly how much RAM your system uses before running it. No malloc() calls, no fragmentation, no surprises.درک مصرف حافظه: ZenOS از تخصیص حافظه پویا صفر استفاده می‌کند — تمام حافظه به طور ایستا در زمان کامپایل تخصیص می‌یابد. یعنی دقیقاً می‌دانید چقدر RAM سیستم شما استفاده می‌کند.

Flash (code + constants): ├── Application code ├── ZenOS kernel code ├── STM32 HAL library └── Interrupt vector table SRAM (data + stacks): ├── BSS segment (zero-initialized globals) ├── Data segment (initialized globals) ├── Task stacks (per-task, static) ├── Task stacks (per-task, static; effective allocation floor 256 bytes) ├── Error log (OS_MONITORING_ERROR_LOG_SIZE * ~8 bytes, when OS_MONITORING_EN is on) ├── Idle task stack (512 bytes — OS_IDLE_STACK_WORDS = 128) └── Fault task stack (256 bytes — OS_FAULT_STACK_WORDS = 64)

📚 Common Patterns Cookbookکتابخانه الگوهای رایج

State Machine in a Taskماشین حالت در یک تسک

enum State { INIT, RUNNING, ERROR, SLEEP };
static State state = INIT;

void task_state_machine(void) {
    while (1) {
        switch (state) {
            case INIT:
                if (hardware_ready()) state = RUNNING;
                break;
            case RUNNING:
                if (error_detected()) state = ERROR;
                else do_work();
                break;
            case ERROR:
                if (error_cleared()) state = RUNNING;
                else enter_safe_state();
                break;
            case SLEEP:
                os_delay_ms(1000);
                break;
        }
        os_yield();        // Always yield
    }
}

Debounced Button Handlingمدیریت دکمه با دبیونس

OS_KEY_EVT;

void EXTI0_IRQHandler(void) {
    OS_KEY_EVT.signal_from_isr();
}

void task_button(void) {
    while (1) {
        if (OS_KEY_EVT.wait(5000)) {
            os_delay_ms(50);  // Debounce delay
            if (read_button()) {
                handle_button_press();
            }
        }
    }
}

Software PWM via Periodic TaskPWM نرم‌افزاری با تسک دوره‌ای

void task_pwm(void) {
    uint8_t duty = 128;  // 50% duty
    while (1) {
        HAL_GPIO_WritePin(PWM_PORT, PWM_PIN, GPIO_PIN_SET);
        os_delay_us(duty * 10);  // ON time
        HAL_GPIO_WritePin(PWM_PORT, PWM_PIN, GPIO_PIN_RESET);
        os_delay_us((255 - duty) * 10);  // OFF time
    }
}
os_task_create(task_pwm, 15);  // High priority for timing

Multi-Stage Sensor Pipelineخط لوله حسگر چند مرحله‌ای

OS_QUEUE<RawData, 8> raw_queue;
OS_QUEUE<ProcessedData, 8> processed_queue;

void task_acquire(void) {
    while (1) {
        RawData raw = read_sensor();
        raw_queue.put(raw);
        os_yield();
    }
}

void task_process(void) {
    while (1) {
        RawData raw;
        if (raw_queue.get(raw, 100)) {
            ProcessedData proc = filter_and_calibrate(raw);
            processed_queue.put(proc);
        }
    }
}

void task_output(void) {
    while (1) {
        ProcessedData proc;
        if (processed_queue.get(proc, 100)) {
            display(proc);
        }
    }
}

// Pipeline: acquire(3) → process(5) → output(4)
os_task_create(task_acquire, 3, 10);
os_task_create(task_process, 5);
os_task_create(task_output, 4);

Graceful Shutdownخاموش کردن صحیح

static volatile bool shutdown_requested = false;

void task_shutdown_handler(void) {
    while (1) {
        if (shutdown_button.wait(1000)) {
            shutdown_requested = true;
            os_task_stop(task_ui);
            os_task_stop(task_led);
            save_critical_data();
            enter_safe_mode();
        }
    }
}

📋 Complete API Referenceمرجع کامل API

Core Functions (C)توابع هسته (C)

FunctionتابعDescriptionتوضیحات
os_init()Initialize RTOS (call before task creation)مقداردهی اولیه RTOS
os_start()Start scheduler (never returns)شروع زمان‌بند (هرگز برنمی‌گردد)
os_tick()Tick handler (call from SysTick_Handler)هندلر تیک
os_delay_ms(ms)Sleep for ms millisecondsخواب به مدت ms میلی‌ثانیه
os_delay_us(us)Busy-wait for us microsecondsانتظار مشغول به مدت us میکروثانیه
os_yield()Yield to next ready taskواگذاری به تسک بعدی
os_get_tick()Get raw tick countدریافت شمارنده تیک خام
os_get_ms()Get milliseconds since bootدریافت میلی‌ثانیه از شروع
os_get_us()Get microseconds since bootدریافت میکروثانیه از شروع
os_task_start(entry)Start a stopped taskشروع تسک متوقف شده
os_task_stop(entry)Stop a running taskتوقف تسک در حال اجرا
os_task_isActive(entry)Check if task is activeبررسی فعال بودن تسک
os_get_task_count()Get number of registered tasksدریافت تعداد تسک‌های ثبت شده
os_get_task_priority(entry)Get task's active priorityدریافت اولویت فعال تسک
os_get_stack_usage(entry)Get peak stack usage (bytes)دریافت حداکثر مصرف پشته
os_get_task_cpu_usage(entry)Get task CPU usage (%)دریافت مصرف CPU تسک
os_get_version_string()Get version stringدریافت رشته نسخه

RAII Classes (C++)کلاس‌های RAII (C++)

ClassکلاسMacroماکروDescriptionتوضیحات
_OsSafeGuardOS_SAFE { ... }Interrupt-disable guardمحافظ غیرفعال کردن وقفه
_OsLockGuardOS_LOCK(mtx) { ... }Mutex lock guardمحافظ قفل mutex
OS_EVENT—Inter-task event signalingسیگنال‌دهی رویداد بین تسک‌ها
OS_MUTEX—Mutex with IPC priority ceilingMutex با سقف اولویت IPC
OS_QUEUE<T,N>—Bounded FIFO queueصف FIFO محدود
OS_SEMAPHORE—Counting semaphoreسمافور شمارشی

⚙️ Configuration Guideراهنمای پیکربندی

ZenOS is configured via ZenOS_Config.hpp. Safety mechanisms are configurable and not all are enabled by default. This guide helps you decide what to enable based on your application needs.ZenOS از طریق ZenOS_Config.hpp پیکربندی می‌شود. مکانیسم‌های ایمنی قابل پیکربندی هستند و همه به طور پیش‌فرض فعال نیستند. این راهنما به شما کمک می‌کند بر اساس نیازهای برنامه‌تان تصمیم بگیرید چه چیزی را فعال کنید.

1. What Do You Need?چه چیزی نیاز دارید؟

Answer these questions to determine your configuration:این سؤالات را پاسخ دهید تا پیکربندی خود را تعیین کنید:

QuestionسؤالIf YESاگر بلهWhat to Enableچه چیزی فعال شود
Is this a hobby/learning project?آیا این پروژه تفریحی/آموزشی است؟Keep defaultsپیش‌فرض‌ها را نگه داریدUse the repository defaults; optional mechanisms are not all enabledهمه چیز (از قبل فعال)
Is memory very limited (<20KB RAM)?آیا حافظه بسیار محدود است؟Disable unused featuresویژگی‌های استفاده نشده را غیرفعال کنیدSee "Minimal Config"به "حداقل پیکربندی" مراجعه کنید
Is this a medical device?آیا این یک دستگاه پزشکی است؟Enable IEC 62304IEC 62304 را فعال کنید-DOS_TARGET_MEDICAL_CLASS=2 or -DOS_TARGET_MEDICAL_CLASS=3
Is this an industrial system?آیا این یک سیستم صنعتی است؟Enable IEC 61508IEC 61508 را فعال کنید-DOS_TARGET_INDUSTRIAL_SIL=2 or -DOS_TARGET_INDUSTRIAL_SIL=3
Do you need hardware watchdog?آیا به تایمر سخت‌افزاری نیاز دارید؟Enable IWDG in CubeMXIWDG را در CubeMX فعال کنیدOS_SAFETY_HW_WATCHDOG_EN = 1

2. Configuration Profilesپروفایل‌های پیکربندی

2.1 Minimal Configuration (Constrained Devices)حداقل پیکربندی (دستگاه‌های محدود)

For devices with <20KB RAM or when you need maximum flash/RAM savings:برای دستگاه‌هایی با کمتر از ۲۰KB RAM یا زمانی که به حداکثر صرفه‌جویی نیاز دارید:

// ZenOS_Config.hpp — Minimal configuration (explicit overrides)
// Source defaults: tick=100us, stack request=128B (effective floor=256B),
// priorities=16 slots, IPC=1, monitoring=0, safety features=0.
#define OS_KERNEL_TICK_PERIOD_US      1000UL  // override: valid 100..1000us; must divide 1000
#define OS_KERNEL_DEFAULT_STACK_SIZE  128     // source default request; effective floor=256B
#define OS_KERNEL_MAX_PRIORITIES      2       // override: valid 2..256; priority 0=idle

#define OS_IPC_TOOLS_EN               0       // explicit override: disable all IPC
#define OS_MONITORING_EN              0       // source default

#define OS_SAFETY_RAM_TEST_EN         0
#define OS_SAFETY_MPU_EN              0
#define OS_SAFETY_HW_WATCHDOG_EN      0
#define OS_SAFETY_CRC_EN              0
#define OS_SAFETY_SOFT_WATCHDOG_EN    0

2.2 Standard Configuration (Recommended)پیکربندی استاندارد (پیشنهادی)

Repository defaults — optional mechanisms are not all enabled; verify each default and its valid range in the configuration reference:تنظیمات پیش‌فرض مخزن — مکانیسم‌های اختیاری همگی فعال نیستند؛ مقدار پیش‌فرض و محدوده هر گزینه را در مرجع پیکربندی بررسی کنید:

// ZenOS_Config.hpp — Standard configuration (all defaults)
// No changes needed — features follow the defaults in ZenOS_Config.hpp.
// Just use the file as-is.

2.3 Medical Device Configuration (IEC 62304 Class B)پیکربندی دستگاه پزشکی (کلاس B)

// ZenOS_Config.hpp — Medical Class B
// Keep ALL defaults (optional mechanisms are not all enabled)
// Then add to compiler flags: -DOS_TARGET_MEDICAL_CLASS=2

// This enables compile-time enforcement:
// - OS_MONITORING_EN must be 1
// - OS_SAFETY_SOFT_WATCHDOG_EN must be 1
// - OS_MONITORING_DEADLINE_ACTION must be >= 1

2.4 Medical Device Configuration (IEC 62304 Class C)پیکربندی دستگاه پزشکی (کلاس C)

// ZenOS_Config.hpp — Medical Class C (life-critical)
// Keep ALL defaults (optional mechanisms are not all enabled)
// Then add to compiler flags: -DOS_TARGET_MEDICAL_CLASS=3

// This enables compile-time enforcement for ALL features:
// - OS_MONITORING_EN must be 1
// - OS_SAFETY_SOFT_WATCHDOG_EN must be 1
// - OS_SAFETY_HW_WATCHDOG_EN must be 1
// - OS_SAFETY_MPU_EN must be 1
// - OS_SAFETY_CRC_EN must be 1
// - OS_SAFETY_RAM_TEST_EN must be 1

2.5 Industrial Configuration (IEC 61508 SIL 2)پیکربندی صنعتی (SIL 2)

// ZenOS_Config.hpp — Industrial SIL 2
// Keep ALL defaults (optional mechanisms are not all enabled)
// Then add to compiler flags: -DOS_TARGET_INDUSTRIAL_SIL=2

// Required features:
// - OS_SAFETY_SOFT_WATCHDOG_EN = 1
// - OS_MONITORING_EN = 1
// - OS_IPC_TOOLS_EN = 1
// - OS_SAFETY_HW_WATCHDOG_EN = 1
// - OS_MONITORING_DEADLINE_ACTION >= 1

3. What ZenOS Handles AutomaticallyZenOS چه چیزی را خودکار مدیریت می‌کند

These are configured automatically by os_init() — you don't need to set them up:این موارد به طور خودکار توسط os_init() پیکربندی می‌شوند — نیازی به تنظیم دستی نیست:

FeatureویژگیStatusوضعیتDetailsجزئیات
PendSV handler✅ Automatic✅ خودکارContext switch interruptوقفه تغییر زمینه
Fault handlers✅ Automatic✅ خودکارHardFault, MemManage, BusFault, UsageFaultانواع خطاهای پردازنده
DWT cycle counter✅ Automatic✅ خودکارFor microsecond timingبرای زمان‌بندی میکروثانیه
MCU family detection✅ Automatic✅ خودکارVia ZenOS_Port.hppاز طریق ZenOS_Port.hpp

4. What You Must Configureچه چیزی را باید خودتان پیکربندی کنید

SettingتنظیمWhereمحلDetailsجزئیات
HAL TimebaseCubeMXSystem Core → SYS → Timebase = TIM1System Core → SYS → Timebase = TIM1
os_tick()stm32fxxx_it.cMust be in SysTick_Handlerباید در SysTick_Handler باشد
C++11 flagCompiler settings-std=c++11
IWDG (if using HW watchdog)CubeMXEnable IWDG timeout configured for the target applicationIWDG را با تایم‌اوت متناسب با کاربرد تنظیم کنید
CRC (if using CRC check)CubeMXEnable CRC peripheralپیرفرال CRC را فعال کنید

5. Complete Configuration Referenceمرجع کامل پیکربندی

ConstantثابتDefaultپیش‌فرضValid values / limitمحدوده / محدودیتDescriptionتوضیحات
OS_KERNEL_TICK_PERIOD_US100100..1000 µs; must divide 1000 evenlyKernel tick period.دوره تیک هسته؛ باید ۱۰۰۰ را بدون باقیمانده تقسیم کند.
OS_KERNEL_DEFAULT_STACK_SIZE128 BRequest ≥64 B; effective allocation floor 256 B; no explicit source maxDefault task stack request; practical maximum is constrained by target RAM, linker/toolchain and uint32_t.درخواست پیش‌فرض پشته؛ حداکثر عملی به RAM هدف، ابزار لینک/کامپایل و uint32_t وابسته است.
OS_KERNEL_MAX_PRIORITIES16 slots2..256 slots; priority 0 reserved; application range 1..N-1At 256 slots, application priorities are 1..255; larger numeric values mean higher priority.در ۲۵۶ اسلات، اولویت‌های کاربردی 1..255 هستند؛ عدد بزرگ‌تر یعنی اولویت بالاتر.
OS_KERNEL_TICKLESS_IDLE_EN10 or 1WFI-based tickless idle.idle بدون تیک مبتنی بر WFI.
OS_IPC_TOOLS_EN10 or 1Single master switch for events, mutexes, queues, semaphores and lock guards; all are enabled/disabled together.کلید واحد برای فعال/غیرفعال کردن همه IPC.
OS_MONITORING_EN00 or 1Master switch for deadline, TCB integrity, error log and CPU/stack instrumentation.کلید اصلی پایش deadline، یکپارچگی TCB، ثبت خطا و آمار CPU/stack.
OS_MONITORING_DEADLINE_ACTION10..20 = log only; 1 = reset task; 2 = disable task.۰ = فقط ثبت؛ ۱ = ریست تسک؛ ۲ = غیرفعال کردن تسک.
OS_MONITORING_ERROR_LOG_SIZE16>=1 entryRAM ring-buffer capacity.ظرفیت بافر حلقه‌ای خطا در RAM.
OS_SAFETY_RAM_TEST_EN00 or 1Background March-C SRAM integrity test.آزمون یکپارچگی SRAM به روش March-C.
OS_SAFETY_MPU_EN00 or 1; 1 requires MPUPer-task MPU protection; unsupported hardware causes a compile-time error.حفاظت MPU هر تسک؛ سخت‌افزار فاقد MPU باعث خطای کامپایل می‌شود.
OS_SAFETY_HW_WATCHDOG_EN00 or 1; 1 requires IWDGSTM32 IWDG integration; unsupported hardware causes a compile-time error.ادغام IWDG؛ نبود IWDG باعث خطای کامپایل می‌شود.
OS_SAFETY_CRC_EN00 or 1; 1 requires CRCFlash CRC integrity check; unsupported hardware causes a compile-time error.بررسی CRC فلش؛ نبود CRC باعث خطای کامپایل می‌شود.
OS_SAFETY_SOFT_WATCHDOG_EN00 or 1Software stuck-task detection and recovery.تشخیص و بازیابی تسک‌های گیرکرده.
OS_SAFETY_TASK_MAX_RECOVERY3>=0Maximum recovery attempts; 0 means immediate safe-state/disable path.حداکثر تلاش بازیابی؛ ۰ یعنی مسیر حالت ایمن/غیرفعال‌سازی فوری.
OS_SAFETY_SOFT_WDG_TIMEOUT_MS3000 ms>=0 ms; bounded by application safety/process timeSoftware watchdog timeout.تایم‌اوت watchdog نرم‌افزاری.
OS_SAFETY_MAX_CRITICAL_US1000 µs>=0 µs; 0 disables checkMaximum diagnostic duration of an OS_SAFE section.حد تشخیصی مدت OS_SAFE.
OS_TARGET_MEDICAL_CLASS00..3; 0 disabled, 1=A, 2=B, 3=CIEC 62304 target profile selector.انتخاب پروفایل هدف IEC 62304.
OS_TARGET_INDUSTRIAL_SIL00..4; 0 disabled, 1..4=SIL 1..4IEC 61508 target profile selector.انتخاب پروفایل هدف IEC 61508.

📊 ZenOS vs FreeRTOS vs Zephyrمقایسه ZenOS با FreeRTOS و Zephyr

FeatureویژگیZenOSFreeRTOSZephyr
Tick resolutionرزولوشن تیک100μs1ms10ms
Schedulerزمان‌بندPriority bitmap + queue scan for eligibilityO(n)O(n)
Heapحافظه پویاNeverAvailableAvailable
SafetyایمنیBuilt-inOptionalOptional
IEC 62304/61508IEC 62304/61508Compile-timeNoneNone
C++ RAIIC++ RAIIFullNonePartial
Periodic tasksتسک‌های دوره‌ایPeriod information is recorded; verify scheduler behaviorTimersTimers
IPC priority ceilingسقف IPCImmediateInheritanceNone

🏗️ Architectureمعماری

┌───────────────────────────────────────────────────┐ │ Application Tasks │ ├───────────────────────────────────────────────────┤ │ ZenOS Kernel (C++11) │ │ ┌────────────┬─────────────┬──────────────────┐ │ │ │ Scheduler │ IPC │ Safety Layer │ │ │ │ Bitmap │ Events │ Stack Canary │ │ │ │ priority │ Mutexes │ MPU Protection │ │ │ │ queue │ Queues │ HW/SW Watchdog │ │ │ │ │ Semaphores │ RAM integrity │ │ │ │ │ │ CRC ROM Check │ │ │ │ │ │ Deadline Mon. │ │ │ └────────────┴─────────────┴──────────────────┘ │ ├───────────────────────────────────────────────────┤ │ STM32 HAL (CubeMX-generated) │ ├───────────────────────────────────────────────────┤ │ ARM Cortex-M Hardware (M3/M4/M7) │ └───────────────────────────────────────────────────┘

🚨 Error Codes Referenceمرجع کدهای خطا

CodeNameنامDescriptionتوضیحاتTypical Causeعلت معمول
4STACK_OVERFLOWStack canary check failedبررسی کاناری پشته ناموفقStack too smallپشته خیلی کوچک
5INVALID_EVENT_IDOut-of-range event IDشناسه رویداد خارج از محدودهUninitialized eventرویداد مقداردهی نشده
6TASK_AFTER_STARTTask created after os_start()تسک بعد از os_start() ایجاد شدهWrong creation orderترتیب ایجاد نادرست
7TASK_STUCKSoftware watchdog timeoutتایمر نرم‌افزاری منقضی شدهTask not yieldingتسک واگذاری نمی‌کند
8SAFE_TOO_LONGOS_SAFE exceeded max durationOS_SAFE از حداکثر مدت تجاوز کردهLong critical sectionبخش بحرانی طولانی
9HARDFAULTCPU fault exceptionخطای پردازندهMemory access violationنقض دسترسی حافظه
10PRIORITY_CONFLICTMutex ceiling conflictتعارض سقف mutexMisconfigured ceilingپیکربندی نادرست سقف
11DEADLINE_MISSTask missed its deadlineتسک ددلاین را از دست دادهTask overloadedتسک بیش از حد بارگذاری شده
12TCB_CORRUPTEDTCB magic number invalidعدد جادوی TCB نامعتبرMemory corruptionخرابی حافظه
15RAM_TEST_FAILRAM test detected faultآزمون RAM خطا تشخیص دادهHardware SRAM failureخرابی سخت‌افزاری SRAM

🔧 Troubleshootingعیب‌یابی

IssueمشکلSolutionراه‌حل
LED doesn't blinkLED چشمک نمی‌زندSet HAL timebase to TIM1 in CubeMXتایمر HAL را روی TIM1 تنظیم کنید
HardFault on startupخطا در شروعAdd os_tick() to SysTick_Handleros_tick() را به SysTick_Handler اضافه کنید
Stack overflow detectedسرریز پشته تشخیص داده شدهIncrease stack size, use os_get_stack_usage()اندازه پشته را افزایش دهید
Watchdog resetریست تایمرAdd os_delay_ms() or os_yield()os_delay_ms() یا os_yield() اضافه کنید
Compilation error about C++خطای کامپایل مربوط به C++Add -std=c++11 to compiler flags
Priority inversionوارونگی اولویتSet correct IPC priority ceiling priorityاولویت سقف IPC را درست تنظیم کنید

📬 Contact Usتماس با ما

Raymon Research Team — Rahman Heidariتیم تحقیقاتی رایمون — رحمان حیدری

📧 Email: rahman.h22@gmail.com

🔗 GitHub: github.com/Raymon-Research-Team/ZenOS-RTOS

For questions, suggestions, or collaboration opportunities, feel free to reach out.برای سؤالات، پیشنهادات یا فرصت‌های همکاری، با ما در تماس باشید.