Модуль dev.h
Взаимодействие с ресурсами контроллера
#include <dev.h> предоставляет доступ к регистрам, входам, выходам, событиям, авариям и планировщику. Индексы начинаются с нуля. Физическое число каналов зависит от модели; текущие и предельные количества можно узнать через countGet() и /json?static → countAll. Константы COUNT_* в текущем заголовке содержат значения X0, поэтому для другой модели сверяйте их с устройством.
#ifndef __DEV_H
#define __DEV_H
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#ifndef NULL
#define NULL (0)
#endif
#define bitGet(v, n) ((v & (1 << (n))) ? 1 : 0)
#define bitOn(v, n) (v |= (1 << (n)))
#define bitOff(v, n) (v &= ~(1 << (n)))
#define bitInvert(v, n) (v ^= (1 << (n)))
#define bitSet(v, n, s) (s) ? bitOn(v, (n)) : bitOff(v, (n))
#define ADDR_ALARM (0x4002410C)
#define ADDR_REG (0x40024110)
#define ADDR_DO (0x40024190)
#define ADDR_DI (0x400241B0)
#define ADDR_AI (0x400241D0)
#define ADDR_AO (0x40024250)
#define ADDR_PWM (0x40024290)
#define COUNT_REG (32)
#define COUNT_DO (3)
#define COUNT_DI (5)
#define COUNT_AO (3)
#define COUNT_AI (3)
// Получение значения регистра без проверки (макрос)
#define regVal(n) (*(uint32_t *)(ADDR_REG + n*4))
// Получение значения регистра без проверки, по с приведением типа (макросы)
#define regValBool(n) (*(bool *)(ADDR_REG + n*4))
#define regValInt(n) (*(int32_t *)(ADDR_REG + n*4))
#define regValUint(n) (*(uint32_t *)(ADDR_REG + n*4))
#define regValFloat(n) (*(float *)(ADDR_REG + n*4))
#define regValEnum(n) (*(size_t *)(ADDR_REG + n*4))
#define doVal(n) (*(bool *)(ADDR_DO + n*1))
#define diVal(n) (*(bool *)(ADDR_DI + n*1))
#define aiVal(n) (*(float *)(ADDR_AI + (n)*4))
#define aoVal(n) (*(uint16_t *)(ADDR_AO + n*2))
#define doDutyVal(n) (*(uint16_t *)(ADDR_PWM + n*2))
#define alarmVal(n) bitGet(*(uint32_t *)ADDR_ALARM, n)
// Типы элементов для панели управления
typedef enum {
uiDefault = 0,
uiInput,
uiList,
uiRadio,
uiButton,
} uiType_t;
// Установка значения регистра без проверки типа
int regSet(uint8_t num, uint32_t value);
// Установка значения регистра с проверкой типа
int regSetBool(uint8_t num, bool value);
int regSetInt(uint8_t num, int32_t value);
int regSetUint(uint8_t num, uint32_t value);
int regSetFloat(uint8_t num, float value);
int regSetEnum(uint8_t num, uint8_t value);
// Получение значения регистра без проверки типа
int regGet(uint8_t num, uint32_t *value);
// Получение значения регистра с проверкой типа
int regGetBool(uint8_t num, bool *value);
int regGetInt(uint8_t num, int32_t *value);
int regGetUint(uint8_t num, uint32_t *value);
int regGetFloat(uint8_t num, float *value);
int regGetEnum(uint8_t num, uint8_t *value);
// Инкремент, декремент и инверсия значения регистра
int regInc(uint8_t num);
int regDec(uint8_t num);
int regToggle(uint8_t num);
// Базовая конфигурация пользовательского регистра
int regConf(const uint8_t num, const char *name, const char *access);
// Расширенная конфигурация для каждого типа
int regConfBool(const uint8_t num, bool defaultValue);
int regConfInt(uint8_t num, int32_t min, int32_t max, uint16_t step, uint8_t dec, int32_t defaultValue);
int regConfUint(uint8_t num, uint32_t min, uint32_t max, uint16_t step, uint8_t dec, uint32_t defaultValue);
int regConfFloat(uint8_t num, float min, float max, float step, uint8_t dec, float defaultValue);
int regConfEnum(uint8_t num, char *items, uint8_t defaultValue);
// Настройка элемента ввода на панели управления
int regConfUi(uint8_t num, uiType_t ui);
// do
int doSet(uint8_t num, bool value);
int doGet(uint8_t num, bool *value);
int doToggle(uint8_t num);
int doSetDuty(uint8_t num, uint16_t duty);
int doGetDuty(uint8_t num, uint16_t *duty);
int doConf(uint8_t num, char *name, char *access, uint16_t pwmPeriodSec);
// di
int diGet(uint8_t num, bool *value);
int diConf(uint8_t num, char *name, char *access, bool useNormalOpen);
// ao
int aoSet(uint8_t num, uint16_t value);
int aoGet(uint8_t num, uint16_t *value);
int aoInc(uint8_t num);
int aoDec(uint8_t num);
int aoConf(uint8_t num, char *name, char *access);
// ai
int aiGet(uint8_t num, float *value);
int aiConf(uint8_t num, char *name, char *access, int type);
// event
typedef enum {
eReasonNone,
eReasonError,
eReasonAuto,
eReasonUser,
eReasonOk,
eReasonAlgo,
eReasonTime,
eReasonWeb,
eReasonExt,
eReasonPu,
} eReason_t;
int eventConf(uint8_t num, char *name);
int eventAdd(uint8_t num, void *par1, void *par2, eReason_t *reason);
// alarm
int alarmConf(uint8_t num, char *name);
int alarmOn(uint8_t num, void *par1, void *par2, eReason_t *reason);
int alarmOff(uint8_t num);
int alarmGet(uint8_t num, bool *value);
// others functions
#define micros() ((*(volatile uint32_t *)0xE0001004) / 168)
typedef enum {
devDo = 0,
devDi,
devAo,
devAi,
devReg,
devEvent,
devAlarm
} devItem_t;
int countGet(const devItem_t item);
int countSet(const devItem_t item, const size_t count);
bool isChange(const devItem_t item, uint8_t num);
typedef int (*runFn_t)(uint32_t count);
int runAdd(runFn_t fn, uint32_t freq);
int runStart(void);
int run(runFn_t fn, uint32_t freq);
void webconf(bool display, bool reg, bool pin, bool console);
void sleep(uint32_t val);
#endif
Общие правила
Указатель результата getter должен указывать на переменную точно того типа, который указан в сигнатуре; NULL отклоняется с -3. При ошибке узкого getter выходная переменная не обновляется. Ошибки API выводятся в консоль и RAM-журнал /txt?log.
name — нуль-терминированное имя ресурса в UTF-8; NULL оставляет имя прежним. Строка access задаёт доступ веб-интерфейса первым символом и внешних служб вторым: - — закрыт, r — чтение, w — чтение и запись. Регистр букв не важен. Для одного символа меняется только веб-доступ. NULL оставляет оба режима прежними, пустая строка разрешает чтение и запись обоим. Например, "wr" разрешает запись из веб-интерфейса и только чтение внешним службам. Сценарий сам не ограничивается этими флагами.
Конфигурирующие функции меняют текущие настройки ресурса, но не выполняют отдельную команду сохранения настроек во flash. Вызов с ошибкой не гарантирует отката уже выполненных изменений: проверяйте параметры заранее и анализируйте код возврата.
Пользовательские регистры
Доступны 32 регистра, каждый хранит 32 бита. Активное количество задаётся countSet(devReg, count). Тип устанавливается функциями regConfBool/Int/Uint/Float/Enum; отдельного публичного regType_t в dev.h нет.
Для int/uint поле dec задаёт десятичный масштаб отображения: C getter/setter работает с хранимым целым без автоматического умножения или деления. Например, при dec=1 сырое значение 235 отображается как 23,5. Float передаётся непосредственно как float.
regSet
int regSet(uint8_t num, uint32_t value);
Передаёт 32-битное представление значения без проверки совпадения типа функции с типом регистра. Ограничения самого регистра проверяются. Возвращает 0 при успехе, в том числе если значение совпадало; -1 при неверном индексе (также возможен для неверного enum), -2 при нарушении числовых ограничений, -3 при неподдерживаемом типе. Для float используйте regSetFloat(), а не числовое приведение float к uint32_t.
regSetBool
int regSetBool(uint8_t num, bool value);
Записывает значение с проверкой типа регистра. Для enum передаётся индекс варианта, начиная с нуля. Возвращает 0 при успехе, -1 при несовпадении типа, -2 при неверном индексе регистра; ошибки проверки значения нижнего уровня также передаются вызывающему коду. Эти коды могут совпадать, поэтому при диагностике учитывайте тип и границы значения.
regSetInt
int regSetInt(uint8_t num, int32_t value);
Записывает значение с проверкой типа регистра. Для enum передаётся индекс варианта, начиная с нуля. Возвращает 0 при успехе, -1 при несовпадении типа, -2 при неверном индексе регистра; ошибки проверки значения нижнего уровня также передаются вызывающему коду. Эти коды могут совпадать, поэтому при диагностике учитывайте тип и границы значения.
regSetUint
int regSetUint(uint8_t num, uint32_t value);
Записывает значение с проверкой типа регистра. Для enum передаётся индекс варианта, начиная с нуля. Возвращает 0 при успехе, -1 при несовпадении типа, -2 при неверном индексе регистра; ошибки проверки значения нижнего уровня также передаются вызывающему коду. Эти коды могут совпадать, поэтому при диагностике учитывайте тип и границы значения.
regSetFloat
int regSetFloat(uint8_t num, float value);
Записывает значение с проверкой типа регистра. Для enum передаётся индекс варианта, начиная с нуля. Возвращает 0 при успехе, -1 при несовпадении типа, -2 при неверном индексе регистра; ошибки проверки значения нижнего уровня также передаются вызывающему коду. Эти коды могут совпадать, поэтому при диагностике учитывайте тип и границы значения.
regSetEnum
int regSetEnum(uint8_t num, uint8_t value);
Записывает значение с проверкой типа регистра. Для enum передаётся индекс варианта, начиная с нуля. Возвращает 0 при успехе, -1 при несовпадении типа, -2 при неверном индексе регистра; ошибки проверки значения нижнего уровня также передаются вызывающему коду. Эти коды могут совпадать, поэтому при диагностике учитывайте тип и границы значения.
regGet
int regGet(uint8_t num, uint32_t *value);
Читает сырые 32 бита. Возвращает 0, либо -1 для неверного индекса и -3 для NULL. Для float предпочтителен regGetFloat().
regGetBool
int regGetBool(uint8_t num, bool *value);
Читает значение в переменную соответствующего типа. Возвращает 0, -1 при несовпадении типа, -2 при неверном индексе и -3 для NULL. Enum возвращается как индекс варианта uint8_t.
regGetInt
int regGetInt(uint8_t num, int32_t *value);
Читает значение в переменную соответствующего типа. Возвращает 0, -1 при несовпадении типа, -2 при неверном индексе и -3 для NULL. Enum возвращается как индекс варианта uint8_t.
regGetUint
int regGetUint(uint8_t num, uint32_t *value);
Читает значение в переменную соответствующего типа. Возвращает 0, -1 при несовпадении типа, -2 при неверном индексе и -3 для NULL. Enum возвращается как индекс варианта uint8_t.
regGetFloat
int regGetFloat(uint8_t num, float *value);
Читает значение в переменную соответствующего типа. Возвращает 0, -1 при несовпадении типа, -2 при неверном индексе и -3 для NULL. Enum возвращается как индекс варианта uint8_t.
regGetEnum
int regGetEnum(uint8_t num, uint8_t *value);
Читает значение в переменную соответствующего типа. Возвращает 0, -1 при несовпадении типа, -2 при неверном индексе и -3 для NULL. Enum возвращается как индекс варианта uint8_t.
regVal
#define regVal(n) (*(uint32_t *)(ADDR_REG + n*4))
Прямое обращение к памяти без проверки индекса и конфигурации. Макрос может использоваться как lvalue, но такая запись обходит проверки диапазона. Предпочитайте проверяемые функции. regValEnum() в текущем заголовке обращается к size_t, то есть ко всем 32 битам регистра.
regValBool
#define regValBool(n) (*(bool *)(ADDR_REG + n*4))
Прямое обращение к памяти без проверки индекса и конфигурации. Макрос может использоваться как lvalue, но такая запись обходит проверки диапазона. Предпочитайте проверяемые функции. regValEnum() в текущем заголовке обращается к size_t, то есть ко всем 32 битам регистра.
regValInt
#define regValInt(n) (*(int32_t *)(ADDR_REG + n*4))
Прямое обращение к памяти без проверки индекса и конфигурации. Макрос может использоваться как lvalue, но такая запись обходит проверки диапазона. Предпочитайте проверяемые функции. regValEnum() в текущем заголовке обращается к size_t, то есть ко всем 32 битам регистра.
regValUint
#define regValUint(n) (*(uint32_t *)(ADDR_REG + n*4))
Прямое обращение к памяти без проверки индекса и конфигурации. Макрос может использоваться как lvalue, но такая запись обходит проверки диапазона. Предпочитайте проверяемые функции. regValEnum() в текущем заголовке обращается к size_t, то есть ко всем 32 битам регистра.
regValFloat
#define regValFloat(n) (*(float *)(ADDR_REG + n*4))
Прямое обращение к памяти без проверки индекса и конфигурации. Макрос может использоваться как lvalue, но такая запись обходит проверки диапазона. Предпочитайте проверяемые функции. regValEnum() в текущем заголовке обращается к size_t, то есть ко всем 32 битам регистра.
regValEnum
#define regValEnum(n) (*(size_t *)(ADDR_REG + n*4))
Прямое обращение к памяти без проверки индекса и конфигурации. Макрос может использоваться как lvalue, но такая запись обходит проверки диапазона. Предпочитайте проверяемые функции. regValEnum() в текущем заголовке обращается к size_t, то есть ко всем 32 битам регистра.
regInc
int regInc(uint8_t num);
Меняет числовой регистр на настроенный шаг; при выключенном шаге используется 1. Для enum шаг равен одному индексу. Bool отклоняется. Целочисленное переполнение и выход за границы не приводят к циклическому оборачиванию: возвращается ошибка. 0 — изменение, возможен 1 при совпадении результата, отрицательное значение — отказ.
regDec
int regDec(uint8_t num);
Меняет числовой регистр на настроенный шаг; при выключенном шаге используется 1. Для enum шаг равен одному индексу. Bool отклоняется. Целочисленное переполнение и выход за границы не приводят к циклическому оборачиванию: возвращается ошибка. 0 — изменение, возможен 1 при совпадении результата, отрицательное значение — отказ.
regToggle
int regToggle(uint8_t num);
Инвертирует младший бит сырых 32 бит (value ^= 1). Тип и min/max не проверяет; используйте для логического регистра. Это не арифметическое отрицание float и не переключение произвольного enum. 0 — успех, -1 — неверный индекс.
regConf
int regConf(const uint8_t num, const char *name, const char *access);
Задаёт имя и доступ, сохраняя тип. Аргумента типа здесь нет. 0 — успех; -1 — индекс, -2 — имя, -3 — access.
regConfBool
int regConfBool(const uint8_t num, bool defaultValue);
Выбирает тип bool. Если старое сырое значение не равно 0 или 1, заменяет его defaultValue. Допустимое старое значение сохраняется; default не присваивается безусловно. 0 — успех; -1 — индекс, -5 — недопустимый default.
regConfInt
int regConfInt(uint8_t num, int32_t min, int32_t max, uint16_t step, uint8_t dec, int32_t defaultValue);
Границы — полные int32_t. min == max отключает обе границы; при включённых границах требуется min < max. Шаг uint16_t: 0 выключает настроенный шаг, иначе шаг должен быть меньше max-min. dec допускается от 0 до 5. Default проверяется и записывается только если прежнее значение не подходит. 0 — успех; -1 — индекс, -2 — границы, -3 — шаг, -4 — dec, -5 — default.
regConfUint
int regConfUint(uint8_t num, uint32_t min, uint32_t max, uint16_t step, uint8_t dec, uint32_t defaultValue);
Аналог regConfInt с границами uint32_t. Диапазон до 4294967295; шаг по-прежнему uint16_t. В этой реализации код -4 используется и для неверного dec, и для недопустимого default; -1/-2/-3 означают индекс/границы/шаг.
regConfFloat
int regConfFloat(uint8_t num, float min, float max, float step, uint8_t dec, float defaultValue);
Границы, шаг и default передаются как float; min == max отключает ограничения. step == 0 выключает настроенный шаг; задавайте положительный конечный шаг. Шаг хранится в компактном формате и может округляться. dec от 0 до 5 влияет на отображение. 0 — успех; -1/-2/-3/-4/-5 — индекс/границы/шаг/dec/default.
regConfEnum
int regConfEnum(uint8_t num, char *items, uint8_t defaultValue);
Варианты задаются одной нуль-терминированной строкой с разделителем ;, например "Off;On;Auto". Индексы — 0, 1, 2; завершающий ; не добавляйте. Используйте от 1 до 256 вариантов и не допускайте пустых элементов. Для хранения текста используется общий ограниченный пул имён. Default заменяет старое значение только при его недопустимости. 0 — успех; -1 — индекс, -2 — запись строки, -3 — пустая строка, -5 — default.
regConfUi
typedef enum {
uiDefault = 0,
uiInput,
uiList,
uiRadio,
uiButton,
} uiType_t;
int regConfUi(uint8_t num, uiType_t ui);
Выбирает элемент пользовательской панели, не меняя тип и значение. Имена констант: uiDefault, uiInput, uiList, uiRadio, uiButton. 0 — успех, -1 — индекс.
Пример конфигурации регистра
Пример меняет настройки регистра 0 и его значение.
#include <dev.h>
#include <stdio.h>
int main(void) {
if (countSet(devReg, 1) < 0) {return 1;}
if (regConf(0, "Temperature", "wr") < 0) {return 1;}
if (regConfInt(0, -400, 1000, 5, 1, 200) < 0) {return 1;}
if (regSetInt(0, 235) < 0) {return 1;}
int32_t raw;
if (regGetInt(0, &raw) < 0) {return 1;}
printf("Temperature: %.1f\n", (double)raw / 10.0);
return 0;
}
Дискретные выходы
Состояние Do передаётся как bool. PWM управляется отдельно: duty=0..1000 соответствует 0..100 %; физическое число PWM-каналов зависит от модели (X0: один, X1: пять). Это не число всех Do.
doConf
int doConf(uint8_t num, char *name, char *access, uint16_t pwmPeriodSec);
Имя, доступ и режим Do. pwmPeriodSec=0 выбирает обычный выход; ненулевое значение включает программный PWM с периодом в секундах. Применяйте PWM только на поддерживающих его каналах. Включает флаг en. 0 — успех; -1/-2/-3 — индекс/имя/access.
doSet
int doSet(uint8_t num, bool value);
Записывает логическое состояние активного Do. 0 — изменён, 1 — уже имел это значение, -1 — индекс, отрицательный код — отказ.
doGet
int doGet(uint8_t num, bool *value);
Читает bool. 0 — успех; -1 — физический индекс, -3 — NULL.
doToggle
int doToggle(uint8_t num);
Переключает состояние Do. 0 — успех, -1 — индекс. Для аппаратного управления состоянием предпочтителен doSet(): текущая реализация toggle меняет значение в памяти.
doSetDuty
int doSetDuty(uint8_t num, uint16_t duty);
Записывает заполнение PWM от 0 до 1000. 0 — изменён, 1 — уже совпадал, -1 — индекс PWM, -2 — диапазон, -3 — Do не настроен на PWM.
doGetDuty
int doGetDuty(uint8_t num, uint16_t *duty);
Читает заполнение в uint16_t. 0 — успех, -1 — индекс PWM, -3 — NULL.
doVal
#define doVal(n) (*(bool *)(ADDR_DO + n*1))
Читает память напрямую, без проверки индекса и без вызова аппаратного setter. Не используйте запись через макрос для управления выходом.
doDutyVal
#define doDutyVal(n) (*(uint16_t *)(ADDR_PWM + n*2))
Читает память напрямую, без проверки индекса и без вызова аппаратного setter. Не используйте запись через макрос для управления выходом.
Дискретные входы
diConf
int diConf(uint8_t num, char *name, char *access, bool useNormalOpen);
Задаёт имя, access и нормальное состояние входа (useNormalOpen записывается в конфигурацию). Включает en. 0 — успех, -1 — индекс; -2 используется и для ошибки имени, и для access. Поведение при физическом замыкании зависит от этой настройки.
diGet
int diGet(uint8_t num, bool *value);
Читает логическое состояние в bool. 0 — успех; -1 — физический индекс, -3 — NULL.
diVal
Макрос diVal(n) читает bool напрямую, без проверки физического индекса.
Аналоговые выходы
Ao хранит uint16_t от 0 до 1000: значение 1000 соответствует 10 В, 235 — 2,35 В. C API не выполняет автоматическое масштабирование.
aoConf
int aoConf(uint8_t num, char *name, char *access);
Задаёт имя и доступ, включает en. 0 — успех; -1/-2/-3 — индекс/имя/access.
aoSet
int aoSet(uint8_t num, uint16_t value);
Задаёт значение в сотых долях вольта. 0 — изменён, 1 — совпадал, -1 — индекс активного Ao, -3 — диапазон.
aoGet
int aoGet(uint8_t num, uint16_t *value);
Читает сырое значение в uint16_t. 0 — успех; -1 — физический индекс, -3 — NULL.
aoInc
int aoInc(uint8_t num);
Увеличивает сырое значение на 10, то есть на 0,1 В. 0 — успех, отрицательный код — индекс или диапазон.
aoDec
int aoDec(uint8_t num);
Уменьшает сырое значение на 10, то есть на 0,1 В. Выход за допустимый диапазон возвращает ошибку.
aoVal
Макрос aoVal(n) читает uint16_t из памяти. Для записи используйте aoSet(), чтобы проверить диапазон.
Аналоговые входы
Ai хранит и возвращает float (32 бита) в физических единицах: температура NTC10K — в °C, сопротивление — в омах, а поддерживаемый режим напряжения X1 — в вольтах. Например, 23.5f — 23,5 °C, а 10000.0f в режиме сопротивления — 10 кОм. Повторное деление результата на 10 или 100 не требуется.
При ошибке измерения значение — NaN. Это отличается от старого целочисленного формата: проверка на 32767 / 0x7FFF для aiGet() больше не применяется. Маркер 0x7FFF относится к целочисленному представлению внешних протоколов, а не к C API.
После обновления прошивки перекомпилируйте C-сценарии. Вызов нового aiGet() со старым указателем int16_t * недопустим: функция записывает четыре байта, поэтому такой вызов может повредить соседнюю память.
aiConf
int aiConf(uint8_t num, char *name, char *access, int type);
type=0 — сопротивление в омах, type=1 — температура NTC10K в °C. Имя и access имеют общую семантику; канал включается. 0 — успех; -1/-2/-3/-4 — индекс/имя/access/type.
На X1 предусмотрен отдельный режим напряжения (type=2), но его настройка пока не согласована со всеми способами проверки и сохранения конфигурации. Не считайте type=0 или type=1 режимом 0–10 В и перед использованием напряжения проверьте поддержку в вашей версии прошивки. Хотя функция принимает значения 0…5, варианты 3…5 не задают поддерживаемые дополнительные режимы измерения.
aiGet
int aiGet(uint8_t num, float *value);
Записывает float в переданную переменную. 0 — успешно прочитано; -1 — физический индекс, -3 — NULL. При отрицательном коде результат не использовать. Успех чтения API сам по себе не означает исправность датчика: затем проверьте isfinite(value) или isnan(value) из <math.h>.
#include <stdio.h>
#include <math.h>
#include <dev.h>
static int showTemperature(uint32_t count) {
(void)count;
float temperature;
int result = aiGet(0, &temperature);
if (result < 0) {
printf("Ai read error: %d\n", result);
return -1;
}
if (!isfinite(temperature)) {
puts("Sensor error");
return 0;
}
printf("Temperature: %.2f C\n", (double)temperature);
return 0;
}
int main(void) {
if (countSet(devAi, 1) < 0) {return 1;}
if (aiConf(0, "Temperature", "rr", 1) < 0) {return 1;}
return run(showTemperature, 1000);
}
aiVal
#define aiVal(n) (*(float *)(ADDR_AI + (n) * 4))
Прямое чтение float из памяти, четыре байта на канал, без проверки индекса. Для прикладного кода предпочтителен aiGet(). Адреса массивов зависят от формата данных прошивки: используйте заголовок, полученный вашим компилятором от контроллера, а не адреса из старого сценария. Запись через aiVal() не поддерживается.
События и аварии
Для Event и Alarm предварительно задайте активное количество через countSet(). Их номера независимы. События записываются в журнал; Alarm дополнительно имеет текущее состояние.
eventConf
int eventConf(uint8_t num, char *name);
Задаёт имя события. 0 — успех; -1 — индекс, -2 — имя.
eventAdd
int eventAdd(uint8_t num, void *par1, void *par2, eReason_t *reason);
par1/par2 — NULL или указатели на доступные 32-битные значения, а не сами числа. reason — NULL или указатель на eReason_t (eReasonNone, eReasonError, eReasonAuto, eReasonUser, eReasonOk, eReasonAlgo, eReasonTime, eReasonWeb, eReasonExt, eReasonPu). Не передавайте указатель на uint8_t/uint16_t вместо параметра. Записывает событие. 0 — успех; -1 — индекс, -3 — причина или журнал.
alarmOn
int alarmOn(uint8_t num, void *par1, void *par2, eReason_t *reason);
par1/par2 — NULL или указатели на доступные 32-битные значения, а не сами числа. reason — NULL или указатель на eReason_t (eReasonNone, eReasonError, eReasonAuto, eReasonUser, eReasonOk, eReasonAlgo, eReasonTime, eReasonWeb, eReasonExt, eReasonPu). Не передавайте указатель на uint8_t/uint16_t вместо параметра. Записывает аварийное событие и включает бит Alarm. 0 — успех; -1 — индекс, -3 — причина/журнал, -4 — установка состояния.
alarmConf
int alarmConf(uint8_t num, char *name);
Задаёт имя аварии. 0 — успех; -1 — индекс, -2 — имя.
alarmOff
int alarmOff(uint8_t num);
Сбрасывает бит Alarm, без отдельной записи события выключения в этой функции. 0 — успех, отрицательное значение — ошибка индекса или установки.
alarmGet
int alarmGet(uint8_t num, bool *value);
Читает текущее состояние в bool. 0 — успех, -1 — индекс, -3 — NULL.
alarmVal
Макрос alarmVal(n) извлекает бит из общей 32-битной маски Alarm без проверки номера. Это выражение чтения; для изменения используйте alarmOn()/alarmOff().
Количество ресурсов и изменения
Параметр devItem_t принимает devDo, devDi, devAo, devAi, devReg, devEvent или devAlarm. Отдельного значения для PWM в этом enum нет.
countSet
int countSet(const devItem_t item, const size_t count);
Задаёт активное количество от 0 до физического/логического предела. Для входов/выходов также меняет en у каналов. 0 — успех, -1 — неверный вид ресурса или превышение максимума. Уменьшение не является командой очистки старых значений.
countGet
int countGet(const devItem_t item);
Возвращает активное количество либо -1 при неизвестном виде ресурса. Для чтения физического предела используйте данные модели в /json?static.
isChange
bool isChange(const devItem_t item, uint8_t num);
Сравнивает значение с последним снимком: true — изменилось, false — не изменилось или произошла ошибка. Ошибка журналируется. Снимок обновляется при проверке; это не очередь всех произошедших изменений. Поддерживаются значения Do, Di, Ao, Ai и Reg. Alarm и Event в этой функции не поддерживаются и дают false с записью ошибки.
Планировщик и интерфейс
runFn_t — int (*)(uint32_t count). Callback вызываются последовательно в одной задаче; это не параллельные потоки. count начинается с нуля. Возврат -1 удаляет callback из расписания, любой другой результат оставляет его.
run
int run(runFn_t fn, uint32_t freq);
Регистрирует один callback и блокируется в runStart(). freq — период в миллисекундах от 1 до INT32_MAX; не частота в герцах. Вложенный запуск запрещён. Функция возвращается, когда callback удалены или запрошена внешняя остановка.
runAdd
int runAdd(runFn_t fn, uint32_t freq);
Добавляет callback в один из восьми слотов, но не запускает цикл. 0 — успех; -1 — NULL или нет свободного слота, -2 — период. Проверка периода и указателя выполняется до регистрации.
runStart
int runStart(void);
Начинает цикл зарегистрированных callback; первый вызов планируется через их период. Период отсчитывается от фактического начала предыдущего вызова, пропущенные периоды не воспроизводятся пачкой. Просроченные callback выбираются по величине просрочки; переполнение millis учитывается. Медленный callback задерживает остальные. 0 — цикл завершён, -1 — уже выполняется.
sleep
void sleep(uint32_t val);
Приостанавливает задачу сценария на заданное число миллисекунд (тиков в текущей конфигурации). При вызове из callback задерживает весь его планировщик.
webconf
void webconf(bool display, bool reg, bool pin, bool console);
Управляет видимостью блоков display/reg/pin/console в пользовательской панели. Не является настройкой прав доступа к самим значениям.
Время
Функции millis() и timePowerOff() объявлены в tools.h; подключайте его явно. micros() — макрос из dev.h.
millis
uint32_t millis(void) возвращает счётчик миллисекунд sysTime, который оборачивается через 2³² мс (около 49,7 суток). Интервалы вычисляйте как (uint32_t)(millis() - start), а не сравнением абсолютных дедлайнов.
micros
micros() читает DWT_CYCCNT и делит на 168. Это текущее значение 32-битного счётчика тактов, а не неограниченный uptime в микросекундах: при частоте 168 МГц оно скачком возвращается к нулю примерно через 25,6 с. Для измерения короткого интервала вычтите исходные значения clock() в uint32_t и затем разделите на 168.
timePowerOff
uint32_t timePowerOff(void) возвращает длительность предыдущего отключения в секундах. При отсутствии пригодной сохранённой метки возможен UINT32_MAX; это не время работы текущего сценария.
Битовые макросы
Все перечисленные макросы из dev.h используют выражение 1 << n. Передавайте простую целочисленную переменную и индекс в пределах её разрядности. Для старшего бита uint32_t предпочтительно явное 1U << n: знаковый литерал 1 в текущих макросах не даёт корректного общего контракта для n=31. Аргументы со сменой состояния и сложные выражения не используйте.
bitGet
#define bitGet(v, n) ((v & (1 << (n))) ? 1 : 0)
Возвращает 0 или 1 для выбранного бита.
bitOn
#define bitOn(v, n) (v |= (1 << (n)))
Устанавливает бит в переменной.
bitOff
#define bitOff(v, n) (v &= ~(1 << (n)))
Сбрасывает бит.
bitInvert
#define bitInvert(v, n) (v ^= (1 << (n)))
Инвертирует бит.
bitSet
#define bitSet(v, n, s) (s) ? bitOn(v, (n)) : bitOff(v, (n))
Устанавливает либо сбрасывает бит по истинности третьего аргумента.