Центр поддержки

Документация и инструменты для запуска fsm32

Начните с языка FSMC, подготовьте firmware для своей платы или безопасно посмотрите интерфейс IDE в изолированной песочнице.

01

Описывайте поведение устройства как конечный автомат

Справочник синтаксиса, типов, состояний, ожиданий и аппаратных входов/выходов.

Открыть справочник →
02

Загрузи образ для поддерживаемой платы

Профили C3, S3, ESP32 и LCD-панели, требования к ESP-IDF и различие firmware с пакетом логики.

Страница загрузок →
03

Посмотрите инженерный интерфейс без доступа к объекту

Изолированная песочница показывает путь от логики к симуляции и не отправляет команды на устройства.

Открыть песочницу →
04

Прошейте первую ESP32 и проверьте RGB LED

Пошаговый запуск Work-ноды: ESP-IDF, monitor, терминал и прямое управление встроенным светодиодом.

Начать Tutorial 1 →

FSMC: краткий справочник

FSMC — декларативный язык для описания конечных автоматов, исполняемых в fsm32. Он помогает выразить ожидаемые события, безопасные переходы и реакцию на таймауты.

1. Базовая идея

Программа описывает начальное состояние, условия перехода и действия на выходах. Логика выполняется циклически: система фиксирует входы, исполняет правила и обновляет выходы.

codename HomeLight;
#include <ESP32-C3-MINI.hw>

fsm LightControl : Button {
  initial state Idle : Button {
    if (Button == true) {
      STATE(Active);
    }
  }
}

2. Синтаксис языка (EBNF)

Ниже — основной синтаксис FSMC. Квадратные скобки означают необязательную часть, фигурные — повторение одного или нескольких элементов по правилам конструкции.

program ::= codename_decl include_directive*
            common_decl*
            in_services_block?
            unused_block?
            init_block?
            (fsm_decl | stateless_decl)+

codename_decl ::= "codename" identifier ";"
include_directive ::= "#include" "<" include_path ">"

fsm_decl ::= [ "unsafe" ] "fsm" identifier [ ":" trigger_list ] "{"
               { on_overflow_block | out_services_block | state_decl }
             "}"

state_decl ::= [ "initial" ] "state" identifier [ ":" watch_list ] "{"
                 { statement }
               "}"

Идентификатор начинается с буквы; далее допускаются буквы, цифры, _ и .. Однострочный комментарий начинается с //.

Типы
bool, int8, uint8, int16, uint16, int32, uint32, float, bit.
Операторы
=, ==, !=, <, >, <=, >=, !, &&, ||, +, -, *, /, %, <<, >>, &, |, ^, ~, =>.
Директивы
#include <File.hw> подключает аппаратный каталог; #hardware_profile Name задаётся только внутри .hw и должен совпадать с идентификатором профиля в firmware контроллера.

3. Каталог ключевых слов, операторов и функций

Все конструкции ниже реализованы в текущем профиле языка. Нажмите на название конструкции, чтобы перейти к отдельной теме с синтаксисом и многострочным примером.

