diff --git a/modbus_params/Makefile b/modbus_params/Makefile new file mode 100644 index 0000000..bbd8f39 --- /dev/null +++ b/modbus_params/Makefile @@ -0,0 +1,59 @@ +# run `make DEF=...` to add extra defines +PROGRAM := modbus_par +LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all +LDFLAGS += -lusefull_macros -lmodbus +SRCS := $(wildcard *.c) +DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 +OBJDIR := mk +CFLAGS += -O2 -Wall -Wextra -Wno-trampolines +OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) +DEPS := $(OBJS:.o=.d) +TARGFILE := $(OBJDIR)/TARGET +CC = gcc +#TARGET := RELEASE + +ifeq ($(shell test -e $(TARGFILE) && echo -n yes),yes) + TARGET := $(file < $(TARGFILE)) +else + TARGET := RELEASE +endif + +ifeq ($(TARGET), DEBUG) + .DEFAULT_GOAL := debug +endif + +release: CFLAGS += -flto +release: LDFLAGS += -flto +release: $(PROGRAM) + +debug: CFLAGS += -DEBUG -Werror +debug: TARGET := DEBUG +debug: $(PROGRAM) + +$(TARGFILE): $(OBJDIR) + @echo -e "\t\tTARGET: $(TARGET)" + @echo "$(TARGET)" > $(TARGFILE) + +$(PROGRAM) : $(TARGFILE) $(OBJS) + @echo -e "\t\tLD $(PROGRAM)" + $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM) + +$(OBJDIR): + @mkdir $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR)/%.o: %.c + @echo -e "\t\tCC $<" + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< + +clean: + @echo -e "\t\tCLEAN" + @rm -rf $(OBJDIR) 2>/dev/null || true + +xclean: clean + @rm -f $(PROGRAM) + +.PHONY: clean xclean diff --git a/modbus_params/Readme b/modbus_params/Readme new file mode 100644 index 0000000..b54898c --- /dev/null +++ b/modbus_params/Readme @@ -0,0 +1,18 @@ + +modbus_par: reading/writing/dumping modbus registers using `dictionary` + + -D, --dictionary=arg file with dictionary (format: code register value writeable) + -O, --outdic=arg output dictionary for full device dump by input dictionary registers + -R, --readc registers (by keycodes, checked by dictionary) to read; multiply parameter + -W, --writec write new value to register by keycode (format: keycode=val); multiply parameter + -b, --baudrate=arg modbus baudrate (default: 9600) + -d, --device=arg modbus device (default: /dev/ttyUSB0) + -h, --help show this help + -k, --dumpkey dump entry with this keycode; multiply parameter + -o, --outfile=arg file with parameter's dump + -r, --readr registers (by address) to read; multiply parameter + -s, --slave=arg slave ID (default: 1) + -t, --dumptime=arg dumping time interval (seconds, default: 0.1) + -v, --verbose verbose level (each -v adds 1) + -w, --writer write new value to register (format: reg=val); multiply parameter + diff --git a/modbus_params/dictionary.dic b/modbus_params/dictionary.dic new file mode 100644 index 0000000..4aefe87 --- /dev/null +++ b/modbus_params/dictionary.dic @@ -0,0 +1,522 @@ +# awk '{printf "%s\t%s\t%s\t0\t# ", $1, $2, $3; $1=""; $2=""; $3=""; print $0}' orig > dictionary.dic +F00.00 61440 1 0 # Управление двигателем (V/F) +F00.01 61441 0 0 # Выбор задания команды ПУСК [0-с клавиатуры; 3,4 Modbus RTU] +F00.02 61442 0 0 # Тип связи [0 - MODbus RTU] +F00.03 61443 5000 0 # Максимальная частота для П.Ч. х100, Гц [от F00.04 до 500.00 Гц] (750 rpm) +F00.04 61444 5000 0 # Верхний предел рабочей частоты х100, Гц [F00.05 - F00.03] (610 rpm) +F00.05 61445 0 0 # Минимальная частота х100, Гц [от 0.00 до F00.04 Гц] +F00.06 61446 0 0 # Источник частоты А от … [0 — 9] [9 – Modbus RTU] +F00.07 61447 0 0 # Источник частоты B от … [0 — 9] (3) +F00.08 61448 0 0 # Задание частоты по каналу B [0 – макс.частота; 1-частота канала A] +F00.09 61449 1000 0 # Максимальная частота по каналу В х10 в % (100 rpm) +F00.10 61450 0 0 # Комбинированный режим регулирования [от 0 до 5] (0 => только А) +F00.11 61451 5000 0 # Частота комбинированного режима х100, Гц [от 0.00 до F00.03] (600 rpm) +F00.12 61452 100 0 # Время разгона 1 х 10, сек. (30s) +F00.13 61453 100 0 # Время торможения 1 х 10, сек. (30s) +F00.14 61454 0 0 # Направление вращения [от 0 – CW; 1 – CCW; 2 – запрет CCW] +F00.15 61455 50 0 # Несущая частота модуляции 1 х 10 [от 2.0 до 10.0 кГц] (5 kHz) +F00.16 61456 0 0 # Отслеживание скорости [от 0 до 2] +F00.17 61457 0 0 # Автонастройка двигателя [0 – off;1 – on with run; 2 - on without run;] +F00.18 61458 0 0 # Сброс параметров [от 0 до 3; 0 - без сброса] +F01.00 61696 0 0 # Тип запуска: 0 — запуск со стартовой частоты; 1 — запуск после торможения; 2 — запуск с поиском скорости +F01.01 61697 50 0 # Стартовая частота х100, [от 0 до 10 Гц] (7,5/101.48 = 0,074 rpm каток) +F01.02 61698 0 0 # Время удержания стартовой частоты х10, [от 0.0 до 100.0 сек.] (тест 1 с.) +F01.03 61699 0 0 # Ток торможения перед стартом х10, % [от 00 до 150.0%] +F01.04 61700 0 0 # Время торможения перед стартом х10, сек. [от 0.0 до 100.0 сек] +F01.05 61701 0 0 # Тип разгона/торможения [0 — линейный; 1 — S кривая;] +F01.06 61702 300 0 # Стартовая фаза S-кривой х10, % [от 0.0 — 50.0% времени разг./торм.] +F01.07 61703 300 0 # Конечная фаза S-кривой х10, % [от 0.0 — 50.0% времени разг./торм.] +F01.08 61704 0 0 # Метод остановки [0 — замедление до остан.; 1 — свободн. выбег] +F01.09 61705 0 0 # Частота включения торможения постоянным током х100, Гц +F01.10 61706 0 0 # Время ожидания торможения постоянным током х10, сек. [0 до100] +F01.11 61707 0 0 # Постоянный ток торможения во время остановки х10, % [0 до100] +F01.12 61708 0 0 # Время торможения пост. током во время остановки х10, сек. +F01.13 61709 0 0 # Время бездействия между сменой направлений вращения х10, сек. +F01.14 61710 50 0 # Частота остановки х10, Гц +F01.15 61711 0 0 # Зарезервировано +F01.16 61712 0 0 # Зарезервировано +F01.17 61713 0 0 # Перезапуск с клемм после включения [0 — не действ. 1 - действует] +F01.18 61714 0 0 # Перезапуск после потери напряжения [0 — запрет; 1 - перезапуск] +F01.19 61715 10 0 # Задержка перезапуска х10, сек. [0.0 до 6000.0] (Только если F1.18 = 1) +F01.20 61716 0 0 # Зарезервировано +F01.21 61717 0 0 # Действие, если выходная частота меньше минимальной; 0 — работа на мин.частоте; 1 - остановка; 2 - работа на нулевой скорости вращения. +F01.22 61718 5000 0 # Задание частоты при работе в пожарном режиме (х100), Гц. +F02.00 61952 0 0 # Тип нагрузки [0 — тип G; 1 – тип P;] +F02.01 61953 0 0 # Тип двигателя [0 - АСИНХРОННЫЙ] +F02.02 61954 15 0 # Мощность двигателя х10, кВт (5.5 кВт) +F02.03 61955 380 0 # Напряжение двигателя, В [0 — 1000.0] (380 В) +F02.04 61956 65 0 # Номинальный ток х10, А (14.8А) +F02.05 61957 5000 0 # Номинальная частота для двигателя х100, Гц +F02.06 61958 1450 0 # Номинальные обороты двигателя по паспорту, об/мин +F02.07 61959 1414 0 # Сопротивление статора х100, Ом (Значение после автонастройки!) +F02.08 61960 1264 0 # Сопротивление ротора х100, Ом (Значение после автонастройки!) +F02.09 61961 67 0 # Индуктивность рассеивания х10, мГн (Значение после автонастройки!) +F02.10 61962 956 0 # Индуктивность двигателя х10, мГн (Значение после автонастройки!) +F02.11 61963 33 0 # Ток холостого хода х10, А (Значение после автонастройки!) +F02.12 61964 880 0 # Зарезервировано +F02.13 61965 810 0 # Зарезервировано +F02.14 61966 750 0 # Зарезервировано +F02.15 61967 0 0 # Выбор типа энкодера +F02.16 61968 1024 0 # Число импульсов энкодера на оборот +F02.17 61969 0 0 # Последовательность фаз энкодера ABZ +F02.18 61970 1 0 # Количество пар полюсов резольвера +F02.19 61971 1 0 # Зарезервировано +F02.20 61972 3 0 # Зарезервировано +F02.21 61973 3 0 # Зарезервировано +F02.22 61974 10 0 # Зарезервировано +F02.23 61975 10 0 # Зарезервировано +F02.24 61976 1000 0 # Зарезервировано +F02.25 61977 1 0 # Защита от перегрузки [0 — не действует; 1 — действует;] +F02.26 61978 1000 0 # Коэффициент защиты от перегрузки х10, % [F02.26 x F02.04] +F03.00 62208 30 0 # Пропорциональный коэффициент контура скорости 1 +F03.01 62209 50 0 # Время интегрирования контура скорости 1 х1000, сек +F03.02 62210 500 0 # Пороговое значение низкой скорости х100, Гц +F03.03 62211 20 0 # Пропорциональный коэффициент контура скорости 2 +F03.04 62212 100 0 # Время интегрирования контура скорости 2 х1000, сек +F03.05 62213 1000 0 # Пороговое значение высокой скорости 2 х100, Гц +F03.06 62214 15 0 # Коэффициент фильтрации обратной связи х100, сек +F03.07 62215 0 0 # Пропорциональный коэффициент контура тока 1 +F03.08 62216 0 0 # Время интегрирования контура тока 1 +F03.09 62217 0 0 # Пропорциональный коэффициент контура тока 2 +F03.10 62218 0 0 # Время интегрирования контура тока 2 +F03.11 62219 0 0 # Выбор канала ограничения крутящего момента +F03.12 62220 0 0 # Выбор канала ограничения момента торможения +F03.13 62221 1500 0 # Цифровое задание крутящего момента х10, % +F03.14 62222 1500 0 # Цифровое задание момента торможения х10, % +F03.15 62223 100 0 # Коэффициент ограничения момента +F03.16 62224 100 0 # Коэффициент компенсации скольжения, % +F04.00 62464 0 0 # Выбор кривой V/F (линейная х-ка) +F04.01 62465 0 0 # Усиление момента х10, % +F04.02 62466 200 0 # Частота усиления момента х10, % ((300rpm/750rpm)*100)*10% +F04.03 62467 0 0 # V/F частота 1 х100, Гц +F04.04 62468 0 0 # V/F напряжение 1 х10, % +F04.05 62469 0 0 # V/F частота 2 х100, Гц +F04.06 62470 0 0 # V/F напряжение 2 х10, % +F04.07 62471 0 0 # V/F частота 3 х100, Гц +F04.08 62472 0 0 # V/F напряжение 3 х10, % +F04.09 62473 100 0 # Компенсация скольжения х10, % +F04.10 62474 2 0 # Контроль вибрации при низкой частоте +F04.11 62475 2 0 # Контроль вибрации при высокой частоте +F04.12 62476 3000 0 # Порог контроля вибрации х100, Гц +F04.13 62477 0 0 # Выбор кривой V/F Мотор 2 +F04.14 62478 0 0 # Усиление момента х10, % +F04.15 62479 200 0 # Частота усиления момента х10, % +F04.16 62480 0 0 # V/F частота 1 х100, Гц +F04.17 62481 0 0 # V/F напряжение 1 х10, % +F04.18 62482 0 0 # V/F частота 2 х100, Гц +F04.19 62483 0 0 # V/F напряжение 2 х10, % +F04.20 62484 0 0 # V/F частота 3 х100, Гц +F04.21 62485 0 0 # V/F напряжение 3 х10, % +F04.22 62486 1000 0 # Компенсация скольжения х10, % +F04.23 62487 2 0 # Контроль вибрации при низкой частоте +F04.24 62488 2 0 # Контроль вибрации при высокой частоте +F04.25 62489 3000 0 # Порог контроля вибрации х100, Гц +F04.26 62490 0 0 # Энергосбережение +F04.27 62491 0 0 # Установка напряжения +F04.28 62492 1000 0 # Задание с клавиатуры х10, % +F04.29 62493 50 0 # Время повышения напряжения х10, сек. +F04.30 62494 50 0 # Время понижения напряжения х10, сек. +F04.31 62495 1000 0 # Максимальное выходное напряжение х10, % +F04.32 62496 0 0 # Минимальное выходное напряжение х10, % +F04.33 62497 1 0 # Выбор функции АВР +F04.34 62498 400 0 # Зарезервировано +F05.00 62720 0 0 # Выбор клеммы DI5 +F05.01 62721 1 0 # Клемма DI1 +F05.02 62722 4 0 # Клемма DI2 +F05.03 62723 7 0 # Клемма DI3 +F05.04 62724 0 0 # Клемма DI4 +F05.05 62725 0 0 # Клемма DI5 (дискретный) +F05.06 62726 0 0 # Клемма DI6 +F05.07 62727 0 0 # Клемма DI7 (опционально) +F05.08 62728 0 0 # Клемма DI8 (опционально) +F05.09 62729 0 0 # Выбор полярности входных клемм +F05.10 62730 10 0 # Фильтр дребезга входных клемм х1000, сек. +F05.11 62731 0 0 # Настройка управления входных клемм +F05.12 62732 0 0 # Настройка подключения входных клемм +F05.13 62733 0 0 # Задержка включения клеммы DI1 х1000, сек. +F05.14 62734 0 0 # Задержка выключения клеммы DI1 х1000, сек. +F05.15 62735 0 0 # Задержка включения клеммы DI2 х1000, сек. +F05.16 62736 0 0 # Задержка выключения клеммы DI2 х1000, сек. +F05.17 62737 0 0 # Задержка включения клеммы DI3 х1000, сек. +F05.18 62738 0 0 # Задержка выключения клеммы DI3 х1000, сек. +F05.19 62739 0 0 # Задержка включения клеммы DI4 х1000, сек. +F05.20 62740 0 0 # Задержка выключения клеммы DI4 х1000, сек. +F05.21 62741 0 0 # Задержка включения клеммы DI5 х1000, сек. +F05.22 62742 0 0 # Задержка выключения клеммы DI5 х1000, сек. +F05.23 62743 0 0 # Задержка включения клеммы DI6 х1000, сек. +F05.24 62744 0 0 # Задержка выключения клеммы DI6 х1000, сек. +F05.25 62745 0 0 # Задержка включения клеммы DI7 х1000, сек. +F05.26 62746 0 0 # Задержка выключения клеммы DI7 х1000, сек. +F05.27 62747 0 0 # Задержка включения клеммы DI8 х1000, сек. +F05.28 62748 0 0 # Задержка выключения клеммы DI8 х1000, сек. +F05.29 62749 0 0 # Зарезервировано +F05.30 62750 0 0 # Нижний предел частоты DI5 х100, КГц +F05.31 62751 0 0 # Настройка нижнего предела частоты DI5 х10, % +F05.32 62752 5000 0 # Верхний предел частоты DI5 х100, КГц +F05.33 62753 1000 0 # Настройка верхнего предела частоты DI5 х10, % +F05.34 62754 100 0 # Время фильтрации DI5 х1000, сек. +F05.35 62755 0 0 # Режим работы клеммы пожарного режима +F06.00 62976 0 0 # Конфигурация клеммы HDO1 +F06.01 62977 0 0 # Функция клеммы DO1 +F06.02 62978 0 0 # Функция клеммы HDO1 +F06.03 62979 1 0 # Функция реле Т1 +F06.04 62980 5 0 # Функция реле Т2 +F06.05 62981 0 0 # Выбор полярности выходных клемм +F06.06 62982 0 0 # Задержка включения клеммы DO1 х1000, сек. +F06.07 62983 0 0 # Задержка выключения клеммы DO1 х1000, сек. +F06.08 62984 0 0 # Задержка включения клеммы НDO1 х1000, сек. +F06.09 62985 0 0 # Задержка выключения клеммы НDO1 х1000, сек. +F06.10 62986 0 0 # Задержка включения реле Т1 х1000, сек. +F06.11 62987 0 0 # Задержка выключения реле Т1 х1000, сек. +F06.12 62988 0 0 # Задержка включения реле Т2 х1000, сек. +F06.13 62989 0 0 # Задержка выключения реле Т2 х1000, сек. +F06.14 62990 0 0 # Выход АО1 +F06.15 62991 0 0 # Выход АО2 +F06.16 62992 0 0 # Выход HDO1 (высокоскоростной выход) +F06.17 62993 0 0 # Нижний предел АО1 х10. % +F06.18 62994 200 0 # Значение нижнего предела АО1 х100, В +F06.19 62995 1000 0 # Верхний предел АО1 х10, % +F06.20 62996 1000 0 # Значение верхнего предела АО1 х100, В +F06.21 62997 0 0 # Время фильтрации выхода АО1 х1000, сек. +F06.22 62998 0 0 # Нижний предел АО2 х10, % +F06.23 62999 0 0 # Значение нижнего предела АО2 х100, В +F06.24 63000 1000 0 # Верхний предел АО2 х10, % +F06.25 63001 1000 0 # Значение верхнего предела АО2 х100, В +F06.26 63002 0 0 # Время фильтрации выхода АО2 х1000, сек. +F06.27 63003 0 0 # Нижний предел HDO1 х10, % +F06.28 63004 0 0 # Значение нижнего предела HDO1 х100, КГц +F06.29 63005 1000 0 # Верхний предел HDO1 х10, % +F06.30 63006 5000 0 # Значение верхнего предела HDO1 х100, КГц +F06.31 63007 0 0 # Время фильтрации выхода HDO1 х1000, сек. +F06.32 63008 1 0 # Функция управления тормозом +F06.33 63009 500 0 # Частота отпускания тормоза при подъеме х100, Гц +F06.34 63010 20 0 # Ток отпускания тормоза при подъеме, % от ном.тока +F06.35 63011 600 0 # Частота задержки отпускания тормоза при подъеме х100, Гц +F06.36 63012 2 0 # Время задержки отпускания тормоза при подъеме х10, сек. +F06.37 63013 500 0 # Частота включения тормоза при подъеме х100, Гц +F06.38 63014 450 0 # Частота задержки включения тормоза при подъеме х100, Гц +F06.39 63015 2 0 # Время задержки включения тормоза при подъеме х10, сек. +F06.40 63016 500 0 # Частота отпускания тормоза при спуске х100, Гц +F06.41 63017 20 0 # Ток отпускания тормоза при спуске, % от ном.тока +F06.42 63018 600 0 # Частота задержки отпускания тормоза при спуске х100, Гц +F06.43 63019 2 0 # Время задержки отпускания тормоза при спуске х100, сек. +F06.44 63020 500 0 # Частота включения тормоза при спуске х100, Гц +F06.45 63021 450 0 # Частота задержки включения тормоза при спуске х100, сек. +F06.46 63022 2 0 # Время задержки включения тормоза при спуске х10, сек. +F06.47 63023 1000 0 # Ограничение момента при включенном тормозе х10, % +F07.00 63232 0 0 # Пароль пользователя +F07.01 63233 0 0 # Выбор функции кнопки S +F07.02 63234 255 0 # Параметры состояния 1 +F07.03 63235 255 0 # Параметры состояния 2 +F07.04 63236 255 0 # Параметры состояния при остановке +F07.05 63237 100 0 # Коэффициент частоты х100 +F07.06 63238 1000 0 # Скорость вращения х10, % +F07.07 63239 10 0 # Коэффициент линейной скорости х10, % +F07.08 63240 36 0 # Температура выпрямителя, С +F07.09 63241 36 0 # Температура инвертора, С +F07.10 63242 60770 0 # Версия ПО +F07.11 63243 0 0 # Время наработки, час. +F07.12 63244 0 0 # Нижний предел сигнализации AI1, В +F07.13 63245 680 0 # Верхний предел сигнализации AI1, В +F07.14 63246 0 0 # Выбор канала ограничения верхнего предела выхода ПИД-регулятора +F07.15 63247 15 0 # Номинальная мощность ПЧ х10, КВт +F07.16 63248 380 0 # Номинальное напряжение, В +F07.17 63249 75 0 # Номинальный ток х10, А +F07.18 63250 0 0 # Текущая ошибка +F07.19 63251 0 0 # Ошибка при предыдущем отключении +F07.20 63252 0 0 # Ошибка при 2-м отключении +F07.21 63253 0 0 # Ошибка при 3-м отключении +F07.22 63254 0 0 # Ошибка при 4-м отключении +F07.23 63255 0 0 # Ошибка при 5-м отключении +F07.24 63256 0 0 # Частота в момент текущей аварии х100, Гц +F07.25 63257 0 0 # Опорная частота в момент текущей аварии х100, Гц +F07.26 63258 0 0 # Выходное напряжение в момент текущей аварии, В +F07.27 63259 0 0 # Выходной ток в момент текущей аварии х10, В +F07.28 63260 0 0 # Напряжение звена постоянного тока в момент текущей аварии х10, В +F07.29 63261 0 0 # Максимальная температура ПЧ в момент текущей аварии х10, С +F07.30 63262 0 0 # Состояние входных клемм в момент текущей аварии +F07.31 63263 0 0 # Состояние выходных клемм в момент текущей аварии +F07.32 63264 0 0 # Выходная частота в момент предыдущей аварии х100, Гц +F07.33 63265 0 0 # Опорная частота в момент предыдущей аварии х100, Гц +F07.34 63266 0 0 # Выходное напряжение в момент предыдущей аварии, В +F07.35 63267 0 0 # Выходной ток в момент предыдущей аварии х10, А +F07.36 63268 0 0 # Напряжение звена постоянного тока в момент предыдущей аварии х10, В +F07.37 63269 0 0 # Максимальная температура ПЧ в момент предыдущей аварии х10, С +F07.38 63270 0 0 # Состояние входных клемм в момент предыдущей аварии +F07.39 63271 0 0 # Состояние выходных клемм в момент предыдущей аварии +F07.40 63272 0 0 # Частота в момент 2-й аварии х100, Гц +F07.41 63273 0 0 # Опорная частота в момент 2-й аварии х100, Гц +F07.42 63274 0 0 # Выходное напряжение в момент 2-й аварии, В +F07.43 63275 0 0 # Выходной ток в момент 2-й аварии х10, А +F07.44 63276 0 0 # Напряжение звена постоянного тока в момент 2-й аварии, В +F07.45 63277 0 0 # Максимальная температура ПЧ в момент 2-й аварии х10, С +F07.46 63278 0 0 # Состояние входных клемм в момент 2-й аварии +F07.47 63279 0 0 # Состояние выходных клемм в момент 2-й аварии +F08.00 63488 100 0 # Время разгона 2 х10, сек. +F08.01 63489 100 0 # Время торможения 2 х10, сек. +F08.02 63490 100 0 # Время разгона 3 х10, сек. +F08.03 63491 100 0 # Время торможения 3 х10, сек. +F08.04 63492 100 0 # Время разгона 4 х10, сек. +F08.05 63493 100 0 # Время торможения 4 х10, сек. +F08.06 63494 500 0 # Толчковая частота х100, Гц +F08.07 63495 100 0 # Время разгона толчкового режима х10, сек. +F08.08 63496 100 0 # Время торможения толчкового режима х10, сек. +F08.09 63497 0 0 # Количество сбросов аварии +F08.10 63498 10 0 # Время задержки автоматического сброса х10, сек. +F08.11 63499 0 0 # Контроль снижения частоты х100, Гц +F08.12 63500 0 0 # Переключение двигателя +F08.13 63501 5000 0 # Уровень достижения частоты FDT1 х100, Гц +F08.14 63502 50 0 # Удержание FDT1 х10, % +F08.15 63503 5000 0 # Уровень достижения частоты FDT1 х100, Гц +F08.16 63504 50 0 # Удержание FDT2 х10, % +F08.17 63505 0 0 # Ширина обнаружения частоты х100, Гц +F08.18 63506 1 0 # Тормозной прерыватель +F08.19 63507 3800 0 # Уровень напряжения срабатывания х10, В +F08.20 63508 0 0 # Компенсация ШИМ +F08.21 63509 0 0 # Функция кнопок пульта +F08.22 63510 10 0 # Время задержки кнопок 'ВВЕРХ'/'ВНИЗ х10, сек.' +F08.23 63511 0 0 # Задание кнопок 'ВВЕРХ'/'ВНИЗ' +F08.24 63512 50 0 # Время задержки кнопки 'ВВЕРХ' х100, сек. +F08.25 63513 50 0 # Время задержки кнопки 'ВНИЗ' х100, сек. +F08.26 63514 0 0 # Частота при потере питания +F08.27 63515 50 0 # Торможение магнитным потоком х100, сек. +F08.28 63516 1 0 # Вспомогательный мониторинг +F08.29 63517 0 0 # Копирование параметров (только для панели) +F08.30 63518 0 0 # Дополнительная плата входов/выходов +F08.31 63519 0 0 # Торможение при потере питания +F08.32 63520 0 0 # Время торможения при потере питания х10, сек. +F08.33 63521 2000 0 # Напряжение срабатывания, В +F08.34 63522 5000 0 # Произвольная частота 1 х100, Гц +F08.35 63523 0 0 # Ширина обнаружения произвольной частоты 1 +F08.36 63524 5000 0 # Произвольная частота 2 х100, Гц +F08.37 63525 0 0 # Ширина обнаружения произвольной частоты 2 +F08.38 63526 0 0 # Толчковый режим во время работы +F09.00 63744 0 0 # Источник задания уставки ПИД +F09.01 63745 500 0 # Уставка ПИД х10, % +F09.02 63746 0 0 # Обратная связь ПИД +F09.03 63747 0 0 # Тип обратной связи +F09.04 63748 200 0 # Пропорциональная составляющая (Кр) х10 +F09.05 63749 20 0 # Интегральная составляющая (Ti) х10 +F09.06 63750 0 0 # Дифференциальная составляющая (Td) х100 +F09.07 63751 10 0 # Цикл выборки(T) х100, сек. +F09.08 63752 2 0 # Предел отклонения ПИД х10, % +F09.09 63753 1000 0 # Верхний предел ПИД х10, % +F09.10 63754 0 0 # Нижний предел ПИД х10, % +F09.11 63755 0 0 # Величина сигнала обратной связи, активирущая ошибку пропажи сигнала х10, % +F09.12 63756 10 0 # Задержка включения ошибки пропажи сигнала х10, сек. +F09.13 63757 0 0 # Зарезервировано +F09.14 63758 50 0 # Пропорциональная составляющая 2 (Кр2) х100 +F09.15 63759 20 0 # Интегральная составляющая 2 (Ti2) х100 +F09.16 63760 0 0 # Дифференциальная составляющая 2 (Td2) х100 +F09.17 63761 0 0 # Переключение ПИД параметров +F09.18 63762 200 0 # Пороговое отклонение ПИД х10, % +F09.19 63763 600 0 # Частота засыпания х100, % +F09.20 63764 0 0 # Задержка засыпания х10, сек. +F09.21 63765 0 0 # Коэффициент пробуждения х10, % +F09.22 63766 5 0 # Задержка пробуждения х10, сек +F09.23 63767 0 0 # Предустановленное значение ПИД х10, % +F09.24 63768 0 0 # Время удержания предустановленного значения ПИД х10, сек. +F0A.00 64000 0 0 # Частота колебаний х10, % +F0A.01 64001 0 0 # Амплитуда частоты толчка х10, сек. +F0A.02 64002 0 0 # Время увеличения частоты колебаний х10, сек. +F0A.03 64003 0 0 # Время снижения частоты колебаний х10, сек. +F0A.04 64004 0 0 # Установка длины, м +F0A.05 64005 0 0 # Заданная длина, м +F0A.06 64006 1 0 # Количество импульсов на оборот +F0A.07 64007 1000 0 # Длина окружности вала х100, м +F0A.08 64008 1000 0 # Множитель х1000 +F0A.09 64009 1000 0 # Корректирующий коэффициент х1000 +F0A.10 64010 0 0 # Установленное значение счетчика +F0A.11 64011 0 0 # Определяемое значение счетчика +F0A.12 64012 0 0 # Время работы, мин. +F0A.13 64013 0 0 # Метод остановки +F0A.14 64014 0 0 # Зарезервировано +F0B.00 64256 0 0 # Режим простого ПЛК +F0B.01 64257 0 0 # Режим работы ПЛК при перебое с питанием +F0B.02 64258 0 0 # Многоскоростной режим 0 х10, % +F0B.03 64259 0 0 # Время работы в режиме 0 х10, сек. +F0B.04 64260 0 0 # Многоскоростной режим 1 х10, % +F0B.05 64261 0 0 # Время работы в режиме 1 х10, сек. +F0B.06 64262 0 0 # Многоскоростной режим 2 х10, % +F0B.07 64263 0 0 # Время работы в режиме 2 х10, сек. +F0B.08 64264 0 0 # Многоскоростной режим 3 х10, % +F0B.09 64265 0 0 # Время работы в режиме 3 х10, сек. +F0B.10 64266 0 0 # Многоскоростной режим 4 х10, % +F0B.11 64267 0 0 # Время работы в режиме 4 х10, сек. +F0B.12 64268 0 0 # Многоскоростной режим 5 х10, % +F0B.13 64269 0 0 # Время работы в режиме 5 х10, сек. +F0B.14 64270 0 0 # Многоскоростной режим 6 х10, % +F0B.15 64271 0 0 # Время работы в режиме 6 х10, сек. +F0B.16 64272 0 0 # Многоскоростной режим 7 х10, % +F0B.17 64273 0 0 # Время работы в режиме 7 х10, сек. +F0B.18 64274 0 0 # Многоскоростной режим 8 х10, % +F0B.19 64275 0 0 # Время работы в режиме 8 х10, сек. +F0B.20 64276 0 0 # Многоскоростной режим 9 х10, % +F0B.21 64277 0 0 # Время работы в режиме 9 х10, сек. +F0B.22 64278 0 0 # Многоскоростной режим 10 х10, % +F0B.23 64279 0 0 # Время работы в режиме 10 х10, сек. +F0B.24 64280 0 0 # Многоскоростной режим 11 х10, % +F0B.25 64281 0 0 # Время работы в режиме 11 х10, сек. +F0B.26 64282 0 0 # Многоскоростной режим 12 х10, % +F0B.27 64283 0 0 # Время работы в режиме 12 х10, сек. +F0B.28 64284 0 0 # Многоскоростной режим 13 х10, % +F0B.29 64285 0 0 # Время работы в режиме 13 х10, сек. +F0B.30 64286 0 0 # Многоскоростной режим 14 х10, % +F0B.31 64287 0 0 # Время работы в режиме 14 х10, сек. +F0B.32 64288 0 0 # Многоскоростной режим 15 х10, % +F0B.33 64289 0 0 # Время работы в режиме 15 х10, сек. +F0B.34 64290 0 0 # Значения разгона и торможения ПЛК (0 - 7) +F0B.35 64291 0 0 # Значения разгона и торможения ПЛК (8 - 15) +F0B.36 64292 0 0 # Перезапуск ПЛК +F0B.37 64293 0 0 # Режим перезапуска ПЛК +F0C.00 64512 11 0 # Защита от потери фазы +F0C.01 64513 0 0 # Снижение частоты при перебое c питанием х100, Гц/сек. +F0C.02 64514 1000 0 # Скорость снижения частоты при перебое с питанием х100, Гц/сек. +F0C.03 64515 0 0 # Превышение напряжения при блокировке вала +F0C.04 64516 140 0 # Уровень превышения напряжения при блокировке вала, % +F0C.05 64517 1 0 # Ограничение тока +F0C.06 64518 1660 0 # Автоматическое ограничение тока х10, % +F0C.07 64519 1000 0 # Шаг понижения частоты при ограничении тока х100, Гц/сек. +F0C.08 64520 0 0 # Защита от перегрузки +F0C.09 64521 166 0 # Предварительный сигнал обнаружения перегрузки, % +F0C.10 64522 0 0 # Время обнаружения перегрузки х100, сек. +F0C.11 64523 0 0 # Предварительный сигнал низкой нагрузки, % +F0C.12 64524 30 0 # Предварительный сигнал обнаружения низкой нагрузки, % +F0C.13 64525 10 0 # Время обнаружения низкой нагрузки х10, сек. +F0C.14 64526 0 0 # Режимы оповещения при обнаружении низкой нагрузки +F0C.15 64527 0 0 # Выбор регулировки несущей частоты +F0C.16 64528 1 0 # Режим ШИМ +F0C.17 64529 1 0 # Фильтр низких частот +F0C.18 64530 1 0 # Зарезервирован +F0D.00 64768 1 0 # Метод управления вторым двигателем +F0D.01 64769 1 0 # Тип нагрузки +F0D.02 64770 1 0 # Тип второго двигателя +F0D.03 64771 15 0 # Номинальная мощность двигателя 2 х10, КВт +F0D.04 64772 380 0 # Номинальное напряжение двигателя 2, В +F0D.05 64773 65 0 # Номинальный ток двигателя 2 х10, А +F0D.06 64774 5000 0 # Номинальная чаcтота двигателя 2 х100, Гц +F0D.07 64775 1450 0 # Номинальные обороты двигателя 2 х10, об/мин. +F0D.08 64776 1414 0 # Сопротивление статора двигателя 2 х1000, Ом +F0D.09 64777 1264 0 # Сопротивление ротора двигателя 2 х1000, Ом +F0D.10 64778 67 0 # Индуктивность рассеяния двигателя 2 х10 +F0D.11 64779 956 0 # Индуктивность двигателя 2 х10 +F0D.12 64780 33 0 # Ток холостого хода двигателя 2 х10, А +F0D.13 64781 1 0 # Зарезервировано +F0D.14 64782 1 0 # Зарезервировано +F0D.15 64783 1 0 # Зарезервировано +F0D.16 64784 1 0 # Зарезервировано +F0D.17 64785 1 0 # Зарезервировано +F0D.18 64786 1 0 # Зарезервировано +F0D.19 64787 1 0 # Зарезервировано +F0D.20 64788 1 0 # Зарезервировано +F0D.21 64789 1 0 # Зарезервировано +F0D.22 64790 1 0 # Зарезервировано +F0D.23 64791 1 0 # Зарезервировано +F0D.24 64792 1 0 # Зарезервировано +F0D.25 64793 1 0 # Зарезервировано +F0D.26 64794 1 0 # Защита от перегрузки для двигателя 2 +F0D.27 64795 1000 0 # Обнаружение перегрузки двигателя 2 х10, % +F0E.00 65024 1 0 # Сетевой адрес +F0E.01 65025 4 0 # Скорость передачи данных +F0E.02 65026 4 0 # Тип связи +F0E.03 65027 5 0 # Задержка ответа +F0E.04 65028 0 0 # Время обнаружения потери связи х10, сек +F0E.05 65029 0 0 # Ошибка передачи данных +F0E.06 65030 0 0 # Зарезервировано +F0E.07 65031 200 0 # Зарезервировано +F0E.08 65032 0 0 # Зарезервировано +A00.00 40960 0 0 # Управление скоростью/моментом +A00.01 40961 0 0 # Канал задания при выбранном управлении моментом +A00.02 40962 1500 0 # Цифровое задание момента х10, % +A00.03 40963 0 0 # Время разгона при управлении моментом х10, сек. +A00.04 40964 0 0 # Время замедления при управлении моментом х10, сек. +A00.05 40965 0 0 # Выбор канала ограничения частоты прямого вращения при управлении моментом +A00.06 40966 5000 0 # Цифровое ограничение частоты прямого вращения х100, Гц +A00.07 40967 0 0 # Выбор канала ограничения частоты обратного вращения при управлении моментом +A00.08 40968 5000 0 # Цифровое ограничение частоты обратного вращения х100, Гц +A00.09 40969 0 0 # Коэффициент компенсации момента нулевой скорости х10, % +A00.10 40970 300 0 # Уровень определения нулевой скорости х100, Гц +A00.11 40971 0 0 # Коэффициент компенсации трения скольжения х10, % +A01.00 41216 0 0 # Нижний предел входа AI1 х100, В, мА +A01.01 41217 0 0 # Соответствие нижнему пределу входа AI1 х10, % +A01.02 41218 1000 0 # Верхний предел входа AI1 х100, В, мА +A01.03 41219 1000 0 # Соответствие верхнему пределу входа AI1 х10, % +A01.04 41220 100 0 # Фильтр входа AI1 х1000, сек. +A01.05 41221 0 0 # Нижний предел входа AI2 х100, В, мА +A01.06 41222 0 0 # Соответствие нижнему пределу входа AI2 х10, % +A01.07 41223 1000 0 # Верхний предел входа AI2 х100, В, мА +A01.08 41224 1000 0 # Соответствие верхнему пределу входа AI2 х10, % +A01.09 41225 0 0 # Среднее значение входа AI2 х100, В +A01.10 41226 0 0 # Соответствие среднему значению входа AI2 х10, % +A01.11 41227 100 0 # Фильтр входа AI2 х1000, сек. +A01.12 41228 0 0 # Нижний предел входа AI3 х100, В +A01.13 41229 0 0 # Соответствие нижнему пределу входа AI3 х10, % +A01.14 41230 1000 0 # Верхний предел входа AI3 х100, В +A01.15 41231 1000 0 # Соответствие верхнему пределу входа AI3 х10, % +A01.16 41232 500 0 # Среднее значение входа AI3 х100, В +A01.17 41233 500 0 # Соответствие среднему значению входа AI3 х10, % +A01.18 41234 100 0 # Фильтр входа AI3 х1000, сек +A01.19 41235 50 0 # Фильтр дребезга контактов х1000, сек. +A02.00 41472 0 0 # Заданная частота х100, Гц +A02.01 41473 0 0 # Выходная частота х100, Гц +A02.02 41474 0 0 # Опорная частота разгона х100, Гц +A02.03 41475 0 0 # Выходное напряжение, В +A02.04 41476 0 0 # Выходной ток х10, А +A02.05 41477 0 0 # Обороты двигателя, об/мин +A02.06 41478 0 0 # Зарезервировано +A02.07 41479 0 0 # Зарезервировано +A02.08 41480 0 0 # Выходная мощность х10, % +A02.09 41481 0 0 # Выходной момент х10, % +A02.10 41482 0 0 # Оценка частоты двигателя х100, Гц +A02.11 41483 0 0 # Напряжение звена постоянного тока, В +A02.12 41484 0 0 # Состояние дискретных входов +A02.13 41485 0 0 # Состояние дискретных выходов +A02.14 41486 0 0 # Цифровое задание частоты х100, Гц +A02.15 41487 0 0 # Зарезервировано +A02.16 41488 0 0 # Линейная скорость +A02.17 41489 0 0 # Длина импульсов +A02.18 41490 0 0 # Счетчик значения +A02.19 41491 0 0 # Напряжение на входе AI1 х100, В +A02.20 41492 0 0 # Напряжение на входе AI2 х100, В +A02.21 41493 0 0 # Напряжение на входе AI3 х100, В +A02.22 41494 0 0 # Частота на входе HDI1 х100, КГц +A02.23 41495 0 0 # Уставка ПИД х10, % +A02.24 41496 0 0 # Обратная связь ПИД х10, % +A02.25 41497 0 0 # Выходной сигнал ПИД х100, % +A02.26 41498 0 0 # Коэффициент мощности х10, % +A02.27 41499 0 0 # Время работы, мин. +A02.28 41500 0 0 # Шаг работы ПЛК +A02.29 41501 0 0 # Выходной сигнал регулятора ASR х10, % +A02.30 41502 0 0 # Напряжение на выходе A01 х100, В +A02.31 41503 0 0 # Напряжение на выходе A02 х100, В +A02.32 41504 0 0 # Ток ПЧ х10, А +A02.33 41505 0 0 # Момент х10 +A02.34 41506 0 0 # Счетчик перегрузок двигателя +A02.35 41507 0 0 # Зарезервировано +A02.36 41508 1 0 # Текущий выбор двигателя +A03.00 41728 0 0 # Тип телеграммы +A03.01 41729 1 0 # Адрес устройства +A03.02 41730 0 0 # Параметр в телеграмме PZD3 (запись в ПЧ - DateOutput, %QW) +A03.03 41731 0 0 # Параметр в телеграмме PZD4 (запись в ПЧ - DateOutput, %QW) +A03.04 41732 0 0 # Параметр в телеграмме PZD5 (запись в ПЧ - DateOutput, %QW) +A03.05 41733 0 0 # Параметр в телеграмме PZD6 (запись в ПЧ - DateOutput, %QW) +A03.06 41734 0 0 # Параметр в телеграмме PZD7 (запись в ПЧ - DateOutput, %QW) +A03.07 41735 0 0 # Параметр в телеграмме PZD8 (запись в ПЧ - DateOutput, %QW) +A03.08 41736 0 0 # Параметр в телеграмме PZD9 (запись в ПЧ - DateOutput, %QW) +A03.09 41737 0 0 # Параметр в телеграмме PZD10 (запись в ПЧ - DateOutput, %QW) +A03.10 41738 0 0 # Параметр в телеграмме PZD11 (запись в ПЧ - DateOutput, %QW) +A03.11 41739 0 0 # Параметр в телеграмме PZD12 (запись в ПЧ - DateOutput, %QW) +A03.12 41740 0 0 # Зарезервировано +A03.13 41741 0 0 # Зарезервировано +A03.14 41742 0 0 # Параметр в телеграмме PZD3 (чтение из ПЧ - DateInput, %IW) +A03.15 41743 0 0 # Параметр в телеграмме PZD4 (чтение из ПЧ - DateInput, %IW) +A03.16 41744 0 0 # Параметр в телеграмме PZD5 (чтение из ПЧ - DateInput, %IW) +A03.17 41745 0 0 # Параметр в телеграмме PZD6 (чтение из ПЧ - DateInput, %IW) +A03.18 41746 0 0 # Параметр в телеграмме PZD7 (чтение из ПЧ - DateInput, %IW) +A03.19 41747 0 0 # Параметр в телеграмме PZD8 (чтение из ПЧ - DateInput, %IW) +A03.20 41748 0 0 # Параметр в телеграмме PZD9 (чтение из ПЧ - DateInput, %IW) +A03.21 41749 0 0 # Параметр в телеграмме PZD10 (чтение из ПЧ - DateInput, %IW) +A03.22 41750 0 0 # Параметр в телеграмме PZD11 (чтение из ПЧ - DateInput, %IW) +A03.23 41751 0 0 # Параметр в телеграмме PZD12 (чтение из ПЧ - DateInput, %IW) +A03.24 41752 0 0 # Зарезервировано +A03.25 41753 0 0 # Зарезервировано diff --git a/modbus_params/main.c b/modbus_params/main.c new file mode 100644 index 0000000..77b3260 --- /dev/null +++ b/modbus_params/main.c @@ -0,0 +1,120 @@ +/* + * This file is part of the modbus_param project. + * Copyright 2025 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "modbus.h" +#include "verbose.h" + +typedef struct{ + int help; // help + int verbose; // verbose level (not used yet) + int slave; // slave ID + char **dumpcodes; // keycodes to dump into file + char **writeregs; // reg=val to write + char **writecodes; // keycode=val to write + int **readregs; // regs to write + char **readcodes; // keycodes to write + char *dumpfile; // dump file name + char *outdic; // output dictionary to save everything read from slave + char *dicfile; // file with dictionary + char *device; // serial device + int baudrate; // baudrate + double dTdump; // dumping time interval (s) +} parameters; + +static parameters G = { + .slave = 1, + .device = "/dev/ttyUSB0", + .baudrate = 9600, + .dTdump = 0.1, +}; + +static sl_option_t cmdlnopts[] = { + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"}, + {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), "verbose level (each -v adds 1)"}, + {"outfile", NEED_ARG, NULL, 'o', arg_string, APTR(&G.dumpfile), "file with parameter's dump"}, + {"dumpkey", MULT_PAR, NULL, 'k', arg_string, APTR(&G.dumpcodes), "dump entry with this keycode; multiply parameter"}, + {"dumptime", NEED_ARG, NULL, 't', arg_double, APTR(&G.dTdump), "dumping time interval (seconds, default: 0.1)"}, + {"dictionary", NEED_ARG, NULL, 'D', arg_string, APTR(&G.dicfile), "file with dictionary (format: code register value writeable)"}, + {"slave", NEED_ARG, NULL, 's', arg_int, APTR(&G.slave), "slave ID (default: 1)"}, + {"device", NEED_ARG, NULL, 'd', arg_string, APTR(&G.device), "modbus device (default: /dev/ttyUSB0)"}, + {"baudrate", NEED_ARG, NULL, 'b', arg_int, APTR(&G.baudrate), "modbus baudrate (default: 9600)"}, + {"writer", MULT_PAR, NULL, 'w', arg_string, APTR(&G.writeregs), "write new value to register (format: reg=val); multiply parameter"}, + {"writec", MULT_PAR, NULL, 'W', arg_string, APTR(&G.writecodes),"write new value to register by keycode (format: keycode=val); multiply parameter"}, + {"outdic", NEED_ARG, NULL, 'O', arg_string, APTR(&G.outdic), "output dictionary for full device dump by input dictionary registers"}, + {"readr", MULT_PAR, NULL, 'r', arg_int, APTR(&G.readregs), "registers (by address) to read; multiply parameter"}, + {"readc", MULT_PAR, NULL, 'R', arg_string, APTR(&G.readcodes), "registers (by keycodes, checked by dictionary) to read; multiply parameter"}, + end_option +}; + +void signals(int sig){ + if(sig > 0) WARNX("Exig with signal %d", sig); + close_modbus(); + exit(sig); +} + +int main(int argc, char **argv){ + sl_init(); + sl_parseargs(&argc, &argv, cmdlnopts); + if(G.help) sl_showhelp(-1, cmdlnopts); + sl_loglevel_e lvl = G.verbose + LOGLEVEL_ERR; + set_verbose_level(lvl); + if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1; + if(!G.dicfile) ERRX("Point filename of dictionary"); + if(!opendict(G.dicfile)) signals(-1); + if(G.dumpcodes && !setdumppars(G.dumpcodes)) signals(-1); + if(G.dumpfile && !opendumpfile(G.dumpfile)) signals(-1); + if(!open_modbus(G.device, G.baudrate)) signals(-1); + if(!set_slave(G.slave)) signals(-1); + signal(SIGTERM, signals); // kill (-15) - quit + signal(SIGHUP, SIG_IGN); // hup - ignore + signal(SIGINT, signals); // ctrl+C - quit + signal(SIGQUIT, signals); // ctrl+\ - quit + signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z + if(G.writeregs){ + DBG("writeregs"); + green("Write user registers to slave %d\n", G.slave); + green("Total: %d written successfully", write_regval(G.writeregs)); + fflush(stdout); + } + if(G.writecodes){ + DBG("writecodes"); + green("Write user registers coded by keycode to slave %d\n", G.slave); + green("Total: %d written successfully", write_codeval(G.writecodes)); + fflush(stdout); + } + if(G.outdic){ + DBG("outdic"); + int N = dumpall(G.outdic); + if(N < 1) WARNX("Dump full dictionary failed"); + else green("Read %N registers, dump to %s\n", N, G.outdic); + fflush(stdout); + } + if(G.readregs) dumpregs(G.readregs); + if(G.readcodes) dumpcodes(G.readcodes); + if(G.dumpfile){ + DBG("dumpfile"); + if(!rundump(G.dTdump)) signals(-1); + DBG("Done, wait for ctrl+C"); + while(1); + } + return 0; +} diff --git a/modbus_params/modbus.c b/modbus_params/modbus.c new file mode 100644 index 0000000..f708a19 --- /dev/null +++ b/modbus_params/modbus.c @@ -0,0 +1,409 @@ +/* + * This file is part of the modbus_param project. + * Copyright 2025 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "modbus.h" +#include "verbose.h" + +static FILE *dumpfile = NULL; +static dicentry_t *dumppars = NULL; +static int dumpsize = 0; + +static dicentry_t *dictionary = NULL; +static int dictsize = 0; + +static modbus_t *modbus_ctx = NULL; +static pthread_mutex_t modbus_mutex = PTHREAD_MUTEX_INITIALIZER; + +static atomic_int stopdump = FALSE, isstopped = TRUE; + +// open dictionary file and check it; return TRUE if all OK +// all after "#" is comment; +// dictionary format: "'code' 'register' 'value' 'readonly flag'\n", e.g. +// "F00.09 61444 5000 1" +int opendict(const char *dic){ + FILE *f = fopen(dic, "r"); + if(!f){ + WARN("Can't open %s", dic); + return FALSE; + } + int dicsz = 0; + size_t linesz = BUFSIZ; + char *line = MALLOC(char, linesz); + dicentry_t curentry; + curentry.code = MALLOC(char, BUFSIZ); + int retcode = TRUE; + while(1){ + if(getline(&line, &linesz, f) < 0) break; + // DBG("Original LINE: '%s'", line); + char *comment = strchr(line, '#'); + if(comment) *comment = 0; + char *newline = strchr(line, '\n'); + if(newline) *newline = 0; + // DBG("LINE: '%s'", line); + if(*line == 0) continue; + if(4 != sscanf(line, "%s %" SCNu16 " %" SCNu16 " %" SCNu8, curentry.code, &curentry.reg, &curentry.value, &curentry.readonly)){ + WARNX("Can't understand this line: '%s'", line); + continue; + } + // DBG("Got line: '%s %" PRIu16 " %" PRIu16 " %" PRIu8, curentry.code, curentry.reg, curentry.value, curentry.readonly); + if(++dictsize >= dicsz){ + dicsz += 50; + dictionary = realloc(dictionary, sizeof(dicentry_t) * dicsz); + if(!dictionary){ + WARN("Can't allocate memory for dictionary"); + retcode = FALSE; + goto ret; + } + } + dicentry_t *entry = &dictionary[dictsize-1]; + entry->code = strdup(curentry.code); + entry->reg = curentry.reg; + entry->value = curentry.value; + entry->readonly = curentry.readonly; + //DBG("Add entry; now dictsize is %d", dictsize); + } +ret: + fclose(f); + FREE(curentry.code); + FREE(line); + return retcode; +} + +static int chkdict(){ + if(dictsize < 1){ + WARNX("Open dictionary first"); + return FALSE; + } + return TRUE; +} + +// find dictionary entry +dicentry_t *findentry_by_code(const char *code){ + if(!chkdict()) return NULL; + for(int i = 0; i < dictsize; ++i){ + if(strcmp(code, dictionary[i].code)) continue; + return &dictionary[i]; + } + return NULL; +} +dicentry_t *findentry_by_reg(uint16_t reg){ + if(!chkdict()) return NULL; + for(int i = 0; i < dictsize; ++i){ + if(reg != dictionary[i].reg) continue; + return &dictionary[i]; + } + return NULL; +} + +// prepare a list with dump parameters +int setdumppars(char **pars){ + if(!pars || !*pars) return FALSE; + if(!chkdict()) return FALSE; + FNAME(); + char **p = pars; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static int cursz = -1; // current allocated size + int N = 0; + pthread_mutex_lock(&mutex); + while(*p){ // count parameters and check them + dicentry_t *e = findentry_by_code(*p); + if(!e){ + WARNX("Can't find entry with code %s", *p); + pthread_mutex_unlock(&mutex); + return FALSE; + } + DBG("found entry do dump, reg=%d", e->reg); + if(cursz <= N){ + cursz += 50; + DBG("realloc list to %d", cursz); + dumppars = realloc(dumppars, sizeof(dicentry_t) * (cursz)); + DBG("zero mem"); + bzero(&dumppars[N], sizeof(dicentry_t)*(cursz-N)); + } + FREE(dumppars[N].code); + dumppars[N] = *e; + dumppars[N].code = strdup(e->code); + DBG("Add %s", e->code); + ++N; ++p; + } + dumpsize = N; + pthread_mutex_unlock(&mutex); + return TRUE; +} + +// open dump file and add header; return FALSE if failed +int opendumpfile(const char *name){ + if(!chkdict()) return FALSE; + if(dumpsize < 1){ + WARNX("Set dump parameters first"); + return FALSE; + } + if(!name) return FALSE; + closedumpfile(); + dumpfile = fopen(name, "w+"); + if(!dumpfile){ + WARN("Can't open %s", name); + return FALSE; + } + fprintf(dumpfile, "# time,s "); + for(int i = 0; i < dumpsize; ++i){ + fprintf(dumpfile, "%s ", dumppars[i].code); + } + fprintf(dumpfile, "\n"); + return TRUE; +} + +void closedumpfile(){ + if(dumpfile && !isstopped){ + if(!isstopped){ + stopdump = TRUE; + while(!isstopped); + } + fclose(dumpfile); + } +} + +static void *dumpthread(void *p){ + isstopped = FALSE; + stopdump = FALSE; + double dT = *(double*)p; + DBG("Dump thread started. Period: %gs", dT); + double startT = sl_dtime(); + while(!stopdump){ + double t0 = sl_dtime(); + fprintf(dumpfile, "%6.3g", t0 - startT); + for(int i = 0; i < dumpsize; ++i){ + if(!read_entry(&dumppars[i])) fprintf(dumpfile, "---- "); + else fprintf(dumpfile, "%4d ", dumppars[i].value); + } + fprintf(dumpfile, "\n"); + while(sl_dtime() - t0 < dT) usleep(100); + } + isstopped = TRUE; + return NULL; +} + +int rundump(double dT){ + if(!dumpfile){ + WARNX("Open dump file first"); + return FALSE; + } + if(dT < 0.){ + WARNX("Time interval should be > 0"); + return FALSE; + } + pthread_t thread; + static double T = 0.; + if(T != dT) T = dT; + DBG("user give dT: %g", T); + if(pthread_create(&thread, NULL, dumpthread, (void*)&T)){ + WARN("Can't create dumping thread"); + return FALSE; + } + DBG("Thread created, detach"); + pthread_detach(thread); + return TRUE; +} + +void close_modbus(){ + if(modbus_ctx){ + closedumpfile(); + modbus_close(modbus_ctx); + modbus_free(modbus_ctx); + } +} + +// read register and modify entry->reg; return FALSE if failed +int read_entry(dicentry_t *entry){ + if(!entry) return FALSE; + int ret = TRUE; + pthread_mutex_lock(&modbus_mutex); + if(modbus_read_registers(modbus_ctx, entry->reg, 1, &entry->value) < 0) ret = FALSE; + pthread_mutex_unlock(&modbus_mutex); + return ret; +} +// write register value; FALSE - if failed or read-only +int write_entry(dicentry_t *entry){ + if(!entry || entry->readonly) return FALSE; + int ret = TRUE; + pthread_mutex_lock(&modbus_mutex); + if(modbus_write_register(modbus_ctx, entry->reg, entry->value) < 0) ret = FALSE; + pthread_mutex_unlock(&modbus_mutex); + return ret; +} + +// write multiply regs (without checking by dict) by NULL-terminated array "reg=val"; return amount of items written +int write_regval(char **keyval){ + int written = 0; + dicentry_t entry = {0}; + while(*keyval){ + DBG("Parse %s", *keyval); + char key[SL_KEY_LEN], value[SL_VAL_LEN]; + if(2 != sl_get_keyval(*keyval, key, value)){ + WARNX("%s isn't in format reg=val", *keyval); + }else{ + DBG("key: %s, val: %s", key, value); + int r=-1, v=-1; + if(!sl_str2i(&r, key) || !sl_str2i(&v, value) || r < 0 || v < 0 || r > UINT16_MAX || v > UINT16_MAX){ + WARNX("Wrong register number or value: %d=%d; should be uint16_t", r, v); + }else{ + entry.value = (uint16_t)v; + entry.reg = (uint16_t)r; + if(write_entry(&entry)){ + ++written; + verbose(LOGLEVEL_MSG, "Written %u to register %u", entry.value, entry.reg); + }else verbose(LOGLEVEL_WARN, "Can't write %u to register %u", entry.value, entry.reg); + } + } + ++keyval; + } + return written; +} + +// write multiply regs by NULL-terminated array "keycode=val" (checking `keycode`); return amount of items written +int write_codeval(char **codeval){ + if(!chkdict()) return FALSE; + int written = 0; + dicentry_t entry = {0}; + while(*codeval){ + char key[SL_KEY_LEN], value[SL_VAL_LEN]; + if(2 != sl_get_keyval(*codeval, key, value)){ + WARNX("%s isn't in format keycode=val"); + }else{ + int v=-1; + if(!sl_str2i(&v, value) || v < 0 || v > UINT16_MAX){ + WARNX("Wrong value: %d; should be uint16_t", v); + }else{ + dicentry_t *de = findentry_by_code(key); + if(!de){ + WARNX("Keycode %s not found in dictionary", key); + }else{ + entry.readonly = de->readonly; + entry.reg = de->reg; + if(entry.readonly){ + verbose(LOGLEVEL_WARN, "Can't change readonly register %d", entry.reg); + }else{ + entry.value = (uint16_t)v; + if(write_entry(&entry)){ + ++written; + verbose(LOGLEVEL_MSG, "Written %u to register %u", entry.value, entry.reg); + }else verbose(LOGLEVEL_WARN, "Can't write %u to register %u", entry.value, entry.reg); + } + } + } + } + ++codeval; + } + return written; +} + +int open_modbus(const char *path, int baudrate){ + int ret = FALSE; + if(modbus_ctx) close_modbus(); + pthread_mutex_lock(&modbus_mutex); + modbus_ctx = modbus_new_rtu(path, baudrate, 'N', 8, 1); + if(!modbus_ctx){ + WARNX("Can't open device %s @ %d", path, baudrate); + goto rtn; + } + modbus_set_response_timeout(modbus_ctx, 0, 100000); + if(modbus_connect(modbus_ctx) < 0){ + WARNX("Can't connect to device %s", path); + modbus_free(modbus_ctx); + modbus_ctx = NULL; + goto rtn; + } + ret = TRUE; +rtn: + pthread_mutex_unlock(&modbus_mutex); + return ret; +} + +int set_slave(int ID){ + int ret = TRUE; + pthread_mutex_lock(&modbus_mutex); + if(modbus_set_slave(modbus_ctx, ID)){ + WARNX("Can't set slave ID to %d", ID); + ret = FALSE; + } + pthread_mutex_unlock(&modbus_mutex); + return ret; +} + +// dump all registers by input dictionary into output; also modify values of registers in dictionary +int dumpall(const char *outdic){ + if(!chkdict()) return -1; + int got = 0; + FILE *o = fopen(outdic, "w"); + if(!o){ + WARN("Can't open %s", outdic); + return -1; + } + for(int i = 0; i < dictsize; ++i){ + if(read_entry(&dictionary[i])){ + verbose(LOGLEVEL_MSG, "Read register %d, value: %d\n", dictionary[i].reg, dictionary[i].value); + ++got; + fprintf(o, "%s %4" PRIu16 " %4" PRIu16 " %" PRIu8 "\n", dictionary[i].code, dictionary[i].reg, dictionary[i].value, dictionary[i].readonly); + }else verbose(LOGLEVEL_WARN, "Can't read value of register %d\n", dictionary[i].reg); + } + fclose(o); + return got; +} + +// read dump register values and dump to stdout +void dumpregs(int **addresses){ + dicentry_t entry = {0}; + green("Dump registers: (reg val)\n"); + while(*addresses){ + int addr = **addresses; + if(addr < 0 || addr > UINT16_MAX){ + WARNX("Wrong register number: %d", addr); + }else{ + entry.reg = (uint16_t) addr; + if(!read_entry(&entry)) WARNX("Can't read register %d", addr); + else printf("%4d %4d\n", entry.reg, entry.value); + } + ++addresses; + } + printf("\n"); +} +// `dumpregs` but by keycodes (not modifying dictionary) +void dumpcodes(char **keycodes){ + if(!chkdict()) return; + dicentry_t entry = {0}; + green("Dump registers: (code (reg) val)\n"); + while(*keycodes){ + dicentry_t *de = findentry_by_code(*keycodes); + if(!de){ + WARNX("Can't find keycode %s in dictionary", *keycodes); + }else{ + entry.reg = de->reg; + if(!read_entry(&entry)) WARNX("Can't read register %s (%d)", *keycodes, entry.reg); + else printf("%s (%4d) %4d\n", de->code, entry.reg, entry.value); + } + ++keycodes; + } + printf("\n"); +} diff --git a/modbus_params/modbus.h b/modbus_params/modbus.h new file mode 100644 index 0000000..cab5ff7 --- /dev/null +++ b/modbus_params/modbus.h @@ -0,0 +1,51 @@ +/* + * This file is part of the modbus_param project. + * Copyright 2025 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +typedef struct{ + char *code; // mnemonic code + uint16_t value; // value + uint16_t reg; // register number + uint8_t readonly; // ==1 if can't be changed +} dicentry_t; + +int setdumppars(char **pars); +int opendumpfile(const char *name); +void closedumpfile(); +int rundump(double dT); + +int opendict(const char *dic); + +dicentry_t *findentry_by_code(const char *code); +dicentry_t *findentry_by_reg(uint16_t reg); + +int open_modbus(const char *path, int baudrate); +void close_modbus(); +int set_slave(int ID); + +int read_entry(dicentry_t *entry); +int write_entry(dicentry_t *entry); +int write_regval(char **keyval); +int write_codeval(char **codeval); + +int dumpall(const char *outdic); +void dumpregs(int **addresses); +void dumpcodes(char **keycodes); diff --git a/modbus_params/modbus_param.cflags b/modbus_params/modbus_param.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/modbus_params/modbus_param.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/modbus_params/modbus_param.config b/modbus_params/modbus_param.config new file mode 100644 index 0000000..809111b --- /dev/null +++ b/modbus_params/modbus_param.config @@ -0,0 +1,2 @@ +#define _XOPEN_SOURCE 1111 +#define _GNU_SOURCE diff --git a/modbus_params/modbus_param.creator b/modbus_params/modbus_param.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/modbus_params/modbus_param.creator @@ -0,0 +1 @@ +[General] diff --git a/modbus_params/modbus_param.cxxflags b/modbus_params/modbus_param.cxxflags new file mode 100644 index 0000000..6435dfc --- /dev/null +++ b/modbus_params/modbus_param.cxxflags @@ -0,0 +1 @@ +-std=c++17 \ No newline at end of file diff --git a/modbus_params/modbus_param.files b/modbus_params/modbus_param.files new file mode 100644 index 0000000..5b6d0ff --- /dev/null +++ b/modbus_params/modbus_param.files @@ -0,0 +1,5 @@ +main.c +modbus.c +modbus.h +verbose.c +verbose.h diff --git a/modbus_params/modbus_param.includes b/modbus_params/modbus_param.includes new file mode 100644 index 0000000..e69de29 diff --git a/modbus_params/verbose.c b/modbus_params/verbose.c new file mode 100644 index 0000000..94418bf --- /dev/null +++ b/modbus_params/verbose.c @@ -0,0 +1,40 @@ +/* + * This file is part of the modbus_param project. + * Copyright 2025 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "verbose.h" + +static sl_loglevel_e verblvl = LOGLEVEL_WARN; + +void set_verbose_level(sl_loglevel_e level){ + if(level >= LOGLEVEL_AMOUNT) level = LOGLEVEL_AMOUNT - 1; + else if(level < 0) level = 0; + verblvl = level; +} + +void verbose(sl_loglevel_e lvl, const char *fmt, ...){ + if(lvl > verblvl) return; + va_list ar; + va_start(ar, fmt); + vprintf(fmt, ar); + va_end(ar); + fflush(stdout); +} + diff --git a/modbus_params/verbose.h b/modbus_params/verbose.h new file mode 100644 index 0000000..f2476af --- /dev/null +++ b/modbus_params/verbose.h @@ -0,0 +1,24 @@ +/* + * This file is part of the modbus_param project. + * Copyright 2025 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +void set_verbose_level(sl_loglevel_e level); +void verbose(sl_loglevel_e lvl, const char *fmt, ...);