Потребовалось мне в одном проекте передавать несколько потоков данных с приличной скоростью по одному каналу. Нужен был подходящий способ упаковки и распаковки данных. А для большой скорости лучше бы использовать не байты, а как минимум, слова данных. Для такой цели точкой старта подошёл протокол WAKE (ссылка на источник). Я немного доработал этот протокол, перевёл его на 16-бит и написал функции на Си для любого процессора ARM ( в данном случае был STM32). В результате получился Qwick WAKE протокол:
QWAKE
Serial Protocol
extern qwake_transmit_parameters qt;
#endif // _QWAKE_H_
QWAKE
Serial Protocol
specification
Протокол QWAKE является логическим уровнем интерфейса
управления оборудованием с помощью асинхронного последовательного канала.
Физический уровень интерфейса протоколом не определяется, может использоваться,
например, RS-232 или RS-485. В данном примере протокол QWAKE является
надстройкой UDP протокола передачи данных по WIFI. Протокол позволяет
производить обмен пакетами данных (data frames) длиной до 32767 байт с
адресуемыми устройствами, которых может быть до 127.
Последовательный канал SPI должен быть сконфигурирован
следующим образом:
• число бит в посылке – 16
• скорость обмена – 300…2000000 бод
• скорость обмена – 300…2000000 бод
Протокол QWAKE разработан для передачи по одной асинхронной
линии нескольких независимых потоков данных: управления, MIDI, PCM audio.
Протокол является расширением протокола WAKE. Основой
протокола WAKE является протокол SLIP (UNIX™ Serial Link Interface Protocol).
Передача данных осуществляется в двоичном виде, т.е. используются все возможные
значения слова (0000h…FFFFh).
Для передачи служебной информации зарезервированы два кода: FEND = E3E3h (Frame End) и FESC = D6D2h (Frame Escape). Управляющий код FEND служит для обозначения
начала посылки, а код FESC служит для передачи ESC-последовательностей. Если в
потоке данных встречаются байты, значения которых совпадают с управляющими
кодами, производится подмена этих байт ESC последовательностями. Такой механизм
называют стаффингом (stuffing). Код FEND заменяется последовательностью
<FESC>, <TFEND>, а код FESC – последовательностью <FESC>, <TFESC>, где TFEND = D6D3h (Transposed FEND), TFESC = D6D4h (Transposed FESC). Коды TFEND и TFESC
являются управляющими только в ESC последовательностях, поэтому при передаче
данных они в подмене не нуждаются.
|
Таблица 1.
Управляющие коды протокола WAKE
|
||
|
Обозначение
|
Пояснение
|
HEX-значение
|
|
FEND
|
Frame
End
|
E3E3h
|
|
FESC
|
Frame
Escape
|
D6D2h
|
|
TFEND
|
Transposed
Frame End
|
D6D3h
|
|
TFESC
|
Transposed
Frame Escape
|
D6D4h
|
|
Таблица 2.
Подмена слов данных ESC-последовательностями
|
|
|
Слово данных
|
Передаваемая
последовательность
|
|
E3E3h
|
D6D2h, D6D3h
|
|
D6D2h
|
D6D2h, D6D4h
|
Структура пакета QWAKE следующая: пакет всегда начинается
управляющим кодом FEND (E3E3h). Затем следует слово адреса. За ним
следует слово количества данных и собственно слова данных. Завершает пакет необязательное
слово контрольной суммы CRC-16 (в данном случае не используется).
|
Таблица 3.
Структура пакета QWAKE
|
||||||
|
FEND
|
ADDR
|
N
|
Data1
|
…
|
DataN
|
CRC
|
FEND: Управляющий
код FEND (E3E3h) является признаком начала пакета. Благодаря стаффингу, этот
код больше нигде в потоке данных не встречается, что позволяет в любой ситуации
однозначно определять начало пакета.
ADDR: Слово адреса
используется для адресации отдельных устройств. Слово адреса разделено на два
байта. Первый байт определяет адрес устройства. Для адресации используется 7
бит, а старший бит, передаваемый вместе с адресом, должен всегда быть сброшен:
|
|
D7
|
D6
|
D5
|
D4
|
D3
|
D2
|
D1
|
D0
|
|
ADDR =
|
0
|
A6
|
A5
|
A4
|
A3
|
A2
|
A1
|
A0
|
Адрес 0 –
широкополосный.
Иногда возникает необходимость передать какую-то команду или
данные сразу всем устройствам. Для этого предусмотрен коллективный вызов
(broadcast), который осуществляется путем передачи нулевого адреса. Учитывая
разрядность адреса и один зарезервированный адрес для коллективного вызова,
максимальное количество адресуемых устройств составляет 127.
CH: Второй байт адреса определяет
номер потока данных в устройстве (канал). В протоколе WAKE этот байт отвечал за
команду. Для того, чтобы передавать несколько потоков данных в устройстве,
применяется нумерация каналов. Неявно нумерация каналов определяет команду.
Всего каналов 256.
|
|
D7
|
D6
|
D5
|
D4
|
D3
|
D2
|
D1
|
D0
|
|
CH =
|
C7
|
C6
|
C5
|
C4
|
C3
|
C2
|
C1
|
C0
|
Каналы выбираются произвольно в зависимости от нужд приложения.
Рекомендуется использовать несколько стандартных кодов каналов:
|
Таблица 4.
Стандартные каналы протокола QWAKE
|
||
|
Код
|
Название
|
Описание канала
|
|
00h
|
С_Nop
|
Нет операции
|
|
01h
|
C_Err
|
Передача кода ошибки
|
|
02h
|
C_Echo
|
Запрос возврата переданного пакета
|
|
03h
|
C_Info
|
Запрос информации об устройстве
|
Коды остальных каналов выбираются в зависимости от нужд
приложения. Каналы обычно имеют несколько параметров, которые передаются далее
в виде пакета данных.
N: Слово количества
данных имеет значение, равное количеству передаваемых байт данных:
|
|
D15
|
D14
|
D13
|
D12
|
D11
|
D10
|
D9
|
D8
|
D7
|
D6
|
D5
|
D4
|
D3
|
D2
|
D1
|
D0
|
|
N =
|
0
|
N14
|
N13
|
N12
|
N11
|
N10
|
N9
|
N8
|
N7
|
N6
|
N5
|
N4
|
N3
|
N2
|
N1
|
N0
|
Таким образом, код количества данных занимает 16 бит, старший
бит всегда равен 0. В результате один пакет может содержать до 32767 байт данных.
Значение N не учитывает служебные байты пакета FEND, ADDR, CH, N и CRC. В
результате стаффинга фактическая длина пакета может возрасти. Значение N не
учитывает этот факт и отражает количество полезных байт данных (т.е. значение N
всегда таково, как будто стаффинг не осуществляется). Если передаваемая команда
не имеет параметров, то передается N = 00h и байты данных опускаются.
Благодаря резервированию старшего бита во время передачи
адреса и размера данных стаффинга не происходит, и данные передаются в прямом
виде.
Data1…DataN: Слова
данных, количество байт в которых определяется значением N. При N = 00h байты
данных отсутствуют. При нечётном N последнее слово передаётся с нулями в младшем
байте. Слова данных могут иметь любое значение, кроме FEND (E3E3h) и FESC (D6D2h). Если возникает необходимость
передать одно из этих значений, то производится стаффинг, т.е. передача
ESC-последовательности (см. таблицу 2), состоящей из управляющего кода FESC и кода
TFEND (TFESC).
СRC: Слово контрольной
суммы CRC-16. Может отсутствовать в некоторых реализациях протокола.
Контрольная сумма CRC-16 рассчитывается перед операцией стаффинга для всего
пакета, начиная с слова FEND и заканчивая последним байтом данных. Для расчета
контрольной суммы используется полином CRC = X16 + X7 + X4 + 1. Значение CRC
перед вычислением инициализируется числом F3DEh. При передаче значения слова контрольной суммы E3E3h и D6D2h
заменяются ESC-последовательностями (см. таблицу 2).
Программы.
Заголовочный файл qwake.h:
/*------------------------------------------------------------------------------
* файл qwake.h
* определения функций протокола QWAKE
*-----------------------------------------------------------------------------*/
#ifndef _QWAKE_H_
#define _QWAKE_H_
typedef void (*q_callback) (void);
typedef union _adch_t
{
uint16_t adch;
struct
{
uint8_t addr; // little-endian: по старшему адресу
uint8_t ch; // little-endian: по младшему адресу
};
} adch_t;
typedef struct _qwake_transmit_parameters
{
uint16_t size_out;
uint16_t *output;
} qwake_transmit_parameters;
void qwake_transmit (uint16_t *in, uint16_t n_in, uint16_t adch);
void qwake_receive (uint16_t *input, uint16_t size_in);
uint16_t **qwake_receive_set (uint16_t *buf, q_callback fn, uint16_t adch);
* файл qwake.h
* определения функций протокола QWAKE
*-----------------------------------------------------------------------------*/
#ifndef _QWAKE_H_
#define _QWAKE_H_
typedef void (*q_callback) (void);
typedef union _adch_t
{
uint16_t adch;
struct
{
uint8_t addr; // little-endian: по старшему адресу
uint8_t ch; // little-endian: по младшему адресу
};
} adch_t;
typedef struct _qwake_transmit_parameters
{
uint16_t size_out;
uint16_t *output;
} qwake_transmit_parameters;
void qwake_transmit (uint16_t *in, uint16_t n_in, uint16_t adch);
void qwake_receive (uint16_t *input, uint16_t size_in);
uint16_t **qwake_receive_set (uint16_t *buf, q_callback fn, uint16_t adch);
extern qwake_transmit_parameters qt;
#endif // _QWAKE_H_
Файл qwake.c:
/*------------------------------------------------------------------------------
* файл qwake.c
* работа с протоколом QWAKE
*-----------------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "stm32f446_it.h"
#include "global.h"
#include "qwake.h"
#define FEND (uint16_t)0xE3E3 // Frame End
#define FESC (uint16_t)0xD6D2 // Frame Escape
#define TFEND (uint16_t)0xD6D3 // Transposed Frame End
#define TFESC (uint16_t)0xD6D4 // Transposed Frame Escape
// структура с данными принимаемых потоков
typedef struct _qwake_receive_struct
{
uint8_t num_channels; // число запрограммированных каналов в приёмнике
uint16_t n_out; // размер выходного буфера
adch_t adch[MAX_QCHANNEL]; // адреса и каналы в приёмнике
uint16_t *output[MAX_QCHANNEL]; // адреса выходного буфера для каждого канала
q_callback q_func[MAX_QCHANNEL]; // функции по заполнению выходных каналов
} qwake_receive_struct;
qwake_transmit_parameters qt = {0};
static qwake_receive_struct qr = {0}; // по умолчанию потоки не запрограммированы
/*******************************************************************************
* Заполнение внутренней структуры адресов и каналов
* Вход: адрес, номер канала, адрес функции возврата
* Выход: заполняется структура при наличии места
* при успешном заполнении возвращает адрес указателя на выходной буфер канала, иначе 0
*******************************************************************************/
uint16_t **qwake_receive_set (uint16_t *buf, q_callback fn, uint16_t adch)
{
uint16_t **temp = ((uint16_t **)0); // если нет места
uint8_t num = qr.num_channels;
if (num < MAX_QCHANNEL)
{
qr.adch[num].adch = adch;
qr.output[num] = buf;
qr.q_func[num] = fn;
qr.num_channels++;
temp = &qr.output[num];
}
return temp;
}
/*******************************************************************************
* формирование выходного потока по протоколу QWAKE
* Вход: адрес буфера in с данными, размер буфера, адрес и канал передачи
* Выход: заполняется буфер qt.output
* Буфер всегда пополняется, обнулять его будет драйвер передатчика.
*******************************************************************************/
void qwake_transmit (uint16_t *in, uint16_t n_in, uint16_t adch)
{
uint16_t n_out = qt.size_out + 6; // минимальный размер пакета
uint16_t *out = qt.output;
*out++ = FEND; // заголовок
*out++ = adch; // адрес-канал
*out++ = n_in; // размер данных
while (n_in)
{
if (n_in == 1) // передача последнего байта
{
*(uint8_t *)out = *(uint8_t *)in;
out++;
n_out += 2;
n_in = 0;
}
else
{
switch (*in)
{
case FEND: // байт-стаффинг FEND
*out++ = FESC;
*out++ = TFEND;
in++;
n_out += 4;
n_in -= 2;
break;
case FESC: // байт-стаффинг FESC
*out++ = FESC;
*out++ = TFESC;
in++;
n_out += 4;
n_in -= 2;
break;
default: // обычные данные
*out++ = *in++;
n_out += 2;
n_in -= 2;
break;
}
}
}
qt.size_out = n_out; // сохранение размера и указателя
qt.output = out;
}
/*******************************************************************************
* разборка входного потока по протоколу QWAKE
* Вход: адрес буфера input с данными, размер буфера
* в структуре qr хранятся каналы приёмника и их параметры
* Выход: заполняется буфер qr.output[nch] соответствующего канала приёмника
* по приёму пакета выполняется функция qr.q_func[nch] ()
*******************************************************************************/
void qwake_receive (uint16_t *input, uint16_t size_in)
{
typedef enum _q_in_states
{
Q_IN_WAIT = 0,
Q_IN_ADCH,
Q_IN_NUM,
Q_IN_DATA,
} q_in_states;
typedef struct _q_in_parameters
{
q_in_states q_in_state; // состояние парсера
uint16_t *out; // указатель на выходной буфер
uint16_t n_out; // размер выходного буфера
uint8_t channel; // номер принимаемого канала
} q_in_parameters;
static q_in_parameters qin =
{
Q_IN_WAIT,
0,
0,
0
};
uint16_t adch; // замена статических переменных регистровыми
q_in_states qstate = qin.q_in_state;
uint16_t *nout = qin.out;
uint16_t nn_out = qin.n_out;
uint8_t nch = qin.channel;
while (size_in) // разбирать до конца входных данных
{
switch (qstate)
{
// ожидание начала пакета
case Q_IN_WAIT:
if (*input == FEND) // ожидаем стартовой посылки
{
qstate = Q_IN_ADCH;
}
input++; // продвигаемся по входной цепочке
size_in -= 2;
break;
// сравнение с нашим адресом и номером канала
case Q_IN_ADCH:
adch = *input++; // прочитать адрес пакета
size_in -= 2;
// определение канала приёма данных
nch = 0;
while ((adch != qr.adch[nch].adch) // наш канал
&& (adch != (qr.adch[nch].adch & 0xFF00)) // широкополосный канал (little-endian)
&& (nch < qr.num_channels)) // всего наших каналов
{
nch++;
}
if (nch < qr.num_channels) // если нашли совпадение
{
nout = qr.output[nch]; // записываем адрес буфера канала приёмника
qstate = Q_IN_NUM;
}
else // не наш пакет - ждём следующего
{
qstate = Q_IN_WAIT;
}
break;
// получение числа байт на входе
case Q_IN_NUM:
qr.n_out = nn_out = *input++;// записать количество параметров
size_in -= 2;
if (nn_out) // есть данные - разбираем
{
qstate = Q_IN_DATA;
}
else // нет данных - просто команда без параметров
{
qr.q_func[nch] (); // отдать буфер
qstate = Q_IN_WAIT; // разбирать входной пакет дальше
}
break;
// приём данных
case Q_IN_DATA:
if (*input != FESC)
{
if (nn_out > 1) // передача слов данных
{
*nout++ = *input++;
nn_out -= 2;
}
else // передача последнего байта
{
*(uint8_t *)nout = *(uint8_t *)input;
input++;
nn_out = 0;
}
size_in -= 2;
}
else // стаффинг
{
input++;
switch (*input)
{
case TFEND: // подмена символов при стаффинге
*nout++ = FEND;
input++;
size_in -= 2;
nn_out -= 2;
break;
case TFESC:
*nout++ = FESC;
input++;
size_in -= 2;
nn_out -= 2;
break;
default: // в случае ошибки стаффинга - сброс
qstate = Q_IN_WAIT;
break;
}
}
if (!nn_out) // по окончании посылки
{
qr.q_func[nch] (); // отдать буфер
qstate = Q_IN_WAIT; // разбирать входной пакет дальше
}
break;
default:
qstate = Q_IN_WAIT;
break;
}
}
// сохранение регистровых переменных в статических
qin.q_in_state = qstate;
qin.out = nout;
qin.n_out = nn_out;
qin.channel = nch;
}
* файл qwake.c
* работа с протоколом QWAKE
*-----------------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "stm32f446_it.h"
#include "global.h"
#include "qwake.h"
#define FEND (uint16_t)0xE3E3 // Frame End
#define FESC (uint16_t)0xD6D2 // Frame Escape
#define TFEND (uint16_t)0xD6D3 // Transposed Frame End
#define TFESC (uint16_t)0xD6D4 // Transposed Frame Escape
// структура с данными принимаемых потоков
typedef struct _qwake_receive_struct
{
uint8_t num_channels; // число запрограммированных каналов в приёмнике
uint16_t n_out; // размер выходного буфера
adch_t adch[MAX_QCHANNEL]; // адреса и каналы в приёмнике
uint16_t *output[MAX_QCHANNEL]; // адреса выходного буфера для каждого канала
q_callback q_func[MAX_QCHANNEL]; // функции по заполнению выходных каналов
} qwake_receive_struct;
qwake_transmit_parameters qt = {0};
static qwake_receive_struct qr = {0}; // по умолчанию потоки не запрограммированы
/*******************************************************************************
* Заполнение внутренней структуры адресов и каналов
* Вход: адрес, номер канала, адрес функции возврата
* Выход: заполняется структура при наличии места
* при успешном заполнении возвращает адрес указателя на выходной буфер канала, иначе 0
*******************************************************************************/
uint16_t **qwake_receive_set (uint16_t *buf, q_callback fn, uint16_t adch)
{
uint16_t **temp = ((uint16_t **)0); // если нет места
uint8_t num = qr.num_channels;
if (num < MAX_QCHANNEL)
{
qr.adch[num].adch = adch;
qr.output[num] = buf;
qr.q_func[num] = fn;
qr.num_channels++;
temp = &qr.output[num];
}
return temp;
}
/*******************************************************************************
* формирование выходного потока по протоколу QWAKE
* Вход: адрес буфера in с данными, размер буфера, адрес и канал передачи
* Выход: заполняется буфер qt.output
* Буфер всегда пополняется, обнулять его будет драйвер передатчика.
*******************************************************************************/
void qwake_transmit (uint16_t *in, uint16_t n_in, uint16_t adch)
{
uint16_t n_out = qt.size_out + 6; // минимальный размер пакета
uint16_t *out = qt.output;
*out++ = FEND; // заголовок
*out++ = adch; // адрес-канал
*out++ = n_in; // размер данных
while (n_in)
{
if (n_in == 1) // передача последнего байта
{
*(uint8_t *)out = *(uint8_t *)in;
out++;
n_out += 2;
n_in = 0;
}
else
{
switch (*in)
{
case FEND: // байт-стаффинг FEND
*out++ = FESC;
*out++ = TFEND;
in++;
n_out += 4;
n_in -= 2;
break;
case FESC: // байт-стаффинг FESC
*out++ = FESC;
*out++ = TFESC;
in++;
n_out += 4;
n_in -= 2;
break;
default: // обычные данные
*out++ = *in++;
n_out += 2;
n_in -= 2;
break;
}
}
}
qt.size_out = n_out; // сохранение размера и указателя
qt.output = out;
}
/*******************************************************************************
* разборка входного потока по протоколу QWAKE
* Вход: адрес буфера input с данными, размер буфера
* в структуре qr хранятся каналы приёмника и их параметры
* Выход: заполняется буфер qr.output[nch] соответствующего канала приёмника
* по приёму пакета выполняется функция qr.q_func[nch] ()
*******************************************************************************/
void qwake_receive (uint16_t *input, uint16_t size_in)
{
typedef enum _q_in_states
{
Q_IN_WAIT = 0,
Q_IN_ADCH,
Q_IN_NUM,
Q_IN_DATA,
} q_in_states;
typedef struct _q_in_parameters
{
q_in_states q_in_state; // состояние парсера
uint16_t *out; // указатель на выходной буфер
uint16_t n_out; // размер выходного буфера
uint8_t channel; // номер принимаемого канала
} q_in_parameters;
static q_in_parameters qin =
{
Q_IN_WAIT,
0,
0,
0
};
uint16_t adch; // замена статических переменных регистровыми
q_in_states qstate = qin.q_in_state;
uint16_t *nout = qin.out;
uint16_t nn_out = qin.n_out;
uint8_t nch = qin.channel;
while (size_in) // разбирать до конца входных данных
{
switch (qstate)
{
// ожидание начала пакета
case Q_IN_WAIT:
if (*input == FEND) // ожидаем стартовой посылки
{
qstate = Q_IN_ADCH;
}
input++; // продвигаемся по входной цепочке
size_in -= 2;
break;
// сравнение с нашим адресом и номером канала
case Q_IN_ADCH:
adch = *input++; // прочитать адрес пакета
size_in -= 2;
// определение канала приёма данных
nch = 0;
while ((adch != qr.adch[nch].adch) // наш канал
&& (adch != (qr.adch[nch].adch & 0xFF00)) // широкополосный канал (little-endian)
&& (nch < qr.num_channels)) // всего наших каналов
{
nch++;
}
if (nch < qr.num_channels) // если нашли совпадение
{
nout = qr.output[nch]; // записываем адрес буфера канала приёмника
qstate = Q_IN_NUM;
}
else // не наш пакет - ждём следующего
{
qstate = Q_IN_WAIT;
}
break;
// получение числа байт на входе
case Q_IN_NUM:
qr.n_out = nn_out = *input++;// записать количество параметров
size_in -= 2;
if (nn_out) // есть данные - разбираем
{
qstate = Q_IN_DATA;
}
else // нет данных - просто команда без параметров
{
qr.q_func[nch] (); // отдать буфер
qstate = Q_IN_WAIT; // разбирать входной пакет дальше
}
break;
// приём данных
case Q_IN_DATA:
if (*input != FESC)
{
if (nn_out > 1) // передача слов данных
{
*nout++ = *input++;
nn_out -= 2;
}
else // передача последнего байта
{
*(uint8_t *)nout = *(uint8_t *)input;
input++;
nn_out = 0;
}
size_in -= 2;
}
else // стаффинг
{
input++;
switch (*input)
{
case TFEND: // подмена символов при стаффинге
*nout++ = FEND;
input++;
size_in -= 2;
nn_out -= 2;
break;
case TFESC:
*nout++ = FESC;
input++;
size_in -= 2;
nn_out -= 2;
break;
default: // в случае ошибки стаффинга - сброс
qstate = Q_IN_WAIT;
break;
}
}
if (!nn_out) // по окончании посылки
{
qr.q_func[nch] (); // отдать буфер
qstate = Q_IN_WAIT; // разбирать входной пакет дальше
}
break;
default:
qstate = Q_IN_WAIT;
break;
}
}
// сохранение регистровых переменных в статических
qin.q_in_state = qstate;
qin.out = nout;
qin.n_out = nn_out;
qin.channel = nch;
}
Как использовать.
Тестирование я проводил в такой программе:
/*------------------------------------------------------------------------------
* файл test.c
* проверка работы системы
*-----------------------------------------------------------------------------*/
#include <string.h>
#include "stm32f4xx.h"
#include "stm32f446_it.h"
#include "test.h"
#include "global.h"
#include "qwake.h"
static uint16_t **adr_inbuf_ch6;
static uint16_t **adr_inbuf_ch3;
static uint8_t ch6_inbuf1[128];
static uint8_t ch6_inbuf2[128];
static uint8_t ch3_inbuf1[128];
static uint8_t ch3_inbuf2[128];
static uint8_t qbuffer1[128];
static uint8_t qbuffer2[128];
void test_qwake (void);
void q_ch6 (void); // ф-я по приёму сообщения
void q_ch3 (void); // ф-я по приёму сообщения
/*******************************************************************************
* Проверка работы QWAKE упаковщика и распаковщика
*
*
*******************************************************************************/
void test_qwake (void)
{
static const uint8_t test_string1[] =
{0xE3, 0xE3, 0xD2, 0xD6, 0x10, 0x11, 0x12, 0x13, 0x14};
static const uint8_t test_string2[] = "Это вторая тестовая строка для упаковки. Test2";
adch_t adr_ch;
// упаковка и распаковка по адресу
qt.output = (uint16_t *)qbuffer1; // обнуление адресов и размеров будет в драйвере передачи
qt.size_out = 0; // а пока на стороне отправителя
adr_ch.addr = 10;
adr_ch.ch = 6;
// подготовить распаковщик с каналом 6
adr_inbuf_ch6 = qwake_receive_set ((uint16_t *)ch6_inbuf1, &q_ch6, adr_ch.adch);
// передать сообщение в канал 6
qwake_transmit ((uint16_t *)test_string1, sizeof (test_string1), adr_ch.adch);
adr_ch.addr = 10;
adr_ch.ch = 3;
// подготовить распаковщик с каналом 3
adr_inbuf_ch3 = qwake_receive_set ((uint16_t *)ch3_inbuf1, &q_ch3, adr_ch.adch);
// передать сообщение в канал 3
qwake_transmit ((uint16_t *)test_string2, sizeof (test_string2), adr_ch.adch);
// проверить выходной буфер
qwake_receive ((uint16_t *)qbuffer1, qt.size_out);
// сформировать широкополосный пакет
qt.output = (uint16_t *)qbuffer2;
qt.size_out = 0;
adr_ch.addr = 0;
adr_ch.ch = 6;
qwake_transmit ((uint16_t *)test_string2, sizeof (test_string2), adr_ch.adch);
// принять широкополосный пакет
qwake_receive ((uint16_t *)qbuffer2, qt.size_out);
}
// коллбэк по приёму сообщения в потоке 6
void q_ch6 (void)
{
if (*adr_inbuf_ch6 == (uint16_t *)ch6_inbuf1)
{
*adr_inbuf_ch6 = (uint16_t *)ch6_inbuf2;
}
else
{
*adr_inbuf_ch6 = (uint16_t *)ch6_inbuf1;
}
}
// коллбэк по приёму сообщения в потоке 3
void q_ch3 (void)
{
if (*adr_inbuf_ch3 == (uint16_t *)ch3_inbuf1)
{
*adr_inbuf_ch3 = (uint16_t *)ch3_inbuf2;
}
else
{
*adr_inbuf_ch3 = (uint16_t *)ch3_inbuf1;
}
}
* файл test.c
* проверка работы системы
*-----------------------------------------------------------------------------*/
#include <string.h>
#include "stm32f4xx.h"
#include "stm32f446_it.h"
#include "test.h"
#include "global.h"
#include "qwake.h"
static uint16_t **adr_inbuf_ch6;
static uint16_t **adr_inbuf_ch3;
static uint8_t ch6_inbuf1[128];
static uint8_t ch6_inbuf2[128];
static uint8_t ch3_inbuf1[128];
static uint8_t ch3_inbuf2[128];
static uint8_t qbuffer1[128];
static uint8_t qbuffer2[128];
void test_qwake (void);
void q_ch6 (void); // ф-я по приёму сообщения
void q_ch3 (void); // ф-я по приёму сообщения
/*******************************************************************************
* Проверка работы QWAKE упаковщика и распаковщика
*
*
*******************************************************************************/
void test_qwake (void)
{
static const uint8_t test_string1[] =
{0xE3, 0xE3, 0xD2, 0xD6, 0x10, 0x11, 0x12, 0x13, 0x14};
static const uint8_t test_string2[] = "Это вторая тестовая строка для упаковки. Test2";
adch_t adr_ch;
// упаковка и распаковка по адресу
qt.output = (uint16_t *)qbuffer1; // обнуление адресов и размеров будет в драйвере передачи
qt.size_out = 0; // а пока на стороне отправителя
adr_ch.addr = 10;
adr_ch.ch = 6;
// подготовить распаковщик с каналом 6
adr_inbuf_ch6 = qwake_receive_set ((uint16_t *)ch6_inbuf1, &q_ch6, adr_ch.adch);
// передать сообщение в канал 6
qwake_transmit ((uint16_t *)test_string1, sizeof (test_string1), adr_ch.adch);
adr_ch.addr = 10;
adr_ch.ch = 3;
// подготовить распаковщик с каналом 3
adr_inbuf_ch3 = qwake_receive_set ((uint16_t *)ch3_inbuf1, &q_ch3, adr_ch.adch);
// передать сообщение в канал 3
qwake_transmit ((uint16_t *)test_string2, sizeof (test_string2), adr_ch.adch);
// проверить выходной буфер
qwake_receive ((uint16_t *)qbuffer1, qt.size_out);
// сформировать широкополосный пакет
qt.output = (uint16_t *)qbuffer2;
qt.size_out = 0;
adr_ch.addr = 0;
adr_ch.ch = 6;
qwake_transmit ((uint16_t *)test_string2, sizeof (test_string2), adr_ch.adch);
// принять широкополосный пакет
qwake_receive ((uint16_t *)qbuffer2, qt.size_out);
}
// коллбэк по приёму сообщения в потоке 6
void q_ch6 (void)
{
if (*adr_inbuf_ch6 == (uint16_t *)ch6_inbuf1)
{
*adr_inbuf_ch6 = (uint16_t *)ch6_inbuf2;
}
else
{
*adr_inbuf_ch6 = (uint16_t *)ch6_inbuf1;
}
}
// коллбэк по приёму сообщения в потоке 3
void q_ch3 (void)
{
if (*adr_inbuf_ch3 == (uint16_t *)ch3_inbuf1)
{
*adr_inbuf_ch3 = (uint16_t *)ch3_inbuf2;
}
else
{
*adr_inbuf_ch3 = (uint16_t *)ch3_inbuf1;
}
}
Комментариев нет:
Отправить комментарий