Директивы и объявления
КонструкцияСинтаксисОписание
codenamecodename identifier;Задаёт имя программы.
#include#include <File.hw>Подключает аппаратный каталог .hw.
#hardware_profile#hardware_profile NameЗадаёт имя профиля в .hw; оно должно совпадать с профилем firmware.
in_services, inin_services { in type Name; }Объявляет программные входы узла.
out_services, outout_services { type Name; }В .fsmc объявляет программные выходы; в .hw out задаёт направление HW-сервиса.
commoncommon type Name;Создаёт общую переменную для автоматов программы.
unusedunused { Name; }Скрывает HW-сервис из Composer, но сохраняет его VM-слот.
initinit { Name = value; }Задаёт начальные присваивания до запуска автоматов.
Автоматы, состояния и управление выполнением
КонструкцияСинтаксисОписание
fsmfsm Name [: triggers] { ... }Объявляет конечный автомат с состояниями.
statelessstateless Name [: triggers] { ... }Объявляет реактивный блок без состояний и ожиданий.
initial state, state[initial] state Name [: watch] { ... }Описывает начальный или обычный режим; watch перезапускает тело при изменении сигнала.
STATESTATE(Name);Переходит в состояние и прерывает текущий scan.
STABILIZESTABILIZE;Прерывает текущий scan без смены состояния и локально фиксирует результат.
any, allfsm Name : any { ... }Эквивалентные указатели всех in-сервисов в trigger/watch-списке.
unsafeunsafe fsm Name { ... }Отключает проверки overflow/div0 и narrowing для конкретного блока.
ON_OverflowON_Overflow { statements }Обрабатывает overflow и деление либо остаток от деления на ноль.
Условия, циклы и ожидания
КонструкцияСинтаксисОписание
if, elseif (condition) { ... } [else { ... }]Выполняет ветвление по булеву условию.
while, dowhile (condition) { ... }Повторяет блок, пока условие истинно; do гарантирует первый проход.
forfor (init; condition; update) { ... }Задаёт инициализацию, условие и обновление цикла.
break, continuebreak; / continue;Завершает цикл либо начинает его следующую итерацию.
awaitawait(Signal => condition|any);Приостанавливает FSM до изменения сигнала либо выполнения условия.
waitforwaitfor(ms, Signal => condition|any, State);Ожидает условие с таймаутом; по таймауту переходит в указанный state.
sleepsleep(milliseconds);Приостанавливает FSM на интервал, квантуемый VM tick в 100 мс.
true, falseName = true;Булевы литералы.
Операторы и числовые функции
КонструкцияСинтаксисОписание
=identifier = expression;Присваивает значение сервису или переменной.
== != < > <= >=left operator rightСравнивает числовые выражения и возвращает bit.
! && ||!condition, A && BВыполняет логическое НЕ, И и ИЛИ.
+ - * / %A + B, A / BВыполняет арифметические операции; / возвращает float, % — только для целых.
<< >> & | ^ ~A << 1, A | BСдвиги и побитовые операции для unsigned-типов.
( )(numeric expression)Группирует числовое выражение и меняет приоритет.
CEILCEIL(number)Округляет значение вверх до целого.
FLOORFLOOR(number)Округляет значение вниз до целого.
ROUNDROUND(number)Округляет значение до ближайшего целого.

4. Темы и примеры использования

Каждая тема раскрывает конструкцию из каталога: имя, синтаксис, назначение и минимальный рабочий контекст.

codename и #include

Синтаксис: codename identifier;, #include <File.hw>.

Имя открывает программу, а директива подключает аппаратный каталог.

codename HomeLight;
#include <ESP32-C3-MINI.hw>

fsm Control { ... }

#hardware_profile и unused

Синтаксис: #hardware_profile Name, unused { Name; }.

Первое допустимо только в .hw и обязано совпадать с идентификатором профиля в firmware. Второе скрывает HW-сервис из System Composer, но не удаляет выделенный ему VM-слот.

#hardware_profile ESP32-C3-MINI
out bool StatusLed;
in bool BootButton;

// В .fsmc:
unused { StatusLed; }

in_services, out_services, common, init

Синтаксис: блоки сервисов, common type Name;, init { assignment; }.

Объявляют программные сигналы, общие данные и начальные значения. init выполняется один раз при запуске; common можно использовать в trigger/watch и ожиданиях.

common uint16 Attempts;
in_services { in bool Command; }
out_services { bool IsActive; }
init {
  Attempts = 0;
  IsActive = false;
}

fsm

Синтаксис: fsm Name [: trigger_list] { state... }.

Создаёт автомат с набором явно описанных состояний.

fsm LightControl : Button {
  initial state Idle {
    if (Button) { STATE(Active); }
  }
}

stateless

Синтаксис: stateless Name [: trigger_list] { statements }.

Подходит для реактивных правил без состояний и ожиданий.

stateless Mirror : any {
  IsActive = Command;
}

any и all

Синтаксис: fsm Name : any { ... } или state Name : Signal, Shared { ... }.

any и all эквивалентны: каждый означает маску всех in-сервисов и должен быть единственным элементом списка. Именованный список допускает конкретные in- и common-сервисы. У fsm это trigger, у state — watch; отсутствие списка запускает блок в каждом проходе стабилизации.

fsm Monitor : any {
  initial state Observe {
    IsActive = Command;
  }
}

unsafe

Синтаксис: unsafe fsm Name { ... }.

Отключает checked-ветки переполнения, деления на ноль и compile-time narrowing только для следующего fsm или stateless-блока.

unsafe fsm FastPath {
  initial state Run {
    Counter = Counter + 1;
  }
}

ON_Overflow

Синтаксис: ON_Overflow { statements }.

Задаёт единственный обработчик в теле fsm или stateless для арифметического overflow и деления либо остатка от деления на ноль. Без него VM фиксирует FAULT ArithmeticOverflow.

fsm Guard {
  ON_Overflow {
    Fault = true;
    STATE(Error);
  }
}

