
Ультралегковесная ОСРВ для Интернета вещей с вытесняющим планированием, поддержкой TLS/DTLS, MQTT, CoAP, совместимостью с POSIX и защитой памяти на основе MPU. Ядро — менее 10 КБ.
Сверхлегкая операционная система реального времени для устройств Интернета вещей и встраиваемых систем с ограниченными ресурсами.
Размер ядра менее 10 КБ, минимум 2 КБ ОЗУ, вытесняющее планирование на основе приоритетов.
| Категория | Детали |
|---|---|
| Ядро | Вытесняющее планирование на основе приоритетов (256 уровней), циклическое планирование для одного приоритета, поиск приоритета O(1) через битовую маску, наследование приоритета |
| Синхронизация | Мьютекс (с наследованием приоритета), семафор, условная переменная, группы событий, очереди сообщений |
| Программные таймеры | Одноразовые и с автоперезагрузкой, точность до миллисекунды, изменение периода во время выполнения |
| Память | Аллокатор first-fit с немедленной коалесценцией (8 КБ кучи, выравнивание по 8 байт), обнаружение переполнения стека, метка максимального использования для каждой задачи |
| Оболочка | Интерактивная оболочка VT100 — 23 встроенные команды, история команд (↑↓), автодополнение по табуляции, полноценный редактор строки |
| Совместимость с POSIX | pthreads (create/join/detach/exit, мьютекс, условная переменная) · BSD socket API (socket/bind/listen/accept/connect/send/recv, inet_pton/ntop, htons/htonl) |
| Файловая система | Журналируемая ФС на блочных устройствах (WAL, восстановление после сбоя), совместное использование блоков COW, атомарные снимки, API, подобный POSIX |
| Сеть | Ethernet, IPv4, ICMP, UDP, TCP, HTTP клиент/сервер, DNS |
| TLS / DTLS | TLS 1.2/1.3 через TCP, DTLS 1.2 через UDP (бэкенд mbedTLS) |
| MQTT | Полный MQTT 3.1.1 — QoS 0/1/2 с таблицей повторных попыток в полёте, офлайн-очередь, автоматическое переподключение с экспоненциальной отсрочкой |
| CoAP | Клиент/сервер, совместимый с RFC 7252, шаблон observe |
| OTA | Обновления прошивки с разделами A/B, проверка CRC32, откат |
| Сторожевой таймер | Аппаратный и программный сторожевой таймер, мониторинг тайм-аута для каждой задачи |
| Энергопитание | Режимы бездействия / сна / глубокого сна, безтиковое бездействие, масштабирование частоты ЦП |
| Безопасность | Защита памяти на основе MPU, поддержка безопасной загрузки |
| HAL | Универсальный уровень аппаратной абстракции — ARM Cortex-M / RISC-V / AVR; выбор архитектуры на этапе компиляции, таблицы операций периферии |
| Архитектура | Примеры |
|---|---|
| ARM Cortex-M (M0/M0+/M3/M4/M7) | STM32, nRF52, Raspberry Pi Pico |
| RISC-V (RV32I) | ESP32-C3 |
| AVR (экспериментально) | ATmega |
sudo apt-get install -y gcc-arm-none-eabi binutils-arm-none-eabi
sudo apt-get install -y qemu-system
Проверьте установку:```bash
arm-none-eabi-gcc --version # 10.x or later
qemu-system-arm --version # 6.x or later
make
make ARCH=cortex-m0 # Cortex-M0/M0+ make ARCH=cortex-m7 # Cortex-M7 make ARCH=riscv32 # RISC-V RV32I (uses riscv32-unknown-elf-gcc) make ARCH=avr5 # AVR ATmega (uses avr-gcc)
make EXAMPLE=blink_led # LED blink + task scheduler demo make EXAMPLE=event_groups # Event group AND/OR/NOT/SYNC demo make EXAMPLE=iot_sensor # Multi-sensor IoT node make EXAMPLE=shell_demo # Interactive UART shell make EXAMPLE=mqtt_demo # MQTT publish/subscribe make EXAMPLE=condition_variable # Producer/consumer
make example-blink make example-events make example-shell make example-mqtt make example-iot
make size # Print ROM/RAM usage
Build artifacts are placed in `build/`:
| File | Описание |
|---|---|
| `build/tinyos.elf` | ELF-образ с отладочными символами |
| `build/tinyos.bin` | Сырой бинарный файл для прошивки |
| `build/tinyos.map` | Карта компоновщика (размеры символов) |
### Запуск на QEMU
TinyOS работает на QEMU-цели `mps2-an385` (ARM Cortex-M3, 4 МБ флеш-памяти, 4 МБ ОЗУ):```bash
# Run indefinitely (Ctrl-A X to quit)
qemu-system-arm \
-machine mps2-an385 \
-cpu cortex-m3 \
-nographic \
-kernel build/tinyos.elf
# Run for a fixed duration (e.g. 10 seconds)
timeout 10 qemu-system-arm \
-machine mps2-an385 \
-cpu cortex-m3 \
-nographic \
-kernel build/tinyos.elf
# Debug: trace interrupts
qemu-system-arm \
-machine mps2-an385 \
-cpu cortex-m3 \
-nographic \
-d int \
-kernel build/tinyos.elf
Ожидаемый вывод из трассировки прерываний: повторяющиеся строки successful exception return подтверждают, что планировщик работает, SysTick тикает, и переключения контекста PendSV выполняются корректно.
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg
-c "program build/tinyos.bin verify reset exit 0x08000000"
pyocd flash --target cortex_m build/tinyos.bin
### Сборка с TLS (mbedTLS)
Поддержка TLS включается автоматически, когда mbedTLS находится в `~/mbedtls`.
Чтобы использовать другой путь:```bash
# Clone and build mbedTLS
git clone https://github.com/Mbed-TLS/mbedtls ~/mbedtls
make -C ~/mbedtls
# Build TinyOS with TLS
make MBEDTLS_DIR=~/mbedtls
Минимальный пример задачи:```c #include "tinyos.h"
void my_task(void param) { while (1) { / work */ os_task_delay_ms(100); } }
int main(void) { tcb_t task; os_init(); os_task_create(&task, "my_task", my_task, NULL, PRIORITY_NORMAL); os_start(); }
---
## Обзор API
### Управление задачами```c
os_task_create(tcb, name, entry, param, priority)
os_task_delete(task)
os_task_suspend(task) / os_task_resume(task)
os_task_delay(ticks) / os_task_delay_ms(ms)
os_task_set_priority(task, priority)
os_task_get_stats(task, stats)
os_task_get_stats_by_index(index, stats) /* iterate all tasks by index */
os_task_find_by_name(name) /* returns tcb_t*, NULL if not found */
os_get_system_stats(stats)
os_get_memory_stats(&free, &used, &allocs, &frees)
os_mutex_init(mutex) / os_mutex_lock(mutex, timeout) / os_mutex_unlock(mutex) os_semaphore_init(sem, count) / os_semaphore_wait(sem, timeout) / os_semaphore_post(sem) os_cond_init(cond) / os_cond_wait(cond, mutex, timeout) os_cond_signal(cond) / os_cond_broadcast(cond) os_event_group_set_bits(eg, bits) / os_event_group_wait_bits(eg, bits, opts, out, timeout) os_queue_init(q, buf, item_size, max) / os_queue_send(q, item, timeout) os_queue_receive(q, item, timeout) / os_queue_peek(q, item, timeout)
### Таймеры```c
os_timer_create(timer, name, type, period_ms, callback, param)
os_timer_start(timer) / os_timer_stop(timer) / os_timer_reset(timer)
os_timer_change_period(timer, ms) / os_timer_get_remaining_ms(timer)
/* Register custom commands before calling shell_start() */ shell_register_cmd(name, handler_fn, help_text)
/* Provide UART I/O callbacks and start the shell task */ shell_io_t io = { .getc = uart_getc, .puts = uart_puts }; shell_start(&io)
/* Change the prompt at any time */ shell_set_prompt("mydevice> ")
/* Execute a single line programmatically */ shell_exec(line)
**Пример пользовательской команды:**```c
static int cmd_led(int argc, char *argv[]) {
if (argc < 2) return 1; /* non-zero → prints usage */
bool on = (strcmp(argv[1], "on") == 0);
gpio_write(LED_PIN, on);
return 0;
}
/* In main(), before shell_start(): */
shell_register_cmd("led", cmd_led, "led <on|off> Toggle LED");
Привязки клавиш редактора строки:
Конфигурация оболочки (include/tinyos/shell.h):```c
#define SHELL_MAX_COMMANDS 32 /* max registered commands /
#define SHELL_LINE_MAX 128 / max input line length (bytes) /
#define SHELL_ARGV_MAX 16 / max arguments per command /
#define SHELL_HISTORY_DEPTH 8 / command history entries */
### Сеть```c
net_init(driver, config) / net_start()
net_socket(type) / net_bind(sock, addr) / net_connect(sock, addr, timeout_ms)
net_send(sock, data, len, timeout_ms) / net_recv(sock, buf, len, timeout_ms)
net_sendto(sock, data, len, addr) / net_recvfrom(sock, buf, len, addr)
net_close(sock)
net_ping(dest_ip, timeout_ms, rtt)
net_dns_resolve(hostname, ip, timeout_ms)
net_http_get(url, response, timeout_ms)
net_http_post(url, content_type, body, len, response, timeout_ms)
TinyOS предоставляет два тонких уровня совместимости, которые позволяют компилировать и запускать стандартный переносимый код на TinyOS с минимальными изменениями.
include/tinyos/posix_threads.h)Добавьте src/posix/posix_threads.c в свою сборку.```c
#include "tinyos/posix_threads.h"
/* ── Thread ── / pthread_t tid; pthread_attr_t attr; pthread_attr_init(&attr); tinyos_pthread_attr_setpriority(&attr, PRIORITY_NORMAL); / TinyOS extension / pthread_create(&tid, &attr, my_fn, arg); pthread_join(tid, &retval); pthread_detach(tid); / free resources automatically on exit / pthread_exit(retval); / terminate calling thread / pthread_self(); / handle of calling thread */
/* ── Mutex ── / pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mtx); pthread_mutex_trylock(&mtx); / returns EBUSY if already locked */ pthread_mutex_unlock(&mtx);
/* ── Condition variable ── / pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_cond_wait(&cond, &mtx); pthread_cond_timedwait(&cond, &mtx, &abstime); / abstime relative to boot */ pthread_cond_signal(&cond); pthread_cond_broadcast(&cond);
| Понятие | Сопоставляется с |
|---|---|
| `pthread_t` | Индекс во внутреннем пуле слотов TinyOS `tcb_t` |
| `pthread_mutex_t` | Встраивает `mutex_t` напрямую (валидна инициализация нулём / `PTHREAD_MUTEX_INITIALIZER`) |
| `pthread_cond_t` | Встраивает `cond_var_t` напрямую (валидна инициализация нулём / `PTHREAD_COND_INITIALIZER`) |
| `pthread_join` | Ожидает поточный `semaphore_t`, установленный `pthread_exit` |
**Не поддерживается:** `pthread_cancel`, поточно-локальное хранилище (`pthread_key_*`),
рекурсивные мьютексы (возвращает `ENOTSUP`).
**Конфигурация** (`include/tinyos/posix_threads.h`):```c
#define PTHREAD_MAX_THREADS MAX_TASKS /* max concurrent pthreads */
include/tinyos/posix_socket.h)Добавьте src/posix/posix_socket.c в вашу сборку.```c
#include "tinyos/posix_socket.h"
/* ── TCP server ── */ int srv = socket(AF_INET, SOCK_STREAM, 0);
int reuse = 1; setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(8080), .sin_addr = { htonl(INADDR_ANY) }, }; bind(srv, (struct sockaddr *)&addr, sizeof(addr)); listen(srv, 4);
struct sockaddr_in peer; socklen_t plen = sizeof(peer); int client = accept(srv, (struct sockaddr )&peer, &plen); recv(client, buf, sizeof(buf), 0); send(client, response, response_len, 0); posix_sock_close(client); / or define TINYOS_POSIX_WRAP_CLOSE to use close() */ posix_sock_close(srv);
/* ── TCP client ── */ int fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in dest = { .sin_family = AF_INET, .sin_port = htons(80), .sin_addr = { inet_addr("192.168.1.1") }, }; connect(fd, (struct sockaddr *)&dest, sizeof(dest)); send(fd, request, request_len, 0); recv(fd, buf, sizeof(buf), 0); posix_sock_close(fd);
/* ── UDP ── */ int udp = socket(AF_INET, SOCK_DGRAM, 0); sendto(udp, data, len, 0, (struct sockaddr *)&dest, sizeof(dest)); recvfrom(udp, buf, sizeof(buf), 0, (struct sockaddr *)&src, &srclen); posix_sock_close(udp);
/* ── Address utilities ── / htons(port) / htonl(addr) / ntohs(n) / ntohl(n) inet_addr("192.168.1.1") / → in_addr_t, network byte order / inet_ntoa(in) / → "192.168.1.1" (static buffer) */ inet_pton(AF_INET, "192.168.1.1", &in_addr) inet_ntop(AF_INET, &in_addr, buf, sizeof(buf))
| BSD call | Mapped to |
|---|---|
| `socket()` | `net_socket()` |
| `bind()` | `net_bind()` |
| `listen()` | `net_listen()` |
| `accept()` | `net_accept()` |
| `connect()` | `net_connect()` |
| `send()` / `recv()` | `net_send()` / `net_recv()` |
| `sendto()` / `recvfrom()` | `net_sendto()` / `net_recvfrom()` |
| `posix_sock_close()` | `net_close()` |
**Поддерживаемые опции `setsockopt`:**
| Опция | Эффект |
|---|---|
| `SO_REUSEADDR` | Принято; бездействие (всегда повторно используемо в TinyOS) |
| `SO_RCVTIMEO` | Устанавливает таймаут приема на сокет (struct timeval → мс) |
| `SO_SNDTIMEO` | Устанавливает таймаут отправки/подключения на сокет |
**Перенаправление `close()`:** определите `TINYOS_POSIX_WRAP_CLOSE` перед включением заголовка для сопоставления `close(fd)` → `posix_sock_close(fd)`.
**Не поддерживается:** `select` / `poll` / `epoll`, неблокирующий режим (`O_NONBLOCK`), IPv6 (`AF_INET6` возвращает `EAFNOSUPPORT`).
---
### TLS / DTLS
TLS 1.2/1.3 через TCP и DTLS 1.2 через UDP на базе **mbedTLS**.
Включите во время сборки с помощью `-DTINYOS_TLS_ENABLE` и слинкуйтесь с mbedTLS.```c
/* Client (TLS over TCP) */
tls_context_t tls;
tls_config_t cfg = TLS_CONFIG_DEFAULT_CLIENT;
cfg.ca_cert = ca_cert_pem;
cfg.ca_cert_len = sizeof(ca_cert_pem);
tls_init(&tls, &cfg);
net_socket_t sock = net_socket(SOCK_STREAM);
net_connect(sock, &broker_addr, 5000);
tls_connect(&tls, sock, "example.com", 5000);
tls_send(&tls, data, len);
tls_recv(&tls, buf, sizeof(buf), 5000);
tls_close(&tls);
/* Server (TLS accept) */
tls_config_t srv_cfg = TLS_CONFIG_DEFAULT_SERVER;
srv_cfg.cert = server_cert_pem;
srv_cfg.cert_len = sizeof(server_cert_pem);
srv_cfg.key = server_key_pem;
srv_cfg.key_len = sizeof(server_key_pem);
tls_init(&tls, &srv_cfg);
tls_accept(&tls, client_sock, 5000);
/* DTLS over UDP */
tls_config_t dtls_cfg = TLS_CONFIG_DEFAULT_DTLS_CLIENT;
net_socket_t usock = net_socket(SOCK_DGRAM);
tls_connect_dtls(&tls, usock, "example.com", 5000);
Полный MQTT 3.1.1 с гарантиями доставки QoS для каждого сообщения.```c mqtt_config_t cfg = { .broker_host = "mqtt.example.com", .client_id = "tinyos-01", .keepalive_sec = 60, .clean_session = true, .auto_reconnect = true, .reconnect_interval_ms = 3000, /* base; doubles each attempt (max 60 s) */ }; mqtt_client_t client; mqtt_client_init(&client, &cfg); mqtt_set_connection_callback(&client, on_connect, NULL); mqtt_set_message_callback(&client, on_message, NULL); mqtt_connect(&client);
/* Publish — QoS1/2 are buffered offline if disconnected */ mqtt_publish(&client, "sensors/temp", "23.5", 4, MQTT_QOS_1, false);
/* Inspect reliability queues / uint8_t in_flight = mqtt_get_inflight_count(&client); / sent, awaiting ACK / uint8_t pending = mqtt_get_pending_count(&client); / queued while offline */
mqtt_subscribe(&client, "cmd/#", MQTT_QOS_1); mqtt_flush_pending(&client); /* discard offline queue */ mqtt_disconnect(&client);
#### Модель надежности MQTT```
QoS 0 ─── fire-and-forget; dropped if disconnected
QoS 1 ─── in-flight table tracks each PUBLISH until PUBACK
↳ retransmits with DUP=1 every 5 s, up to 5 times
↳ if offline → offline queue (up to 8 messages)
QoS 2 ─── full PUBLISH → PUBREC → PUBREL → PUBCOMP handshake
↳ each step is retried independently on timeout
Auto-reconnect back-off: 3 s → 6 s → 12 s → … → 60 s (cap)
On reconnect: re-subscribes all topics, flushes offline queue
Конфигурация надежности MQTT (include/tinyos/mqtt.h):```c
#define MQTT_MAX_INFLIGHT 8 /* in-flight slots /
#define MQTT_MAX_PENDING 8 / offline queue slots /
#define MQTT_MAX_PAYLOAD_SIZE 512 / bytes per queued msg /
#define MQTT_RETRY_INTERVAL_MS 5000 / retry after (ms) /
#define MQTT_MAX_RETRY_COUNT 5 / retries before drop /
#define MQTT_RECONNECT_BASE_MS 3000 / first reconnect delay /
#define MQTT_RECONNECT_MAX_MS 60000 / backoff ceiling */
### CoAP```c
coap_init(ctx, config, is_server) / coap_start(ctx) / coap_stop(ctx)
coap_get(ctx, ip, port, path, response, timeout_ms)
coap_post(ctx, ip, port, path, format, payload, len, response, timeout_ms)
coap_resource_create(ctx, path, handler, user_data)
coap_process(ctx, timeout_ms)
ota_init(config) ota_start_update(url, callback, user_data) ota_write_chunk(data, size, offset) / ota_finalize_update() ota_confirm_boot() / ota_rollback() ota_verify_partition(type)
### Файловая система```c
fs_format(device) / fs_mount(device) / fs_unmount()
fs_open(path, flags) / fs_close(fd)
fs_read(fd, buf, size) / fs_write(fd, buf, size)
fs_seek(fd, offset, whence) / fs_tell(fd)
fs_mkdir(path) / fs_remove(path) / fs_rmdir(path)
fs_stat(path, stat)
fs_opendir(path) / fs_readdir(dir, entry) / fs_closedir(dir)
fs_get_stats(stats) / fs_get_free_space() / fs_is_mounted()
/* Copy-on-Write snapshots */
fs_snapshot(source_path, snapshot_name) /* atomic COW snapshot of a file */
fs_get_block_refcount(block_nr) /* reference count of a data block */
Файловая система использует журналирование только метаданных (упорядоченный режим). Перед изменением любого inode, битовой карты или блока каталога запись журнала записывается в выделенную область WAL размером 32 блока в начале раздела. При следующем монтировании после сбоя fs_mount воспроизводит журнал и восстанавливает согласованное состояние.```
Disk layout (FS_BLOCK_SIZE = 512 bytes)
Block 0 Superblock (version 0x00020000 — v2 with journaling)
Block 1 Block bitmap
Block 2 Journal header
Blocks 3-33 Journal data (31 slots)
Blocks 34-41 Inode table (8 blocks, 128 inodes)
Block 42+ Data blocks
#### Copy-on-Write (COW)
Каждый блок данных содержит in-memory счетчик ссылок, восстанавливаемый из inode-таблицы при монтировании. Запись в блок, который является общим (`refcount > 1`), сначала выделяет приватную копию — счетчик исходного блока уменьшается, и все изменения происходят в новом блоке.
`fs_snapshot()` создает атомарный мгновенный снимок (snapshot) путем дублирования исходного inode (те же указатели на блоки, увеличенные счетчики ссылок) в рамках одной журнальной транзакции. Либо полный снимок фиксируется, либо ничего не меняется.```c
/* Create a snapshot of /data/config → /snapshots/config-20260101 */
fs_snapshot("/data/config", "/snapshots/config-20260101");
/* Inspect sharing */
uint8_t rc = fs_get_block_refcount(42); /* 1 = private, >1 = shared */
os_power_init() os_power_set_mode(mode) /* ACTIVE / IDLE / SLEEP / DEEP_SLEEP */ os_power_get_mode() os_power_enter_sleep(duration_ms) os_power_enter_deep_sleep(duration_ms) os_power_enable_tickless_idle(enable) os_power_set_cpu_frequency(freq_hz) os_power_configure_wakeup(source, enable) os_power_get_stats(stats) os_power_get_consumption_mw() os_power_estimate_battery_life_hours()
### Сторожевой таймер```c
wdt_init(config) / wdt_start() / wdt_stop()
wdt_feed() / wdt_set_timeout(ms)
wdt_register_task(task, timeout_ms) / wdt_feed_task(task)
TinyOS предоставляет общий уровень HAL, который скрывает весь доступ к регистрам, специфичным для архитектуры, за стабильным интерфейсом на C. Архитектура выбирается на этапе компиляции с помощью переменной Makefile ARCH; в коде ядра не встречаются ограждения #ifdef.
static inline в каждом заголовочном файле архитектуры)```cuint32_t hal_irq_save(void) /* disable IRQs, return saved state / void hal_irq_restore(uint32_t s) / restore IRQ state / void hal_context_switch_trigger() / pend PendSV / raise MSIP / Timer0 / void hal_cpu_wait_for_interrupt() / WFI / wfi / sleep instruction / void hal_cpu_dsb(void) / data synchronization barrier / void hal_cpu_isb(void) / instruction synchronization barrier */
#### Non-inline функции (реализованы для каждой архитектуры в `hal/<arch>/hal_<arch>.c`)```c
void hal_init(void)
void hal_tick_init(uint32_t core_clock_hz, uint32_t tick_rate_hz)
void hal_tick_suppress(uint32_t max_ticks)
uint32_t hal_tick_unsuppress(void)
uint32_t hal_core_clock_hz(void)
bool hal_cycle_counter_init(void)
void hal_cycle_counter_reset(void)
uint32_t hal_cycle_counter_read(void)
bool hal_mpu_init(uint8_t *region_count)
int hal_mpu_configure_region(uint8_t region, uint32_t base,
uint32_t size, uint32_t attrs)
void hal_mpu_enable(bool allow_privileged_default)
void hal_mpu_disable(void)
void hal_irq_set_priority(int irq_num, uint8_t priority)
void hal_system_reset(void) /* does not return */
void hal_fault_capture(const uint32_t *frame, hal_fault_info_t *info)
Регистрируйте периферийные устройства платы один раз при запуске; ядро и менеджер питания запрашивают таблицу через hal_platform_get() вместо использования слабых символов.```c
static const hal_uart_ops_t my_uart = { .init = ..., .putc = ... };
static const hal_power_ops_t my_power = { .enter_sleep = ...,
.set_clock_hz = ... };
static const hal_platform_t board = { .uart[0] = &my_uart, .power = &my_power, };
hal_platform_register(&board); /* call before os_start() */
`hal_platform_t` предоставляет слоты для `uart[4]`, `flash`, `gpio`, `spi[4]`,
`i2c[4]`, и `power`. Любой указатель `NULL` означает "не присутствует на этой плате".
#### Матрица поддержки архитектур
| Архитектура | Источник тактов | Счётчик циклов | MPU / PMP | Триггер переключения контекста |
|---|---|---|---|---|
| Cortex-M0/M0+/M3/M4/M7 | SysTick | DWT CYCCNT (M3+) | MPU | PendSV via ICSR |
| RISC-V RV32I/IM | CLINT MTIMECMP | `rdcycle` CSR | PMP (4 regions) | MSIP software interrupt |
| AVR ATmega/ATtiny | Timer0 CTC | — (returns 0) | — | Timer0 overflow |
---
## Конфигурация
**`include/tinyos.h`** — ядро и ОС:```c
#define MAX_TASKS 16 /* max concurrent tasks */
#define STACK_SIZE 256 /* stack size per task (words) */
#define TICK_RATE_HZ 1000 /* scheduler tick frequency (Hz) */
#define TIME_SLICE_MS 10 /* round-robin time slice (ms) */
#define TICKLESS_MAX_SLEEP_TICKS 100U /* tickless idle: max ticks per WFI sleep */
include/tinyos/shell.h — интерактивная оболочка:```c
#define SHELL_MAX_COMMANDS 32 /* max registered commands /
#define SHELL_LINE_MAX 128 / max input line length (bytes) /
#define SHELL_ARGV_MAX 16 / max arguments per command /
#define SHELL_HISTORY_DEPTH 8 / command history ring buffer */
**`include/tinyos/mqtt.h`** — надежность MQTT:```c
#define MQTT_MAX_INFLIGHT 8 /* in-flight QoS1/2 slots */
#define MQTT_MAX_PENDING 8 /* offline queue slots */
#define MQTT_MAX_PAYLOAD_SIZE 512 /* max queued payload bytes */
#define MQTT_RETRY_INTERVAL_MS 5000 /* unACKed retry interval */
#define MQTT_MAX_RETRY_COUNT 5 /* retries before discard */
#define MQTT_RECONNECT_BASE_MS 3000 /* initial reconnect delay */
#define MQTT_RECONNECT_MAX_MS 60000 /* back-off ceiling */
TLS — требуется mbedTLS; включите с помощью:```makefile CFLAGS += -DTINYOS_TLS_ENABLE LDFLAGS += -lmbedtls -lmbedcrypto -lmbedx509
## Структура проекта```
tinyos-rtos/
├── include/
│ ├── tinyos.h # Core API (tasks, sync, timers, memory, FS, power)
│ └── tinyos/
│ ├── shell.h # Interactive shell API & configuration
│ ├── net.h # Network stack
│ ├── tls.h # TLS 1.2/1.3 + DTLS 1.2 (mbedTLS)
│ ├── mqtt.h # MQTT 3.1.1 client
│ ├── coap.h # CoAP RFC 7252
│ ├── ota.h # OTA firmware updates
│ ├── watchdog.h # Watchdog timer
│ ├── posix_threads.h # POSIX pthreads compatibility layer
│ └── posix_socket.h # BSD socket compatibility layer
├── src/
│ ├── startup.s # Vector table, Reset_Handler, SysTick/SVC/PendSV stubs
│ ├── context_switch.s # Thumb-2: PendSV_Handler, SVC_Handler, os_pend_sv
│ ├── kernel.c # Preemptive scheduler & task management
│ ├── sync.c # Mutex, semaphore, queue, condition var, event groups
│ ├── timer.c # Software timers
│ ├── memory.c # Heap allocator
│ ├── shell.c # Interactive shell (VT100, history, tab completion)
│ ├── filesystem.c # Block-device file system
│ ├── security.c # MPU memory protection
│ ├── power.c # Power management & CPU frequency scaling
│ ├── watchdog.c # Watchdog (HW + SW, per-task monitoring)
│ ├── bootloader.c # Secure bootloader
│ ├── ota.c # OTA A/B partition updates
│ ├── mqtt.c # MQTT client (in-flight table, offline queue)
│ ├── coap.c # CoAP client/server
│ ├── net/
│ │ ├── network.c # Core & buffer management
│ │ ├── ethernet.c # Ethernet / ARP
│ │ ├── ip.c # IPv4 / ICMP
│ │ ├── socket.c # UDP / TCP socket API
│ │ ├── http_dns.c # HTTP client & DNS resolver
│ │ └── tls.c # TLS/DTLS (mbedTLS wrapper, excluded when mbedTLS absent)
│ └── posix/
│ ├── posix_threads.c # pthreads → TinyOS task/sync wrapper
│ └── posix_socket.c # BSD socket → net_* wrapper
├── hal/
│ ├── hal.h # Portable HAL interface (arch-agnostic API + peripheral op-tables)
│ ├── cortex_m/
│ │ ├── hal_cortex_m.h # Register defines + static inline primitives (irq_save, WFI, DSB …)
│ │ └── hal_cortex_m.c # SysTick, DWT, MPU, AIRCR reset, fault capture
│ ├── riscv/
│ │ ├── hal_riscv.h # csrrci/csrw inline primitives, CLINT defines
│ │ └── hal_riscv.c # CLINT tick, rdcycle counter, PMP, PLIC priority, CSR fault capture
│ └── avr/
│ ├── hal_avr.h # SREG-based irq_save, Timer0 context-switch trigger
│ └── hal_avr.c # Timer0 CTC tick, watchdog reset, stub MPU/cycle-counter
├── drivers/
│ ├── flash.c / flash.h # Flash memory driver
│ ├── ramdisk.c / ramdisk.h # RAM disk (testing)
│ └── loopback_net.c # Loopback network driver (testing)
├── linker.ld # Linker script (mps2-an385: Flash 0x0/4MB, RAM 0x20000000/4MB)
└── examples/
├── blink_led.c # GPIO blink
├── iot_sensor.c # Multi-task sensor node
├── shell_demo.c # Custom shell commands over UART
├── network_demo.c # TCP/UDP/HTTP/ping
├── tls_demo.c # TLS client/server
├── mqtt_demo.c # MQTT publish/subscribe (QoS 1/2)
├── coap_demo.c # CoAP client/server
├── ota_demo.c # Firmware update flow
├── filesystem_demo.c # File I/O
├── watchdog_demo.c # Watchdog configuration
├── low_power.c # Power mode transitions
├── software_timers.c # Timer creation and callbacks
├── event_groups.c # Event synchronisation
├── event_flags_logic.c # AND / OR / NOT(CLEAR) / SYNC(barrier) patterns
├── condition_variable.c # Producer/consumer
├── priority_adjustment.c # Dynamic priority
├── task_statistics.c # CPU and stack monitoring
└── posix_compat_demo.c # POSIX pthreads + socket usage examples
| Архитектура | Переключение контекста |
|---|---|
| Cortex-M0 | ~2 мкс |
| Cortex-M4 | ~1 мкс |
| RISC-V | ~1.5 мкс |
Системные требования: минимум 2 КБ ОЗУ · < 10 КБ ПЗУ для одного ядра
Новые возможности
Журналируемая файловая система (src/filesystem.c) — журнал упреждающей записи (WAL) защищает
все записи метаданных (inodes, битовая карта, суперблок, каталоги).
Формат на диске увеличен до FS_VERSION 0x00020000. Журнал занимает 32 блока,
начиная с блока 2; fs_mount воспроизводит все зафиксированные, но не применённые транзакции,
прежде чем передать управление приложению. Журналирование только метаданных (упорядоченное)
обеспечивает низкую амплитуду записи, гарантируя согласованность файловой системы после
сбоя питания или сброса в любой момент записи.
Совместное использование блоков с копированием при записи (src/filesystem.c) — каждый блок данных
содержит счётчик ссылок в памяти (восстанавливается из таблицы inodes при монтировании).
Запись в совместно используемый блок незаметно выделяет приватную копию; счётчик ссылок
исходного блока уменьшается. fs_snapshot(source, name) создаёт атомарный
снимок на момент времени в рамках одной транзакции журнала — либо всё, либо ничего
фиксируется. Новый публичный API: fs_snapshot() и
fs_get_block_refcount() (см. include/tinyos.h).
Универсальный уровень аппаратной абстракции (HAL) (hal/) — двухуровневый слой HAL отделяет
ядро от специфики ARM Cortex-M.
Критические изменения
src/kernel.c больше не содержит голых определений регистров SYST_*, SCB_SHPR3, SCB_AIRCR или
DWT_* — теперь они предоставляются HAL. Код, напрямую ссылавшийся на эти макросы,
необходимо обновить для использования API HAL.src/power.c (platform_enter_sleep_mode и т.д.) теперь делегируют
вызов hal_platform_t->power, когда платформа зарегистрирована; платы, полагавшиеся на
стандартное __asm__ volatile("wfi"), увидят идентичное поведение, если не зарегистрирован
hal_power_ops_t.0x00020000. Тома, отформатированные в v1.x,
необходимо переформатировать (fs_format).Исправления ошибок
startup.s — MemManage_Handler, BusFault_Handler и UsageFault_Handler теперь указывают на корректные обработчики в fault.c.Default_Handler, поэтому ошибки MPU, шины и использования беззвучно проглатывались вместо запуска диагностического дампа.os_cond_wait — cond_remove_task() уже уменьшает waiting_count; три места вызова, которые уменьшали его повторно, исправлены.os_mutex_lock теперь вызывает mutex_pip_recalculate() перед возвратом OS_ERROR_TIMEOUT.
Ранее буст приоритета, применённый к владельцу, никогда не отменялся, когда ожидающая задача отказывалась от ожидания, что приводило к постоянному повышению приоритета.Улучшения
src/memory.c) — фиксированный пул блоков по 32 байта заменён на аллокатор first-fit со следующими особенностями:
os_free() (вперёд и назад)BLK_HDR + ALIGN)os_init() — os_mem_init() и os_power_init() теперь вызываются до os_timer_init(), чтобы куча и подсистема питания были готовы до выполнения любых callback-ов таймера или кода задач.src/kernel.c: os_kernel_tickless_sleep) — при включении через os_power_enable_tickless_idle(true) задача простоя отключает SysTick перед WFI и использует счётчик циклов DWT CYCCNT для измерения фактического прошедшего времени.
После пробуждения SysTick перезапускается, увеличивается на измеренные тики (с ограничением ), и вызывается для немедленного разблокирования просроченных задач.
Ранее флаг существовал, но путь простоя всегда выполнял простой с работающим SysTick.Новые возможности
EVENT_WAIT_CLEAR для групп событий — ожидание, пока биты станут равны 0 (условие NOT).EVENT_WAIT_ALL | EVENT_WAIT_CLEAR пробуждается, когда все маскированные биты равны 0; EVENT_WAIT_ANY | EVENT_WAIT_CLEAR — когда любой из них равен 0.os_event_group_sync() — примитив рандеву / барьер.examples/event_flags_logic.c, демонстрирующий все четыре режима (AND, OR, NOT, SYNC).Исправления сборки и времени выполнения
src/startup.s: таблица векторов, Reset_Handler (копирование .data, обнуление .bss), заглушка SysTick_Handler, HardFault_Handler.linker.ld: расположение памяти для mps2-an385 (Flash 0x00000000 / 4 МБ, RAM 0x20000000 / 4 МБ).LDMIA {R4-R11} в PendSV корректно работал при первом переключении контекста на любую вновь созданную задачу.SVC_Handler обновлён на использование LDMIA {R4-R11} перед установкой PSP, что делает пути SVC и PendSV симметричными.MPU_TYPE в os_mpu_configure_default() — настройка MPU беззвучно пропускается, если MPU отсутствует (QEMU ).Лицензия MIT — подробности см. в файле LICENSE.
| Команда | Описание |
|---|
help [cmd] | Вывести список всех команд или подробную справку по cmd |
clear | Очистить экран терминала (VT100) |
echo <text> | Вывести текст на терминал |
history | Показать историю команд |
ps | Список всех задач (состояние, приоритет, загрузка ЦП, использование стека) |
top | Список задач, отсортированный по загрузке ЦП, по убыванию |
kill <name> [suspend|resume|delete] | Управление задачей по имени |
mem | Статистика кучи (всего / использовано / свободно, количество выделений/освобождений) |
ver | Версия TinyOS и отформатированное время работы |
net | Сетевая статистика (счётчики Ethernet, IP, UDP, TCP) |
ping <ip> [count] | Отправить ICMP-запросы эхо |
ifconfig [ip|netmask|gw|dns <addr>] | Показать или изменить сетевую конфигурацию |
power [active|idle|sleep|deepsleep] | Статистика энергопотребления или смена режима |
ls [path] | Вывести содержимое каталога (по умолчанию: /) |
cat <file> | Вывести содержимое файла |
mkdir <path> | Создать каталог |
rm <path> | Удалить файл или пустой каталог |
df | Статистика использования файловой системы |
touch <file> | Создать пустой файл |
cp <src> <dst> | Копировать файл |
uptime | Показать время работы системы (ЧЧ:ММ:СС или N дн., ЧЧ:ММ:СС) |
sleep <ms> | Задержка задачи оболочки на N миллисекунд |
reboot | Перезагрузить систему |
| Клавиша | Действие |
|---|
← / Ctrl-B | Переместить курсор влево |
→ / Ctrl-F | Переместить курсор вправо |
Home / Ctrl-A | Перейти к началу строки |
End / Ctrl-E | Перейти в конец строки |
↑ / ↓ | Навигация по истории команд |
Tab | Дополнить имя команды |
Ctrl-K | Удалить до конца строки |
Ctrl-U | Удалить до начала строки |
Ctrl-W | Удалить предыдущее слово |
Ctrl-L | Очистить экран и перерисовать |
Ctrl-C | Отменить текущую строку |
| Компонент | ПЗУ | ОЗУ |
|---|
| Ядро | 6 КБ | 512 Б |
| На задачу | — | ~1 КБ |
| Мьютекс | — | 12 Б |
| Семафор | — | 8 Б |
| Очередь сообщений (10 элементов) | — | 40 Б + данные |
| Оболочка (с 23 встроенными командами) | ~4 КБ | ~2.5 КБ |
| MQTT-клиент (с очередями) | ~8 КБ | ~10 КБ |
| Слой POSIX-потоков | ~2 КБ | ~PTHREAD_MAX_THREADS × (tcb_t + 32 Б) |
| Слой POSIX-сокетов | ~1 КБ | ~NET_MAX_SOCKETS × 12 Б |
hal/hal.h — архитектурно-независимый интерфейс: тик, счётчик циклов, MPU,
сохранение/восстановление IRQ, триггер переключения контекста, сброс системы,
захват ошибок и таблицы операций периферии (hal_platform_t с прорезями для
UART / flash / GPIO / SPI / I²C / питания).hal/cortex_m/ — полноценная реализация для Cortex-M0–M7 (SysTick, DWT, AIRCR,
PRIMASK, PendSV).hal/riscv/ — заглушка для RISC-V RV32 (тик CLINT MTIMECMP, счётчик rdcycle,
PMP, приоритет PLIC, захват ошибок CSR).hal/avr/ — заглушка для AVR ATmega (тик Timer0 CTC, критические секции SREG,
сброс сторожевого таймера).ARCH= (cortex-m* / riscv* / avr*)
и передаёт -DHAL_ARCH_* компилятору.kernel.tick_countTICKLESS_MAX_SLEEP_TICKSdelay_queue_tick()WFIMAX_TASKS — поднято с 8 до 16 для поддержки более реалистичных нагрузок IoT без модификации конфигурации пользователем.mps2-an385timer_t → os_timer_t во избежание конфликта с POSIX <sys/types.h>.-I. для включений из drivers/; источники TLS автоматически исключаются при отсутствии mbedTLS; добавлен -Wno-stringop-truncation для ложных предупреждений strncpy.coap.c, filesystem.c, mqtt.c, ota.c, security.c, net/ip.c, net/http_dns.c.