Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
LTA_mcu
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
CI / CD Analytics
Repository Analytics
Value Stream Analytics
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Александр Пчелин
LTA_mcu
Commits
c500d6a7
Commit
c500d6a7
authored
May 05, 2026
by
Александр Пчелин
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Обновлен протокол, изменение колбека приема, реализация вывода информации о модуле.
parent
cc944181
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
466 additions
and
472 deletions
+466
-472
src/cli_protocol/cli_protocol.c
src/cli_protocol/cli_protocol.c
+416
-406
src/cli_protocol/cli_protocol.h
src/cli_protocol/cli_protocol.h
+40
-63
src/cli_protocol/cli_protocol_cfg.h
src/cli_protocol/cli_protocol_cfg.h
+10
-2
src/main.c
src/main.c
+0
-1
No files found.
src/cli_protocol/cli_protocol.c
View file @
c500d6a7
...
@@ -6,27 +6,33 @@
...
@@ -6,27 +6,33 @@
//!
//!
//! @details Протокол предназначен для тестирования и диагностики встроенного ПО устройств,
//! @details Протокол предназначен для тестирования и диагностики встроенного ПО устройств,
//! подключенных к ПК через UART (COM-порт). ПК выступает мастером, устройство — подчинённым.
//! подключенных к ПК через UART (COM-порт). ПК выступает мастером, устройство — подчинённым.
//! Команды передаются в текстовом виде
, данные кодируются в HEX.
//! Команды передаются в текстовом виде
//!
//!
//! Расширение протокола: новые команды регистрируются через cli_register_command().
//! Расширение протокола: новые команды регистрируются через cli_register_command().
//!
//!
//! Максимальный размер поля данных:
64 байта.
//! Максимальный размер поля данных:
задается в конфигурации
//!
//!
//! @note Для работы необходимо наличие LMCAL, ring_buffer, а также tsp_dev_info из модуля tcp.h.
//***********************************************************************************************************
//***********************************************************************************************************
#include "cli_protocol.h"
#include "cli_protocol.h"
#include "flash_mem.h"
#include "ring_buffer.h"
#include "ring_buffer.h"
#include "lmcal.h"
#include "lmcal.h"
#include "tcp.h"
// #include <string.h>
#include "fpga_cmn.h"
#include "flash_mem.h"
#include "submodule.h"
//******************************************** Определения типов ********************************************
#include <string.h>
#include <stdio.h>
// Коды ошибок по протоколу
typedef
enum
{
CLI_ERR_NONE
=
0x00U
,
// Нет ошибки
CLI_ERR_UNKNOWN_CMD
=
0x01U
,
// Неизвестная команда
CLI_ERR_INVALID_ARG
=
0x02U
,
// Неверный формат или значение аргумента
CLI_ERR_INTERNAL
=
0x03U
,
// Внутренняя ошибка устройства
CLI_ERR_CON
=
0x04U
,
// Устройство не подключено
}
cli_error_t
;
// Включаем заголовок для доступа к регистрам USART (только для ожидания TC)
#include "gd32f4xx_usart.h"
//************************************ Локальные константы **************************************************
//************************************ Локальные константы **************************************************
#define CLI_CMD_PREFIX 'T' // Префикс команды
#define CLI_CMD_PREFIX 'T' // Префикс команды
...
@@ -43,42 +49,21 @@
...
@@ -43,42 +49,21 @@
static
ringbuf_t
fifo_rx
;
// Кольцевой буфер приёма байт из UART
static
ringbuf_t
fifo_rx
;
// Кольцевой буфер приёма байт из UART
static
u8
fifo_rx_buf
[
CLI_CMD_BUFFER_SIZE
];
// Память для кольцевого буфера
static
u8
fifo_rx_buf
[
CLI_CMD_BUFFER_SIZE
];
// Память для кольцевого буфера
static
char
cli_cmd_buffer
[
CLI_CMD_BUFFER_SIZE
];
// Буфер для накопления строки команды
static
u8
cli_connected
=
0
;
static
u16
cli_cmd_index
=
0
;
// Текущая длина строки в буфере
static
bool
cli_connected
=
false
;
// Флаг активного соединения (после успешной T00)
static
cli_device_info_t
cli_device_info
;
static
u32
cli_last_activity
=
0
;
// Время последней активности (тики)
static
u32
(
*
cli_get_tick
)(
void
)
=
NULL
;
// Счётчик
static
cli_
device_info_t
cli_device_info
;
// Информация об устройстве (имя, серийный номер, версия, board_id)
static
cli_
cmd_handler_t
cmd_handlers
[
CLI_MAX_COMMANDS
];
// Пароль хранится как байтовый массив с завершающим нулём (для удобства отладки)
static
char
buf_tmp
[
CLI_DATA_MAX_SIZE
];
static
u8
cli_password
[
CLI_PASSWORD_MAX_LEN
+
1
];
static
u8
data_size
;
static
u8
cli_password_len
=
0
;
// Фактическая длина пароля в байтах
// Таблица обработчиков команд. Индекс = код команды (0..255)
static
cli_cmd_handler_t
cmd_handlers
[
CLI_MAX_COMMANDS
];
//************************************ Прототипы локальных функций ******************************************
//***********************************************************************************************************
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-символа (старший и младший полубайт)
// Преобразование байта в два HEX-символа (старший и младший полубайт)
//-----------------------------------------------------------------------------------------------------------
static
inline
void
byte_to_hex
(
u8
byte
,
char
*
hex
)
static
inline
void
byte_to_hex
(
u8
byte
,
char
*
hex
)
{
{
const
char
*
d
=
"0123456789ABCDEF"
;
const
char
*
d
=
"0123456789ABCDEF"
;
...
@@ -86,9 +71,9 @@ static inline void byte_to_hex(u8 byte, char* hex)
...
@@ -86,9 +71,9 @@ static inline void byte_to_hex(u8 byte, char* hex)
hex
[
1
]
=
d
[
byte
&
0x0F
];
hex
[
1
]
=
d
[
byte
&
0x0F
];
}
}
//-----------------------------------------------------------------------------------------------------------
// Преобразование двух HEX-символов в байт. Возвращает 0xFF при ошибке.
// Преобразование двух 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
]);
...
@@ -96,10 +81,10 @@ static u8 hex_to_byte(const char* hex)
...
@@ -96,10 +81,10 @@ 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' в конце буфера.
// Аналог strncpy, но всегда добавляет '\0' в конце буфера.
//-----------------------------------------------------------------------------------------------------------
static
void
safe_strncpy
(
char
*
dst
,
const
char
*
src
,
size_t
dst_size
)
static
void
safe_strncpy
(
char
*
dst
,
const
char
*
src
,
size_t
dst_size
)
{
{
if
(
dst
==
NULL
||
src
==
NULL
||
dst_size
==
0
)
return
;
if
(
dst
==
NULL
||
src
==
NULL
||
dst_size
==
0
)
return
;
...
@@ -107,497 +92,522 @@ static void safe_strncpy(char* dst, const char* src, size_t dst_size)
...
@@ -107,497 +92,522 @@ static void safe_strncpy(char* dst, const char* src, size_t dst_size)
dst
[
dst_size
-
1
]
=
'\0'
;
dst
[
dst_size
-
1
]
=
'\0'
;
}
}
//-----------------------------------------------------------------------------------------------------------
// Отправка строки через UART (публичная обёртка)
//-----------------------------------------------------------------------------------------------------------
void
cli_send_string
(
const
char
*
str
)
{
if
(
!
str
)
return
;
while
(
*
str
)
{
lmcal_uart_write
(
CLI_UART_CHANNEL
,
(
u16
)
*
str
++
);
}
// Ждём завершения передачи, чтобы не смешивать вывод
uart_wait_tx_done
();
}
//-----------------------------------------------------------------------------------------------------------
// Ожидание завершения передачи UART (флаг TC)
// Используем прямой доступ к регистрам, т.к. LMCAL не предоставляет такой функции.
//-----------------------------------------------------------------------------------------------------------
static
void
uart_wait_tx_done
(
void
)
{
#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
u32
timeout
=
100000
;
while
(
usart_flag_get
(
CLI_USART
,
USART_FLAG_TC
)
==
RESET
&&
--
timeout
);
}
//-----------------------------------------------------------------------------------------------------------
// Формирование и отправка успешного ответа на команду.
// Формирование и отправка успешного ответа на команду.
// Формат: t[cmd][board_id][data...]\r
// Формат: xx[cmd][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
;
// 't'
buf
[
idx
++
]
=
CLI_RESPONSE_PREFIX
;
// 't'
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
;
// board_id
for
(
u8
i
=
0
;
i
<
len
;
i
++
)
{
for
(
u8
i
=
0
;
i
<
len
;
i
++
)
{
byte_to_hex
(
data
[
i
],
(
char
*
)
&
buf
[
idx
]);
// данные в HEX
buf
[
idx
++
]
=
data
[
i
];
idx
+=
2
;
// byte_to_hex(data[i], (char*)&buf[idx]); // данные в HEX
// idx += 2;
}
}
buf
[
idx
++
]
=
CLI_MSG_TERMINATOR
;
// '\r'
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
// Формат: xx[cmd][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
;
// 'e'
buf
[
idx
++
]
=
CLI_ERROR_PREFIX
;
// 'e'
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
(
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)
// Обработчик команды открытия соединения (CLI_CMD_OPEN = 0x00)
// Данные могут содержать пароль. Если пароль задан, проверяем его.
// Данные могут содержать пароль. Если пароль задан, проверяем его.
//-----------------------------------------------------------------------------------------------------------
static
i8
handle_cmd_open
(
const
u8
*
data
,
u8
len
)
static
void
handle_cmd_open
(
const
u8
*
data
,
u8
len
)
{
{
(
void
)
len
;
i8
err
=
CLI_HND_OK_RX
;
cli_connected
=
1
;
return
err
;
}
if
(
cli_connected
)
{
send_error
(
CLI_CMD_OPEN
,
CLI_ERR_INTERNAL
);
return
;
}
if
(
len
!=
cli_password_len
||
memcmp
(
data
,
cli_password
,
len
)
!=
0
)
{
send_error
(
CLI_CMD_OPEN
,
CLI_ERR_INTERNAL
);
return
;
}
cli_connected
=
true
;
if
(
cli_get_tick
)
cli_last_activity
=
cli_get_tick
();
send_response
(
CLI_CMD_OPEN
,
NULL
,
0
);
}
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды закрытия соединения (CLI_CMD_CLOSE = 0x01)
// Обработчик команды закрытия соединения (CLI_CMD_CLOSE = 0x01)
//-----------------------------------------------------------------------------------------------------------
static
i8
handle_cmd_close
(
const
u8
*
data
,
u8
len
)
static
void
handle_cmd_close
(
const
u8
*
data
,
u8
len
)
{
{
(
void
)
data
;
(
void
)
len
;
i8
err
=
CLI_HND_OK_RX
;
cli_connected
=
false
;
cli_connected
=
0
;
send_response
(
CLI_CMD_CLOSE
,
NULL
,
0
);
return
err
;
cli_cmd_index
=
0
;
memset
(
cli_cmd_buffer
,
0
,
sizeof
(
cli_cmd_buffer
));
}
}
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды проверки соединения (CLI_CMD_PING = 0x02)
// Обработчик команды проверки соединения (CLI_CMD_ECHO = 0x02)
// Возвращает эхо переданных данных.
// Возвращает эхо переданных данных.
//
-----------------------------------------------------------------------------------------------------------
//
data в hex
static
void
handle_cmd_ping
(
const
u8
*
data
,
u8
len
)
static
i8
handle_cmd_echo
(
const
u8
*
data
,
u8
len
)
{
{
if
(
!
cli_connected
)
{
i8
err
=
CLI_HND_OK_TX
;
send_error
(
CLI_CMD_PING
,
CLI_ERR_INTERNAL
);
return
;
u8
tmp
[
CLI_DATA_MAX_SIZE
];
}
memcpy
(
tmp
,
data
,
len
);
send_response
(
CLI_CMD_PING
,
data
,
len
);
cli_prepare_tx_data
(
tmp
,
len
);
return
err
;
}
}
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды получения информации об устройстве (CLI_CMD_GET_INFO = 0x0A)
// Обработчик команды получения информации об устройстве (CLI_CMD_GET_INFO = 0x0A)
// Формат ответа:
board_id (1 байт),
длина имени, имя, длина серийного, серийный,
// Формат ответа: длина имени, имя, длина серийного, серийный,
// длина версии, версия (ASCII).
// длина версии, версия (ASCII).
//-----------------------------------------------------------------------------------------------------------
static
i8
handle_cmd_get_info
(
const
u8
*
data
,
u8
len
)
static
void
handle_cmd_get_info
(
const
u8
*
data
,
u8
len
)
{
{
//i8 err = CLI_HND_OK_RX;
//return err;
(
void
)
data
;
(
void
)
len
;
(
void
)
data
;
(
void
)
len
;
if
(
!
cli_connected
)
{
send_error
(
CLI_CMD_GET_INFO
,
CLI_ERR_INTERNAL
);
return
;
}
u8
buf
[
CLI_DATA_MAX_SIZE
];
u16
idx
=
0
;
u8
str_len
;
buf
[
idx
++
]
=
cli_device_info
.
board_id
;
u8
raw
[
CLI_DATA_MAX_SIZE
];
// временный буфер для бинарных данных
u8
str_len
;
u8
raw_idx
=
0
;
// if (!cli_connected) {
// send_error(CLI_CMD_GET_INFO, CLI_ERR_INTERNAL);
// return;
// }
// u8 buf[CLI_DATA_MAX_SIZE];
// u16 idx = 0;
// u8 str_len;
// buf[idx++] = cli_device_info.board_id;
// Имя устройства
str_len
=
strlen
(
cli_device_info
.
name
);
str_len
=
strlen
(
cli_device_info
.
name
);
if
(
str_len
>
31
)
str_len
=
31
;
if
(
str_len
>
15
)
str_len
=
15
;
buf
[
idx
++
]
=
str_len
;
raw
[
raw_idx
++
]
=
str_len
;
// байт длины
memcpy
(
&
buf
[
idx
],
cli_device_info
.
name
,
str_len
);
memcpy
(
&
raw
[
raw_idx
],
cli_device_info
.
name
,
str_len
);
// строка
idx
+=
str_len
;
raw_
idx
+=
str_len
;
// Серийный номер
str_len
=
strlen
(
cli_device_info
.
serial
);
str_len
=
strlen
(
cli_device_info
.
serial
);
if
(
str_len
>
15
)
str_len
=
15
;
if
(
str_len
>
15
)
str_len
=
15
;
buf
[
idx
++
]
=
str_len
;
raw
[
raw_
idx
++
]
=
str_len
;
memcpy
(
&
buf
[
idx
],
cli_device_info
.
serial
,
str_len
);
memcpy
(
&
raw
[
raw_
idx
],
cli_device_info
.
serial
,
str_len
);
idx
+=
str_len
;
raw_
idx
+=
str_len
;
char
ver
[
16
];
// char ver[16] = "0";
snprintf
(
ver
,
sizeof
(
ver
),
"%lu"
,
tsp_dev_info
.
mcu_ver
);
// snprintf(ver, sizeof(ver), "%lu", tcp_dev_info.mcu_ver);
str_len
=
strlen
(
ver
);
// Версия
str_len
=
strlen
(
cli_device_info
.
version
);
if
(
str_len
>
15
)
str_len
=
15
;
if
(
str_len
>
15
)
str_len
=
15
;
buf
[
idx
++
]
=
str_len
;
raw
[
raw_idx
++
]
=
str_len
;
memcpy
(
&
buf
[
idx
],
ver
,
str_len
);
memcpy
(
&
raw
[
raw_idx
],
cli_device_info
.
version
,
str_len
);
idx
+=
str_len
;
raw_idx
+=
str_len
;
// Преобразование в HEX-строку ===
u8
hex_idx
=
0
;
for
(
u8
i
=
0
;
i
<
raw_idx
;
i
++
)
{
byte_to_hex
(
raw
[
i
],
&
buf_tmp
[
hex_idx
]);
hex_idx
+=
2
;
}
send_response
(
CLI_CMD_GET_INFO
,
buf
,
idx
);
data_size
=
hex_idx
;
// send_response(CLI_CMD_GET_INFO, buf, idx);
return
CLI_HND_OK_TX
;
}
}
//-----------------------------------------------------------------------------------------------------------
// Обработчик команды чтения памяти (CLI_CMD_READ_MEM = 0x14)
// Данные: 4 байта адреса (big-endian), 1 байт размера (1-64)
// Исправлена проверка границ: теперь учитывается размер
//-----------------------------------------------------------------------------------------------------------
static
void
handle_cmd_read_mem
(
const
u8
*
data
,
u8
len
)
{
if
(
!
cli_connected
)
{
send_error
(
CLI_CMD_READ_MEM
,
CLI_ERR_INTERNAL
);
return
;
}
if
(
len
!=
5
)
{
send_error
(
CLI_CMD_READ_MEM
,
CLI_ERR_INVALID_ARG
);
return
;
}
u32
addr
=
0
;
for
(
u8
i
=
0
;
i
<
4
;
i
++
)
addr
=
(
addr
<<
8
)
|
data
[
i
];
u8
size
=
data
[
4
];
if
(
size
==
0
||
size
>
CLI_DATA_MAX_SIZE
)
{
send_error
(
CLI_CMD_READ_MEM
,
CLI_ERR_INVALID_ARG
);
return
;
}
// Проверка на переполнение адреса
u32
end_addr
=
addr
+
size
;
if
(
end_addr
<
addr
)
{
send_error
(
CLI_CMD_READ_MEM
,
CLI_ERR_INTERNAL
);
return
;
}
// Проверка допустимых диапазонов (GD32F450: Flash 2MB, SRAM 192KB)
// Колбек прерывания по приёму байта из UART.
bool
valid
=
false
;
// static void uart_rx_cb(void)
// {
if
((
addr
>=
0x08000000
)
&&
(
end_addr
<=
0x081FFFFF
))
{
// u16 rx = lmcal_uart_read(CLI_UART_CHANNEL);
valid
=
true
;
// Flash (банк 0 + банк 1 = 2 МБ)
// rb_add_item(&fifo_rx, (u8*)&rx);
}
else
if
((
addr
>=
0x20000000
)
&&
(
end_addr
<=
0x2002FFFF
))
{
// }
valid
=
true
;
// SRAM (192 КБ)
}
if
(
valid
)
{
static
void
uart_rx_cb
(
void
)
u8
buf
[
CLI_DATA_MAX_SIZE
];
{
for
(
u8
i
=
0
;
i
<
size
;
i
++
)
{
u16
rx
=
lmcal_uart_read
(
CLI_UART_CHANNEL
);
buf
[
i
]
=
*
(
volatile
u8
*
)(
addr
+
i
);
u8
ch
=
(
u8
)(
rx
&
0xFF
);
}
rb_add_item
(
&
fifo_rx
,
&
ch
);
send_response
(
CLI_CMD_READ_MEM
,
buf
,
size
);
}
else
{
printf
(
"READ_MEM error: addr=0x%08X, size=%d, end=0x%08X
\n
"
,
addr
,
size
,
end_addr
);
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
)
{
if
(
!
cli_connected
)
{
send_error
(
CLI_CMD_WRITE_MEM
,
CLI_ERR_INTERNAL
);
return
;
}
if
(
len
<
5
)
{
send_error
(
CLI_CMD_WRITE_MEM
,
CLI_ERR_INVALID_ARG
);
return
;
}
u32
addr
=
0
;
for
(
u8
i
=
0
;
i
<
4
;
i
++
)
addr
=
(
addr
<<
8
)
|
data
[
i
];
u8
size
=
len
-
4
;
if
(
size
>
CLI_DATA_MAX_SIZE
)
{
send_error
(
CLI_CMD_WRITE_MEM
,
CLI_ERR_INVALID_ARG
);
return
;
}
// Проверка на переполнение
u32
end_addr
=
addr
+
size
;
if
(
end_addr
<
addr
)
{
send_error
(
CLI_CMD_WRITE_MEM
,
CLI_ERR_INTERNAL
);
return
;
}
// Запись разрешена только в SRAM
if
((
addr
>=
0x20000000
)
&&
(
end_addr
<=
0x2002FFFF
))
{
for
(
u8
i
=
0
;
i
<
size
;
i
++
)
{
*
(
volatile
u8
*
)(
addr
+
i
)
=
data
[
4
+
i
];
}
send_response
(
CLI_CMD_WRITE_MEM
,
NULL
,
0
);
}
else
{
printf
(
"WRITE_MEM error: addr=0x%08X, size=%d, end=0x%08X
\n
"
,
addr
,
size
,
end_addr
);
send_error
(
CLI_CMD_WRITE_MEM
,
CLI_ERR_INTERNAL
);
}
}
//-----------------------------------------------------------------------------------------------------------
// Обработка буфера, 4 первых символа должны содержать код и длину данных
// Разбор принятой строки и вызов соответствующего обработчика.
static
i8
parse_cmd
(
char
*
buf
,
u8
*
cmd
,
u8
*
data
)
//-----------------------------------------------------------------------------------------------------------
static
void
parse_and_execute
(
void
)
{
{
char
*
buf
=
cli_cmd_buffer
;
i8
err
=
0
;
u16
len
=
cli_cmd_index
;
if
(
len
<
6
)
{
cli_cmd_index
=
0
;
return
;
}
if
(
buf
[
0
]
!=
CLI_CMD_PREFIX
)
{
cli_cmd_index
=
0
;
return
;
}
if
(
buf
[
len
-
1
]
!=
CLI_MSG_TERMINATOR
)
return
;
u8
cmd
=
hex_to_byte
(
&
buf
[
1
]);
if
(
cmd
==
0xFF
)
{
cli_cmd_index
=
0
;
return
;
}
u8
board_id
=
hex_to_byte
(
&
buf
[
3
]);
if
(
board_id
==
0xFF
)
{
cli_cmd_index
=
0
;
return
;
}
if
(
board_id
!=
cli_device_info
.
board_id
)
{
cli_cmd_index
=
0
;
return
;
}
u16
data_start
=
5
;
u16
chars
=
len
-
1
-
data_start
;
u8
data
[
CLI_DATA_MAX_SIZE
+
4
];
u8
data_len
=
0
;
if
(
chars
>
0
)
{
if
(
chars
%
2
!=
0
)
{
send_error
(
cmd
,
CLI_ERR_INVALID_ARG
);
cli_cmd_index
=
0
;
return
;
}
data_len
=
chars
/
2
;
if
(
data_len
>
CLI_DATA_MAX_SIZE
+
4
)
{
send_error
(
cmd
,
CLI_ERR_INVALID_ARG
);
cli_cmd_index
=
0
;
return
;
}
for
(
u8
i
=
0
;
i
<
data_len
;
i
++
)
{
data
[
i
]
=
hex_to_byte
(
&
buf
[
data_start
+
i
*
2
]);
if
(
data
[
i
]
==
0xFF
)
{
send_error
(
cmd
,
CLI_ERR_INVALID_ARG
);
cli_cmd_index
=
0
;
return
;
}
}
}
if
(
cli_get_tick
)
cli_last_activity
=
cli_get_tick
();
u8
cmd_tmp
=
hex_to_byte
(
&
buf
[
0
]);
u8
data_tmp
=
hex_to_byte
(
&
buf
[
2
]);
if
(
cmd_handlers
[
cmd
]
!=
NULL
)
{
if
((
cmd_tmp
!=
0xFF
)
&&
(
data_tmp
!=
0xFF
))
cmd_handlers
[
cmd
](
data
,
data_len
);
{
}
else
{
*
cmd
=
cmd_tmp
;
send_error
(
cmd
,
CLI_ERR_UNKNOWN_CMD
);
*
data
=
data_tmp
;
}
else
{
err
=
-
1
;
}
}
cli_cmd_index
=
0
;
return
err
;
}
}
//-----------------------------------------------------------------------------------------------------------
// Колбек прерывания по приёму байта из UART.
//-----------------------------------------------------------------------------------------------------------
// Преобразование буфера символов в буфер с hex
static
void
uart_rx_cb
(
void
)
// Принимает: указатель на строку и кол-во символов
// Возвращает: буфер с байтами и кол-во байт
static
void
parse_data
(
char
*
buf
,
u8
*
size
)
{
{
u16
rx
=
lmcal_uart_read
(
CLI_UART_CHANNEL
);
u8
tmp
;
u8
ch
=
(
u8
)(
rx
&
0xFF
);
u8
tmp_size
=
*
size
/
2
;
rb_add_item
(
&
fifo_rx
,
&
ch
);
for
(
u8
i
=
0
,
j
=
0
;
i
<
*
size
;
i
+=
2
,
j
++
)
{
tmp
=
hex_to_byte
(
&
buf
[
i
]);
buf
[
j
]
=
tmp
;
}
*
size
=
tmp_size
;
}
}
//-----------------------------------------------------------------------------------------------------------
// Регистрация встроенных команд протокола.
// Чтение байта из ФИФО. При ошибке возвращает -1
//-----------------------------------------------------------------------------------------------------------
static
u8
read_fifo
(
u8
*
byte
)
static
void
register_builtin_commands
(
void
)
{
{
const
cli_command_t
builtin
[]
=
{
i8
err
=
0
;
{
CLI_CMD_OPEN
,
handle_cmd_open
},
{
CLI_CMD_CLOSE
,
handle_cmd_close
},
if
(
rb_get_items_qty
(
&
fifo_rx
)
>
0
)
{
CLI_CMD_PING
,
handle_cmd_ping
},
{
{
CLI_CMD_GET_INFO
,
handle_cmd_get_info
},
rb_get_item
(
&
fifo_rx
,
byte
);
{
CLI_CMD_READ_MEM
,
handle_cmd_read_mem
},
}
{
CLI_CMD_WRITE_MEM
,
handle_cmd_write_mem
},
else
};
{
for
(
size_t
i
=
0
;
i
<
sizeof
(
builtin
)
/
sizeof
(
builtin
[
0
]);
i
++
)
{
err
=
-
1
;
cli_register_command
(
&
builtin
[
i
]);
}
}
return
err
;
}
}
//************************************ Публичные функции ****************************************************
//************************************ Публичные функции ****************************************************
//-----------------------------------------------------------------------------------------------------------
fun_res_t
cli_protocol_init
(
void
)
fun_res_t
cli_protocol_init
(
void
)
{
{
fifo_rx
.
item_size
=
sizeof
(
u8
);
fifo_rx
.
item_size
=
sizeof
(
u8
);
rb_init
(
&
fifo_rx
,
fifo_rx_buf
,
sizeof
(
fifo_rx_buf
));
rb_init
(
&
fifo_rx
,
fifo_rx_buf
,
sizeof
(
fifo_rx_buf
));
rb_clear
(
&
fifo_rx
);
rb_clear
(
&
fifo_rx
);
lmcal_uart_set_callback
(
CLI_UART_CHANNEL
,
CB_INT_RX_CALLBACK
,
uart_rx_cb
);
lmcal_uart_set_callback
(
CLI_UART_CHANNEL
,
CB_INT_RX_CALLBACK
,
uart_rx_cb
);
lmcal_uart_enable
(
CLI_UART_CHANNEL
,
1
);
cli_connected
=
0
;
const
char
*
dev_name
=
NULL
;
const
char
*
dev_serial
=
NULL
;
const
char
*
dev_version
=
"1.0.0"
;
// Пытаемся взять данные из заводской памяти
extern
fm_factory_mem_data_t
*
fm_factory_mem_data
;
if
(
fm_factory_mem_data
!=
NULL
)
{
dev_name
=
fm_factory_mem_data
->
name
;
dev_serial
=
fm_factory_mem_data
->
serial
;
}
cli_cmd_index
=
0
;
// Версия из макроса сборки
cli_connected
=
false
;
#ifdef PROJECT_VERSION
cli_last_activity
=
0
;
dev_version
=
PROJECT_VERSION
;
memset
(
cli_cmd_buffer
,
0
,
sizeof
(
cli_cmd_buffer
));
#endif
safe_strncpy
(
cli_device_info
.
name
,
"CLI Device"
,
sizeof
(
cli_device_info
.
name
));
cli_protocol_set_device_info
(
dev_name
,
dev_serial
,
dev_version
);
safe_strncpy
(
cli_device_info
.
serial
,
"00000000"
,
sizeof
(
cli_device_info
.
serial
));
safe_strncpy
(
cli_device_info
.
version
,
"1.0.0"
,
sizeof
(
cli_device_info
.
version
));
cli_device_info
.
board_id
=
0
;
// Инициализация встроенных обработчиков
memset
(
cmd_handlers
,
0
,
sizeof
(
cmd_handlers
));
memset
(
cmd_handlers
,
0
,
sizeof
(
cmd_handlers
));
register_builtin_commands
();
const
cli_command_t
builtin
[]
=
{
{
CLI_CMD_OPEN
,
handle_cmd_open
},
const
u8
default_pass
[]
=
CLI_DEFAULT_PASSWORD_BYTES
;
{
CLI_CMD_CLOSE
,
handle_cmd_close
},
cli_protocol_set_password
(
default_pass
,
sizeof
(
default_pass
));
{
CLI_CMD_ECHO
,
handle_cmd_echo
},
{
CLI_CMD_GET_INFO
,
handle_cmd_get_info
},
cli_send_string
(
"
\r\n
********** LTA PROTOCOL ENABLED **********
\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
"
);
for
(
size_t
i
=
0
;
i
<
sizeof
(
builtin
)
/
sizeof
(
builtin
[
0
]);
i
++
)
{
cli_send_string
(
"|> T0201AABB - ping with data 0xAA,0xBB
\r\n
"
);
cmd_handlers
[
builtin
[
i
].
code
]
=
builtin
[
i
].
handler
;
cli_send_string
(
"|> T0A01 - get device info
\r\n
"
);
}
cli_send_string
(
"|> T14010800000004 - read 4 bytes from 0x08000000
\r\n
"
);
cli_send_string
(
"|> T14012000000004 - read 4 bytes from 0x20000000
\r\n
"
);
cli_send_string
(
"|> T150120000000AABB - write 0xAA,0xBB to SRAM 0x20000000
\r\n
"
);
cli_send_string
(
"******************************************************
\r\n
"
);
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
);
cli_connected
=
false
;
cli_connected
=
0
;
return
ERR_OK
;
return
ERR_OK
;
}
}
//-----------------------------------------------------------------------------------------------------------
void
cli_protocol_process
(
void
)
void
cli_protocol_process
(
void
)
{
{
static
u8
buf_index
;
// Текущая команда и размер данных для приема
static
u8
cur_cmd
;
static
enum
{
static
enum
{
WAIT_CMD
,
// Ожидание первого символа команды
RESET
,
// Сброс
RECEIVING
,
// Приём символов команды
WAIT_START
,
// Ожидание первого символа команды
EXPECT_NL
// Ожидание \n после \r
WAIT_CMD
,
// Прием аргументов команды
}
state
=
WAIT_CMD
;
WAIT_DATA
,
// Приём данных команды
WAIT_CR
,
// Ожидание \r
while
(
rb_get_items_qty
(
&
fifo_rx
)
>
0
)
{
EXECUTE
,
// Выполнение
u8
ch
;
}
state
=
RESET
;
if
(
rb_get_item
(
&
fifo_rx
,
&
ch
)
!=
RB_RES_OK
)
continue
;
u8
tmp
;
switch
(
state
)
{
i8
err
;
case
WAIT_CMD
:
if
(
ch
==
' '
||
ch
==
'\t'
||
ch
==
'\r'
||
ch
==
'\n'
)
continue
;
switch
(
state
)
cli_cmd_index
=
0
;
{
cli_cmd_buffer
[
cli_cmd_index
++
]
=
ch
;
case
RESET
:
state
=
RECEIVING
;
buf_index
=
0
;
break
;
cur_cmd
=
0
;
case
RECEIVING
:
data_size
=
0
;
if
(
ch
==
'\r'
||
ch
==
'\n'
)
{
state
=
WAIT_START
;
while
(
cli_cmd_index
>
0
&&
(
cli_cmd_buffer
[
cli_cmd_index
-
1
]
==
' '
break
;
||
cli_cmd_buffer
[
cli_cmd_index
-
1
]
==
'\t'
))
{
cli_cmd_index
--
;
case
WAIT_START
:
}
if
(
read_fifo
(
&
tmp
)
==
0
)
{
if
(
cli_cmd_index
>
0
)
{
if
(
tmp
==
CLI_CMD_PREFIX
)
cli_cmd_buffer
[
cli_cmd_index
]
=
CLI_MSG_TERMINATOR
;
{
cli_cmd_index
++
;
state
=
WAIT_CMD
;
parse_and_execute
();
buf_index
=
0
;
cli_send_string
(
"|> "
);
}
}
break
;
case
WAIT_CMD
:
if
(
read_fifo
(
&
tmp
)
==
0
)
{
buf_tmp
[
buf_index
++
]
=
tmp
;
if
(
buf_index
==
4
)
{
if
(
parse_cmd
(
buf_tmp
,
&
cur_cmd
,
&
data_size
)
==
0
)
{
if
((
data_size
>
0
)
&&
(
CLI_DATA_MAX_SIZE
>=
data_size
)
&&
(
data_size
%
2
==
0
))
state
=
WAIT_DATA
;
else
state
=
WAIT_CR
;
buf_index
=
0
;
}
}
state
=
EXPECT_NL
;
else
}
else
{
{
if
(
cli_cmd_index
<
CLI_CMD_BUFFER_SIZE
-
1
)
{
// Ошибка в формате команды
cli_cmd_buffer
[
cli_cmd_index
++
]
=
ch
;
state
=
RESET
;
}
else
{
cli_cmd_index
=
0
;
state
=
WAIT_CMD
;
}
}
}
}
break
;
}
case
EXPECT_NL
:
break
;
if
(
ch
==
'\n'
)
{
state
=
WAIT_CMD
;
}
else
{
case
WAIT_DATA
:
cli_cmd_index
=
0
;
if
(
data_size
>
buf_index
)
cli_cmd_buffer
[
cli_cmd_index
++
]
=
ch
;
{
state
=
RECEIVING
;
if
(
read_fifo
(
&
tmp
)
==
0
)
{
buf_tmp
[
buf_index
++
]
=
tmp
;
}
}
else
{
state
=
WAIT_CR
;
}
break
;
case
WAIT_CR
:
if
(
read_fifo
(
&
tmp
)
==
0
)
{
if
(
tmp
==
CLI_MSG_TERMINATOR
)
{
if
(
cmd_handlers
[
cur_cmd
]
!=
NULL
)
{
state
=
EXECUTE
;
// Преобразование данных из строки в hex
if
(
data_size
>
0
)
parse_data
(
buf_tmp
,
&
data_size
);
}
else
{
// Данная команда не зарегестрирована
send_error
(
cur_cmd
,
CLI_ERR_UNKNOWN_CMD
);
state
=
RESET
;
}
}
else
{
state
=
RESET
;
}
}
break
;
case
EXECUTE
:
#if 0
if (cli_connected == 0)
{
if (cur_cmd != CLI_CMD_OPEN)
{
send_error(cur_cmd, CLI_ERR_CON);
state = WAIT_START;
break;
}
}
}
#endif
err
=
cmd_handlers
[
cur_cmd
](
buf_tmp
,
data_size
);
switch
(
err
)
{
case
(
CLI_HND_OK_RX
):
send_response
(
cur_cmd
,
NULL
,
0
);
state
=
WAIT_START
;
break
;
case
(
CLI_HND_OK_TX
):
send_response
(
cur_cmd
,
buf_tmp
,
data_size
);
state
=
WAIT_START
;
break
;
case
(
CLI_HND_ERR_ARG
):
send_error
(
cur_cmd
,
CLI_ERR_INVALID_ARG
);
state
=
WAIT_START
;
break
;
case
(
CLI_HND_ERR_INT
):
send_error
(
cur_cmd
,
CLI_ERR_INTERNAL
);
state
=
WAIT_START
;
break
;
case
(
CLI_HND_BUSY
):
// Ждем, когда хзндл выполнится
break
;
default:
// хэндл вернул недопустимый ответ
send_error
(
cur_cmd
,
CLI_ERR_INTERNAL
);
state
=
WAIT_START
;
break
;
break
;
}
}
break
;
default:
while
(
1
);
break
;
}
}
}
// Таймаут соединения (работает только если cli_get_tick != NULL)
if
(
cli_connected
&&
cli_get_tick
)
{
void
cli_prepare_tx_data
(
u8
*
hex_data
,
u8
size
)
if
((
cli_get_tick
()
-
cli_last_activity
)
>
CLI_CONNECTION_TIMEOUT_MS
)
{
{
cli_connected
=
false
;
if
(
hex_data
==
NULL
)
return
;
}
u8
tmp
[
3
];
for
(
u8
i
=
0
,
j
=
0
;
i
<
size
;
i
++
,
j
+=
2
)
{
// Преобразуем каждый байт в два hex‑символа (с ведущими нулями)
sprintf
(
tmp
,
"%02X"
,
hex_data
[
i
]);
buf_tmp
[
j
]
=
tmp
[
0
];
buf_tmp
[
j
+
1
]
=
tmp
[
1
];
}
}
data_size
=
size
*
2
;
}
}
//-----------------------------------------------------------------------------------------------------------
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
)
{
{
if
(
name
)
safe_strncpy
(
cli_device_info
.
name
,
name
,
sizeof
(
cli_device_info
.
name
));
if
(
name
)
safe_strncpy
(
cli_device_info
.
name
,
name
,
sizeof
(
cli_device_info
.
name
));
if
(
serial
)
safe_strncpy
(
cli_device_info
.
serial
,
serial
,
sizeof
(
cli_device_info
.
serial
));
if
(
serial
)
safe_strncpy
(
cli_device_info
.
serial
,
serial
,
sizeof
(
cli_device_info
.
serial
));
if
(
ver
)
safe_strncpy
(
cli_device_info
.
version
,
ver
,
sizeof
(
cli_device_info
.
version
));
if
(
ver
)
safe_strncpy
(
cli_device_info
.
version
,
ver
,
sizeof
(
cli_device_info
.
version
));
cli_device_info
.
board_id
=
board_id
;
return
ERR_OK
;
return
ERR_OK
;
}
}
//-----------------------------------------------------------------------------------------------------------
fun_res_t
cli_protocol_set_board_id
(
u8
board_id
)
{
cli_device_info
.
board_id
=
board_id
;
return
ERR_OK
;
}
//-----------------------------------------------------------------------------------------------------------
u8
cli_protocol_get_board_id
(
void
)
{
return
cli_device_info
.
board_id
;
}
//-----------------------------------------------------------------------------------------------------------
void
cli_protocol_set_password
(
const
u8
*
pass
,
u8
len
)
{
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
u8
*
pass
,
u8
len
)
{
return
(
len
==
cli_password_len
)
&&
(
memcmp
(
pass
,
cli_password
,
len
)
==
0
);
}
//-----------------------------------------------------------------------------------------------------------
fun_res_t
cli_register_command
(
const
cli_command_t
*
cmd
)
fun_res_t
cli_register_command
(
const
cli_command_t
*
cmd
)
{
{
if
(
cmd
==
NULL
||
cmd
->
handler
==
NULL
)
{
if
(
cmd
==
NULL
||
cmd
->
handler
==
NULL
||
(
CLI_INT_CMD_NUM
>
cmd
->
code
))
return
ERR_INVALID_ARGUMENT
;
{
}
if
((
int
)
cmd
->
code
>=
CLI_MAX_COMMANDS
)
{
return
ERR_INVALID_ARGUMENT
;
return
ERR_INVALID_ARGUMENT
;
}
}
if
(
cmd_handlers
[
cmd
->
code
]
!=
NULL
)
{
if
(
cmd_handlers
[
cmd
->
code
]
!=
NULL
)
{
return
ERR_RUNTIME_ERROR
;
return
ERR_RUNTIME_ERROR
;
}
}
cmd_handlers
[
cmd
->
code
]
=
cmd
->
handler
;
cmd_handlers
[
cmd
->
code
]
=
cmd
->
handler
;
return
ERR_OK
;
return
ERR_OK
;
}
}
void
cli_unregister_command
(
u8
code
)
{
if
(
CLI_INT_CMD_NUM
>
code
)
{
cmd_handlers
[
code
]
=
NULL
;
}
}
//*********************************************** КОНЕЦ ФАЙЛА ***********************************************
src/cli_protocol/cli_protocol.h
View file @
c500d6a7
...
@@ -3,106 +3,78 @@
...
@@ -3,106 +3,78 @@
#include "cli_protocol_cfg.h"
#include "cli_protocol_cfg.h"
#include "l_macro_types.h"
#include "l_macro_types.h"
#include <stdbool.h>
//************************************ Константы протокола *************************************************
#define CLI_BROADCAST_ID 0xFFU // Широковещательный адрес (команды для всех плат без ответа)
//************************************ Коды команд (по протоколу 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_ECHO
=
0x02U
,
// T02 - проверка соединения (ping)
CLI_CMD_GET_INFO
=
0x0AU
,
// T0A - получить информацию об устройстве (имя, серийный, версия)
CLI_CMD_GET_INFO
=
0x03U
,
// T03 - получить информацию об устройстве (имя, серийный, версия)
CLI_CMD_READ_MEM
=
0x14U
,
// T14 - чтение памяти (адрес 4 байта + размер 1 байт)
CLI_CMD_WRITE_MEM
=
0x15U
,
// T15 - запись памяти (адрес 4 байта + данные, только SRAM)
}
cli_cmd_t
;
}
cli_cmd_t
;
//************************************ Коды ошибок (только 00-03 по протоколу) ****************************
// Коды ошибок хэндла команды
typedef
enum
{
typedef
enum
{
CLI_ERR_NONE
=
0x00U
,
// Нет ошибки
CLI_HND_OK_RX
=
0
,
// Прием данных успешен
CLI_ERR_UNKNOWN_CMD
=
0x01U
,
// Неизвестная команда
CLI_HND_OK_TX
,
// Хэндл подготовил ответ для передачи
CLI_ERR_INVALID_ARG
=
0x02U
,
// Неверный формат или значение аргумента
CLI_HND_ERR_ARG
,
// Неверный формат или значение аргумента
CLI_ERR_INTERNAL
=
0x03U
,
// Внутренняя ошибка устройства
CLI_HND_ERR_INT
,
// Ошибка выполнения
}
cli_error_t
;
CLI_HND_BUSY
,
// Хэндл пока не может быть выполнен
}
cli_hnd_err_t
;
//************************************ Информация об устройстве **********************************************
//! @brief Структура с информацией об устройстве, возвращаемая командой T0A
// Структура с информацией об устройстве
typedef
struct
{
typedef
struct
{
char
name
[
32
];
// Имя устройства (ASCII, до 31 символа + \\0)
char
name
[
16
];
// Имя устройства (ASCII, до 15 символа + \0)
char
serial
[
16
];
// Серийный номер (ASCII, до 15 символов + \\0)
char
serial
[
16
];
// Серийный номер (ASCII, до 15 символов + \0)
char
version
[
16
];
// Версия ПО (ASCII, до 15 символов + \\0)
char
version
[
16
];
// Версия команд CLI (ASCII, до 15 символов + \0)
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 Структура для регистрации пользовательской команды
// - data Указатель на сырые данные команды (после board_id)
// - len Длина данных в байтах
// Выозвращает код ошибки (cli_hnd_err_t)
typedef
i8
(
*
cli_cmd_handler_t
)(
const
u8
*
data
,
u8
len
);
// Структура для регистрации пользовательской команды
typedef
struct
{
typedef
struct
{
u8
code
;
// Код команды (0x00–0xFF)
u8
code
;
// Код команды (0x00–0xFF)
cli_cmd_handler_t
handler
;
// Указатель на функцию-обработчик
cli_cmd_handler_t
handler
;
// Указатель на функцию-обработчик
}
cli_command_t
;
}
cli_command_t
;
//************************************ Публичные функции ****************************************************
//************************************ Публичные функции ****************************************************
//---------------------------------------------------------------------
//! @brief Инициализация протокола CLI
//! @brief Инициализация протокола CLI
//! @return ERR_OK при успехе, иначе код ошибки
//! @return ERR_OK при успехе, иначе код ошибки
fun_res_t
cli_protocol_init
(
void
);
fun_res_t
cli_protocol_init
(
void
);
//---------------------------------------------------------------------
//! @brief Деинициализация протокола CLI
//! @brief Деинициализация протокола CLI
//! @return ERR_OK при успехе, иначе код ошибки
//! @return ERR_OK при успехе, иначе код ошибки
fun_res_t
cli_protocol_deinit
(
void
);
fun_res_t
cli_protocol_deinit
(
void
);
//---------------------------------------------------------------------
//! @brief Основной цикл обработки (вызывать в главном цикле программы)
//! @brief Основной цикл обработки (вызывать в главном цикле программы)
void
cli_protocol_process
(
void
);
void
cli_protocol_process
(
void
);
//---------------------------------------------------------------------
//! @brief Отправка строки через UART (с ожиданием завершения передачи)
//! @brief Отправка строки через UART (с ожиданием завершения передачи)
//! @param str Указатель на нуль-терминированную строку
//! @param str Указатель на нуль-терминированную строку
void
cli_send_string
(
const
char
*
str
);
void
cli_prepare_tx_data
(
u8
*
hex_data
,
u8
size
);
//---------------------------------------------------------------------
//! @brief Установка информации об устройстве
//! @brief Установка информации об устройстве
//! @param name Имя устройства (до
31
символа)
//! @param name Имя устройства (до
15
символа)
//! @param serial Серийный номер (до 15 символов)
//! @param serial Серийный номер (до 15 символов)
//! @param ver Версия ПО (до 15 символов)
//! @param ver Версия ПО (до 15 символов)
//! @param board_id Идентификатор платы (0–254)
//! @return ERR_OK при успехе
//! @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
);
//---------------------------------------------------------------------
//! @brief Установка board_id устройства
//! @param board_id Идентификатор платы (0–254)
//! @return ERR_OK при успехе
fun_res_t
cli_protocol_set_board_id
(
u8
board_id
);
//---------------------------------------------------------------------
//! @brief Получение текущего board_id устройства
//! @return Идентификатор платы
u8
cli_protocol_get_board_id
(
void
);
//---------------------------------------------------------------------
//! @brief Установка пароля для открытия соединения
//! @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 Регистрация новой команды
//! @brief Регистрация новой команды
//! @param cmd Указатель на структуру с кодом и обработчиком
//! @param cmd Указатель на структуру с кодом и обработчиком
//! @return ERR_OK при успехе, ERR_INVALID_ARGUMENT – неверные параметры,
//! @return ERR_OK при успехе, ERR_INVALID_ARGUMENT – неверные параметры,
...
@@ -110,4 +82,9 @@ bool cli_protocol_verify_password(const u8* pass, u8 len);
...
@@ -110,4 +82,9 @@ bool cli_protocol_verify_password(const u8* pass, u8 len);
fun_res_t
cli_register_command
(
const
cli_command_t
*
cmd
);
fun_res_t
cli_register_command
(
const
cli_command_t
*
cmd
);
#endif
//! @brief Обнулить регистрацию указанной команды
\ No newline at end of file
//! @param cmd Код команды
void
cli_unregister_command
(
u8
code
);
#endif
src/cli_protocol/cli_protocol_cfg.h
View file @
c500d6a7
...
@@ -6,18 +6,26 @@
...
@@ -6,18 +6,26 @@
//************************************ Конфигурация UART ****************************************************
//************************************ Конфигурация UART ****************************************************
#define CLI_UART_CHANNEL (LMCAL_UART_CHANNEL1)
#define CLI_UART_CHANNEL (LMCAL_UART_CHANNEL1)
//************************************ Размеры буферов ******************************************************
//************************************ Размеры буферов ******************************************************
#define CLI_CMD_BUFFER_SIZE (128) // Размер буфера команды
#define CLI_CMD_BUFFER_SIZE (128) // Размер буфера команды
#define CLI_DATA_MAX_SIZE (64) // Максимальный размер данных
#define CLI_DATA_MAX_SIZE (64) // Максимальный размер данных
#define CLI_MAX_COMMANDS 255 // Максимальное количество регистрируемых команд (0x00..0xFF)
#define CLI_INT_CMD_NUM (10) // Количество встроенных команд
//************************************ Таймауты ************************************************************
//************************************ Таймауты ************************************************************
#define CLI_CONNECTION_TIMEOUT_MS (20000U) // Таймаут соединения 20 секунд
#define CLI_CONNECTION_TIMEOUT_MS (20000U) // Таймаут соединения 20 секунд
//************************************ Пароль по умолчанию **************************************************
//************************************ Пароль по умолчанию **************************************************
// Пароль по умолчанию "1357"
// Пароль по умолчанию "1357"
#define CLI_DEFAULT_PASSWORD_BYTES {0x31, 0x33, 0x35, 0x37}
#define CLI_DEFAULT_PASSWORD_BYTES {0x31, 0x33, 0x35, 0x37}
#define CLI_DEFAULT_PASSWORD_LEN 4
#define CLI_DEFAULT_PASSWORD_LEN 4
#define CLI_MAX_COMMANDS 256 // Максимальное количество регистрируемых команд (0x00..0xFF)
#define CLI_PASSWORD_MAX_LEN 15 // Максимальная длина пароля в байтах
#define CLI_PASSWORD_MAX_LEN 15 // Максимальная длина пароля в байтах
#endif
#endif
\ No newline at end of file
src/main.c
View file @
c500d6a7
...
@@ -26,7 +26,6 @@ void main(void)
...
@@ -26,7 +26,6 @@ void main(void)
// Инициализация LTA протокола
// Инициализация LTA протокола
cli_protocol_init
();
cli_protocol_init
();
cli_protocol_set_device_info
(
"LTA27 MCU"
,
"LTA27V2-001"
,
"1.0.0"
,
0x01
);
while
(
1
)
while
(
1
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment