Skip to content

Commit 9f34ad6

Browse files
committed
Обновлено описание
1 parent 0f14e57 commit 9f34ad6

4 files changed

Lines changed: 224 additions & 306 deletions

File tree

README.md

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,114 @@
1-
# object314_low_level_protocol
2-
Протокол связи нижнего уровня управления проекта "Объект 314"
1+
# CSUP
32

4-
Возможные доработки:
5-
- nibble-wise CRC
3+
**CSUP (Cross-platform Safe UART Protocol)** - лёгкий, надёжный, кроссплатформенный протокол обмена данными поверх UART, предназначенный для встраиваемых систем.
4+
5+
Протокол обеспечивает безопасную передачу данных между устройствами, защищая сообщения от потерь, искажений и коллизий с помощью подтверждений и проверки целостности.
6+
7+
## Основные функции
8+
9+
* **Проверка целостности данных** - CRC-16 (алгоритм *CCITT-FALSE*).
10+
* **Подтверждение доставки (ACK)** - гарантирует успешную передачу сообщений.
11+
* **Обнаружение и разрешение коллизий** - если оба устройства отправляют данные одновременно.
12+
* **Системное сообщение HEARTBEAT** - проверка активности соединения и синхронизация передачи.
13+
* **Фиксированный внутренний буфер** - исключает динамическое выделение памяти.
14+
* **Минимальный накладной размер** - протокол увеличивает длину сообщения на 6 байт.
15+
16+
Полное описание структуры сообщений, типов системных сообщений и кодов результата доступно в файле: [`docs/protocol.md`](./docs/protocol.md).
17+
18+
## Структура библиотеки
19+
20+
| Папка | Описание |
21+
| ---------------------- | --------------------------------------------------------------- |
22+
| `csup/hal/` | Абстракции аппаратного слоя (UART, таймеры, типы) |
23+
| `csup/hal/<platform>/` | Реализация HAL для конкретной платформы (Arduino, Linux и т.д.) |
24+
| `csup/protocol/` | Реализация протокола CSUP, включая COBS и структуру сообщений |
25+
| `csup/utils/` | Утилиты для работы с буферами и проверки целостности |
26+
| `csup/definitions.hpp` | Общие определения |
27+
| `csup/csup.hpp` | Основной заголовочный файл библиотеки |
28+
29+
## Кроссплатформенность
30+
31+
Вся логика протокола CSUP построена на интерфейсах, определяемых через **HAL (Hardware Abstraction Layer)**. Это позволяет использовать протокол на любой платформе, для которой реализована HAL-обёртка.
32+
33+
На данный момент поддерживаются **Arduino** и **Linux**.
34+
35+
Пользователь может создавать собственные обёртки для UART и таймера, а затем выбирать их при создании экземпляра протокола:
36+
37+
```cpp
38+
template <typename Uart = hal::DefaultUart,
39+
typename Time = hal::DefaultTime,
40+
typename Crc = CRC16_CCITT_FALSE,
41+
CollisionBehavior Collision = CollisionBehavior::BALANCED,
42+
types::size MaxMsgSize = 256>
43+
class Protocol;
44+
```
45+
46+
Таким образом один и тот же код протокола может работать на разных платформах без изменений, используя соответствующие реализации HAL.
47+
48+
## Установка
49+
50+
CSUP — это **заголовочная библиотека**, не требующая сборки.
51+
52+
Для установки достаточно скопировать папку `csup` в каталог с заголовочными файлами вашего проекта или в стандартный путь поиска компилятора.
53+
54+
После этого вы сможете подключать библиотеку в коде:
55+
56+
```cpp
57+
#include <csup/csup.hpp>
58+
```
59+
60+
## Примеры использования
61+
62+
В папке `examples/` содержатся готовые примеры работы протокола CSUP для различных платформ.
63+
64+
Простой пример для Linux:
65+
66+
```cpp
67+
#include "csup/csup.hpp"
68+
#include <iostream>
69+
#include <thread>
70+
71+
int main()
72+
{
73+
csup::hal::UartConfig cfg;
74+
cfg.device = "/dev/ttyUSB0";
75+
76+
csup::Result result;
77+
78+
csup::Protocol<> csup;
79+
80+
result = csup.start(cfg);
81+
if (result != csup::Result::SUCCESS)
82+
{
83+
std::cerr << "Failed to start CSUP\n";
84+
return -1;
85+
}
86+
87+
// Send a simple message with ACK
88+
uint8_t data[10] = {0,1,2,3,4,5,6,7,8,9};
89+
csup::BufferView buf(data, sizeof(data));
90+
result = csup.send(0x10, buf, true);
91+
if (result != csup::Result::SUCCESS)
92+
{
93+
std::cerr << "Send error\n";
94+
return -1;
95+
}
96+
97+
// Receive a response
98+
csup::BufferView recv;
99+
uint8_t type;
100+
result = csup.receive(type, recv);
101+
if (result != csup::Result::SUCCESS)
102+
{
103+
std::cerr << "Receive error\n";
104+
return -1;
105+
}
106+
107+
std::cout << "Received message of type " << int(type) << "\n";
108+
109+
// Check connection
110+
csup.heartbeat();
111+
112+
csup.stop();
113+
}
114+
```