initial state и state

Синтаксис: [initial] state Name [: watch_list] { ... }.

initial выбирает точку старта; обычный state описывает режим. Изменение сигнала из watch-списка перезапускает тело текущего state.

initial state Idle : Button {
  Lamp = false;
}
state Active : Button {
  Lamp = true;
}

STATE

Синтаксис: STATE(StateName);.

Переходит к названному состоянию и прерывает текущий scan: код после команды не выполняется. Целевой state может начать выполнение в том же цикле VM.

if (Button == true) {
  STATE(Active);
}

STABILIZE

Синтаксис: STABILIZE;.

Прерывает текущий scan state без перехода в другое состояние и выполняет локальную фиксацию результата. Код после команды в этом scan не выполняется; повторный запуск зависит от масок активации.

Relay = Command;
STABILIZE;
Ready = Relay;

if и else

Синтаксис: if (condition) { ... } else { ... }.

Выбирает один из блоков по булеву условию.

if (Pressure >= Minimum) {
  Pump = true;
} else {
  Pump = false;
}

while и do ... while

Синтаксис: while (condition) { ... }, do { ... } while (condition);.

do выполняет тело хотя бы один раз.

do {
  Count = Count + 1;
} while (Count < 3);

for

Синтаксис: for (init; condition; update) { ... }.

Собирает счётчик, условие и изменение счётчика в одном заголовке.

for (Index = 0; Index < 3; Index = Index + 1) {
  Total = Total + Index;
}

break и continue

Синтаксис: break;, continue;.

Управляют выполнением текущего цикла.

while (Count < Limit) {
  if (Stop) { break; }
  Count = Count + 1;
  if (!Enabled) { continue; }
  Total = Total + Count;
}

await

Синтаксис: await(Signal => condition|any);.

Приостанавливает FSM в режиме Awaited. Signal — in- или common-сервис; => any ждёт его изменения, а выражение — выполнения условия.

await(Button => Button == true);
Lamp = true;
STATE(Active);

waitfor

Синтаксис: waitfor(timeout, Signal => condition|any, TimeoutState);.

Добавляет ограниченное по времени ожидание. Третий аргумент — имя state: при таймауте VM автоматически выполняет STATE(TimeoutState), а не записывает флаг в сервис.

waitfor(5000, Pressure => Pressure == true, Error);
Pump = true;

state Error {
  Alarm = true;
}

sleep

Синтаксис: sleep(milliseconds);.

Приостанавливает FSM на заданный интервал; длительность квантуется VM tick в 100 мс (округление вверх).

Lamp = true;
sleep(1000);
Lamp = false;

true и false

Синтаксис: булевы литералы в выражениях и присваиваниях.

Задают логическое значение.

Enabled = true;
if (Enabled == false) {
  STATE(Idle);
}

=

Синтаксис: identifier = expression;.

Присваивает вычисленный результат сервису либо переменной.

Setpoint = Target + Offset;
Ready = Pressure >= Minimum;

Операторы сравнения

Синтаксис: == != < > <= >=.

Сравнивают числовые операнды и возвращают bit, который можно использовать в условии. Для bool/bit используйте == true или == false.

if (Temperature >= Limit) {
  Alarm = true;
}
if (Mode != PreviousMode) {
  Changed = true;
}

Логические операторы

Синтаксис: !condition, A && B, A || B.

Комбинируют булевы условия.

if (!Fault && Enabled) {
  Pump = true;
}
if (Stop || Timeout) {
  STATE(Error);
}

Арифметические операторы

Синтаксис: + - * / %.

Выполняют вычисления над числовыми значениями. Деление всегда возвращает float; остаток % допустим только для целых. В checked-блоке overflow и деление на ноль передаются в ON_Overflow.

Average = Sum / Count;
Remainder = Total % 10;
Scaled = Raw * Factor + Offset;

Сдвиги и побитовые операторы

Синтаксис: << >> & | ^ ~.

Работают только с беззнаковыми типами.

Mask = Mask << 1;
Flags = (Flags | 1) & 255;
Inverted = ~Flags;

( ) в числовых выражениях

Синтаксис: (numeric_expression).

Меняют порядок вычислений.

Scaled = (Raw + Offset) * Factor;
// Без скобок: Raw + (Offset * Factor)

CEIL

Синтаксис: CEIL(number).

Округляет число вверх.

Required = CEIL(Voltage);
if (Required > Limit) {
  Alarm = true;
}

FLOOR

Синтаксис: FLOOR(number).

