Display_Avr_3/hdlc/hdlc.c
2023-05-24 18:09:43 +03:00

257 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "hdlc.h"
#define HDLC_CONTROL_S_OR_U_FRAME_BIT 0
#define HDLC_CONTROL_SEND_SEQ_NO_BIT 1
#define HDLC_CONTROL_S_FRAME_TYPE_BIT 2
#define HDLC_CONTROL_POLL_BIT 4
#define HDLC_CONTROL_RECV_SEQ_NO_BIT 5
// HDLC Control type definitions
#define HDLC_CONTROL_TYPE_RECEIVE_READY 0
#define HDLC_CONTROL_TYPE_RECEIVE_NOT_READY 1
#define HDLC_CONTROL_TYPE_REJECT 2
#define HDLC_CONTROL_TYPE_SELECTIVE_REJECT 3
static hdlc_state_t hdlc_state = {
.control_escape = 0,
.fcs = FCS_INIT_VALUE,
.start_index = -1,
.end_index = -1,
.src_index = 0,
.dest_index = 0,
};
int hdlc_set_state(hdlc_state_t *state) {
if (!state) {
return -EINVAL;
}
hdlc_state = *state;
return 0;
}
int hdlc_get_state(hdlc_state_t *state) {
if (!state) {
return -EINVAL;
}
*state = hdlc_state;
return 0;
}
void hdlc_escape_value(char value, char *dest, int *dest_index) {
// Проверяет и экранируйте значение, если это необходимо
if ((value == HDLC_FLAG_SEQUENCE) || (value == HDLC_CONTROL_ESCAPE)) {
dest[(*dest_index)++] = HDLC_CONTROL_ESCAPE;
value ^= 0x20;
}
// Добавляет значение в буфер назначения и увеличьте индекс назначения
dest[(*dest_index)++] = value;
}
hdlc_control_t hdlc_get_control_type(unsigned char control) {
hdlc_control_t value;
// Проверяет, является ли S-фреймом (или U-фреймом)
if (control & (1 << HDLC_CONTROL_S_OR_U_FRAME_BIT)) {
// Проверяет, есть ли S-фрейм тип в Receive Ready (ACK)
if (((control >> HDLC_CONTROL_S_FRAME_TYPE_BIT) & 0x3)
== HDLC_CONTROL_TYPE_RECEIVE_READY) {
value.frame = HDLC_FRAME_ACK;
} else {
// Предположим, что это отрицательное подтверждение (NACK), так как функции "Receive Not Ready", "Selective Reject" и U-фреймы не поддерживаются.
value.frame = HDLC_FRAME_NACK;
}
// Добавляет номер последовательности приема из S-фрейма (или U-фрейма).
value.seq_no = (control >> HDLC_CONTROL_RECV_SEQ_NO_BIT);
} else {
// Должен быть I-фрейм, поэтому добавляет номер последовательности отправки (номер последовательности приема не используется).
value.frame = HDLC_FRAME_DATA;
value.seq_no = (control >> HDLC_CONTROL_SEND_SEQ_NO_BIT);
}
return value;
}
unsigned char hdlc_frame_control_type(hdlc_control_t *control) {
unsigned char value = 0;
switch (control->frame) {
case HDLC_FRAME_DATA:
// Создает байт управления HDLC I-фрейма с установленным битом опроса.
value |= (control->seq_no << HDLC_CONTROL_SEND_SEQ_NO_BIT);
value |= (1 << HDLC_CONTROL_POLL_BIT);
break;
case HDLC_FRAME_ACK:
// Создает байт управления HDLC S-фрейма "Receive Ready" с сброшенным битом опроса.
value |= (control->seq_no << HDLC_CONTROL_RECV_SEQ_NO_BIT);
value |= (1 << HDLC_CONTROL_S_OR_U_FRAME_BIT);
break;
case HDLC_FRAME_NACK:
// Создает байт управления HDLC S-фрейма "Receive Ready" с сброшенным битом опроса.
value |= (control->seq_no << HDLC_CONTROL_RECV_SEQ_NO_BIT);
value |= (HDLC_CONTROL_TYPE_REJECT << HDLC_CONTROL_S_FRAME_TYPE_BIT);
value |= (1 << HDLC_CONTROL_S_OR_U_FRAME_BIT);
break;
}
return value;
}
void hdlc_get_data_reset() {
hdlc_get_data_reset_with_state(&hdlc_state);
}
void hdlc_get_data_reset_with_state(hdlc_state_t *state) {
state->fcs = FCS_INIT_VALUE;
state->start_index = state->end_index = -1;
state->src_index = state->dest_index = 0;
state->control_escape = 0;
}
int hdlc_get_data(hdlc_control_t *control, const char *src,
unsigned int src_len, char *dest, unsigned int *dest_len) {
return hdlc_get_data_with_state(&hdlc_state, control, src, src_len, dest, dest_len);
}
int hdlc_get_data_with_state(hdlc_state_t *state, hdlc_control_t *control, const char *src,
unsigned int src_len, char *dest, unsigned int *dest_len) {
int ret;
char value;
unsigned int i;
// Проверка, что все параметры валидны
if (!state || !control || !src || !dest || !dest_len) {
return -EINVAL;
}
// Проход по байтам данных
for (i = 0; i < src_len; i++) {
// В первую очередь находит последовательность начальных флагов
if (state->start_index < 0) {
if (src[i] == HDLC_FLAG_SEQUENCE) {
// Проверяет, присутствует ли дополнительный байт последовательности флагов
if ((i < (src_len - 1)) && (src[i + 1] == HDLC_FLAG_SEQUENCE)) {
// Согласно протоколу HDLC, просто выполните цикл снова, чтобы молча отбросить его.
continue;
}
state->start_index = state->src_index;
}
} else {
// Проверка последовательность флага окончания
if (src[i] == HDLC_FLAG_SEQUENCE) {
// Проверка, присутствует ли дополнительный байт последовательности флага или был ли он получен ранее.
if (((i < (src_len - 1)) && (src[i + 1] == HDLC_FLAG_SEQUENCE))
|| ((state->start_index + 1) == state->src_index)) {
// Согласно протоколу HDLC, просто выполните цикл снова, чтобы молча отбросить его.
continue;
}
state->end_index = state->src_index;
break;
} else if (src[i] == HDLC_CONTROL_ESCAPE) {
state->control_escape = 1;
} else {
// Обновите значение на основе полученного символа управления экранирования (control escape)
if (state->control_escape) {
state->control_escape = 0;
value = src[i] ^ 0x20;
} else {
value = src[i];
}
// Теперь обновите значение FCS (контрольной суммы фрейма).
state->fcs = calc_fcs(state->fcs, value);
if (state->src_index == state->start_index + 2) {
// Поле управления (control field) находится вторым байтом после последовательности стартового флага.
*control = hdlc_get_control_type(value);
} else if (state->src_index > (state->start_index + 2)) {
// Начинает добавлять значения данных после поля управления (control field) в буфер.
dest[state->dest_index++] = value;
}
}
}
state->src_index++;
}
// Проверьте наличие неверного фрейма (отсутствие последовательности стартового или окончательного флага).
if ((state->start_index < 0) || (state->end_index < 0)) {
// Return no message and make sure destination length is 0
*dest_len = 0;
ret = -ENOMSG;
} else {
// Фрейм имеет размер не менее 4 байтов и содержит допустимое значение FCS (контрольной суммы).
if ((state->end_index < (state->start_index + 4))
|| (state->fcs != FCS_GOOD_VALUE)) {
// Возвращает ошибку FCS (контрольной суммы) и указывает, что данные до последовательности флага окончания в буфере должны быть отброшены.
*dest_len = i;
ret = -EIO;
} else {
// Возвращает успешный результат и указывает, что данные до последовательности флага окончания в буфере должны быть отброшены.
*dest_len = state->dest_index - sizeof(state->fcs);
ret = i;
}
// Сбрасывает значения для следующего фрейма
hdlc_get_data_reset_with_state(state);
}
return ret;
}
int hdlc_frame_data(hdlc_control_t *control, const char *src,
unsigned int src_len, char *dest, unsigned int *dest_len) {
unsigned int i;
int dest_index = 0;
unsigned char value = 0;
FCS_SIZE fcs = FCS_INIT_VALUE;
// Проверка, что все параметры валидны
if (!control || (!src && (src_len > 0)) || !dest || !dest_len) {
return -EINVAL;
}
// Добавления последовательности стартового флага.
dest[dest_index++] = HDLC_FLAG_SEQUENCE;
// Добавление адреса "все станции" из протокола HDLC (широковещательный адрес).
fcs = calc_fcs(fcs, HDLC_ALL_STATION_ADDR);
hdlc_escape_value(HDLC_ALL_STATION_ADDR, dest, &dest_index);
// Добавление значения поля управления фрейма.
value = hdlc_frame_control_type(control);
fcs = calc_fcs(fcs, value);
hdlc_escape_value(value, dest, &dest_index);
// Только фреймы типа DATA должны содержать данные.
if (control->frame == HDLC_FRAME_DATA) {
// Вычислите контрольную сумму FCS и экранируйте данные.
for (i = 0; i < src_len; i++) {
fcs = calc_fcs(fcs, src[i]);
hdlc_escape_value(src[i], dest, &dest_index);
}
}
// Инвертирует значения FCS в соответствии со спецификацией.
fcs ^= FCS_INVERT_MASK;
// Проходит по байтам FCS и выполните экранирование значений.
for (i = 0; i < sizeof(fcs); i++) {
value = ((fcs >> (8 * i)) & 0xFF);
hdlc_escape_value(value, dest, &dest_index);
}
// Добавляет последовательность флага окончания и обновляет длину фрейма.
dest[dest_index++] = HDLC_FLAG_SEQUENCE;
*dest_len = dest_index;
return 0;
}
int hello(){
return 1;
}