csup/definitions.hpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,33 @@ namespace csup {
99

1010
enum class Result : types::u8
1111
{
12-
SUCCESS = 0x00,
13-
UART_ERROR = 0x01,
14-
COBS_ERROR = 0x02,
15-
TIMEOUT = 0x03,
16-
OVERFLOW = 0x04,
17-
EMPTY_MSG = 0x05,
18-
CRC_ERROR = 0x06,
19-
WRONG_MSG_TYPE = 0x07,
20-
WRONG_MSG_SIZE = 0x08,
21-
MSG_COLLISION = 0x09,
22-
MAX_ATTEMPT = 0x0A,
12+
// 0x0X — Success
13+
SUCCESS = 0x00, // Operation completed successfully
14+
15+
// 0x1X — Transport / Hardware errors
16+
UART_ERROR = 0x10, // UART communication failure
17+
TIMEOUT = 0x11, // Response timeout
18+
OVERFLOW = 0x12, // Buffer overflow
19+
20+
// 0x2X — Message format / integrity errors
21+
COBS_ERROR = 0x20, // COBS decoding error
22+
CRC_ERROR = 0x21, // CRC check failed
23+
EMPTY_MSG = 0x22, // Received empty message
24+
WRONG_MSG_TYPE = 0x23, // Message type mismatch
25+
WRONG_MSG_SIZE = 0x24, // Message size mismatch
26+
SYS_MSG_HANDLED = 0x25, // System message processed
27+
DUPLICATE_MSG = 0x26, // Duplicate message received
28+
29+
// 0x3X — Protocol / logical errors
30+
MSG_COLLISION = 0x30, // Message collision detected
31+
MAX_ATTEMPT = 0x31, // Maximum retransmission attempts reached
2332
};
2433

2534
enum class SystemMsgType : types::u8
2635
{
2736
ACK = 0xE0,
28-
VERSION_CHECK = 0xE1,
29-
HEARTBEAT = 0xE2,
37+
HEARTBEAT = 0xE1,
38+
VERSION_CHECK = 0xE2,
3039
};
3140

3241
/**

csup/protocol/protocol.hpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,14 @@ class Protocol
106106
// Skip HEARTBEAT frames
107107
if (frame.header.type.value == static_cast<types::u8>(SystemMsgType::HEARTBEAT))
108108
{
109-
result = Result::WRONG_MSG_TYPE;
109+
result = Result::SYS_MSG_HANDLED;
110110
continue;
111111
}
112112

113113
// Skip duplicate
114114
if (frame.header.ack.frame_id == last_received_frame_id_)
115115
{
116-
result = Result::WRONG_MSG_TYPE;
116+
result = Result::DUPLICATE_MSG;
117117
continue;
118118
}
119119

@@ -148,6 +148,9 @@ class Protocol
148148
const types::u8& retries = 3,
149149
const types::u32& timeout = 200)
150150
{
151+
if (type >= 0xE0)
152+
return Result::WRONG_MSG_TYPE;
153+
151154
tp::DataFrame frame;
152155
frame.header.type = type;
153156
frame.header.ack.ack_required = ack;
@@ -182,6 +185,17 @@ class Protocol
182185
/**
183186
* @brief Sends a heartbeat message.
184187
*
188+
* This message can be used to synchronize transmission, since all messages
189+
* sent before a successful acknowledgment are skipped until confirmed.
190+
*
191+
* @note If the remote side currently has a message transmission that requires
192+
* acknowledgment, sending a heartbeat will not break it. The pending data
193+
* will simply be retransmitted if retries remain.
194+
*
195+
* @note To receive acknowledgment for this heartbeat on the remote side, the
196+
* receiver must call `receive()`, `send()` with acknowledgment, or another
197+
* `heartbeat()`.
198+
*
185199
* @return Result::SUCCESS if successful, otherwise error code.
186200
*/
187201
Result heartbeat()
@@ -252,7 +266,7 @@ class Protocol
252266
send_ack(data_header.ack.frame_id);
253267
if (type == static_cast<types::u8>(SystemMsgType::HEARTBEAT))
254268
continue;
255-
return Result::WRONG_MSG_TYPE;
269+
return Result::SYS_MSG_HANDLED;
256270
}
257271
else if (data_header.ack.ack_required) // Collision
258272
{

0 commit comments

Comments
 (0)