Модуль dev.h
Взаимодействие с ресурсами контроллера
Модуль dev.h предоставляет программный интерфейс для взаимодействия с ресурсами контроллера, конфигурацию пользовательской панели управления и вспомагательные функции.
Пользовательские регистры
Пользовательский регистр — это энергонезависимая область памяти контроллера, предназначенная для хранения значений определенного типа (bool, int, uint, float, enum). Регистры доступны для чтения и записи через пользовательские сценарии, веб-интерфейс или внешние службы (например, по протоколам Modbus, SNMP).
Всего в контроллере доступно 32 пользовательских регистра с нумерацией от 0 до 31. Количество доступных регистров можно ограничить с помощью функции countSet. Значения всех регистров хранятся в памяти контроллера в 32-битном формате.
Для работы с регистрами реализованы следующие функции и макросы:
// Типы элементов для панели управления
typedef enum {
uiTypeDefault = 0, // Элемент по умолчанию
uiTypeInput, // Поле ввода
uiTypeList, // Раскрывающийся список
uiTypeRadio, // Радиокнопка
uiTypeButton, // Кнопка или набор кнопок
} uiType_t;
// Тип данных регистра (не указан в исходном коде, предполагается)
typedef enum {
regTypeBool = 0,
regTypeInt,
regTypeUint,
regTypeFloat,
regTypeEnum
} regType_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);
// Получение значения регистра без проверки (макрос)
#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) (*(uint8_t *)(ADDR_REG + n * 4))
// Инкремент, декремент и инверсия значения регистра
int regInc(uint8_t num);
int regDec(uint8_t num);
int regToggle(uint8_t num);
// Базовая конфигурация пользовательского регистра
int regConf(uint8_t num, char *name, char *access, regType_t type);
// Расширенная конфигурация для каждого типа
int regConfBool(uint8_t num, bool defaultValue);
int regConfInt(uint8_t num, int16_t min, int16_t max, uint16_t step, uint8_t dec, int32_t defaultValue);
int regConfUint(uint8_t num, uint16_t min, uint16_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);
regSet
Функция int regSet(uint8_t num, uint32_t value) устанавливают значение пользовательского регистра без проверки типа. Устанавливаемое значение должно быть преобразовано к типу uint32_t.
Для регистров с типов
floatобразование небоходимо выполнять через указательregSet(0, *(uint32_t *)&valF).
Параметры:
num— номер регистра (0–31).value— новое значение регистра.
Возвращаемые значения:
1— текущее значение регистра совпадает с переданным.0— значение успешно установлено.-1— ошибка: неверный номер регистра.-2— ошибка: значение выходит за допустимый диапазон.-3— ошибка: внутренняя ошибка при установке значения.
regSetBool, regSetInt, regSetUint, regSetFloat, regSetEnum
Функции regSetBool, regSetInt, regSetUint, regSetFloat, regSetEnum устанавливают значение пользовательского регистра указанного типа.
Параметры и возвращаемые значения идентичны regSet.
Для типа
enumзначениеvalueдолжно соответствовать индексу элемента, заданного при конфигурации черезregConfEnum.
regGet
Функция int regGet(uint8_t num, uint32_t *value) получают значение пользовательского регистра без проверки типа в формате uint32_t.
Для регистров с типов
floatобразование небоходимо выполнять через указательregGet(0, (uint32_t *)&valF).
Параметры:
num— номер регистра (0–31).value— указатель на переменную, в которую будет записано значение регистра.
Возвращаемые значения:
0— значение успешно получено.-1— ошибка: неверный номер регистра.-3— ошибка: внутренняя ошибка при получении значения.
regGetBool, regGetInt, regGetUint, regGetFloat, regGetEnum
Функции regGetBool, regGetInt, regGetUint, regGetFloat, regGetEnum получают значение пользовательского регистра указанного типа с проверкой.
Параметры и возвращаемые значения идентичны regGet.
regVal
Макросы regVal, возвращают значение регистра в формате uint32_t без проверки корректности номера регистра или типа данных.
Параметры:
n— номер регистра (0–31).
Возвращаемое значение:
- Значение регистра с приведением к соответствующему типу.
Примечание: Использование макросов без проверки может привести к неопределенному поведению, если регистр не был корректно сконфигурирован или его номер неверен.
regValBool, regValInt, regValUint, regValFloat, regValEnum
Макросы regValBool, regValInt, regValUint, regValFloat, regValEnum возвращают значение регистра указанного типа без проверки корректности номера регистра или типа данных.
Пример использования:
#include <stdio.h>
#include <stdint.h>
#include <dev.h>
int main(void) {
const uint8_t num = 0;
// Установка значения регистра
int res = regSetUint(num, 123);
printf("regSetUint res: %d\n", res); // Ожидается: 0 (успех)
// Попытка установки значения для неверного номера регистра
res = regSetUint(32, 123);
printf("regSetUint res: %d\n", res); // Ожидается: -1 (ошибка)
// Получение значения регистра
uint32_t value;
res = regGetUint(num, &value);
printf("regGetUint res: %d, value: %u\n", res, value); // Ожидается: res: 0, value: 123
// Получение значения через макрос
value = regValUint(num);
printf("regValUint value: %u\n", value); // Ожидается: value: 123
return 0;
}
regInc
regDec
Функции regInc и regDec увеличивают или уменьшают значение регистра на заданный в конфигурации шаг.
Параметры:
num— номер регистра (0–31).
Возвращаемые значения:
0— значение успешно изменено.-1— ошибка: неверный номер регистра.-2— ошибка: недопустимый тип регистра (например,bool).-3— ошибка: внутренняя ошибка.
Примечание: Для типов bool и enum функции regInc и regDec не применимы и возвращают ошибку -2.
regToggle
Функция regToggle инвертирует значение регистра типа bool.
Параметры:
num— номер регистра (0–31).
Возвращаемые значения:
0— значение успешно инвертировано.-1— ошибка: неверный номер регистра.-2— ошибка: регистр не имеет типаbool.-3— ошибка: внутренняя ошибка.
regConf
Функция int regConf(uint8_t num, char *name, char *access) выполняет базовую конфигурацию пользовательского регистра.
Параметры:
num— номер регистра (0–31).name— строковое имя регистра, отображаемое в веб-интерфейсе (максимальная длина — 32 символа, включая завершающий нуль).access— строка, определяющая уровни доступа к регистру:-— доступ запрещен.r— только чтение.w— чтение и запись.- Формат: первый символ задает доступ для веб-интерфейса и REST API, второй (опционально) — для внешних служб (Modbus, SNMP).
Возвращаемые значения:
0— конфигурация успешна.-1— ошибка: неверный номер регистра.-2— ошибка: неверный формат строкиname(например, слишком длинная или пустая).-3— ошибка: неверный тип регистра.-4— ошибка: неверный формат строкиaccess.
Тип регистра задается функциями regConfBool, regConfInt, regConfInt, regConfFloat и regConfEnum.
regConfBool
Функция int regConfBool(uint8_t num, bool defaultValue) конфигурирует регистр как тип bool и задает значение по умолчанию.
Параметры:
num— номер регистра (0–31).defaultValue— значение по умолчанию (trueилиfalse).
Возвращаемые значения:
0— конфигурация успешна.-1— ошибка: неверный номер регистра.
regConfInt
Функция int regConfInt(uint8_t num, int16_t min, int16_t max, uint16_t step, uint8_t dec, int32_t defaultValue) конфигурирует регистр как тип int и задает параметры, специфичные для этого типа.
Параметры:
num— номер регистра (0–31).min— минимальное допустимое значение.max— максимальное допустимое значение.step— шаг изменения значения (не равен нулю).dec— количество знаков после запятой для отображения в веб-интерфейсе (0 — отключено).defaultValue— значение по умолчанию, должно быть в диапазоне[min, max].
Примечание:
- Если
minравноmax, ограничения на минимальное и максимальное значения отсутствуют. - Параметр
decпозволяет представлять целое значение в веб-интерфейсе как вещественное. Например, приdec = 2значение2555отображается как25.55. - Параметры
min,maxиstepтакже интерпретируются с учетомdec.
Возвращаемые значения:
0— конфигурация успешна.-1— ошибка: неверный номер регистра.-2— ошибка: неверный диапазон (min > max).-3— ошибка: неверный шаг (step = 0).-4— ошибка: недопустимое значениеdec.-5— ошибка:defaultValueвне диапазона[min, max].
regConfInt
Функция int regConfUint(uint8_t num, uint16_t min, uint16_t max, uint16_t step, uint8_t dec, uint32_t defaultValue) конфигурирует регистр как тип uint и задает параметры, аналогичные regConfInt.
Параметры и возвращаемые значения: Идентичны regConfInt.
regConfFloat
Функция int regConfFloat(uint8_t num, float min, float max, float step, uint8_t dec, float defaultValue) конфигурирует регистр как тип float и задает параметры, специфичные для этого типа.
Параметры:
num— номер регистра (0–31).min— минимальное допустимое значение.max— максимальное допустимое значение.step— шаг изменения значения (не равен нулю).dec— количество знаков после запятой для округления значения в веб-интерфейсе.defaultValue— значение по умолчанию, должно быть в диапазоне[min, max].
Возвращаемые значения: Идентичны regConfInt.
regConfEnum
Функция int regConfEnum(uint8_t num, char *items, uint8_t defaultValue) конфигурирует регистр как тип enum и задает параметры, специфичные для этого типа.
Параметры:
num— номер регистра (0–31).items— строка, содержащая элементы списка, разделенные символом;. Например:"Off;Low;High".defaultValue— значение по умолчанию (индекс элемента в спискеitems).
Примечание: Если текущее значение регистра при конфигурации превышает количество элементов в items, используется defaultValue.
Возвращаемые значения:
0— конфигурация успешна.-1— ошибка: неверный номер регистра.-2— ошибка: неверный формат строкиitems(например, пустая строка или неверный разделитель).-5— ошибка:defaultValueпревышает количество элементов вitems.
Пример использования:
#include <stdio.h>
#include <dev.h>
#define REG 0
int main(void) {
// Конфигурация регистра как enum с тремя значениями
int res = regConf(REG, "Mode", "rw");
res = regConfEnum(REG, "Off;Low;High", 0);
printf("regConfEnum res: %d\n", res); // Ожидается: 0 (успех)
// Установка значения
res = regSetEnum(REG, 1);
printf("regSetEnum res: %d\n", res); // Ожидается: 0 (успех)
// Получение значения
uint8_t value;
res = regGetEnum(REG, &value);
printf("regGetEnum res: %d, value: %u\n", res, value); // Ожидается: res: 0, value: 1 (Low)
return 0;
}
regConfUi
Функция int regConfUi(uint8_t num, uiType_t ui) задает тип элемента управления для регистра в веб-интерфейсе.
Параметры:
num— номер регистра (0–31).ui— тип элемента управления (uiTypeDefault,uiTypeInput,uiTypeList,uiTypeRadio,uiTypeButton).
Примечание: Не все типы элементов управления совместимы с типами регистров. Например, uiTypeButton не применим к регистрам типа float.
Возвращаемые значения:
0— конфигурация успешна.-1— ошибка: неверный номер регистра.-2— ошибка: неверный тип элемента управления.-3— ошибка: тип элемента управления несовместим с типом регистра.
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
// Ограничение количества регистров
int res = countSet(10);
printf("countSet res: %d\n", res); // Ожидается: 0 (успех)
// Получение количества регистров
int count = countGet();
printf("countGet count: %d\n", count); // Ожидается: 10
// Конфигурация регистра #0 как bool с элементом управления "переключатель"
res = regConf(0, "Switch", "rw", regTypeBool);
res = regConfBool(0, false);
res = regConfUi(0, uiTypeDefault);
printf("regConfUi res: %d\n", res); // Ожидается: 0 (успех)
// Конфигурация регистра #1 как enum с элементом управления "список"
res = regConf(1, "Mode", "rw", regTypeEnum);
res = regConfEnum(1, "Off;Low;High", 0);
res = regConfUi(1, uiTypeList);
printf("regConfUi res: %d\n", res); // Ожидается: 0 (успех)
return 0;
}
Цифровые выходы
Цифровые выходы контроллера нумеруются с 0. Значение (состояние) цифрового выхода имеет тип bool (true — высокий уровень, false — низкий уровень).
Цифровой выход может быть сконфигурирован в режиме широтно-импульсной модуляции (ШИМ), реализованной на уровне прерываний микроконтроллера. В этом режиме доступно управление скважностью ШИМ (duty), выраженной в процентах с множителем 10 (диапазон 0–1000, где 1000 соответствует 100%).
Для работы с цифровыми выходами реализованы следующие функции и макросы:
// Конфигурация цифрового выхода
int doConf(uint8_t num, char *name, char *access, uint16_t pwmPeriodSec);
// Установка значения цифрового выхода
int doSet(uint8_t num, bool value);
// Получение значения цифрового выхода с проверкой
int doGet(uint8_t num, bool *value);
// Получение значения цифрового выхода без проверки
#define doVal(n) (*(bool *)(ADDR_DO + n * 1))
// Инверсия значения цифрового выхода
int doToggle(uint8_t num);
// Установка скважности ШИМ (для выходов в режиме ШИМ)
int doSetDuty(uint8_t num, uint16_t duty);
// Получение скважности ШИМ с проверкой (для выходов в режиме ШИМ)
int doGetDuty(uint8_t num, uint16_t *duty);
// Получение скважности ШИМ без проверки
#define doDutyVal(n) (*(uint16_t *)(ADDR_DO_DUTY + n * 2))
doConf
Функция int doConf(uint8_t num, char *name, char *access, uint16_t pwmPeriodSec) выполняет конфигурацию цифрового выхода.
Параметры:
num— номер цифрового выхода (0 и выше, в зависимости от количества доступных выходов).name— строковое имя выхода, отображаемое в веб-интерфейсе (максимальная длина — 32 символа, включая завершающий нуль).access— строка, определяющая уровни доступа:-— доступ запрещен.r— только чтение.w— чтение и запись.- Формат: первый символ задает доступ для веб-интерфейса и REST API, второй (опционально) — для внешних служб (Modbus RTU, Modbus TCP, SNMP). Если строка
NULL, уровни доступа не изменяются.
pwmPeriodSec— период ШИМ в секундах (0 — ШИМ отключен).
Возвращаемые значения:
0— выход успешно сконфигурирован.-1— ошибка: неверный номер выхода.-2— ошибка: неверное или слишком длинное имяname.-3— ошибка: неверный формат строкиaccess.-4— ошибка: неверное значениеpwmPeriodSec.
doSet
Функция int doSet(uint8_t num, bool value) устанавливает значение цифрового выхода.
Параметры:
num— номер цифрового выхода.value— новое состояние выхода (true— высокий уровень,false— низкий уровень).
Возвращаемые значения:
1— текущее значение выхода совпадает с переданным.0— значение успешно установлено.-1— ошибка: неверный номер выхода.-3— внутренняя ошибка при установке значения.
doGet
Функция int doGet(uint8_t num, bool *value) получает значение цифрового выхода с проверкой.
Параметры:
num— номер цифрового выхода.value— указатель на переменную, в которую будет записано значение.
Возвращаемые значения:
0— значение успешно получено.-1— ошибка: неверный номер выхода.-3— внутренняя ошибка при получении значения.
doVal
Макрос doVal(n) возвращает значение цифрового выхода без проверки.
Параметры:
n— номер цифрового выхода.
Возвращаемое значение:
- Значение выхода типа
bool.
Примечание: Использование макроса без проверки корректности номера выхода может привести к неопределенному поведению.
doToggle
Функция int doToggle(uint8_t num) инвертирует значение цифрового выхода.
Параметры:
num— номер цифрового выхода.
Возвращаемые значения:
0— значение успешно инвертировано.-1— ошибка: неверный номер выхода.-3— внутренняя ошибка.
doSetDuty
Функция int doSetDuty(uint8_t num, uint16_t duty) устанавливает скважность ШИМ для выхода в режиме ШИМ.
Параметры:
num— номер цифрового выхода.duty— скважность в процентах с множителем 10 (диапазон 0–1000, где 1000 = 100%).
Возвращаемые значения:
0— значение успешно установлено.-1— ошибка: неверный номер выхода.-2— ошибка:dutyвне диапазона [0, 1000].-3— ошибка: выход не сконфигурирован в режиме ШИМ.
doGetDuty
Функция int doGetDuty(uint8_t num, uint16_t *duty) получает значение скважности ШИМ с проверкой.
Параметры:
num— номер цифрового выхода.duty— указатель на переменную, в которую будет записано значение скважности.
Возвращаемые значения:
0— значение успешно получено.-1— ошибка: неверный номер выхода.-3— ошибка: выход не сконфигурирован в режиме ШИМ.
doDutyVal
Макрос doDutyVal(n) возвращает значение скважности ШИМ без проверки.
Параметры:
n— номер цифрового выхода.
Возвращаемое значение:
- Значение скважности типа
uint16_t.
Примечание: Использование макроса без проверки может привести к неопределенному поведению, если выход не в режиме ШИМ.
Пример использования:
#include <stdio.h>
#include <stdbool.h>
#include <dev.h>
int main(void) {
const uint8_t num = 0;
// Конфигурация цифрового выхода с ШИМ (период 2 секунды)
int res = doConf(num, "PWM Output", "rw", 2);
printf("doConf res: %d\n", res); // Ожидается: 0
// Установка скважности 50%
res = doSetDuty(num, 500);
printf("doSetDuty res: %d\n", res); // Ожидается: 0
// Установка значения выхода
res = doSet(num, true);
printf("doSet res: %d\n", res); // Ожидается: 0
// Получение значения выхода
bool value;
res = doGet(num, &value);
printf("doGet res: %d, value: %s\n", res, value ? "true" : "false"); // Ожидается: res: 0, value: true
// Инверсия значения
res = doToggle(num);
printf("doToggle res: %d\n", res); // Ожидается: 0
// Получение значения через макрос
value = doVal(num);
printf("doVal value: %s\n", value ? "true" : "false"); // Ожидается: value: false
// Получение скважности
uint16_t duty;
res = doGetDuty(num, &duty);
printf("doGetDuty res: %d, duty: %u.%u%%\n", res, duty / 10, duty % 10); // Ожидается: res: 0, duty: 50.0%
return 0;
}
Цифровые входы
Цифровые входы контроллера нумеруются с 0. Значение (состояние) цифрового входа имеет тип bool и доступно только для чтения. Вход может быть сконфигурирован как:
- Нормально открытый (НО):
true, если вход разомкнут (высокий уровень). - Нормально закрытый (НЗ):
false, если вход замкнут (низкий уровень).
Для работы с цифровыми входами реализованы следующие функции и макросы:
// Конфигурация цифрового входа
int diConf(uint8_t num, char *name, char *access, bool useNormalOpen);
// Получение значения цифрового входа с проверкой
int diGet(uint8_t num, bool *value);
// Получение значения цифрового входа без проверки
#define diVal(n) (*(bool *)(ADDR_DI + n * 1))
diConf
Функция int diConf(uint8_t num, char *name, char *access, bool useNormalOpen) выполняет конфигурацию цифрового входа.
Параметры:
num— номер цифрового входа (0 и выше, в зависимости от количества доступных входов).name— строковое имя входа, отображаемое в веб-интерфейсе (максимальная длина — 32 символа, включая завершающий нуль).access— строка, определяющая уровни доступа:-— доступ запрещен.r— только чтение.- Формат: первый символ задает доступ для веб-интерфейса и REST API, второй (опционально) — для внешних служб (Modbus RTU, Modbus TCP, SNMP). Если строка
NULL, уровни доступа не изменяются.
useNormalOpen— режим входа:true— нормально открытый (НО),false— нормально закрытый (НЗ).
Возвращаемые значения:
0— вход успешно сконфигурирован.-1— ошибка: неверный номер входа.-2— ошибка: неверное или слишком длинное имяname.-3— ошибка: неверный формат строкиaccess.
diGet
Функция int diGet(uint8_t num, bool *value) получает значение цифрового входа с проверкой.
Параметры:
num— номер цифрового входа.value— указатель на переменную, в которую будет записано значение.
Возвращаемые значения:
0— значение успешно получено.-1— ошибка: неверный номер входа.-3— внутренняя ошибка при получении значения.
diVal
Макрос diVal(n) возвращает значение цифрового входа без проверки.
Параметры:
n— номер цифрового входа.
Возвращаемое значение:
- Значение входа типа
bool.
Примечание: Использование макроса без проверки корректности номера входа может привести к неопределенному поведению.
Пример использования:
#include <stdio.h>
#include <stdbool.h>
#include <dev.h>
int main(void) {
// Ограничение количества входов
int res = countSet(devDi, 3);
printf("countSet res: %d\n", res); // Ожидается: 0
// Получение количества входов
int count = countGet(devDi);
printf("countGet count: %d\n", count); // Ожидается: 3
// Конфигурация входов
res = diConf(0, "Sensor NO", "r-", true); // Нормально открытый, только чтение через веб
printf("diConf res: %d\n", res); // Ожидается: 0
res = diConf(1, "Sensor NZ", "rr", false); // Нормально закрытый, чтение через веб и службы
res = diConf(2, "Sensor NZ", "rr", false);
// Цикл чтения значений
for (;;) {
bool val;
res = diGet(0, &val);
printf("Di0: %s, Di1: %s, Di2: %s\n",
val ? "true" : "false",
diVal(1) ? "true" : "false",
diVal(2) ? "true" : "false");
sleep_ms(1000); // Предполагаемая функция задержки
}
return 0;
}
Аналоговые выходы
Аналоговые выходы контроллера нумеруются с 0. Выход способен выдавать напряжение в диапазоне 0–10 В. Значение задается типом uint16_t в диапазоне 0–1000, где 1000 соответствует 10 В.
Для работы с аналоговыми выходами реализованы следующие функции и макросы:
// Конфигурация аналогового выхода
int aoConf(uint8_t num, char *name, char *access);
// Установка значения аналогового выхода
int aoSet(uint8_t num, uint16_t value);
// Получение значения аналогового выхода с проверкой
int aoGet(uint8_t num, uint16_t *value);
// Получение значения аналогового выхода без проверки
#define aoVal(n) (*(uint16_t *)(ADDR_AO + n * 2))
// Инкремент значения аналогового выхода
int aoInc(uint8_t num);
// Декремент значения аналогового выхода
int aoDec(uint8_t num);
aoConf
Функция int aoConf(uint8_t num, char *name, char *access) выполняет конфигурацию аналогового выхода.
Параметры:
num— номер аналогового выхода (0 и выше, в зависимости от количества доступных выходов).name— строковое имя выхода, отображаемое в веб-интерфейсе (максимальная длина — 32 символа, включая завершающий нуль).access— строка, определяющая уровни доступа:-— доступ запрещен.r— только чтение.w— чтение и запись.- Формат: первый символ задает доступ для веб-интерфейса и REST API, второй (опционально) — для внешних служб (Modbus RTU, Modbus TCP, SNMP). Если строка
NULL, уровни доступа не изменяются.
Возвращаемые значения:
0— выход успешно сконфигурирован.-1— ошибка: неверный номер выхода.-2— ошибка: неверное или слишком длинное имяname.-3— ошибка: неверный формат строкиaccess.
aoSet
Функция int aoSet(uint8_t num, uint16_t value) устанавливает значение аналогового выхода.
Параметры:
num— номер аналогового выхода.value— новое значение в диапазоне [0, 1000].
Возвращаемые значения:
1— текущее значение выхода совпадает с переданным.0— значение успешно установлено.-1— ошибка: неверный номер выхода.-2— ошибка:valueвне диапазона [0, 1000].-3— внутренняя ошибка при установке значения.
aoGet
Функция int aoGet(uint8_t num, uint16_t *value) получает значение аналогового выхода с проверкой.
Параметры:
num— номер аналогового выхода.value— указатель на переменную, в которую будет записано значение.
Возвращаемые значения:
0— значение успешно получено.-1— ошибка: неверный номер выхода.-3— внутренняя ошибка при получении значения.
aoVal
Макрос aoVal(n) возвращает значение аналогового выхода без проверки.
Параметры:
n— номер аналогового выхода.
Возвращаемое значение:
- Значение выхода типа
uint16_t.
Примечание: Использование макроса без проверки корректности номера выхода может привести к неопределенному поведению.
aoInc
Функция int aoInc(uint8_t num) увеличивает значение аналогового выхода на 0.1 В (10 единиц в диапазоне 0–1000).
Параметры:
num— номер аналогового выхода.
Возвращаемые значения:
0— значение успешно увеличено.-1— ошибка: неверный номер выхода.-2— ошибка: значение достигло максимума (1000).-3— внутренняя ошибка.
aoDec
Функция int aoDec(uint8_t num) уменьшает значение аналогового выхода на 0.1 В (10 единиц в диапазоне 0–1000).
Параметры:
num— номер аналогового выхода.
Возвращаемые значения:
0— значение успешно уменьшено.-1— ошибка: неверный номер выхода.-2— ошибка: значение достигло минимума (0).-3— внутренняя ошибка.
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
const uint8_t num = 0;
// Конфигурация аналогового выхода
int res = aoConf(num, "Voltage Output", "wr");
printf("aoConf res: %d\n", res); // Ожидается: 0
// Установка значения 5 В
res = aoSet(num, 500);
printf("aoSet res: %d\n", res); // Ожидается: 0
// Получение значения
uint16_t value;
res = aoGet(num, &value);
printf("aoGet res: %d, value: %u.%u V\n", res, value / 100, value % 100); // Ожидается: res: 0, value: 5.0 V
// Увеличение значения на 0.1 В
res = aoInc(num);
printf("aoInc res: %d\n", res); // Ожидается: 0
// Получение значения через макрос
value = aoVal(num);
printf("aoVal value: %u.%u V\n", value / 100, value % 100); // Ожидается: value: 5.1 V
return 0;
}
Аналоговые входы
Аналоговые входы контроллера нумеруются с 0. Вход может быть сконфигурирован для работы с датчиком температуры NTC10K (диапазон измерения: -40…100 °C) или источником напряжения в диапазоне 0–10 В.
Для датчика NTC10K значение возвращается в типе int16_t в диапазоне -400…1000 (температура в °C, умноженная на 10 для учета одного знака после запятой). Для напряжения значение также возвращается в int16_t, масштабированное в диапазон 0–1000 (где 1000 соответствует 10 В).
Для работы с аналоговыми входами реализованы следующие функции и макросы:
// Конфигурация аналогового входа
int aiConf(uint8_t num, char *name, char *access, int type);
// Получение значения аналогового входа с проверкой
int aiGet(uint8_t num, int16_t *value);
// Получение значения аналогового входа без проверки
#define aiVal(n) (*(int16_t *)(ADDR_AI + n * 2))
aiConf
Функция int aiConf(uint8_t num, char *name, char *access, int type) выполняет конфигурацию аналогового входа.
Параметры:
num— номер аналогового входа (0 и выше, в зависимости от количества доступных входов).name— строковое имя входа, отображаемое в веб-интерфейсе (максимальная длина — 32 символа, включая завершающий нуль).access— строка, определяющая уровни доступа:-— доступ запрещен.r— только чтение.- Формат: первый символ задает доступ для веб-интерфейса и REST API, второй (опционально) — для внешних служб (Modbus RTU, Modbus TCP, SNMP). Если строка
NULL, уровни доступа не изменяются.
type— тип подключенного устройства:0— напряжение (0–10 В).1— датчик температурыNTC10K.
Возвращаемые значения:
0— вход успешно сконфигурирован.-1— ошибка: неверный номер входа.-2— ошибка: неверное или слишком длинное имяname.-3— ошибка: неверный формат строкиaccess.-4— ошибка: неверное значениеtype.
aiGet
Функция int aiGet(uint8_t num, int16_t *value) получает значение аналогового входа с проверкой.
Параметры:
num— номер аналогового входа.value— указатель на переменную, в которую будет записано значение.
Возвращаемые значения:
0— значение успешно получено.-1— ошибка: неверный номер входа.-3— внутренняя ошибка при получении значения.
aiVal
Макрос aiVal(n) возвращает значение аналогового входа без проверки.
Параметры:
n— номер аналогового входа.
Возвращаемое значение:
- Значение входа типа
int16_t.
Примечание: Использование макроса без проверки корректности номера входа или типа может привести к неопределенному поведению.
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
const uint8_t num = 0;
// Конфигурация входа для датчика NTC10K
int res = aiConf(num, "Temperature Sensor", "r-", 1);
printf("aiConf res: %d\n", res); // Ожидается: 0
// Получение значения
int16_t value;
res = aiGet(num, &value);
float temp = (float)value / 10.0;
printf("aiGet res: %d, temp: %.1f °C\n", res, temp); // Ожидается: res: 0, temp: текущее значение
// Получение значения через макрос
value = aiVal(num);
temp = (float)value / 10.0;
printf("aiVal temp: %.1f °C\n", temp); // Ожидается: temp: текущее значение
return 0;
}
Пользовательские события
Пользовательские события позволяют регистрировать определенные действия или состояния в журнале событий контроллера. События нумеруются с 0 и могут быть сконфигурированы с использованием шаблонов для отображения в веб-интерфейсе.
Для работы с пользовательскими событиями реализованы следующие функции:
// Конфигурация пользовательского события
int eventConf(uint8_t num, char *name);
// Добавление пользовательского события
int eventAdd(uint8_t num, void *par1, void *par2, eReason_t *reason);
eventConf
Функция int eventConf(uint8_t num, char *name) выполняет конфигурацию пользовательского события.
Параметры:
num— номер события (0 и выше, в зависимости от количества доступных событий).name— строковое имя события или шаблон, отображаемый в веб-интерфейсе (максимальная длина — 32 символа, включая завершающий нуль). Если строка содержит фигурные скобки{}, они заменяются значениями параметровpar1иpar2из функцииeventAdd. Для явного указания порядка параметров используется формат{0}или{1}. Поддерживаемые типы данных для параметров:bool,int32_t,uint32_t,float,uint8_t(дляenum).
Примечание: Если в шаблоне указано {0:bool}, значение параметра интерпретируется как bool и отображается как "true" или "false".
Возвращаемые значения:
0— событие успешно сконфигурировано.-1— ошибка: неверный номер события.-2— ошибка: неверное или слишком длинное имяname.
eventAdd
Функция int eventAdd(uint8_t num, void *par1, void *par2, eReason_t *reason) добавляет пользовательское событие в журнал событий контроллера и, при необходимости, в облачный сервис.
Параметры:
num— номер события.par1— указатель на значение первого параметра (типы:bool,int32_t,uint32_t,float,uint8_t). ЕслиNULL, параметр не добавляется.par2— указатель на значение второго параметра (аналогичноpar1). ЕслиNULL, параметр не добавляется.reason— указатель на источник события (типeReason_t). ЕслиNULL, источник не указывается.
Тип eReason_t и значения для reason:
typedef enum {
eReasonNone = 0, // Не указан
eReasonError, // Ошибка
eReasonAuto, // Автоматический режим
eReasonUser, // Пользователь
eReasonRegular, // Нормальное состояние
eReasonAlgo, // Алгоритм
eReasonTime, // Расписание
eReasonWeb, // Веб-интерфейс
eReasonExt, // Внешняя служба
eReasonPu // Панель управления
} eReason_t;
Возвращаемые значения:
0— событие успешно добавлено.-1— ошибка: неверный номер события.-2— ошибка: неверный формат параметров или внутренняя ошибка.-3— ошибка: неверное значениеreason.
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
// Установка количества событий
int res = countSet(devEvent, 4);
printf("countSet res: %d, count: %u\n", res, countGet(devEvent)); // Ожидается: res: 0, count: 4
// Конфигурация событий
res = eventConf(0, "Simple Event");
res = eventConf(1, "Event with Param: {}");
res = eventConf(2, "Event with Params: par1={0}, par2={1}");
res = eventConf(3, "Event with Typed Params: par2={1}, par1={0:bool}");
// Добавление событий
res = eventAdd(0, NULL, NULL, NULL); // Без параметров
printf("eventAdd(0) res: %d\n", res); // Ожидается: 0
uint32_t par1 = 123;
res = eventAdd(1, &par1, NULL, NULL); // С одним параметром
printf("eventAdd(1) res: %d\n", res); // Ожидается: 0
uint32_t par2 = 456;
res = eventAdd(2, &par1, &par2, NULL); // С двумя параметрами
printf("eventAdd(2) res: %d\n", res); // Ожидается: 0
bool par1_bool = true;
eReason_t reason = eReasonRegular;
res = eventAdd(3, &par1_bool, &par2, &reason); // С типизированным параметром и причиной
printf("eventAdd(3) res: %d\n", res); // Ожидается: 0
printf("done\n");
return 0;
}
Пользовательские аварии
Пользовательские аварии позволяют регистрировать критические состояния в журнале событий контроллера. Аварии нумеруются с 0 и могут быть активированы или деактивированы с указанием параметров и причины.
Для работы с пользовательскими авариями реализованы следующие функции и макросы:
// Конфигурация пользовательской аварии
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);
// Получение статуса пользовательской аварии без проверки
#define alarmVal(n) (*(bool *)(ADDR_ALARM + (n / 8))) & (1 << (n % 8))
alarmConf
Функция int alarmConf(uint8_t num, char *name) выполняет конфигурацию пользовательской аварии.
Параметры и возвращаемые значения: Идентичны eventConf.
alarmOn
Функция int alarmOn(uint8_t num, void *par1, void *par2, eReason_t *reason) активирует пользовательскую аварию и добавляет соответствующее событие в журнал.
Параметры и возвращаемые значения: Идентичны eventAdd.
Примечание: При активации аварии автоматически создается событие с использованием шаблона, заданного в alarmConf.
alarmOff
Функция int alarmOff(uint8_t num) деактивирует пользовательскую аварию.
Параметры:
num— номер аварии.
Возвращаемые значения:
0— авария успешно деактивирована.-1— ошибка: неверный номер аварии.-2— внутренняя ошибка.
alarmGet
Функция int alarmGet(uint8_t num, bool *value) получает текущий статус аварии (активна/неактивна).
Параметры:
num— номер аварии.value— указатель на переменную, в которую будет записан статус (true— активна,false— неактивна).
Возвращаемые значения:
0— статус успешно получен.-1— ошибка: неверный номер аварии.-2— внутренняя ошибка.
alarmVal
Макрос alarmVal(n) возвращает статус пользовательской аварии без проверки.
Параметры:
n— номер аварии.
Возвращаемое значение:
true— авария активна.false— авария неактивна.
Примечание: Использование макроса без проверки корректности номера аварии может привести к неопределенному поведению.
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
// Установка количества аварий
int res = countSet(devAlarm, 2);
printf("countSet res: %d, count: %u\n", res, countGet(devAlarm)); // Ожидается: res: 0, count: 2
// Конфигурация аварий
res = alarmConf(0, "Critical Error");
res = alarmConf(1, "Sensor Failure: {}");
// Активация аварий
res = alarmOn(0, NULL, NULL, NULL); // Без параметров
printf("alarmOn(0) res: %d\n", res); // Ожидается: 0
int32_t par1 = 42;
eReason_t reason = eReasonError;
res = alarmOn(1, &par1, NULL, &reason); // С параметром и причиной
printf("alarmOn(1) res: %d\n", res); // Ожидается: 0
// Проверка статуса
bool status;
res = alarmGet(1, &status);
printf("alarmGet res: %d, status: %s\n", res, status ? "active" : "inactive"); // Ожидается: res: 0, status: active
// Деактивация аварии
res = alarmOff(1);
printf("alarmOff res: %d\n", res); // Ожидается: 0
// Проверка статуса через макрос
status = alarmVal(1);
printf("alarmVal status: %s\n", status ? "active" : "inactive"); // Ожидается: status: inactive
printf("done\n");
return 0;
}
Прочие функции
Для управления ресурсами контроллера, периодическим выполнением функций и настройкой веб-интерфейса реализованы следующие функции и макросы:
// Ресурсы контроллера
typedef enum {
devDo = 0, // Цифровые выходы
devDi, // Цифровые входы
devAo, // Аналоговые выходы
devAi, // Аналоговые входы
devReg, // Пользовательские регистры
devEvent, // Пользовательские события
devAlarm // Пользовательские аварии
} devItem_t;
// Установка количества доступных элементов ресурса
int countSet(const devItem_t item, const size_t count);
// Получение количества доступных элементов ресурса
int countGet(const devItem_t item);
// Проверка изменения значения элемента
bool isChange(const devItem_t item, uint8_t num);
// Тип пользовательской функции для периодического выполнения
typedef int (*runFn_t)(uint32_t count);
// Запуск периодического выполнения пользовательской функции
int run(runFn_t fn, uint32_t freq);
// Добавление пользовательской функции в набор для периодического выполнения
int runAdd(runFn_t fn, uint32_t freq);
// Запуск периодического выполнения набора функций
int runStart(void);
// Настройка отображения элементов в веб-интерфейсе
void webconf(bool display, bool reg, bool pin, bool console);
// Получение текущего времени в миллисекундах
uint32_t millis(void);
// Получение текущего времени в микросекундах
#define micros() ((*(volatile uint32_t *)0xE0001004) / 168)
// Получение времени последнего отключения контроллера в формате Unix
uint32_t timePowerOff(void);
countSet
Функция int countSet(const devItem_t item, const size_t count) задает количество доступных элементов для указанного ресурса контроллера.
Параметры:
item— тип ресурса (devDo,devDi,devAo,devAi,devReg,devEvent,devAlarm).count— количество элементов (0–32 для большинства ресурсов, уточняется в зависимости от типа).
Возвращаемые значения:
0— количество элементов успешно установлено.-1— ошибка: неверное значениеcountилиitem.
Примечание: Максимальное значение count зависит от типа ресурса и аппаратных ограничений контроллера.
countGet
Функция int countGet(const devItem_t item) возвращает текущее количество доступных элементов для указанного ресурса.
Параметры:
item— тип ресурса (devDo,devDi,devAo,devAi,devReg,devEvent,devAlarm).
Возвращаемое значение:
- Количество доступных элементов (0–32) или
-1при ошибке.
isChange
Функция bool isChange(const devItem_t item, uint8_t num) проверяет, изменилось ли значение элемента с момента последнего вызова функции для этого элемента.
Параметры:
item— тип ресурса (devDo,devDi,devAo,devAi,devReg,devAlarm). РесурсdevEventне поддерживается.num— номер элемента.
Возвращаемое значение:
true— значение элемента изменилось.false— значение не изменилось или указан неверный тип/номер элемента.
run
Функция int run(runFn_t fn, uint32_t freq) запускает периодическое выполнение пользовательской функции с заданной частотой.
Параметры:
fn— указатель на пользовательскую функцию типаrunFn_t(int (*runFn_t)(uint32_t count)), гдеcount— номер вызова функции.freq— интервал выполнения в миллисекундах (0 — функция выполняется однократно).
Возвращаемые значения:
0— функция успешно запущена.-1— ошибка: периодическое выполнение уже активно илиfnравноNULL.-2— ошибка:freqравно 0 для периодического выполнения.
Примечание: Если функция возвращает -1, ее выполнение приостанавливается.
Пример использования:
#include <stdio.h>
#include <dev.h>
int step(uint32_t count) {
printf("Step %u\n", count);
return count >= 20 ? -1 : 0; // Остановить после 20 вызовов
}
int main(void) {
int res = run(step, 200); // Выполнять каждые 200 мс
printf("run res: %d\n", res); // Ожидается: 0
printf("done\n");
return 0;
}
runAdd
Функция int runAdd(runFn_t fn, uint32_t freq) добавляет пользовательскую функцию в набор для периодического выполнения.
Параметры:
fn— указатель на пользовательскую функцию типаrunFn_t.freq— интервал выполнения в миллисекундах (0 — функция выполняется однократно).
Возвращаемые значения:
0— функция успешно добавлена.-1— ошибка:fnравноNULL.-2— ошибка:freqравно 0 для периодического выполнения.
runStart
Функция int runStart(void) запускает периодическое выполнение всех функций, добавленных через runAdd.
Возвращаемые значения:
0— выполнение успешно запущено.-1— ошибка: периодическое выполнение уже активно.
Пример использования:
#include <stdio.h>
#include <dev.h>
int every50ms(uint32_t count) {
printf("*");
return 0;
}
int every200ms(uint32_t count) {
printf(" ");
return 0;
}
int every1sec(uint32_t count) {
printf("\nCount: %u`\n", count);
return 0;
}
int main(void) {
runAdd(every50ms, 50);
runAdd(every200ms, 200);
runAdd(every1sec, 1000);
runStart();
return 0;
}
webconf
Функция void webconf(bool display, bool reg, bool pin, bool console) настраивает отображение элементов веб-интерфейса контроллера.
Параметры:
display— отображение виртуального дисплея (true— отобразить,false— скрыть).reg— отображение пользовательских регистров (true— отобразить,false— скрыть).pin— отображение входов/выходов (true— отобразить,false— скрыть).console— отображение консоли (true— отобразить,false— скрыть).
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
// Отображение всех элементов веб-интерфейса
webconf(true, true, true, true);
return 0;
}
millis
Функция uint32_t millis(void) возвращает текущее время в миллисекундах с момента включения контроллера.
Возвращаемое значение:
- Текущее время в миллисекундах (тип
uint32_t).
micros
Макрос micros() возвращает текущее время в микросекундах с момента включения контроллера.
Возвращаемое значение:
- Текущее время в микросекундах (тип
uint32_t).
Примечание: Макрос использует прямой доступ к аппаратному таймеру, что может быть специфично для платформы. Частота деления (168) зависит от тактовой частоты микроконтроллера.
timePowerOff
Функция uint32_t timePowerOff(void) возвращает время последнего отключения контроллера в формате Unix (секунды с 1 января 1970 года).
Возвращаемое значение:
- Время последнего отключения в формате Unix (тип
uint32_t).
Пример использования:
#include <stdio.h>
#include <dev.h>
int main(void) {
uint32_t time = timePowerOff();
printf("Last power-off time: %u\n", time);
return 0;
}