257 lines
11 KiB
C
257 lines
11 KiB
C
#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;
|
||
} |