обновление: пароль в hex, защита от перебора пароля, функция регистрации...

обновление: пароль в hex, защита от перебора пароля, функция регистрации команд, иправление проверки границ памяти, ожидание завершения передачи uart, сброс блокировки пароля.
parent 3da7bf37
// // cli.c
// //******************************************** Включаемые файлы *********************************************
// #include "cli.h"
// #include "lmcal.h"
// #include "string.h"
// #include "ring_buffer.h"
// #include <stdio.h>
// #include <stdlib.h>
// #include <stdint.h>
// #include "tcp.h"
// #include "fpga_cmn.h"
// #include "submodule.h"
// #include "submodule_cfg.h"
// #include "lta_private.h"
// //******************************************* Локальные константы *******************************************
// #define CLI_PROMPT "> "
// #define CLI_MSG_UNKNOWN_CMD "\r\nERROR: Unknown command\r\n"
// #define CLI_MSG_OK "OK\r\n"
// #define CLI_MSG_ERROR "ERROR: %s (code: %d)\r\n"
// #define CLI_MSG_BUFFER_OVERFLOW "\r\nERROR: Buffer overflow\r\n"
// //************************************* Локальные (приватные) переменные ************************************
// static ringbuf_t fifo_rx; // Кольцевой буфер приема
// static u8 fifo_rx_buf[CLI_MAX_CMD_LENGTH]; // Буфер данных приема
// static char cli_cmd_buffer[CLI_MAX_CMD_LENGTH]; // Буфер для приема команды
// static u16 cli_cmd_index = 0; // Индекс в буфере команды
// static const cli_command_t* cli_commands[CLI_MAX_COMMANDS]; // Массив зарегистрированных команд
// static u8 cli_cmd_count = 0; // Количество зарегистрированных команд
// static cli_state_t cli_current_state = CLI_STATE_DISABLED; // Текущее состояние CLI
// static char* cli_args[CLI_MAX_ARGS]; // Массив аргументов команды
// static int cli_argc = 0; // Количество аргументов команды
// // Флаг для разрешения отправки в выключенном состоянии (только для инициализации)
// static bool cli_allow_send_in_disabled = true;
// //************************************* Локальные (приватные) функции ***************************************
// // Объявления функций для устранения ошибок компиляции
// static fun_res_t cli_cmd_help_handler(int argc, char** argv);
// static fun_res_t cli_cmd_cli_on_handler(int argc, char** argv);
// static fun_res_t cli_cmd_cli_off_handler(int argc, char** argv);
// static fun_res_t cli_cmd_mem_read_handler(int argc, char** argv);
// static fun_res_t cli_cmd_lta_search_handler(int argc, char** argv);
// static void cli_process_command(void);
// static void cli_process_disabled_mode(void);
// static void cli_process_normal_mode(void);
// /**
// * @brief Безопасное копирование строки с ограничением длины
// */
// static void cli_strncpy_safe(char* dest, const char* src, size_t dest_size) {
// if (dest == NULL || src == NULL || dest_size == 0) return;
// size_t i;
// for (i = 0; i < dest_size - 1 && src[i] != '\0'; i++) {
// dest[i] = src[i];
// }
// dest[i] = '\0';
// }
// /**
// * @brief Разбор команды на аргументы (без модификации исходной строки)
// */
// static void cli_parse_command(const char* cmd) {
// cli_argc = 0;
// if (cmd == NULL) return;
// // Статическое хранилище для копий аргументов, чтобы указатели были валидны после выхода из функции
// static char token_storage[CLI_MAX_ARGS][CLI_MAX_CMD_LENGTH];
// // Обнуляем предыдущее содержимое (необязательно, но полезно для отладки)
// for (int i = 0; i < CLI_MAX_ARGS; i++) {
// token_storage[i][0] = '\0';
// cli_args[i] = NULL;
// }
// // Создаем копию строки для безопасного парсинга
// char cmd_copy[CLI_MAX_CMD_LENGTH];
// cli_strncpy_safe(cmd_copy, cmd, sizeof(cmd_copy));
// char* token = strtok(cmd_copy, " \t\n\r");
// while (token != NULL && cli_argc < CLI_MAX_ARGS) {
// // Копируем токен в постоянное хранилище и сохраняем указатель
// cli_strncpy_safe(token_storage[cli_argc], token, sizeof(token_storage[cli_argc]));
// cli_args[cli_argc] = token_storage[cli_argc];
// cli_argc++;
// token = strtok(NULL, " \t\n\r");
// }
// }
// /**
// * @brief Поиск команды по имени
// */
// static const cli_command_t* cli_find_command(const char* name) {
// if (name == NULL) return NULL;
// for (u8 i = 0; i < cli_cmd_count; i++) {
// if (strcmp(cli_commands[i]->name, name) == 0) {
// return cli_commands[i];
// }
// }
// return NULL;
// }
// /**
// * @brief Получение строкового описания кода ошибки
// */
// static const char* cli_get_error_string(fun_res_t error_code) {
// switch (error_code) {
// case ERR_OK: return "Success";
// case ERR_ASSERT_ERROR: return "Assertion failed";
// case ERR_RUNTIME_ERROR: return "Runtime error";
// case ERR_INVALID_ARGUMENT: return "Invalid argument";
// case ERR_NOT_IMPLEMENTED: return "Not implemented";
// case ERR_TIMEOUT_EXPIRED: return "Timeout expired";
// default: return "Unknown error";
// }
// }
// /**
// * @brief Включение модуля
// */
// static void cli_enable(){
// // Поностью чистим буферы
// rb_clear(&fifo_rx);
// cli_cmd_index = 0;
// memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
// // Вкдючаем cli
// cli_current_state = CLI_STATE_IDLE;
// cli_send_string("\r\n------------------------------------------------\r\n");
// cli_send_string(" ==== CLI Enabled ====\r\n");
// cli_send_string("------------------------------------------------\r\n");
// cli_send_string(" Type 'help' for available commands");
// cli_send_string("\r\n------------------------------------------------\r\n");
// cli_send_string(CLI_PROMPT);
// }
// /**
// * @brief Обработка полученной команды
// */
// static void cli_process_command(void) {
// if (cli_argc == 0) {
// return;
// }
// const cli_command_t* cmd = cli_find_command(cli_args[0]);
// if (cmd == NULL) {
// cli_send_string(CLI_MSG_UNKNOWN_CMD);
// return;
// }
// // Выполнение команды
// fun_res_t result = cmd->handler(cli_argc, cli_args);
// if (result == ERR_OK) {
// cli_send_string(CLI_MSG_OK);
// } else {
// char error_msg[64];
// snprintf(error_msg, sizeof(error_msg), CLI_MSG_ERROR,
// cli_get_error_string(result), result);
// cli_send_string(error_msg);
// }
// }
// /**
// * @brief Обработка выключенного состояния CLI
// */
// static void cli_process_disabled_mode(void) {
// static char temp_buffer[CLI_MAX_CMD_LENGTH] = {0};
// static u16 temp_index = 0;
// static bool promt_shown = false;
// if(!promt_shown) {
// cli_send_string(CLI_PROMPT);
// promt_shown = true;
// }
// while (rb_get_items_qty(&fifo_rx) > 0) {
// u8 received_char;
// if (rb_get_item(&fifo_rx, &received_char) != RB_RES_OK) {
// continue;
// }
// // Добавляем символ во временный буфер
// if (temp_index < (CLI_MAX_CMD_LENGTH - 1) &&
// received_char != '\r' && received_char != '\n') {
// temp_buffer[temp_index++] = received_char;
// }
// // Enter - проверяем команду
// if (received_char == '\r' || received_char == '\n') {
// if (temp_index > 0) {
// temp_buffer[temp_index] = '\0';
// // Временно парсим команду
// char temp_args[CLI_MAX_ARGS][CLI_MAX_CMD_LENGTH];
// int temp_argc = 0;
// char temp_copy[CLI_MAX_CMD_LENGTH];
// cli_strncpy_safe(temp_copy, temp_buffer, sizeof(temp_copy));
// char* token = strtok(temp_copy, " \t\n\r");
// while (token != NULL && temp_argc < CLI_MAX_ARGS) {
// cli_strncpy_safe(temp_args[temp_argc], token, sizeof(temp_args[temp_argc]));
// temp_argc++;
// token = strtok(NULL, " \t\n\r");
// }
// // Если это команда cli_on - обрабатываем
// if (temp_argc > 0 && strcmp(temp_args[0], "cli_on") == 0) {
// cli_enable();
// }
// }
// // Сбрасываем временный буфер
// temp_index = 0;
// memset(temp_buffer, 0, sizeof(temp_buffer));
// }
// }
// }
// /**
// * @brief Обработка нормального режима (CLI включен)
// */
// static void cli_process_normal_mode(void) {
// while (rb_get_items_qty(&fifo_rx) > 0) {
// u8 received_char;
// if (rb_get_item(&fifo_rx, &received_char) != RB_RES_OK) {
// continue;
// }
// // Если мы в состоянии IDLE и получаем первый символ - переходим в RECEIVING
// if (cli_current_state == CLI_STATE_IDLE && cli_cmd_index == 0) {
// cli_current_state = CLI_STATE_RECEIVING;
// }
// // Пропускаем пустые строки в начале
// if (cli_cmd_index == 0 && (received_char == '\n' || received_char == '\r')) {
// cli_current_state = CLI_STATE_IDLE;
// continue;
// }
// // Enter - обработка команды
// if (received_char == '\r' || received_char == '\n') {
// if (cli_cmd_index > 0) {
// cli_cmd_buffer[cli_cmd_index] = '\0';
// // Разбираем команду на аргументы
// cli_parse_command(cli_cmd_buffer);
// // Обрабатываем команду
// cli_current_state = CLI_STATE_PROCESSING;
// cli_process_command();
// // После обработки команды проверяем, не была ли это команда cli_off
// // Если да, то сразу выходим из нормального режима
// if (cli_current_state == CLI_STATE_DISABLED) {
// return;
// }
// }
// // Возвращаемся в состояние IDLE и выводим приглашение
// cli_current_state = CLI_STATE_IDLE;
// cli_cmd_index = 0;
// memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
// cli_send_string(CLI_PROMPT);
// }
// // Backspace - удаление символа
// else if (received_char == 8 || received_char == 127) {
// if (cli_cmd_index > 0) {
// // Уменьшаем индекс и явно очищаем удаленный символ в буфере
// cli_cmd_index--;
// cli_cmd_buffer[cli_cmd_index] = '\0';
// // Эхо: сдвинуть курсор назад, стереть символ, снова сдвинуть
// cli_send_string("\b \b");
// }
// // если индекс == 0 — ничего не делаем
// }
// // Обычный символ - добавление в буфер
// else if (cli_cmd_index < (CLI_MAX_CMD_LENGTH - 1)) {
// cli_cmd_buffer[cli_cmd_index++] = received_char;
// // Эхо символа
// u8 echo_char[2] = {received_char, 0};
// cli_send_string((char*)echo_char);
// }
// // Переполнение буфера команды
// else {
// cli_send_string(CLI_MSG_BUFFER_OVERFLOW);
// cli_current_state = CLI_STATE_IDLE;
// cli_cmd_index = 0;
// memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
// rb_clear(&fifo_rx);
// cli_send_string(CLI_PROMPT);
// }
// }
// }
// /**
// * @brief Колбек прерывания по приему байта через UART
// * @note Добавляет принятый байт в буфер приема
// */
// static void f_uart_read_byte(void) {
// // Исправлено: правильный вызов функции согласно LMCAL API (один аргумент)
// u16 rx_data = lmcal_uart_read(CLI_UART_CHANNEL);
// u8 byte_data = (u8)(rx_data & 0xFF);
// rb_add_item(&fifo_rx, &byte_data);
// }
// /**
// * @brief Отправка строки через UART с буферизацией
// * @param str Указатель на строку для отправки
// */
// void cli_send_string(const char* str) {
// if (str == NULL) return;
// // Разрешаем отправку в следующих случаях:
// // 1. CLI включен (INIT, IDLE, RECEIVING, PROCESSING)
// // 2. Разрешена отправка в выключенном состоянии (только для инициализации)
// if (cli_current_state != CLI_STATE_DISABLED || cli_allow_send_in_disabled) {
// // Отправка каждого символа синхронно
// while (*str != '\0') {
// lmcal_uart_write(CLI_UART_CHANNEL, (u16)*str);
// str++;
// }
// }
// }
// /**
// * @brief Обработчик встроенной команды help
// */
// static fun_res_t cli_cmd_help_handler(int argc, char** argv) {
// L_UNUSED(argc);
// L_UNUSED(argv);
// // В выключенном состоянии команда не должна работать
// if (cli_current_state == CLI_STATE_DISABLED) {
// return ERR_RUNTIME_ERROR;
// }
// cli_send_string("\r\n------------------------------------------------\r\n");
// cli_send_string("============ CLI Help ============\r\n");
// cli_send_string("------------------------------------------------\r\n");
// cli_send_string("Command Line Interface for system control\r\n");
// cli_send_string("------------------------------------------------\r\n");
// for (u8 i = 0; i < cli_cmd_count; i++) {
// // Формируем строку с именем команды и ее описанием
// char help_line[96];
// snprintf(help_line, sizeof(help_line), "%-12s - %s\r\n",
// cli_commands[i]->name,
// cli_commands[i]->description ? cli_commands[i]->description : "No description");
// cli_send_string(help_line);
// }
// cli_send_string("------------------------------------------------\r\n");
// cli_send_string("Type '<command> --help' for more information\r\n");
// cli_send_string("------------------------------------------------\r\n");
// return ERR_OK;
// }
// /**
// * @brief Обработчик встроенной команды cli_on
// */
// static fun_res_t cli_cmd_cli_on_handler(int argc, char** argv) {
// L_UNUSED(argc);
// L_UNUSED(argv);
// // Если уже в режиме пароля или включен, ничего не делаем
// if (cli_current_state != CLI_STATE_DISABLED) {
// cli_send_string("CLI is already enabled\r\n");
// return ERR_OK;
// }
// // Очищаем буфер
// rb_clear(&fifo_rx);
// // Включаем cli
// cli_enable();
// return ERR_OK;
// }
// /**
// * @brief Обработчик встроенной команды cli_off
// */
// static fun_res_t cli_cmd_cli_off_handler(int argc, char** argv) {
// L_UNUSED(argc);
// L_UNUSED(argv);
// if (cli_current_state == CLI_STATE_DISABLED) {
// return ERR_OK; // Уже выключен
// }
// // Временно разрешаем отправку для завершающих сообщений команды cli_off
// bool temp_allow_send = cli_allow_send_in_disabled;
// cli_allow_send_in_disabled = true;
// // Очищаем буферы
// rb_clear(&fifo_rx);
// // Сбрасываем состояние командного буфера
// cli_cmd_index = 0;
// memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
// // Выводим сообщение о выключении (только если CLI был включен)
// cli_send_string("\r\nCLI disabled\r\n");
// // Выключаем CLI
// cli_current_state = CLI_STATE_DISABLED;
// // Восстанавливаем исходное значение флага
// cli_allow_send_in_disabled = temp_allow_send;
// return ERR_OK;
// }
// /**
// * @brief Обработчик команды lta_search
// * Выводит информацию о модуле: имя, серийный номер, версия, board_id
// */
// static fun_res_t cli_cmd_lta_search_handler(int argc, char** argv)
// {
// L_UNUSED(argc);
// L_UNUSED(argv);
// cli_send_string("\r\n========== LTA MODULE INFO ==========\r\n");
// cli_send_string("Module Name: ");
// cli_send_string(tsp_dev_info.name);
// cli_send_string("\r\n");
// cli_send_string("Serial Number: ");
// cli_send_string(tsp_dev_info.serial_dev);
// cli_send_string("\r\n");
// cli_send_string("Board Revision: ");
// cli_send_string(tsp_dev_info.brd_rev);
// cli_send_string("\r\n");
// cli_send_string("Slot Number: ");
// cli_send_string(tsp_dev_info.pos_num);
// cli_send_string("\r\n");
// char ver_str[32];
// snprintf(ver_str, sizeof(ver_str), "MCU Version: %lu\r\n", tsp_dev_info.mcu_ver);
// cli_send_string(ver_str);
// char fpga_ver_str[32];
// snprintf(fpga_ver_str, sizeof(fpga_ver_str), "FPGA Version: %u\r\n", tsp_dev_info.fpga_ver);
// cli_send_string(fpga_ver_str);
// cli_send_string("\r\n========== SUBMODULES ==========\r\n");
// for (u8 i = 0; i < SU_SUBUNITS_MAX_QTY; i++) {
// u8 sub_data[4];
// if (subm_read(i, 0, sub_data, 4) == ERR_OK) {
// char sub_str[64];
// snprintf(sub_str, sizeof(sub_str), "Submodule %d: ID=0x%02X%02X%02X%02X\r\n",
// i, sub_data[0], sub_data[1], sub_data[2], sub_data[3]);
// cli_send_string(sub_str);
// } else {
// char sub_str[32];
// snprintf(sub_str, sizeof(sub_str), "Submodule %d: not present\r\n", i);
// cli_send_string(sub_str);
// }
// }
// cli_send_string("====================================\r\n");
// return ERR_OK;
// }
// /**
// * @brief Проверка адреса/диапазона на принадлежность допустимым диапазонам памяти (Flash или SRAM)
// */
// static bool cli_check_mem_range(u32 addr, u32 size)
// {
// if (size == 0) return false;
// u32 end = addr + size - 1;
// // Flash: 0x0800_0000 - 0x080F_FFFF
// const u32 FLASH_START = 0x08000000UL;
// const u32 FLASH_END = 0x080FFFFFUL;
// // SRAM: 0x2000_0000 - 0x20FF_FFFF
// const u32 SRAM_START = 0x20000000UL;
// const u32 SRAM_END = 0x20FFFFFFUL;
// // Проверяем переполнение при вычислении end
// if (end < addr) return false;
// if ((addr >= FLASH_START && end <= FLASH_END) ||
// (addr >= SRAM_START && end <= SRAM_END)) {
// return true;
// }
// return false;
// }
// /**
// * @brief Обработчик встроенной команды mem_read
// * Формат: mem_read <address> <size>
// * address может быть в 0xHEX или в десятичном виде
// */
// static fun_res_t cli_cmd_mem_read_handler(int argc, char** argv)
// {
// if (cli_current_state == CLI_STATE_DISABLED) {
// return ERR_RUNTIME_ERROR;
// }
// if (argc < 3 || argv == NULL) {
// cli_send_string("\r\nUsage: mem_read <address> <size>\r\n");
// return ERR_INVALID_ARGUMENT;
// }
// // Парсим адрес и размер (поддерживается 0x...)
// char* addr_str = argv[1];
// char* size_str = argv[2];
// unsigned long addr_ul = strtoul(addr_str, NULL, 0);
// unsigned long size_ul = strtoul(size_str, NULL, 0);
// if (size_ul == 0) {
// cli_send_string("ERROR: size must be > 0\r\n");
// return ERR_INVALID_ARGUMENT;
// }
// u32 addr = (u32)addr_ul;
// u32 size = (u32)size_ul;
// if (!cli_check_mem_range(addr, size)) {
// cli_send_string("ERROR: address out of permitted memory ranges (Flash or SRAM)\r\n");
// return ERR_INVALID_ARGUMENT;
// }
// // Переходим на новую строку, чтобы вывод дампа не оказался на той же строке, где была введена команда
// cli_send_string("\r\n");
// // Выводим побайтово. Формат: 0xAAAAAAAA: XX
// char out_line[256];
// for (u32 i = 0; i < size; i++) {
// // Безопасное чтение: приводим к указателю на volatile u8
// volatile u8* ptr = (volatile u8*)(uintptr_t)(addr + i);
// u8 value = *ptr;
// snprintf(out_line, sizeof(out_line), "0x%08lX: %02X\r\n", (unsigned long)(addr + i), (unsigned int)value);
// cli_send_string(out_line);
// }
// return ERR_OK;
// }
// // Структуры встроенных команд
// static const cli_command_t cli_help_cmd = {
// .name = "help",
// .handler = cli_cmd_help_handler,
// .description = "Display available commands and their descriptions"
// };
// static const cli_command_t cli_on_cmd = {
// .name = "cli_on",
// .handler = cli_cmd_cli_on_handler,
// .description = "Enable the Command Line Interface module"
// };
// static const cli_command_t cli_off_cmd = {
// .name = "cli_off",
// .handler = cli_cmd_cli_off_handler,
// .description = "Disable the Command Line Interface module"
// };
// static const cli_command_t cli_mem_cmd = {
// .name = "mem_read",
// .handler = cli_cmd_mem_read_handler,
// .description = "Read memory: mem_read <address> <size> (address supports 0x... or decimal)"
// };
// static const cli_command_t cli_lta_search_cmd = {
// .name = "lta_search",
// .handler = cli_cmd_lta_search_handler,
// .description = "Search and display LTA module info (name, SN, versions, submodules)"
// };
// //*********************************** Глобальные (публичные) функции ***************************************
// bool cli_is_active(void) {
// return (cli_current_state != CLI_STATE_DISABLED);
// }
// cli_state_t cli_get_state(void) {
// return cli_current_state;
// }
// u8 cli_get_command_count(void) {
// return cli_cmd_count;
// }
// /**
// * @brief Инициализация модуля CLI
// * @return ERR_OK - успех, код ошибки - failure
// */
// fun_res_t cli_init(void) {
// if (cli_current_state != CLI_STATE_DISABLED) {
// return ERR_OK; // Уже инициализирован
// }
// // Разрешаем отправку для инициализационных сообщений
// cli_allow_send_in_disabled = true;
// // Проверка инициализации UART канала
// lmcal_ch_sts_t uart_status = lmcal_uart_get_status(CLI_UART_CHANNEL);
// if (uart_status == CH_STS_NOT_INIT) {
// cli_send_string("ERROR: UART channel not initialized\r\n");
// cli_allow_send_in_disabled = false;
// return ERR_RUNTIME_ERROR;
// }
// // Инициализация FIFO
// fifo_rx.item_size = sizeof(u8);
// if (rb_init(&fifo_rx, fifo_rx_buf, sizeof(fifo_rx_buf)/sizeof(u8)) != RB_RES_OK) {
// cli_send_string("ERROR: RX FIFO initialization failed\r\n");
// cli_allow_send_in_disabled = false;
// return ERR_RUNTIME_ERROR;
// }
// rb_clear(&fifo_rx);
// // Колбек по приему байта через UART
// lmcal_uart_set_callback(CLI_UART_CHANNEL, CB_INT_RX_CALLBACK, f_uart_read_byte);
// // TX колбек не нужен в синхронном режиме
// // Инициализация переменных
// cli_cmd_index = 0;
// cli_cmd_count = 0;
// cli_current_state = CLI_STATE_DISABLED;
// // Очистка буферов
// memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
// memset(cli_commands, 0, sizeof(cli_commands));
// // Регистрация встроенных команд
// cli_register_command(&cli_help_cmd);
// cli_register_command(&cli_on_cmd);
// cli_register_command(&cli_off_cmd);
// cli_register_command(&cli_mem_cmd);
// cli_register_command(&cli_lta_search_cmd);
// // Выводим приветственное сообщение при инициализации
// cli_send_string("\r\n------------------------------------------------\r\n");
// cli_send_string("====== CLI Initialized (Disabled) ======\r\n");
// cli_send_string("------------------------------------------------\r\n");
// cli_send_string(" Type 'cli_on' to enable\r\n");
// cli_send_string("------------------------------------------------\r\n");
// // После инициализации запрещаем отправку в выключенном состоянии
// //cli_allow_send_in_disabled = false;
// return ERR_OK;
// }
// /**
// * @brief Включение модуля CLI (с проверкой пароля)
// * @return ERR_OK - успех, код ошибки - failure
// */
// fun_res_t cli_on(void) {
// return cli_cmd_cli_on_handler(0, NULL);
// }
// /**
// * @brief Выключение модуля CLI
// * @return ERR_OK - успех, код ошибки - failure
// */
// fun_res_t cli_off(void) {
// return cli_cmd_cli_off_handler(0, NULL);
// }
// /**
// * @brief Регистрация новой команды в CLI
// * @param cmd Указатель на структуру команды
// * @return ERR_OK - успех, код ошибки - failure
// */
// fun_res_t cli_register_command(const cli_command_t* cmd) {
// if (cli_cmd_count >= CLI_MAX_COMMANDS) {
// return ERR_RUNTIME_ERROR;
// }
// if (cmd == NULL || cmd->name == NULL || cmd->handler == NULL) {
// return ERR_INVALID_ARGUMENT;
// }
// // Проверка длины имени команды
// size_t name_len = strlen(cmd->name);
// if (name_len == 0 || name_len > 16) {
// return ERR_INVALID_ARGUMENT;
// }
// // Проверка на дубликаты
// for (u8 i = 0; i < cli_cmd_count; i++) {
// if (strcmp(cli_commands[i]->name, cmd->name) == 0) {
// return ERR_RUNTIME_ERROR;
// }
// }
// cli_commands[cli_cmd_count++] = cmd;
// return ERR_OK;
// }
// /**
// * @brief Деинициализация модуля CLI
// * @return ERR_OK - успех, код ошибки - failure
// */
// fun_res_t cli_deinit(void) {
// if (cli_current_state == CLI_STATE_DISABLED) {
// return ERR_OK;
// }
// // Отключаем колбеки
// lmcal_uart_set_callback(CLI_UART_CHANNEL, CB_INT_RX_CALLBACK, NULL);
// lmcal_uart_set_callback(CLI_UART_CHANNEL, CB_INT_TX_CALLBACK, NULL);
// // Сбрасываем состояние
// cli_current_state = CLI_STATE_DISABLED;
// return ERR_OK;
// }
// /**
// * @brief Основная функция обработки CLI
// * @note Должна вызываться в основном цикле программы
// */
// void cli_process(void) {
// // Если CLI выключен - только мониторим команду cli_on
// if (cli_current_state == CLI_STATE_DISABLED) {
// cli_process_disabled_mode();
// return;
// }
// // CLI включен - нормальная обработка команд
// cli_process_normal_mode();
// }
\ No newline at end of file
// // cli.h
// #ifndef CLI_H
// #define CLI_H
// //******************************************** Включаемые файлы *********************************************
// #include "cli_cfg.h"
// #include "l_macro_types.h"
// #include "tcp.h"
// #include "fpga_cmn.h"
// #include "submodule.h"
// #include "submodule_cfg.h"
// #include "lta_private.h"
// //******************************************* Определения типов *********************************************
// /**
// * @brief Тип функции-обработчика команды CLI
// */
// typedef fun_res_t (*cli_cmd_handler_t)(int argc, char** argv);
// /**
// * @brief Структура команды CLI
// */
// typedef struct {
// const char* name; // Имя команды
// cli_cmd_handler_t handler; // Обработчик команды
// const char* description; // Описание команды
// } cli_command_t;
// /**
// * @brief Состояния CLI модуля
// */
// typedef enum {
// CLI_STATE_DISABLED, // Модуль инициализирован, но выключен
// CLI_STATE_IDLE, // Ожидание команды (включен)
// CLI_STATE_RECEIVING, // Прием команды
// CLI_STATE_PROCESSING, // Обработка команды
// } cli_state_t;
// //******************************** Объявления глобальных (публичных) функций ********************************
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Отправка строки через UART с буферизацией
// //! @param[in] str Указатель на строку для отправки
// //! @retval -
// //-----------------------------------------------------------------------------------------------------------
// void cli_send_string(const char* str);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Проверка активности модуля CLI
// //! @param Возвращает true если CLI инициализирован и включен
// //! @retval bool true - активен, false - не активен
// //-----------------------------------------------------------------------------------------------------------
// bool cli_is_active(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Инициализация модуля CLI
// //! @param Инициализирует буферы, регистрирует встроенные команды и настраивает UART
// //! @retval fun_res_t ERR_OK - успех, код ошибки - failure
// //-----------------------------------------------------------------------------------------------------------
// fun_res_t cli_init(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Деинициализация модуля CLI
// //! @param Отключает колбеки, очищает буферы и сбрасывает состояние модуля
// //! @retval fun_res_t ERR_OK - успех, код ошибки - failure
// //-----------------------------------------------------------------------------------------------------------
// fun_res_t cli_deinit(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Включение модуля CLI с проверкой пароля
// //! @param Переводит CLI в режим ожидания пароля для активации
// //! @retval fun_res_t ERR_OK - успех, код ошибки - failure
// //-----------------------------------------------------------------------------------------------------------
// fun_res_t cli_on(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Выключение модуля CLI
// //! @param Деактивирует CLI, оставляя возможность повторного включения через cli_on()
// //! @retval fun_res_t ERR_OK - успех, код ошибки - failure
// //-----------------------------------------------------------------------------------------------------------
// fun_res_t cli_off(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Получение текущего состояния CLI модуля
// //! @param -
// //! @retval cli_state_t Текущее состояние модуля
// //-----------------------------------------------------------------------------------------------------------
// cli_state_t cli_get_state(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Регистрация новой команды
// //! @param[in] cmd - указатель на структуру команды
// //! @retval fun_res_t ERR_OK - успех, ERR_INVALID_ARGUMENT - неверные параметры,
// //! ERR_RUNTIME_ERROR - достигнут лимит команд
// //-----------------------------------------------------------------------------------------------------------
// fun_res_t cli_register_command(const cli_command_t* cmd);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Основная функция обработки CLI
// //! @param Должна вызываться в основном цикле программы. Обрабатывает ввод пользователя,
// //! проверяет пароль, выполняет команды и управляет состоянием модуля.
// //! @retval -
// //-----------------------------------------------------------------------------------------------------------
// void cli_process(void);
// //-----------------------------------------------------------------------------------------------------------
// //! @brief Получение количества зарегистрированных команд
// //! @param
// //! @retval u8 Количество зарегистрированных команд
// //-----------------------------------------------------------------------------------------------------------
// u8 cli_get_command_count(void);
// #endif // CLI_H
\ No newline at end of file
// #ifndef CLI_CFG_H
// #define CLI_CFG_H
// //******************************************** Включаемые файлы *********************************************
// #include "lmcal_uart.h"
// //************************************ Глобальные (публичные) константы *************************************
// // Максимальная длина команды (включая аргументы)
// #define CLI_MAX_CMD_LENGTH (128)
// // Максимальная длина команды (включая аргументы)
// #define CLI_MAX_LENGTH (3072)
// // Максимальное количество аргументов в команде
// #define CLI_MAX_ARGS (8)
// // Максимальное количество зарегистрированных команд
// #define CLI_MAX_COMMANDS (16)
// // Символ, обозначающий конец команды
// #define CLI_END_OF_CMD ('\n')
// // Канал UART для CLI (должен соответствовать настройкам в lmcal_uart_cfg.h)
// #define CLI_UART_CHANNEL (LMCAL_UART_CHANNEL1)
// //******************************************* Проверка параметров *******************************************
// #endif // CLI_CFG_H
\ No newline at end of file
//*********************************************************************************************************** //***********************************************************************************************************
//! @file cli_protocol.c //! @file cli_protocol.c
//! @brief Реализация протокола CLI с адресацией (board_id) //! @brief Реализация протокола CLI с адресацией (board_id)
//! @version v1.1.0 //! @version v1.2.1
//! @date 07.04.2026 //! @date 20.04.2026
//!
//! @details Протокол предназначен для тестирования и диагностики встроенного ПО устройств,
//! подключенных к ПК через UART (COM-порт). ПК выступает мастером, устройство — подчинённым.
//! Команды передаются в текстовом виде, данные кодируются в HEX.
//!
//! Расширение протокола: новые команды регистрируются через cli_register_command().
//!
//! Таймаут соединения: 20 секунд бездействия.
//! Максимальный размер поля данных: 64 байта.
//!
//! @note Для работы необходимо наличие LMCAL, ring_buffer, а также tsp_dev_info из модуля tcp.h.
//*********************************************************************************************************** //***********************************************************************************************************
#include "cli_protocol.h" #include "cli_protocol.h"
...@@ -15,28 +26,63 @@ ...@@ -15,28 +26,63 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#define CLI_CMD_PREFIX 'T' // Включаем заголовок для доступа к регистрам USART (только для ожидания TC)
#define CLI_RESPONSE_PREFIX 't' #include "gd32f4xx_usart.h"
#define CLI_ERROR_PREFIX 'e'
#define CLI_MSG_TERMINATOR '\r'
//************************************ Локальные константы **************************************************
#define CLI_CMD_PREFIX 'T' // Префикс команды
#define CLI_RESPONSE_PREFIX 't' // Префикс успешного ответа
#define CLI_ERROR_PREFIX 'e' // Префикс ошибки
#define CLI_MSG_TERMINATOR '\r' // Символ конца сообщения
// Макрос для преобразования ASCII HEX-символа в 4-битное значение (0-15), 0xFF при ошибке
#define HEX_CHAR_TO_NIBBLE(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \ #define HEX_CHAR_TO_NIBBLE(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \ ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : 0xFF) ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : 0xFF)
static ringbuf_t fifo_rx; //************************************ Локальные переменные *************************************************
static u8 fifo_rx_buf[CLI_CMD_BUFFER_SIZE]; static ringbuf_t fifo_rx; // Кольцевой буфер приёма байт из UART
static u8 fifo_rx_buf[CLI_CMD_BUFFER_SIZE]; // Память для кольцевого буфера
static char cli_cmd_buffer[CLI_CMD_BUFFER_SIZE];
static u16 cli_cmd_index = 0; static char cli_cmd_buffer[CLI_CMD_BUFFER_SIZE]; // Буфер для накопления строки команды
static u16 cli_cmd_index = 0; // Текущая длина строки в буфере
static bool cli_connected = false;
static u32 cli_last_activity = 0; static bool cli_connected = false; // Флаг активного соединения (после успешной T00)
static u32 (*cli_get_tick)(void) = NULL; static u32 cli_last_activity = 0; // Время последней активности (тики)
static u32 (*cli_get_tick)(void) = NULL; // Счётчик
static cli_device_info_t cli_device_info;
static char cli_password[16] = CLI_DEFAULT_PASSWORD; static cli_device_info_t cli_device_info; // Информация об устройстве (имя, серийный номер, версия, board_id)
// Пароль хранится как байтовый массив с завершающим нулём (для удобства отладки)
static u8 cli_password[CLI_PASSWORD_MAX_LEN + 1];
static u8 cli_password_len = 0; // Фактическая длина пароля в байтах
// Таблица обработчиков команд. Индекс = код команды (0..255)
static cli_cmd_handler_t cmd_handlers[CLI_MAX_COMMANDS];
// Защита от перебора пароля
static u8 cli_password_attempts = 0; // Счётчик неудачных попыток
static bool cli_blocked = false; // Флаг блокировки всех команд
//************************************ Прототипы локальных функций ******************************************
static inline void byte_to_hex(u8 byte, char* hex);
static u8 hex_to_byte(const char* hex);
static void safe_strncpy(char* dst, const char* src, size_t dst_size);
static void send_response(u8 cmd, const u8* data, u8 len);
static void send_error(u8 cmd, u8 err);
static void uart_wait_tx_done(void);
static void handle_cmd_open(const u8* data, u8 len);
static void handle_cmd_close(const u8* data, u8 len);
static void handle_cmd_ping(const u8* data, u8 len);
static void handle_cmd_get_info(const u8* data, u8 len);
static void handle_cmd_read_mem(const u8* data, u8 len);
static void handle_cmd_write_mem(const u8* data, u8 len);
static void parse_and_execute(void);
static void uart_rx_cb(void);
static void register_builtin_commands(void);
//-----------------------------------------------------------------------------------------------------------
// Преобразование байта в два HEX-символа (старший и младший полубайт)
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
static inline void byte_to_hex(u8 byte, char* hex) static inline void byte_to_hex(u8 byte, char* hex)
{ {
...@@ -45,6 +91,9 @@ static inline void byte_to_hex(u8 byte, char* hex) ...@@ -45,6 +91,9 @@ static inline void byte_to_hex(u8 byte, char* hex)
hex[1] = d[byte & 0x0F]; hex[1] = d[byte & 0x0F];
} }
//-----------------------------------------------------------------------------------------------------------
// Преобразование двух HEX-символов в байт. Возвращает 0xFF при ошибке.
//-----------------------------------------------------------------------------------------------------------
static u8 hex_to_byte(const char* hex) static u8 hex_to_byte(const char* hex)
{ {
u8 h = HEX_CHAR_TO_NIBBLE(hex[0]); u8 h = HEX_CHAR_TO_NIBBLE(hex[0]);
...@@ -52,72 +101,142 @@ static u8 hex_to_byte(const char* hex) ...@@ -52,72 +101,142 @@ static u8 hex_to_byte(const char* hex)
return (h == 0xFF || l == 0xFF) ? 0xFF : (h << 4) | l; return (h == 0xFF || l == 0xFF) ? 0xFF : (h << 4) | l;
} }
//-----------------------------------------------------------------------------------------------------------
// Безопасное копирование строки с гарантированным завершающим нулём.
// Аналог strncpy, но всегда добавляет '\0' в конце буфера.
//-----------------------------------------------------------------------------------------------------------
static void safe_strncpy(char* dst, const char* src, size_t dst_size)
{
if (dst == NULL || src == NULL || dst_size == 0) return;
strncpy(dst, src, dst_size - 1);
dst[dst_size - 1] = '\0';
}
//-----------------------------------------------------------------------------------------------------------
// Отправка строки через UART (публичная обёртка)
//-----------------------------------------------------------------------------------------------------------
void cli_send_string(const char* str) void cli_send_string(const char* str)
{ {
if (!str) return; if (!str) return;
while (*str) lmcal_uart_write(CLI_UART_CHANNEL, (u16)*str++); while (*str) {
lmcal_uart_write(CLI_UART_CHANNEL, (u16)*str++);
}
// Ждём завершения передачи, чтобы не смешивать вывод
uart_wait_tx_done();
}
//-----------------------------------------------------------------------------------------------------------
// Ожидание завершения передачи UART (флаг TC)
// Используем прямой доступ к регистрам, т.к. LMCAL не предоставляет такой функции.
//-----------------------------------------------------------------------------------------------------------
static void uart_wait_tx_done(void)
{
// Попытка использовать функцию LMCAL, если она доступна
#ifdef LMCAL_UART_TX_COMPLETE
uint32_t timeout = 100000; // ~100 мс при типичной скорости
while (!lmcal_uart_tx_complete(CLI_UART_CHANNEL) && --timeout);
#else
// Резервный вариант с прямым доступом к регистрам (для GD32)
#if CLI_UART_CHANNEL == LMCAL_UART_CHANNEL0
#define CLI_USART USART5
#elif CLI_UART_CHANNEL == LMCAL_UART_CHANNEL1
#define CLI_USART USART0
#else
#define CLI_USART USART0
#endif
volatile uint32_t timeout = 100000;
while (usart_flag_get(CLI_USART, USART_FLAG_TC) == RESET && --timeout);
#endif
} }
//-----------------------------------------------------------------------------------------------------------
// Формирование и отправка успешного ответа на команду.
// Формат: t[cmd][board_id][data...]\r
//-----------------------------------------------------------------------------------------------------------
static void send_response(u8 cmd, const u8* data, u8 len) static void send_response(u8 cmd, const u8* data, u8 len)
{ {
u8 buf[CLI_CMD_BUFFER_SIZE]; u8 buf[CLI_CMD_BUFFER_SIZE];
u16 idx = 0; u16 idx = 0;
buf[idx++] = CLI_RESPONSE_PREFIX; buf[idx++] = CLI_RESPONSE_PREFIX; // 't'
byte_to_hex(cmd, (char*)&buf[idx]); idx += 2; byte_to_hex(cmd, (char*)&buf[idx]); idx += 2; // код команды
byte_to_hex(cli_device_info.board_id, (char*)&buf[idx]); idx += 2; byte_to_hex(cli_device_info.board_id, (char*)&buf[idx]); idx += 2; // board_id
for (u8 i = 0; i < len; i++) { for (u8 i = 0; i < len; i++) {
byte_to_hex(data[i], (char*)&buf[idx]); byte_to_hex(data[i], (char*)&buf[idx]); // данные в HEX
idx += 2; idx += 2;
} }
buf[idx++] = CLI_MSG_TERMINATOR; buf[idx++] = CLI_MSG_TERMINATOR; // '\r'
for (u16 i = 0; i < idx; i++) for (u16 i = 0; i < idx; i++) {
lmcal_uart_write(CLI_UART_CHANNEL, buf[i]); lmcal_uart_write(CLI_UART_CHANNEL, buf[i]);
}
uart_wait_tx_done(); // гарантируем, что ответ отправлен полностью
} }
//-----------------------------------------------------------------------------------------------------------
// Формирование и отправка сообщения об ошибке.
// Формат: e[cmd][board_id][err]\r
//-----------------------------------------------------------------------------------------------------------
static void send_error(u8 cmd, u8 err) static void send_error(u8 cmd, u8 err)
{ {
u8 buf[8]; u8 buf[8];
u16 idx = 0; u16 idx = 0;
buf[idx++] = CLI_ERROR_PREFIX; buf[idx++] = CLI_ERROR_PREFIX; // 'e'
byte_to_hex(cmd, (char*)&buf[idx]); idx += 2; byte_to_hex(cmd, (char*)&buf[idx]); idx += 2;
byte_to_hex(cli_device_info.board_id, (char*)&buf[idx]); idx += 2; byte_to_hex(cli_device_info.board_id, (char*)&buf[idx]); idx += 2;
byte_to_hex(err, (char*)&buf[idx]); idx += 2; byte_to_hex(err, (char*)&buf[idx]); idx += 2; // код ошибки
buf[idx++] = CLI_MSG_TERMINATOR; buf[idx++] = CLI_MSG_TERMINATOR;
for (u16 i = 0; i < idx; i++) for (u16 i = 0; i < idx; i++) {
lmcal_uart_write(CLI_UART_CHANNEL, buf[i]); lmcal_uart_write(CLI_UART_CHANNEL, buf[i]);
}
uart_wait_tx_done();
} }
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды открытия соединения (CLI_CMD_OPEN = 0x00)
// Данные могут содержать пароль. Если пароль задан, проверяем его.
//-----------------------------------------------------------------------------------------------------------
static void handle_cmd_open(const u8* data, u8 len) static void handle_cmd_open(const u8* data, u8 len)
{ {
(void)len;
if (cli_connected) { if (cli_connected) {
send_error(CLI_CMD_OPEN, CLI_ERR_INTERNAL); send_error(CLI_CMD_OPEN, CLI_ERR_INTERNAL);
return; return;
} }
if (len > 0) { if (cli_password_attempts >= CLI_MAX_PASSWORD_ATTEMPTS) {
if (len != strlen(cli_password)) { cli_blocked = true;
return;
}
if (cli_password_len > 0) {
if (len != cli_password_len || memcmp(data, cli_password, len) != 0) {
cli_password_attempts++;
if (cli_password_attempts >= CLI_MAX_PASSWORD_ATTEMPTS) {
cli_blocked = true;
}
send_error(CLI_CMD_OPEN, CLI_ERR_INTERNAL); send_error(CLI_CMD_OPEN, CLI_ERR_INTERNAL);
return; return;
} }
for (u8 i = 0; i < len; i++) {
if (data[i] != cli_password[i]) {
send_error(CLI_CMD_OPEN, CLI_ERR_INTERNAL);
return;
}
}
} }
cli_password_attempts = 0;
cli_connected = true; cli_connected = true;
if (cli_get_tick) cli_last_activity = cli_get_tick(); if (cli_get_tick) cli_last_activity = cli_get_tick();
send_response(CLI_CMD_OPEN, NULL, 0); send_response(CLI_CMD_OPEN, NULL, 0);
} }
static void handle_cmd_close(void) //-----------------------------------------------------------------------------------------------------------
// Обработчик команды закрытия соединения (CLI_CMD_CLOSE = 0x01)
//-----------------------------------------------------------------------------------------------------------
static void handle_cmd_close(const u8* data, u8 len)
{ {
(void)data; (void)len;
cli_connected = false; cli_connected = false;
send_response(CLI_CMD_CLOSE, NULL, 0); send_response(CLI_CMD_CLOSE, NULL, 0);
cli_cmd_index = 0; cli_cmd_index = 0;
memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer)); memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
} }
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды проверки соединения (CLI_CMD_PING = 0x02)
// Возвращает эхо переданных данных.
//-----------------------------------------------------------------------------------------------------------
static void handle_cmd_ping(const u8* data, u8 len) static void handle_cmd_ping(const u8* data, u8 len)
{ {
if (!cli_connected) { if (!cli_connected) {
...@@ -127,36 +246,52 @@ static void handle_cmd_ping(const u8* data, u8 len) ...@@ -127,36 +246,52 @@ static void handle_cmd_ping(const u8* data, u8 len)
send_response(CLI_CMD_PING, data, len); send_response(CLI_CMD_PING, data, len);
} }
static void handle_cmd_get_info(void) //-----------------------------------------------------------------------------------------------------------
// Обработчик команды получения информации об устройстве (CLI_CMD_GET_INFO = 0x0A)
// Формат ответа: board_id (1 байт), длина имени, имя, длина серийного, серийный,
// длина версии, версия (ASCII).
//-----------------------------------------------------------------------------------------------------------
static void handle_cmd_get_info(const u8* data, u8 len)
{ {
(void)data; (void)len;
if (!cli_connected) { if (!cli_connected) {
send_error(CLI_CMD_GET_INFO, CLI_ERR_INTERNAL); send_error(CLI_CMD_GET_INFO, CLI_ERR_INTERNAL);
return; return;
} }
u8 buf[CLI_DATA_MAX_SIZE]; u8 buf[CLI_DATA_MAX_SIZE];
u16 idx = 0; u16 idx = 0;
u8 len; u8 str_len;
buf[idx++] = cli_device_info.board_id; buf[idx++] = cli_device_info.board_id;
len = strlen(cli_device_info.name);
if (len > 31) len = 31; str_len = strlen(cli_device_info.name);
buf[idx++] = len; if (str_len > 31) str_len = 31;
memcpy(&buf[idx], cli_device_info.name, len); buf[idx++] = str_len;
idx += len; memcpy(&buf[idx], cli_device_info.name, str_len);
len = strlen(cli_device_info.serial); idx += str_len;
if (len > 15) len = 15;
buf[idx++] = len; str_len = strlen(cli_device_info.serial);
memcpy(&buf[idx], cli_device_info.serial, len); if (str_len > 15) str_len = 15;
idx += len; buf[idx++] = str_len;
memcpy(&buf[idx], cli_device_info.serial, str_len);
idx += str_len;
char ver[16]; char ver[16];
snprintf(ver, sizeof(ver), "%lu", tsp_dev_info.mcu_ver); snprintf(ver, sizeof(ver), "%lu", tsp_dev_info.mcu_ver);
len = strlen(ver); str_len = strlen(ver);
if (len > 15) len = 15; if (str_len > 15) str_len = 15;
buf[idx++] = len; buf[idx++] = str_len;
memcpy(&buf[idx], ver, len); memcpy(&buf[idx], ver, str_len);
idx += len; idx += str_len;
send_response(CLI_CMD_GET_INFO, buf, idx); send_response(CLI_CMD_GET_INFO, buf, idx);
} }
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды чтения памяти (CLI_CMD_READ_MEM = 0x14)
// Данные: 4 байта адреса (big-endian), 1 байт размера (1-64)
// Исправлена проверка границ: теперь учитывается размер
//-----------------------------------------------------------------------------------------------------------
static void handle_cmd_read_mem(const u8* data, u8 len) static void handle_cmd_read_mem(const u8* data, u8 len)
{ {
if (!cli_connected) { if (!cli_connected) {
...@@ -174,16 +309,32 @@ static void handle_cmd_read_mem(const u8* data, u8 len) ...@@ -174,16 +309,32 @@ static void handle_cmd_read_mem(const u8* data, u8 len)
send_error(CLI_CMD_READ_MEM, CLI_ERR_INVALID_ARG); send_error(CLI_CMD_READ_MEM, CLI_ERR_INVALID_ARG);
return; return;
} }
if ((addr >= 0x08000000 && addr < 0x08200000) ||
(addr >= 0x20000000 && addr < 0x20020000)) { // Проверка допустимых диапазонов с учётом размера
bool valid = false;
// Flash: 1 МБ (0x08000000 - 0x080FFFFF) – типично для GD32F450VG
if ((addr >= 0x08000000) && ((addr + size) <= 0x080FFFFF)) {
valid = true;
} else if ((addr >= 0x20000000) && ((addr + size) <= 0x2001FFFF)) {
valid = true; // SRAM (128 КБ)
}
if (valid) {
u8 buf[CLI_DATA_MAX_SIZE]; u8 buf[CLI_DATA_MAX_SIZE];
for (u8 i = 0; i < size; i++) buf[i] = *(volatile u8*)(addr + i); for (u8 i = 0; i < size; i++) {
buf[i] = *(volatile u8*)(addr + i);
}
send_response(CLI_CMD_READ_MEM, buf, size); send_response(CLI_CMD_READ_MEM, buf, size);
} else { } else {
send_error(CLI_CMD_READ_MEM, CLI_ERR_INTERNAL); send_error(CLI_CMD_READ_MEM, CLI_ERR_INTERNAL);
} }
} }
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды записи памяти (CLI_CMD_WRITE_MEM = 0x15)
// Данные: 4 байта адреса, затем записываемые байты (1-64)
// Запись разрешена только в SRAM (0x20000000-0x2001FFFF) с учётом размера
//-----------------------------------------------------------------------------------------------------------
static void handle_cmd_write_mem(const u8* data, u8 len) static void handle_cmd_write_mem(const u8* data, u8 len)
{ {
if (!cli_connected) { if (!cli_connected) {
...@@ -201,18 +352,26 @@ static void handle_cmd_write_mem(const u8* data, u8 len) ...@@ -201,18 +352,26 @@ static void handle_cmd_write_mem(const u8* data, u8 len)
send_error(CLI_CMD_WRITE_MEM, CLI_ERR_INVALID_ARG); send_error(CLI_CMD_WRITE_MEM, CLI_ERR_INVALID_ARG);
return; return;
} }
if ((addr >= 0x20000000 && addr < 0x20020000)) {
for (u8 i = 0; i < size; i++) *(volatile u8*)(addr + i) = data[4 + i]; // Проверка: только SRAM с учётом размера
if ((addr >= 0x20000000) && ((addr + size) <= 0x2001FFFF)) {
for (u8 i = 0; i < size; i++) {
*(volatile u8*)(addr + i) = data[4 + i];
}
send_response(CLI_CMD_WRITE_MEM, NULL, 0); send_response(CLI_CMD_WRITE_MEM, NULL, 0);
} else { } else {
send_error(CLI_CMD_WRITE_MEM, CLI_ERR_INTERNAL); send_error(CLI_CMD_WRITE_MEM, CLI_ERR_INTERNAL);
} }
} }
//-----------------------------------------------------------------------------------------------------------
// Разбор принятой строки и вызов соответствующего обработчика.
//-----------------------------------------------------------------------------------------------------------
static void parse_and_execute(void) static void parse_and_execute(void)
{ {
char* buf = cli_cmd_buffer; char* buf = cli_cmd_buffer;
u16 len = cli_cmd_index; u16 len = cli_cmd_index;
if (len < 6) { cli_cmd_index = 0; return; } if (len < 6) { cli_cmd_index = 0; return; }
if (buf[0] != CLI_CMD_PREFIX) { cli_cmd_index = 0; return; } if (buf[0] != CLI_CMD_PREFIX) { cli_cmd_index = 0; return; }
if (buf[len - 1] != CLI_MSG_TERMINATOR) return; if (buf[len - 1] != CLI_MSG_TERMINATOR) return;
...@@ -221,7 +380,7 @@ static void parse_and_execute(void) ...@@ -221,7 +380,7 @@ static void parse_and_execute(void)
if (cmd == 0xFF) { cli_cmd_index = 0; return; } if (cmd == 0xFF) { cli_cmd_index = 0; return; }
u8 board_id = hex_to_byte(&buf[3]); u8 board_id = hex_to_byte(&buf[3]);
if (board_id == 0xFF) { cli_cmd_index = 0; return; } // broadcast ignored if (board_id == 0xFF) { cli_cmd_index = 0; return; }
if (board_id != cli_device_info.board_id) { cli_cmd_index = 0; return; } if (board_id != cli_device_info.board_id) { cli_cmd_index = 0; return; }
u16 data_start = 5; u16 data_start = 5;
...@@ -240,18 +399,17 @@ static void parse_and_execute(void) ...@@ -240,18 +399,17 @@ static void parse_and_execute(void)
if (cli_get_tick) cli_last_activity = cli_get_tick(); if (cli_get_tick) cli_last_activity = cli_get_tick();
switch (cmd) { if (cmd_handlers[cmd] != NULL) {
case CLI_CMD_OPEN: handle_cmd_open(data, data_len); break; cmd_handlers[cmd](data, data_len);
case CLI_CMD_CLOSE: handle_cmd_close(); break; } else {
case CLI_CMD_PING: handle_cmd_ping(data, data_len); break; send_error(cmd, CLI_ERR_UNKNOWN_CMD);
case CLI_CMD_GET_INFO: handle_cmd_get_info(); break;
case CLI_CMD_READ_MEM: handle_cmd_read_mem(data, data_len); break;
case CLI_CMD_WRITE_MEM: handle_cmd_write_mem(data, data_len); break;
default: send_error(cmd, CLI_ERR_UNKNOWN_CMD); break;
} }
cli_cmd_index = 0; cli_cmd_index = 0;
} }
//-----------------------------------------------------------------------------------------------------------
// Колбек прерывания по приёму байта из UART.
//-----------------------------------------------------------------------------------------------------------
static void uart_rx_cb(void) static void uart_rx_cb(void)
{ {
u16 rx = lmcal_uart_read(CLI_UART_CHANNEL); u16 rx = lmcal_uart_read(CLI_UART_CHANNEL);
...@@ -259,6 +417,26 @@ static void uart_rx_cb(void) ...@@ -259,6 +417,26 @@ static void uart_rx_cb(void)
rb_add_item(&fifo_rx, &ch); rb_add_item(&fifo_rx, &ch);
} }
//-----------------------------------------------------------------------------------------------------------
// Регистрация встроенных команд протокола.
//-----------------------------------------------------------------------------------------------------------
static void register_builtin_commands(void)
{
const cli_command_t builtin[] = {
{ CLI_CMD_OPEN, handle_cmd_open },
{ CLI_CMD_CLOSE, handle_cmd_close },
{ CLI_CMD_PING, handle_cmd_ping },
{ CLI_CMD_GET_INFO, handle_cmd_get_info },
{ CLI_CMD_READ_MEM, handle_cmd_read_mem },
{ CLI_CMD_WRITE_MEM, handle_cmd_write_mem },
};
for (size_t i = 0; i < sizeof(builtin)/sizeof(builtin[0]); i++) {
cli_register_command(&builtin[i]);
}
}
//************************************ Публичные функции ****************************************************
//----------------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------------
fun_res_t cli_protocol_init(void) fun_res_t cli_protocol_init(void)
{ {
...@@ -270,25 +448,33 @@ fun_res_t cli_protocol_init(void) ...@@ -270,25 +448,33 @@ fun_res_t cli_protocol_init(void)
cli_cmd_index = 0; cli_cmd_index = 0;
cli_connected = false; cli_connected = false;
cli_last_activity = 0; cli_last_activity = 0;
cli_get_tick = NULL;
memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer)); memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer));
strcpy(cli_device_info.name, "CLI Device"); safe_strncpy(cli_device_info.name, "CLI Device", sizeof(cli_device_info.name));
strcpy(cli_device_info.serial, "00000000"); safe_strncpy(cli_device_info.serial, "00000000", sizeof(cli_device_info.serial));
strcpy(cli_device_info.version, "1.0.0"); safe_strncpy(cli_device_info.version, "1.0.0", sizeof(cli_device_info.version));
cli_device_info.board_id = 0; cli_device_info.board_id = 0;
cli_send_string("\r\n>----- LTA PROTOCOL ENABLE -----<\r\n"); memset(cmd_handlers, 0, sizeof(cmd_handlers));
cli_send_string("> T00 - Open connection (T0001, T00011357)\r\n"); register_builtin_commands();
cli_send_string("> T01 - Close connection (T0101)\r\n");
cli_send_string("> T02 - Ping (T0201)\r\n"); const u8 default_pass[] = CLI_DEFAULT_PASSWORD_BYTES;
cli_send_string("> T0A - Get device info (T0A01)\r\n"); cli_protocol_set_password(default_pass, sizeof(default_pass));
cli_send_string("> T14 - Read memory (T14012000000004)\r\n");
cli_send_string("> T15 - Write memory (T150120000000AABBCCDD)\r\n"); cli_send_string("\r\n>----- LTA PROTOCOL ENABLED -----<\r\n");
cli_send_string("> T0001 - open without password\r\n");
cli_send_string("> T000131333537 - open with password '1357' (hex bytes 0x31,0x33,0x35,0x37)\r\n");
cli_send_string("> T0101 - close connection\r\n");
cli_send_string("> T0201AABB - ping with data 0xAA,0xBB\r\n");
cli_send_string("> T0A01 - get device info\r\n");
cli_send_string("> T14010800000004 - read 4 bytes from 0x08000000\r\n");
cli_send_string("> T150120000000AABB- write 0xAA,0xBB to SRAM 0x20000000\r\n");
cli_send_string(">------------------------------------------------<\r\n");
cli_send_string("> "); cli_send_string("> ");
return ERR_OK; return ERR_OK;
} }
//-----------------------------------------------------------------------------------------------------------
fun_res_t cli_protocol_deinit(void) fun_res_t cli_protocol_deinit(void)
{ {
lmcal_uart_set_callback(CLI_UART_CHANNEL, CB_INT_RX_CALLBACK, NULL); lmcal_uart_set_callback(CLI_UART_CHANNEL, CB_INT_RX_CALLBACK, NULL);
...@@ -296,57 +482,129 @@ fun_res_t cli_protocol_deinit(void) ...@@ -296,57 +482,129 @@ fun_res_t cli_protocol_deinit(void)
return ERR_OK; return ERR_OK;
} }
//-----------------------------------------------------------------------------------------------------------
void cli_protocol_process(void) void cli_protocol_process(void)
{ {
static enum {
WAIT_CMD, // Ожидание первого символа команды
RECEIVING, // Приём символов команды
EXPECT_NL // Ожидание \n после \r
} state = WAIT_CMD;
if (cli_blocked) {
while (rb_get_items_qty(&fifo_rx) > 0) {
u8 dummy;
rb_get_item(&fifo_rx, &dummy);
}
return;
}
while (rb_get_items_qty(&fifo_rx) > 0) { while (rb_get_items_qty(&fifo_rx) > 0) {
u8 ch; u8 ch;
if (rb_get_item(&fifo_rx, &ch) != RB_RES_OK) continue; if (rb_get_item(&fifo_rx, &ch) != RB_RES_OK) continue;
if (cli_cmd_index == 0 && (ch == '\r' || ch == '\n')) continue;
if (ch == '\r' || ch == '\n') { switch (state) {
if (cli_cmd_index > 0) { case WAIT_CMD:
cli_cmd_buffer[cli_cmd_index] = CLI_MSG_TERMINATOR; if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') continue;
cli_cmd_index++; cli_cmd_index = 0;
parse_and_execute(); cli_cmd_buffer[cli_cmd_index++] = ch;
cli_send_string("> "); state = RECEIVING;
} break;
cli_cmd_index = 0; case RECEIVING:
} else if (cli_cmd_index < CLI_CMD_BUFFER_SIZE - 1) { if (ch == '\r' || ch == '\n') {
cli_cmd_buffer[cli_cmd_index++] = ch; if (cli_cmd_index > 0) {
} else { cli_cmd_buffer[cli_cmd_index] = CLI_MSG_TERMINATOR;
cli_cmd_index = 0; cli_cmd_index++;
memset(cli_cmd_buffer, 0, sizeof(cli_cmd_buffer)); parse_and_execute();
cli_send_string("> ");
}
state = EXPECT_NL;
} else {
if (cli_cmd_index < CLI_CMD_BUFFER_SIZE - 1) {
cli_cmd_buffer[cli_cmd_index++] = ch;
} else {
cli_cmd_index = 0;
state = WAIT_CMD;
}
}
break;
case EXPECT_NL:
if (ch == '\n') {
state = WAIT_CMD;
} else {
cli_cmd_index = 0;
cli_cmd_buffer[cli_cmd_index++] = ch;
state = RECEIVING;
}
break;
} }
} }
// Таймаут соединения (работает только если cli_get_tick != NULL)
if (cli_connected && cli_get_tick) { if (cli_connected && cli_get_tick) {
if ((cli_get_tick() - cli_last_activity) > CLI_CONNECTION_TIMEOUT_MS) if ((cli_get_tick() - cli_last_activity) > CLI_CONNECTION_TIMEOUT_MS) {
cli_connected = false; cli_connected = false;
}
} }
} }
//-----------------------------------------------------------------------------------------------------------
fun_res_t cli_protocol_set_device_info(const char* name, const char* serial, const char* ver, u8 board_id) fun_res_t cli_protocol_set_device_info(const char* name, const char* serial, const char* ver, u8 board_id)
{ {
if (name) strncpy(cli_device_info.name, name, sizeof(cli_device_info.name)-1); if (name) safe_strncpy(cli_device_info.name, name, sizeof(cli_device_info.name));
if (serial) strncpy(cli_device_info.serial, serial, sizeof(cli_device_info.serial)-1); if (serial) safe_strncpy(cli_device_info.serial, serial, sizeof(cli_device_info.serial));
if (ver) strncpy(cli_device_info.version, ver, sizeof(cli_device_info.version)-1); if (ver) safe_strncpy(cli_device_info.version, ver, sizeof(cli_device_info.version));
cli_device_info.board_id = board_id; cli_device_info.board_id = board_id;
return ERR_OK; return ERR_OK;
} }
//-----------------------------------------------------------------------------------------------------------
fun_res_t cli_protocol_set_board_id(u8 board_id) fun_res_t cli_protocol_set_board_id(u8 board_id)
{ {
cli_device_info.board_id = board_id; cli_device_info.board_id = board_id;
return ERR_OK; return ERR_OK;
} }
u8 cli_protocol_get_board_id(void) { return cli_device_info.board_id; } //-----------------------------------------------------------------------------------------------------------
u8 cli_protocol_get_board_id(void)
{
return cli_device_info.board_id;
}
void cli_protocol_set_password(const char* pass) //-----------------------------------------------------------------------------------------------------------
void cli_protocol_set_password(const u8* pass, u8 len)
{ {
if (pass) strncpy(cli_password, pass, sizeof(cli_password)-1); if (len > CLI_PASSWORD_MAX_LEN) len = CLI_PASSWORD_MAX_LEN;
memcpy(cli_password, pass, len);
cli_password_len = len;
cli_password[len] = '\0';
} }
bool cli_protocol_verify_password(const char* pass) //-----------------------------------------------------------------------------------------------------------
bool cli_protocol_verify_password(const u8* pass, u8 len)
{ {
if (!pass) return false; return (len == cli_password_len) && (memcmp(pass, cli_password, len) == 0);
return (strcmp(pass, cli_password) == 0); }
}
\ No newline at end of file //-----------------------------------------------------------------------------------------------------------
void cli_protocol_reset_block(void)
{
cli_password_attempts = 0;
cli_blocked = false;
}
//-----------------------------------------------------------------------------------------------------------
fun_res_t cli_register_command(const cli_command_t* cmd)
{
if (cmd == NULL || cmd->handler == NULL) {
return ERR_INVALID_ARGUMENT;
}
if ((int)cmd->code >= CLI_MAX_COMMANDS) {
return ERR_INVALID_ARGUMENT;
}
if (cmd_handlers[cmd->code] != NULL) {
return ERR_RUNTIME_ERROR;
}
cmd_handlers[cmd->code] = cmd->handler;
return ERR_OK;
}
...@@ -10,53 +10,108 @@ ...@@ -10,53 +10,108 @@
//************************************ Коды команд (по протоколу 1.1) ************************************* //************************************ Коды команд (по протоколу 1.1) *************************************
typedef enum { typedef enum {
CLI_CMD_OPEN = 0x00U, // T00 - открыть соединение CLI_CMD_OPEN = 0x00U, // T00 - открыть соединение (опционально с паролем)
CLI_CMD_CLOSE = 0x01U, // T01 - закрыть соединение CLI_CMD_CLOSE = 0x01U, // T01 - закрыть соединение
CLI_CMD_PING = 0x02U, // T02 - проверка соединения (ping) CLI_CMD_PING = 0x02U, // T02 - проверка соединения (ping) – эхо переданных данных
CLI_CMD_GET_INFO = 0x0AU, // T0A - информация об устройстве CLI_CMD_GET_INFO = 0x0AU, // T0A - получить информацию об устройстве (имя, серийный, версия)
CLI_CMD_READ_MEM = 0x14U, // T14 - чтение памяти CLI_CMD_READ_MEM = 0x14U, // T14 - чтение памяти (адрес 4 байта + размер 1 байт)
CLI_CMD_WRITE_MEM = 0x15U, // T15 - запись памяти CLI_CMD_WRITE_MEM = 0x15U, // T15 - запись памяти (адрес 4 байта + данные, только SRAM)
} cli_cmd_t; } cli_cmd_t;
//************************************ Коды ошибок (только 00-03 по протоколу) **************************** //************************************ Коды ошибок (только 00-03 по протоколу) ****************************
typedef enum { typedef enum {
CLI_ERR_NONE = 0x00U, CLI_ERR_NONE = 0x00U, // Нет ошибки
CLI_ERR_UNKNOWN_CMD = 0x01U, CLI_ERR_UNKNOWN_CMD = 0x01U, // Неизвестная команда
CLI_ERR_INVALID_ARG = 0x02U, CLI_ERR_INVALID_ARG = 0x02U, // Неверный формат или значение аргумента
CLI_ERR_INTERNAL = 0x03U, CLI_ERR_INTERNAL = 0x03U, // Внутренняя ошибка устройства
} cli_error_t; } cli_error_t;
//************************************ Информация об устройстве ********************************************** //************************************ Информация об устройстве **********************************************
//! @brief Структура с информацией об устройстве, возвращаемая командой T0A
typedef struct { typedef struct {
char name[32]; char name[32]; // Имя устройства (ASCII, до 31 символа + \\0)
char serial[16]; char serial[16]; // Серийный номер (ASCII, до 15 символов + \\0)
char version[16]; char version[16]; // Версия ПО (ASCII, до 15 символов + \\0)
u8 board_id; // Уникальный идентификатор платы (0-254) u8 board_id; // Уникальный идентификатор платы (0–254)
} cli_device_info_t; } cli_device_info_t;
//************************************ Тип обработчика команды **********************************************
//! @brief Прототип функции-обработчика команды
//! @param data Указатель на сырые данные команды (после board_id)
//! @param len Длина данных в байтах
typedef void (*cli_cmd_handler_t)(const u8* data, u8 len);
//************************************ Структура регистрируемой команды **************************************
//! @brief Структура для регистрации пользовательской команды
typedef struct {
u8 code; // Код команды (0x00–0xFF)
cli_cmd_handler_t handler; // Указатель на функцию-обработчик
} cli_command_t;
//************************************ Публичные функции **************************************************** //************************************ Публичные функции ****************************************************
// Инициализация протокола //---------------------------------------------------------------------
//! @brief Инициализация протокола CLI
//! @return ERR_OK при успехе, иначе код ошибки
fun_res_t cli_protocol_init(void); fun_res_t cli_protocol_init(void);
// Деинициализация протокола //---------------------------------------------------------------------
//! @brief Деинициализация протокола CLI
//! @return ERR_OK при успехе, иначе код ошибки
fun_res_t cli_protocol_deinit(void); fun_res_t cli_protocol_deinit(void);
// Основной цикл обработки (вызывать в while(1)) //---------------------------------------------------------------------
//! @brief Основной цикл обработки (вызывать в главном цикле программы)
void cli_protocol_process(void); void cli_protocol_process(void);
// Отправка строки через UART //---------------------------------------------------------------------
//! @brief Отправка строки через UART (с ожиданием завершения передачи)
//! @param str Указатель на нуль-терминированную строку
void cli_send_string(const char* str); void cli_send_string(const char* str);
// Установка информации об устройстве //---------------------------------------------------------------------
//! @brief Установка информации об устройстве
//! @param name Имя устройства (до 31 символа)
//! @param serial Серийный номер (до 15 символов)
//! @param ver Версия ПО (до 15 символов)
//! @param board_id Идентификатор платы (0–254)
//! @return ERR_OK при успехе
fun_res_t cli_protocol_set_device_info(const char* name, const char* serial, const char* ver, u8 board_id); fun_res_t cli_protocol_set_device_info(const char* name, const char* serial, const char* ver, u8 board_id);
// Управление board_id //---------------------------------------------------------------------
//! @brief Установка board_id устройства
//! @param board_id Идентификатор платы (0–254)
//! @return ERR_OK при успехе
fun_res_t cli_protocol_set_board_id(u8 board_id); fun_res_t cli_protocol_set_board_id(u8 board_id);
//---------------------------------------------------------------------
//! @brief Получение текущего board_id устройства
//! @return Идентификатор платы
u8 cli_protocol_get_board_id(void); u8 cli_protocol_get_board_id(void);
// Управление паролем //---------------------------------------------------------------------
void cli_protocol_set_password(const char* pass); //! @brief Установка пароля для открытия соединения
bool cli_protocol_verify_password(const char* pass); //! @param pass Указатель на массив байт пароля (до 15 байт)
//! @param len Длина пароля в байтах
void cli_protocol_set_password(const u8* pass, u8 len);
//---------------------------------------------------------------------
//! @brief Проверка пароля
//! @param pass Указатель на массив байт пароля
//! @param len Длина пароля в байтах
//! @return true – пароль верен, false – неверен
bool cli_protocol_verify_password(const u8* pass, u8 len);
//---------------------------------------------------------------------
//! @brief Сброс блокировки после превышения попыток ввода пароля
void cli_protocol_reset_block(void);
//---------------------------------------------------------------------
//! @brief Регистрация новой команды
//! @param cmd Указатель на структуру с кодом и обработчиком
//! @return ERR_OK при успехе, ERR_INVALID_ARGUMENT – неверные параметры,
//! ERR_RUNTIME_ERROR – команда уже зарегистрирована
fun_res_t cli_register_command(const cli_command_t* cmd);
#endif #endif
\ No newline at end of file
...@@ -14,6 +14,12 @@ ...@@ -14,6 +14,12 @@
#define CLI_CONNECTION_TIMEOUT_MS (20000U) // Таймаут соединения 20 секунд #define CLI_CONNECTION_TIMEOUT_MS (20000U) // Таймаут соединения 20 секунд
//************************************ Пароль по умолчанию ************************************************** //************************************ Пароль по умолчанию **************************************************
#define CLI_DEFAULT_PASSWORD "1357" // Пароль по умолчанию "1357"
#define CLI_DEFAULT_PASSWORD_BYTES {0x31, 0x33, 0x35, 0x37}
#define CLI_DEFAULT_PASSWORD_LEN 4
#define CLI_MAX_COMMANDS 256 // Максимальное количество регистрируемых команд (0x00..0xFF)
#define CLI_PASSWORD_MAX_LEN 15 // Максимальная длина пароля в байтах
#define CLI_MAX_PASSWORD_ATTEMPTS 3 // Количество попыток ввода пароля до блокировки
#define CLI_ACTIVITY_TIMEOUT_TICKS 20000U // ~20 сек при вызове каждые 1 мс
#endif #endif
\ No newline at end of file
...@@ -11,11 +11,6 @@ ...@@ -11,11 +11,6 @@
//************************************* Локальные (приватные) переменные ************************************ //************************************* Локальные (приватные) переменные ************************************
static uint32_t get_time_ms(void)
{
static uint32_t ms = 0;
return ++ms;
}
//*********************************************************************************************************** //***********************************************************************************************************
//******************************* Определения глобальных (публичных) функций ******************************** //******************************* Определения глобальных (публичных) функций ********************************
...@@ -27,7 +22,6 @@ void main(void) ...@@ -27,7 +22,6 @@ void main(void)
lmcal_init(); lmcal_init();
subm_init(); subm_init();
streams_init(); streams_init();
//cli_init();
// Инициализация LTA протокола // Инициализация LTA протокола
cli_protocol_init(); cli_protocol_init();
...@@ -36,7 +30,6 @@ void main(void) ...@@ -36,7 +30,6 @@ void main(void)
while(1) while(1)
{ {
streams_loop(); streams_loop();
//cli_process();
tcp_loop(); tcp_loop();
// Обработка команд // Обработка команд
...@@ -45,7 +38,6 @@ void main(void) ...@@ -45,7 +38,6 @@ void main(void)
if (bsp_loop()) break; if (bsp_loop()) break;
} }
//cli_deinit();
cli_protocol_deinit(); cli_protocol_deinit();
streams_deinit(); streams_deinit();
bsp_deinit(); bsp_deinit();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment