This commit is contained in:
Qukich 2023-12-25 20:11:57 +03:00
parent 671c3ba048
commit 0cd965969e
3 changed files with 541 additions and 0 deletions

261
hdlc/hdlc.c Normal file
View File

@ -0,0 +1,261 @@
#include "hdlc.h"
// HDLC Control field bit positions
#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) {
// Check and escape the value if needed
if ((value == HDLC_FLAG_SEQUENCE) || (value == HDLC_CONTROL_ESCAPE)) {
dest[(*dest_index)++] = HDLC_CONTROL_ESCAPE;
value ^= 0x20;
}
// Add the value to the destination buffer and increment destination index
dest[(*dest_index)++] = value;
}
hdlc_control_t hdlc_get_control_type(unsigned char control) {
hdlc_control_t value;
// Check if the frame is a S-frame (or U-frame)
if (control & (1 << HDLC_CONTROL_S_OR_U_FRAME_BIT)) {
// Check if S-frame type is a Receive Ready (ACK)
if (((control >> HDLC_CONTROL_S_FRAME_TYPE_BIT) & 0x3)
== HDLC_CONTROL_TYPE_RECEIVE_READY) {
value.frame = S_FRAME;
} else {
// Assume it is an NACK since Receive Not Ready, Selective Reject and U-frames are not supported
value.frame = S_FRAME_NACK;
}
// Add the receive sequence number from the S-frame (or U-frame)
value.seq_no = (control >> HDLC_CONTROL_RECV_SEQ_NO_BIT);
} else {
// It must be an I-frame so add the send sequence number (receive sequence number is not used)
value.frame = I_FRAME;
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 I_FRAME:
// Create the HDLC I-frame control byte with Poll bit set
value |= (control->seq_no << HDLC_CONTROL_SEND_SEQ_NO_BIT);
value |= (1 << HDLC_CONTROL_POLL_BIT);
break;
case S_FRAME:
// Create the HDLC Receive Ready S-frame control byte with Poll bit cleared
value |= (control->seq_no << HDLC_CONTROL_RECV_SEQ_NO_BIT);
value |= (1 << HDLC_CONTROL_S_OR_U_FRAME_BIT);
break;
case S_FRAME_NACK:
// Create the HDLC Receive Ready S-frame control byte with Poll bit cleared
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)
int hdlc_get_data(hdlc_control_t *control, uint8_t *src,
size_t src_len, uint8_t *dest, size_t *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 hdlc_get_data_with_state(hdlc_state_t *state, hdlc_control_t *control, uint8_t *src,
size_t src_len, uint8_t *dest, size_t *dest_len){
int ret;
char value;
unsigned int i;
// Make sure that all parameters are valid
if (!state || !control || !src || !dest || !dest_len) {
return -EINVAL;
}
// Run through the data bytes
for (i = 0; i < src_len; i++) {
// First find the start flag sequence
if (state->start_index < 0) {
if (src[i] == HDLC_FLAG_SEQUENCE) {
// Check if an additional flag sequence byte is present
if ((i < (src_len - 1)) && (src[i + 1] == HDLC_FLAG_SEQUENCE)) {
// Just loop again to silently discard it (accordingly to HDLC)
continue;
}
state->start_index = state->src_index;
}
} else {
// Check for end flag sequence
if (src[i] == HDLC_FLAG_SEQUENCE) {
// Check if an additional flag sequence byte is present or earlier received
if (((i < (src_len - 1)) && (src[i + 1] == HDLC_FLAG_SEQUENCE))
|| ((state->start_index + 1) == state->src_index)) {
// Just loop again to silently discard it (accordingly to HDLC)
continue;
}
state->end_index = state->src_index;
break;
} else if (src[i] == HDLC_CONTROL_ESCAPE) {
state->control_escape = 1;
} else {
// Update the value based on any control escape received
if (state->control_escape) {
state->control_escape = 0;
value = src[i] ^ 0x20;
} else {
value = src[i];
}
// Now update the FCS value
state->fcs = calc_fcs(state->fcs, value);
if (state->src_index == state->start_index + 2) {
// Control field is the second byte after the start flag sequence
*control = hdlc_get_control_type(value);
} else if (state->src_index > (state->start_index + 2)) {
// Start adding the data values after the Control field to the buffer
dest[state->dest_index++] = value;
}
}
}
state->src_index++;
}
// Check for invalid frame (no start or end flag sequence)
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 {
// A frame is at least 4 bytes in size and has a valid FCS value
if ((state->end_index < (state->start_index + 4))
|| (state->fcs != FCS_GOOD_VALUE)) {
// Return FCS error and indicate that data up to end flag sequence in buffer should be discarded
*dest_len = i;
ret = -EIO;
} else {
// Return success and indicate that data up to end flag sequence in buffer should be discarded
*dest_len = state->dest_index - sizeof(state->fcs);
ret = i;
}
// Reset values for next frame
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)
int hdlc_frame_data(hdlc_control_t *control, uint8_t *src,
size_t src_len, uint8_t *dest, size_t *dest_len){
unsigned int i;
int dest_index = 0;
unsigned char value = 0;
FCS_SIZE fcs = FCS_INIT_VALUE;
// Make sure that all parameters are valid
if (!control || (!src && (src_len > 0)) || !dest || !dest_len) {
return -EINVAL;
}
// Start by adding the start flag sequence
dest[dest_index++] = HDLC_FLAG_SEQUENCE;
// Add the all-station address from HDLC (broadcast)
fcs = calc_fcs(fcs, HDLC_ALL_STATION_ADDR);
hdlc_escape_value(HDLC_ALL_STATION_ADDR, dest, &dest_index);
// Add the framed control field value
value = hdlc_frame_control_type(control);
fcs = calc_fcs(fcs, value);
hdlc_escape_value(value, dest, &dest_index);
// Only DATA frames should contain data
if (control->frame == HDLC_FRAME_DATA) {
// Calculate FCS and escape data
for (i = 0; i < src_len; i++) {
fcs = calc_fcs(fcs, src[i]);
hdlc_escape_value(src[i], dest, &dest_index);
}
}
// Invert the FCS value accordingly to the specification
fcs ^= FCS_INVERT_MASK;
// Run through the FCS bytes and escape the values
for (i = 0; i < sizeof(fcs); i++) {
value = ((fcs >> (8 * i)) & 0xFF);
hdlc_escape_value(value, dest, &dest_index);
}
// Add end flag sequence and update length of frame
dest[dest_index++] = HDLC_FLAG_SEQUENCE;
*dest_len = dest_index;
return 0;
}

126
hdlc/hdlc.h Normal file
View File

@ -0,0 +1,126 @@
//
// Created by 79513 on 15.12.2023.
//
#ifndef HDLC_H
#define HDLC_H
#include "fcs.h"
#include <errno.h>
#include "stdint.h"
/** HDLC start/end flag sequence */
#define HDLC_FLAG_SEQUENCE 0x7E
/** HDLC control escape value */
#define HDLC_CONTROL_ESCAPE 0x7D
/** HDLC all station address */
#define HDLC_ALL_STATION_ADDR 0xFF
/** Supported HDLC frame types */
typedef enum {
I_FRAME,
S_FRAME,
S_FRAME_NACK,
} hdlc_frame_t;
/** Control field information */
typedef struct {
hdlc_frame_t frame;
unsigned char seq_no :3;
} hdlc_control_t;
/** Variables used in hdlc_get_data and hdlc_get_data_with_state
* to keep track of received buffers
*/
typedef struct {
char control_escape;
FCS_SIZE fcs;
int start_index;
int end_index;
int src_index;
int dest_index;
} hdlc_state_t;
/**
* Set the hdlc state
*
* @param[in] state The new hdlc state to be used
* @retval 0 Success
* @retval -EINVAL Invalid parameter
*/
int hdlc_set_state(hdlc_state_t *state);
/**
* Get current hdlc state
*
* @param[out] state Current hdlc state
* @retval 0 Success
* @retval -EINVAL Invalid parameter
*/
int hdlc_get_state(hdlc_state_t *state);
/**
* Retrieves data from specified buffer containing the HDLC frame. Frames can be
* parsed from multiple buffers e.g. when received via UART.
*
* @param[out] control Control field structure with frame type and sequence number
* @param[in] src Source buffer with frame
* @param[in] src_len Source buffer length
* @param[out] dest Destination buffer (should be able to contain max frame size)
* @param[out] dest_len Destination buffer length
* @retval >=0 Success (size of returned value should be discarded from source buffer)
* @retval -EINVAL Invalid parameter
* @retval -ENOMSG Invalid message
* @retval -EIO Invalid FCS (size of dest_len should be discarded from source buffer)
*
* @see hdlc_get_data_with_state
*/
int hdlc_get_data(hdlc_control_t *control, uint8_t *src,
size_t src_len, uint8_t *dest, size_t *dest_len);
/**
* Retrieves data from specified buffer containing the HDLC frame. Frames can be
* parsed from multiple buffers e.g. when received via UART.
*
* This function is a variation of @ref hdlc_get_data
* The difference is only in first argument: hdlc_state_t *state
* Data under that pointer is used to keep track of internal buffers.
*
* @see hdlc_get_data
*/
int hdlc_get_data_with_state(hdlc_state_t *state, hdlc_control_t *control, uint8_t *src,
size_t src_len, uint8_t *dest, size_t *dest_len);
/**
* Resets values used in yahdlc_get_data function to keep track of received buffers
*/
void hdlc_get_data_reset();
/**
* This is a variation of @ref hdlc_get_data_reset
* Resets state values that are under the pointer provided as argument
*
* This function need to be called before the first call to hdlc_get_data_with_state
* when custom state storage is used.
*
* @see hdlc_get_data_reset
*/
void hdlc_get_data_reset_with_state(hdlc_state_t *state);
/**
* Creates HDLC frame with specified data buffer.
*
* @param[in] control Control field structure with frame type and sequence number
* @param[in] src Source buffer with data
* @param[in] src_len Source buffer length
* @param[out] dest Destination buffer (should be bigger than source buffer)
* @param[out] dest_len Destination buffer length
* @retval 0 Success
* @retval -EINVAL Invalid parameter
*/
int hdlc_frame_data(hdlc_control_t *control, uint8_t *src,
size_t src_len, uint8_t *dest, size_t *dest_len);
#endif //HDLC_H

154
hdlc/main.c Normal file
View File

@ -0,0 +1,154 @@
//#include "hdlc.h"
#include "stdio.h"
#include "client.h"
#include <stdlib.h>
#include <inttypes.h>
int main(){
struct Client hdlc;
connect(&hdlc);
uint8_t frame_data[8];
get_frame(&hdlc, frame_data, sizeof(frame_data), 0, 0);
hdlc_get_raw_data(&hdlc, frame_data, sizeof(frame_data));
uint8_t send[64];
uint8_t buffer[134];
for (int i = 0; i < sizeof(send); i++) {
send[i] = (uint8_t) (rand() % 0x70);
}
send_data(&hdlc, send, sizeof(send_data));
//get_frame(&hdlc, buffer, sizeof(buffer), send_data, sizeof(send_data));
hdlc_get_raw_data(&hdlc, buffer, sizeof(buffer));
// test 1
// int ret;
// uint8_t frame_data[8], recv_data[8];
// size_t i, frame_length = 0, recv_length = 0;
// hdlc_control_t control_send, control_recv;
// // Run through the supported sequence numbers (3-bit)
// for (i = 0; i <= 7; i++) {
// // Initialize the control field structure with frame type and sequence number
// control_send.frame = HDLC_FRAME_ACK;
// control_send.seq_no = i;
//
// // Create an empty frame with the control field information
// ret = hdlc_frame_data(&control_send, NULL, 0, frame_data, &frame_length);
//
// // Get the data from the frame
// ret = hdlc_get_data(&control_recv, frame_data, frame_length, recv_data,
// &recv_length);
//
// // Result should be frame_length minus start flag to be discarded and no bytes received
// if(ret != (int )frame_length - 1){
// printf("err");
// }
// }
// if (recv_length != 0){
// printf("err2");
// }
//
// if (control_send.frame != control_recv.frame){
// printf("err3");
// }
//
// if (control_send.seq_no != control_recv.seq_no){
// printf("err4");
// }
// test 2
// Run through the supported sequence numbers (3-bit)
// for (i = 0; i <= 7; i++) {
// // Initialize the control field structure with frame type and sequence number
// control_send.frame = HDLC_FRAME_DATA;
// control_send.seq_no = i;
//
// char* input = "311";
// uint8_t data = (uint8_t)atoi(input);
//
// // Create an empty frame with the control field information
// ret = hdlc_frame_data(&control_send, &data, 3, frame_data, &frame_length);
// if (ret != 0){
// printf("err123\n");
// }
//
// // Get the data from the frame
// ret = hdlc_get_data(&control_recv, frame_data, frame_length, recv_data,
// &recv_length);
//
// // Result should be frame_length minus start flag to be discarded and no bytes received
// if(ret != (int )frame_length - 1){
// printf("err333\n");
// }
// if (recv_length != 0){
// printf("err2\n");
// }
//
// // Verify the control field information
// if (control_send.frame != control_recv.frame){
// printf("err3\n");
// }
//
// if (control_send.seq_no != control_recv.seq_no){
// printf("err4\n");
// }
// }
// int ret;
// hdlc_control_t control;
// uint8_t send_data[512], frame_data[530], recv_data[530];
// size_t i, frame_length = 0, recv_length = 0, buf_length = 16;
//
// // Initialize data to be send with random values (up to 0x70 to keep below the values to be escaped)
// for (i = 0; i < sizeof(send_data); i++) {
// send_data[i] = (uint8_t) (rand() % 0x70);
// }
//
// // Initialize control field structure and create frame
// control.frame = HDLC_FRAME_DATA;
// ret = hdlc_frame_data(&control, send_data, sizeof(send_data), frame_data,
// &frame_length);
//
// // Check that frame length is maximum 2 bytes larger than data due to escape of FCS value
// if(frame_length >= ((sizeof(send_data) + 6) + 2)){
// printf("1");
// }
// if(ret != 0){
// printf("2");
// }
//
// // Run though the different buffers (simulating decode of buffers from UART)
// for (i = 0; i <= sizeof(send_data); i += buf_length) {
// // Decode the data
// ret = hdlc_get_data(&control, &frame_data[i], buf_length, recv_data,
// &recv_length);
//
// printf("%zu: %s\n", i, recv_data);
//
// if (i < sizeof(send_data)) {
// // All chunks until the last should return no message and zero length
// if (ret != -ENOMSG){
// printf("3");
// }
// if (recv_length != 0){
// printf("1231");
// }
// } else {
// if (ret > 7){
// printf("332");
// }
// if (recv_length != sizeof(send_data)){
// printf("88888");
// }
// // The last chunk should return max 6 frame bytes - 1 start flag sequence byte + 2 byte for the possible
// // escaped FCS = 7 bytes
//// BOOST_CHECK(ret <= 7);
//// BOOST_CHECK_EQUAL(recv_length, sizeof(send_data));
// //printf("5");
// }
// }
}