commit f693d28c788fb0475bd72b74463703d369b9fdc5 Author: Egor Tsyganchuk Date: Tue May 6 16:44:21 2025 +0300 Initializing the repository diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e1a0051 --- /dev/null +++ b/.clang-format @@ -0,0 +1,31 @@ +AccessModifierOffset: -4 +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveDeclarations: Consecutive +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLambdasOnASingleLine: None +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: All +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakTemplateDeclarations: Yes +ColumnLimit: 100 +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +IndentExternBlock: NoIndent +IndentPPDirectives: AfterHash +IndentWidth: 4 +NamespaceIndentation: None +PackConstructorInitializers: Never +PointerAlignment: Right +ReflowComments: Always +SortIncludes: CaseSensitive +TabWidth: 4 +UseTab: Never diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6733131 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode +.idea +cache +build \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..687bf56 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.0) +project(jlv135_cli C) + +# Настройка кросс-компиляции +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_C_COMPILER arm-uclinuxfdpiceabi-gcc) +set(CMAKE_STRIP arm-uclinuxfdpiceabi-strip) + +# Настройки компиляции +set(CMAKE_C_FLAGS "-Os -fdata-sections -ffunction-sections -mno-unaligned-access") +set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections") + +# Создание исполняемого файла +add_executable(${PROJECT_NAME} + src/jl_modbus/jl_modbus_config.c + src/jl_modbus/jl_config.c + src/jlv135_cli/main.c) + +# Настройка библиотек +target_link_libraries(${CMAKE_PROJECT_NAME} pthread) + +# Добавление каталогов для поиска заголовков +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE + inc) + +# Опция strip +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_custom_command( + TARGET ${CMAKE_PROJECT_NAME} POST_BUILD + COMMAND strip $ + COMMENT "Stripping debug symbols (Release only)" + ) +endif() \ No newline at end of file diff --git a/inc/jl_modbus/jl_config.h b/inc/jl_modbus/jl_config.h new file mode 100644 index 0000000..01e452f --- /dev/null +++ b/inc/jl_modbus/jl_config.h @@ -0,0 +1,22 @@ +#ifndef JLV135_CLI_CONFIG_H +#define JLV135_CLI_CONFIG_H + +#include +#include + +#define JLV135_BACKUP_BLOCKS_ADDRESS 0x40400 +#define JLV135_DEV_MTD_BLOCK "/dev/mtdblock0" + +void +jl_config_load(const char *name, void *def, size_t size); + +bool +jl_config_read(int block_num, void *data, size_t size); + +bool +jl_config_write(int block_num, void *data, size_t size); + +void +jl_config_save(const char *name, void *def, size_t size); + +#endif // JLV135_CLI_CONFIG_H diff --git a/inc/jl_modbus/jl_modbus_config.h b/inc/jl_modbus/jl_modbus_config.h new file mode 100644 index 0000000..08cbfe4 --- /dev/null +++ b/inc/jl_modbus/jl_modbus_config.h @@ -0,0 +1,54 @@ +#ifndef JLV135_CLI_MODBUS_CONFIG_H +#define JLV135_CLI_MODBUS_CONFIG_H + +#include +#include +#include + +typedef struct jl_version +{ + uint16_t major; + uint16_t minor; + uint16_t path; +} jl_version_t; + +typedef struct jl_modbus_tcp_port +{ + uint32_t addr; + uint16_t port; + uint16_t repeate; + uint16_t timeout; +} jl_modbus_tcp_port_t; + +static const uint32_t jl_modbus_rs485_baud_rates[] = {9600, 19200, 38400, 57600, 115200}; + +typedef struct jl_modbus_rs485_port +{ + uint16_t speed; + uint16_t prop_p; + uint16_t prop_s; + uint16_t repeate; + uint16_t timeout; +} jl_modbus_rs485_port_t; + +typedef struct jl_modbus_config +{ + uint16_t num_port; + uint16_t addr; + uint16_t tcycle; + jl_modbus_rs485_port_t port_rtu; + jl_modbus_tcp_port_t port_tcp; +} jl_modbus_config_t; + +// -------------------------- Методы -------------------------- // + +bool +jl_modbus_rs485_baud_rate_is_index_valid(size_t index); + +uint32_t +jl_modbus_rs485_baud_rate_get_baud_by_index(size_t index); + +int32_t +jl_modbus_rs485_baud_rate_get_index_by_baud(uint32_t baud); + +#endif // JLV135_CLI_MODBUS_CONFIG_H diff --git a/inc/jlv135_cli/jl_util.h b/inc/jlv135_cli/jl_util.h new file mode 100644 index 0000000..f4ff28b --- /dev/null +++ b/inc/jlv135_cli/jl_util.h @@ -0,0 +1,6 @@ +#ifndef JL135_CLI_UTIL +#define JL135_CLI_UTIL + +#define jl_array_size(x) (sizeof(x) / sizeof(x[0])) + +#endif // JL135_CLI_UTIL \ No newline at end of file diff --git a/src/jl_modbus/jl_config.c b/src/jl_modbus/jl_config.c new file mode 100644 index 0000000..3599342 --- /dev/null +++ b/src/jl_modbus/jl_config.c @@ -0,0 +1,173 @@ +#include +#include +#include + +#if JL_CONFIG_SAVE_TO_FILE +static const char *jl_config_path = JL_CONFIG_SAVE_TO_FILE_PATH; +void +jl_config_load(const char *name, void *def, size_t size) +{ + char filename[256] = {0}; + strcat(filename, jl_config_path); + strcat(filename, name); + strcat(filename, ".bcfg"); + + // printf("jl_config_load [%s]\n", filename); + FILE *f = fopen(filename, "rb"); + if (f != NULL) + { + fread(def, 1, size, f); + fclose(f); + // printf("Load %s\n", name); + return; + } + + jl_config_save(name, def, size); +} + +void +jl_config_save(const char *name, void *def, size_t size) +{ + char filename[256] = {0}; + strcat(filename, jl_config_path); + strcat(filename, name); + strcat(filename, ".bcfg"); + + // printf("jl_config_save [%s]\n", filename); + FILE *f = fopen(filename, "wb"); + if (f != NULL) + { + // printf("Save %s\n", name); + fwrite(def, 1, size, f); + fclose(f); + sync(); + } +} + +#else + +const int backup_block_size = 0x80; +struct backup_block_t +{ + char name[32]; + int num; +} backup_blocks[] = {{.name = "wifi", .num = 0}, + {.name = "modbus", .num = 1}, + {.name = "display", .num = 2}, + {.name = "feature", .num = 3}, + {.name = "datatime", .num = 4}, + {.name = "sensor", .num = 5}, + {.name = "secure", .num = 6}, + {.name = "service", .num = 7}, + {{0}}}; + +bool +jl_config_read(int block_num, void *data, size_t size) +{ + FILE *mtd0 = fopen(JLV135_DEV_MTD_BLOCK, "rb"); + size_t read_size = 0; + if (mtd0) + { + bool isSeek = + fseek(mtd0, JLV135_BACKUP_BLOCKS_ADDRESS + backup_block_size * block_num, SEEK_SET) == + 0; + if (isSeek) + { + read_size = fread(data, 1, size, mtd0); + } + } + else + { + return false; + } + + fclose(mtd0); + return read_size == size; +} + +bool +jl_config_write(int block_num, void *data, size_t size) +{ + FILE *mtd0 = fopen(JLV135_DEV_MTD_BLOCK, "r+b"); + size_t write_size = 0; + if (mtd0) + { + bool isSeek = + fseek(mtd0, JLV135_BACKUP_BLOCKS_ADDRESS + backup_block_size * block_num, SEEK_SET) == + 0; + if (isSeek) + { + write_size = fwrite(data, 1, size, mtd0); + rewind(mtd0); + } + } + else + { + return false; + } + + fclose(mtd0); + return write_size == size; +} + +void +jl_config_load(const char *name, void *def, size_t size) +{ + struct backup_block_t *block = backup_blocks; + + while (*block->name) + { + if (strcmp(block->name, name) == 0) + { + unsigned char mem[size]; + bool empty = true; + if (!jl_config_read(block->num, mem, size)) + { + return; + } + + for (int i = 0; i < size; i++) + { + if (mem[i] != 0xFF) + { + empty = false; + break; + } + } + if (empty) + { + jl_config_save(name, def, size); + } + else + { + memcpy(def, mem, size); + } + return; + } + block++; + } +} + +void +jl_config_save(const char *name, void *def, size_t size) +{ + struct backup_block_t *block = backup_blocks; + + while (*block->name) + { + if (strcmp(block->name, name) == 0) + { + unsigned char temp[size]; + if (jl_config_read(block->num, temp, size) && memcmp(temp, def, size) == 0) + { + return; + } + + jl_config_write(block->num, def, size); + return; + } + block++; + } +} + +#endif \ No newline at end of file diff --git a/src/jl_modbus/jl_modbus_config.c b/src/jl_modbus/jl_modbus_config.c new file mode 100644 index 0000000..8f788d0 --- /dev/null +++ b/src/jl_modbus/jl_modbus_config.c @@ -0,0 +1,29 @@ +#include +#include + +bool +jl_modbus_rs485_baud_rate_is_index_valid(size_t index) +{ + size_t sz = jl_array_size(jl_modbus_rs485_baud_rates); + return index < sz; +} + +uint32_t +jl_modbus_rs485_baud_rate_get_baud_by_index(size_t index) +{ + return jl_modbus_rs485_baud_rate_is_index_valid(index) ? jl_modbus_rs485_baud_rates[index] : 0; +} + +int32_t +jl_modbus_rs485_baud_rate_get_index_by_baud(uint32_t baud) +{ + size_t sz = jl_array_size(jl_modbus_rs485_baud_rates); + for (size_t i = 0; i < sz; i++) + { + if (jl_modbus_rs485_baud_rates[i] == baud) + { + return (int32_t)i; + } + } + return -1; +} diff --git a/src/jlv135_cli/main.c b/src/jlv135_cli/main.c new file mode 100644 index 0000000..afdc9c6 --- /dev/null +++ b/src/jlv135_cli/main.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include + +#define JLV135_CLI_OK 0 +#define JLV135_CLI_ERROR 1 + +void +print_version(jl_version_t *ver) +{ + printf("Version:\n"); + printf(" major: %u\n", ver->major); + printf(" minor: %u\n", ver->minor); + printf(" path: %u\n\n", ver->path); +} + +// Функция для печати TCP порта +void +print_tcp_port(jl_modbus_tcp_port_t *tcp) +{ + printf("Modbus TCP Port:\n"); + printf(" addr: %u\n", tcp->addr); + printf(" port: %u\n", tcp->port); + printf(" repeate: %u\n", tcp->repeate); + printf(" timeout: %u\n\n", tcp->timeout); +} + +void +print_rs485_baud_rates(uint16_t speed_index) +{ + if (jl_modbus_rs485_baud_rate_is_index_valid(speed_index)) + { + printf(" speed: %u\n", jl_modbus_rs485_baud_rates[speed_index]); + } + else + { + printf(" speed: %s\n", "unknown"); + } +} + +// Функция для печати RS485 порта +void +print_rs485_port(jl_modbus_rs485_port_t *rs485) +{ + printf("Modbus RS485 Port:\n"); + print_rs485_baud_rates(rs485->speed); + + printf(" prop_p: %u\n", rs485->prop_p); + printf(" prop_s: %u\n", rs485->prop_s); + printf(" repeate: %u\n", rs485->repeate); + printf(" timeout: %u\n\n", rs485->timeout); +} + +// Функция для печати конфигурации Modbus +void +print_modbus_config(jl_modbus_config_t *config) +{ + printf("Modbus Config:\n"); + printf(" num_port: %u\n", config->num_port); + printf(" addr: %u\n", config->addr); + printf(" tcycle: %u\n", config->tcycle); + printf("\n"); + + // Печатаем вложенные структуры + print_rs485_port(&config->port_rtu); + print_tcp_port(&config->port_tcp); +} + +int +main(int argc, const char *argv[]) +{ + jl_modbus_config_t conf = {}; + jl_config_load("modbus", &conf, sizeof(jl_modbus_config_t)); + + if (argc == 1) + { + print_modbus_config(&conf); + } + else + { + bool modbus_mode = false; // Флаг, что был передан --modbus + bool modbus_rs485_mode = true; // Флаг, что был передан --rs485 + + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "--modbus") == 0) + { + modbus_mode = true; + continue; + } + else if (modbus_mode) + { + // Эти параметры обрабатываются только если был --modbus + if (modbus_mode && strcmp(argv[i], "--rs485") == 0) + { + modbus_rs485_mode = true; + continue; + } + else if (modbus_rs485_mode && strcmp(argv[i], "--speed") == 0) + { + if (i + 1 < argc) + { + long val = strtol(argv[i + 1], NULL, 10); + int idx = jl_modbus_rs485_baud_rate_get_index_by_baud(val); + if (idx == -1) + { + fprintf(stderr, "Error: invalid speed value\n"); + return JLV135_CLI_ERROR; + } + else + { + conf.port_rtu.speed = idx; + jl_config_save("modbus", &conf, sizeof(jl_modbus_config_t)); + } + break; + } + else + { + fprintf(stderr, "Error: --speed requires a value\n"); + return JLV135_CLI_ERROR; + } + } + else + { + fprintf(stderr, "Unknown parameter for --modbus: %s\n", argv[i]); + return JLV135_CLI_ERROR; + } + } + else + { + fprintf(stderr, "Unknown parameter: %s (did you forget --modbus?)\n", argv[i]); + return JLV135_CLI_ERROR; + } + } + } + return JLV135_CLI_OK; +} \ No newline at end of file