Округляет число вниз.

LowerBound = FLOOR(Voltage);
Status = LowerBound >= Minimum;

ROUND

Синтаксис: ROUND(number).

Округляет число до ближайшего целого.

DisplayValue = ROUND(Voltage);
Output = DisplayValue * Scale;

4. Структура программы и объявления

codename
Имя программы или узла.
#include <Profile.hw>
Подключает каталог аппаратных сервисов выбранного профиля платы.
in_services / out_services
Объявляют логические входы и выходы.
fsm
Объявляет конечный автомат с набором состояний.

5. Состояния и переходы

state задаёт режим работы. Переход выполняется через STATE, когда выполнено условие.

state Active : Button {
  Lamp = true
  if (Button == false) {
    STATE(Idle);
  }
}

Такой подход подходит для освещения, блокировок, сценариев насосов и других процессов, где допустимые режимы важнее набора несвязанных команд.

6. Автоматы, trigger/watch и защита вычислений

После имени fsm или state можно задать список сигналов через двоеточие. У fsm это trigger, у state — watch: изменение элемента списка активирует автомат или перезапускает состояние. В списке допустимы in- и common-сервисы; без списка блок запускается в каждом проходе стабилизации. any и all эквивалентны, означают все in-сервисы и не совмещаются с именованными элементами.

common uint16 Attempts;

fsm Guard : Button, Pressure {
  ON_Overflow {
    STATE(Error);
  }

  initial state Idle : Button {
    if (Button == true) {
      Attempts = Attempts + 1;
      STATE(CheckPressure);
    }
  }
}

stateless подходит для простого реактивного преобразования сигналов. В нём недоступны STATE, STABILIZE, await, waitfor и sleep. Используйте unsafe только если осознанно отключаете для блока checked-ветки overflow/div0 и compile-time narrowing.

7. Управляющие конструкции

Условия и циклы используют круглые скобки для условия, а фигурные — для тела блока. break и continue применяются внутри циклов.

for (Index = 0; Index < 3; Index = Index + 1) {
  if (!Enabled) {
    break;
  }

  if (Index == 1) {
    continue;
  }

  Total = Total + Index;
}

Циклы выполняются в рамках логики автомата; не используйте их как замену ожиданию внешнего события. Для событий и задержек применяйте await, waitfor и sleep.

8. Ожидания и таймеры

await(Signal => condition|any)
Приостанавливает FSM, ожидая выполнения условия либо изменения in/common-сервиса.
waitfor(timeout, Signal => condition|any, TimeoutState)
Ожидает условие с контролируемым таймаутом и при истечении автоматически переходит в указанный state.
sleep(milliseconds)
Приостанавливает FSM; время квантуется VM tick в 100 мс и округляется вверх.
ON_Overflow
Определяет реакцию на арифметический overflow, деление и остаток от деления на ноль.
waitfor(5000, Pressure => Pressure == true, Error);
Pump = true;

state Error {
  Alarm = true;
}

9. Выражения и операторы

Арифметика, сравнения и логические операторы образуют выражения в присваиваниях и условиях. Скобки меняют порядок числовых вычислений. Побитовые операции &, |, ^, ~ и сдвиги <<, >> допустимы только для беззнаковых типов.

Scaled = (Raw + Offset) * Scale;
Flags = (Flags | 1) & 255;

if ((Pressure >= Minimum) && !Fault) {
  Ready = true;
}

Приоритет: скобки и унарные операции → умножение/деление/остаток → сдвиги → сложение/вычитание → побитовые операции → сравнения → && → ||.

10. Числовые функции

Встроенные функции преобразования чисел принимают числовой фактор и возвращают целочисленный результат. Они используются, когда данные с плавающей точкой нужно привести к дискретному значению.

WholeUp = CEIL(Reading);
WholeDown = FLOOR(Reading);
Nearest = ROUND(Reading);
CEIL(x)
Округляет x вверх.
FLOOR(x)
Округляет x вниз.
ROUND(x)
Округляет x до ближайшего целого.

11. Аппаратные профили

Файл .hw описывает доступные возможности конкретной платы. Он отделяет прикладную логику от распиновки и делает один сценарий переносимым между согласованными профилями.

Важно: FSMC управляет логикой устройства; пакет .fsmb не является прошивкой ESP-IDF. Firmware и пакет логики обновляются разными процессами.

12. Следующий шаг

Для полного синтаксиса и всех конструкций используйте исходную спецификацию в репозитории. Перед работой с физическими платами соберите firmware для нужного профиля.