diff options
Diffstat (limited to 'testing/yup-comm/protocol')
| -rw-r--r-- | testing/yup-comm/protocol/data.c | 312 | ||||
| -rw-r--r-- | testing/yup-comm/protocol/data.h | 16 | ||||
| -rw-r--r-- | testing/yup-comm/protocol/frame.c | 378 | ||||
| -rw-r--r-- | testing/yup-comm/protocol/frame.h | 56 | ||||
| -rw-r--r-- | testing/yup-comm/protocol/return_codes.h | 38 |
5 files changed, 800 insertions, 0 deletions
diff --git a/testing/yup-comm/protocol/data.c b/testing/yup-comm/protocol/data.c new file mode 100644 index 0000000..c93ef6d --- /dev/null +++ b/testing/yup-comm/protocol/data.c @@ -0,0 +1,312 @@ +/* Author: Jan Sucan */ + +#include "data.h" +#include "frame.h" + +#include <stdbool.h> + +#define DATA_PROTOCOL_VERSION 0x0 + +#define DATA_ACK_RETRY_COUNT 4 + + +yup_retcode_t data_is_data_frame (const frame_t * const frame); +yup_retcode_t data_is_starting_frame (const frame_t * const frame); +yup_retcode_t data_is_ack_for_frame (const frame_t * const ack, const frame_t * const frame); +void data_send_ack (uint16_t relation_id, uint16_t seq_number); +void data_send_rej_for_frame(const frame_t * const frame, uint8_t err_code); + + +yup_retcode_t +data_is_data_frame(const frame_t * const frame) +{ + yup_retcode_t yr = DATA_OK; + + if (frame_get_data_length(frame) == 0) { + yr = DATA_DATA_HAS_NO_PAYLOAD; + } else if (frame_is_flag_ack_set(frame)) { + yr = DATA_DATA_HAS_REJ_FLAG; + } else if (frame_is_flag_rej_set(frame)) { + yr = DATA_DATA_HAS_REJ_FLAG; + } + + return yr; +} + +yup_retcode_t +data_is_starting_frame(const frame_t * const frame) +{ + yup_retcode_t yr = DATA_OK; + + if ((yr = data_is_data_frame(frame)) != DATA_OK) { + ; + } else if (frame_get_seq_number(frame) != 0) { + yr = DATA_STARTING_HAS_NONZERO_SEQ_NUMBER; + } + + return yr; +} + +yup_retcode_t +data_is_ack_for_frame(const frame_t * const ack, const frame_t * const frame) +{ + yup_retcode_t yr = DATA_OK; + + if (frame_get_data_length(ack) != 0) { + yr = DATA_ACK_HAS_PAYLOAD; + } else if (!frame_is_flag_ack_set(ack)) { + yr = DATA_ACK_HAS_NOT_ACK_FLAG; + } else if (frame_is_flag_lor_set(ack)) { + yr = DATA_ACK_HAS_LOR_FLAG; + } else if (frame_is_flag_rej_set(ack)) { + yr = DATA_ACK_HAS_REJ_FLAG; + } else if (frame_get_relation_id(ack) != frame_get_relation_id(frame)) { + yr = DATA_ACK_RELATION_ID_MISMATCH; + } else if (frame_get_seq_number(ack) != frame_get_seq_number(frame)) { + yr = DATA_ACK_SEQ_NUMBER_MISMATCH; + } + + return yr; +} + +void +data_send_ack(uint16_t relation_id, uint16_t seq_number) +{ + frame_t ack; + + frame_init(&ack, DATA_PROTOCOL_VERSION); + frame_set_flag_ack(&ack); + frame_set_relation_id(&ack, relation_id); + frame_set_seq_number(&ack, seq_number); + + frame_send(&ack); +} + +void +data_send_rej_for_frame(const frame_t * const frame, uint8_t err_code) +{ + frame_t rej; + + frame_init(&rej, frame_get_protocol_version(frame)); + frame_set_flag_rej(&rej); + frame_set_relation_id(&rej, frame_get_relation_id(frame)); + frame_set_seq_number(&rej, frame_get_seq_number(frame)); + frame_set_data(&rej, &err_code, sizeof(err_code)); + + frame_send(&rej); +} + + +typedef enum data_receive_automaton_states { + DATA_R_WAITING_FOR_STARTING_FRAME, + DATA_R_START_RELATION, + DATA_R_SAVE, + DATA_R_ACK_LAST_FRAME, + DATA_R_WAITING_NEXT_DATA_FRAME, + DATA_R_END +} data_receive_automaton_state_t; + +typedef enum data_send_automaton_states { + DATA_S_START_RELATION, + DATA_S_PEPARE_DATA_FRAME, + DATA_S_SEND_DATA_FRAME, + DATA_S_WAIT_ACK, + DATA_S_END +} data_send_automaton_state_t; + +yup_retcode_t +data_receive(uint8_t * const buf, size_t bufsize, size_t * const bytes_read) +{ + uint16_t relation_id = 0; + uint16_t sequence_num = 0; + size_t data_index = 0; + data_receive_automaton_state_t state = DATA_R_WAITING_FOR_STARTING_FRAME; + + // Kontrola argumentov + if ((buf == NULL) || (bufsize == 0)) { + return DATA_ERROR; + } + + frame_t f; + + while (state != DATA_R_END) { + + yup_retcode_t r; + uint8_t l; + + switch (state) { + case DATA_R_WAITING_FOR_STARTING_FRAME: + // Na prijem startovacieho ramca sa bude cakat donekonecna + r = frame_receive(&f, DATA_PROTOCOL_VERSION); + if (r != FRAME_OK) { + // Chyba pri prijme ramca, posle sa naspat REJ so spravou o chybe + data_send_rej_for_frame(&f, r); + } else if ((r = data_is_starting_frame(&f)) == DATA_OK) { + // Mame platny startovaci ramec, zahajime relaciu + state = DATA_R_START_RELATION; + } + break; + + case DATA_R_START_RELATION: + // Od startovacieho ramca zacne plynut cas pre timeout relacie + relation_id = frame_get_relation_id(&f); + sequence_num = frame_get_seq_number(&f); + data_index = 0; + state = DATA_R_SAVE; + break; + + case DATA_R_SAVE: + if ((bufsize - data_index) < frame_get_data_length(&f)) { + // Data sa nezmestia do bufferu + // Pocka sa na dalsi paket, co sa bude hodit + state = DATA_R_WAITING_NEXT_DATA_FRAME; + } else { + // Data sa ulozia + frame_get_data(&f, buf + data_index, &l); + // Ulozia sa informacie o naposledy prijatom ramci + sequence_num = frame_get_seq_number(&f); + data_index += frame_get_data_length(&f); + // Ramec sa potvrdi + state = DATA_R_ACK_LAST_FRAME; + } + break; + + case DATA_R_ACK_LAST_FRAME: + // Potvrdime naposledy prijaty ramec + data_send_ack(relation_id, sequence_num); + // Na posledny ramec relacie sa uz neocakava odpoved + // Je bezpecne pristupovat k ramcu f, ak ma nastaveny LOR nemoze byt prepisany dalsim ramcom + if (frame_is_flag_lor_set(&f)) { + state = DATA_R_END; + } else { + // Pockame na prijem dalsieho datoveho ramca + state = DATA_R_WAITING_NEXT_DATA_FRAME; + } + break; + + case DATA_R_WAITING_NEXT_DATA_FRAME: + r = frame_receive(&f, DATA_PROTOCOL_VERSION); + if (r == FRAME_TIMEOUT) { + // Pri timeoute prijmu prijmu sa nebude opakovane posielat ACK + // Timeout relacie vyprsal + state = DATA_R_END; + } else if (r != FRAME_OK) { + // Chyba pri prijme datoveho ramca + data_send_rej_for_frame(&f, r); + } else if ((r = data_is_data_frame(&f)) != DATA_OK) { + // Datovy ramec prijaty v poriadku, ale s nespavnym obsahom + data_send_rej_for_frame(&f, r); + } else if ((frame_get_seq_number(&f) == 0) && (frame_get_relation_id(&f) != relation_id)) { + // Jedna sa o zaciatok novej relacie + state = DATA_R_START_RELATION; + } else if (frame_get_relation_id(&f) != relation_id) { + // Obycajny datovy ramec, ale v odlisnej relacii + data_send_rej_for_frame(&f, (uint8_t) DATA_DATA_RELATION_ID_MISMATCH); + } else if (frame_get_seq_number(&f) != (sequence_num + 1)) { + // Obycajny datovy ramec v spravnej relacii, ale nenavazujuci do sekvencie + data_send_rej_for_frame(&f, (uint8_t) DATA_DATA_SEQ_NUMBER_MISMATCH); + } else { + // Spravny navazujuci datovy ramac, ulozia sa jeho data + state = DATA_R_SAVE; + } + break; + + case DATA_R_END: + // Sem sa nedostaneme, len sa umlci prekladac, ze stav nie je osetreny vo switch + break; + } + + } + + // Pocet skutocne prijatych bajtov + *bytes_read = data_index; + + return DATA_OK; +} + +yup_retcode_t +data_send(const uint8_t * const buf, size_t bufsize) +{ + static uint16_t relation_id = 0; + + uint16_t sequence_num = 0; + size_t data_index = 0; + size_t ack_retry_count = DATA_ACK_RETRY_COUNT; + + data_send_automaton_state_t state = DATA_S_START_RELATION; + + // Kontrola argumentov + if ((buf == NULL) || (bufsize == 0)) { + return DATA_ERROR; + } + + frame_t f, a; + + while (state != DATA_S_END) { + + yup_retcode_t r; + + switch (state) { + case DATA_S_START_RELATION: + ++relation_id; + sequence_num = 0; + data_index = 0; + ack_retry_count = DATA_ACK_RETRY_COUNT; + state = DATA_S_PEPARE_DATA_FRAME; + break; + + case DATA_S_PEPARE_DATA_FRAME: + // Pripravi sa ramec s datami + frame_init(&f, DATA_PROTOCOL_VERSION); + frame_set_relation_id(&f, relation_id); + frame_set_seq_number(&f, sequence_num); + size_t len = ((bufsize - data_index) >= FRAME_MAX_DATA_BYTES) ? FRAME_MAX_DATA_BYTES : (bufsize - data_index); + frame_set_data(&f, buf + data_index, len); + data_index += len; + // Je to posledny ramec? + if (data_index >= bufsize) { + frame_set_flag_lor(&f); + } + state = DATA_S_SEND_DATA_FRAME; + break; + + case DATA_S_SEND_DATA_FRAME: + // Odosle sa pripraveny ramec + frame_send(&f); + state = DATA_S_WAIT_ACK; + break; + + case DATA_S_WAIT_ACK: + r = frame_receive(&a, DATA_PROTOCOL_VERSION); + if (r == FRAME_TIMEOUT) { + // Neprijal sa ACK, znovu sa odoslu pipravene data + if (ack_retry_count-- > 0) { + state = DATA_S_SEND_DATA_FRAME; + } else { + // Bol dosiahnuty maximalny pocet pokusov o znozvu odoslanie dat + return DATA_ERROR; + } + } else if (r != FRAME_OK) { + // Chyba pri prijme ACK ramca + data_send_rej_for_frame(&a, r); + } else if ((r = data_is_ack_for_frame(&a, &f)) != DATA_OK) { + // ACK ramec prijaty v poriadku, ale s nespravnym obshom + data_send_rej_for_frame(&a, r); + } else if (frame_is_flag_lor_set(&f)) { + // Datovy ramec, ktory som odoslal, bol posledny + state = DATA_S_END; + } else { + // Naposledy vyslany datovy ramec bol potvrdeny protistranou, odosle sa dalsi + sequence_num++; + state = DATA_S_PEPARE_DATA_FRAME; + } + break; + + case DATA_S_END: + // Sem sa nedostaneme, len sa umlci prekladac, ze stav nie je osetreny vo switch + break; + } + } + + return DATA_OK; +} diff --git a/testing/yup-comm/protocol/data.h b/testing/yup-comm/protocol/data.h new file mode 100644 index 0000000..a0b29db --- /dev/null +++ b/testing/yup-comm/protocol/data.h @@ -0,0 +1,16 @@ +/* Author: Jan Sucan */ + +#ifndef DATA_H_ +#define DATA_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <limits.h> + +#include "return_codes.h" + +yup_retcode_t data_receive(uint8_t * const buf, size_t bufsize, size_t * const bytes_read); +yup_retcode_t data_send (const uint8_t * const buf, size_t bufsize); + +#endif /* DATA_H_ */ + diff --git a/testing/yup-comm/protocol/frame.c b/testing/yup-comm/protocol/frame.c new file mode 100644 index 0000000..42c697a --- /dev/null +++ b/testing/yup-comm/protocol/frame.c @@ -0,0 +1,378 @@ +/* Author: Jan Sucan */ + +#include "frame.h" +#include "../comm/bt.h" +#include "../utils/byte_buffer.h" +#include "../utils/crc32q.h" + +#include <string.h> + +// Bitove masky priznakov ramca +#define FRAME_FLAG_ACK 0x1 // Prijatie paketu +#define FRAME_FLAG_REJ 0x2 // Odmietnutie paketou +#define FRAME_FLAG_LOR 0x8 // Oznacenie posledneho paketu relacie + +// Offsety hodnot v surovych datach ramca +#define FRAME_OFFSET_PROTOCOL_VERSION 0x00 +#define FRAME_OFFSET_FLAGS 0x00 +#define FRAME_OFFSET_DATA_LENGTH 0x00 +#define FRAME_OFFSET_RELATION_ID 0x02 +#define FRAME_OFFSET_SEQ_NUMBER 0x04 +#define FRAME_OFFSET_HEADER_CHECKSUM 0x06 +#define FRAME_OFFSET_DATA 0x0A + +// Bitove masky pre 16-bitovu hodnotu obsahujucu verziu protokolu YUP, priznaky ramca a dlzku pripojenych dat +#define FRAME_MASK_PROTOCOL_VERSION 0xF000 +#define FRAME_MASK_FLAGS 0x0F00 +#define FRAME_MASK_DATA_LENGTH 0x00FF + +// Bitove offsety v 16-bitovej hodnote, v ktorej je obsiahnuta verzia YUP a priznaky +#define FRAME_BITOFF_PROTOCOL_VERSION 12 +#define FRAME_BITOFF_FLAGS 8 + +// Velkost hlavicky v bajtoch +#define FRAME_HEADER_BYTES FRAME_OFFSET_DATA + +// Velkost pola kontrolneho suctu +#define FRAME_CHECKSUM_BYTES 4 + +// Interne pouzivany navratovy kod +#define FRAME_PVT_ERR_DATA_INTERRUPTED 1 + + +static yup_retcode_t frame_receive_header (frame_t * const frame); +static yup_retcode_t frame_verify_header_checksum (const frame_t * const frame); +static yup_retcode_t frame_receive_data (frame_t * const frame); +static yup_retcode_t frame_verify_data_checksum (const frame_t * const frame); +static uint8_t frame_get_flags (const frame_t * const frame); +static void frame_set_flags (frame_t * const frame, uint8_t f); +static yup_retcode_t yup_retcode_from_bt_retcode (bt_retcode_t btr); + +void +frame_init(frame_t * const frame, uint8_t protocol_version) +{ + frame_set_protocol_version(frame, protocol_version); + frame_set_flags(frame, 0); + frame_set_data(frame, NULL, 0); + frame_set_relation_id(frame, 0); + frame_set_seq_number(frame, 0); +} + +void +frame_send(frame_t * const frame) +{ + // Vyplni sa kontrolny sucet hlavicky + frame_set_header_checksum(frame); + + // Vyplni sa kontrolny sucet dat, ak nejake su + frame_set_data_checksum(frame); + + // Odosle sa ramec + bt_send_cobs_data_block(frame->raw, frame_get_length(frame)); +} + +yup_retcode_t +frame_receive(frame_t * const frame, uint8_t protocol_version) +{ + yup_retcode_t retcode = FRAME_OK; + + while (1) { + // Hlavicka sa prijme a skontroluje + if ((retcode = frame_receive_header(frame))) { + break; + } + if ((retcode = frame_verify_header_checksum(frame))) { + break; + } + // Hlavicka ramca je OK, odteraz sa moze getterom pristupovat k informacii o verzii protokolu a dlzke dat + // Skontroluje sa pozadovana verzia protokolu + if (frame_get_protocol_version(frame) != protocol_version) { + retcode = FRAME_PROTOCOL_VERSION_MISMATCH; + break; + } + // Prijmu sa data + yup_retcode_t r = frame_receive_data(frame); + + if (r == FRAME_OK) { + break; + } else if (r == FRAME_PVT_ERR_DATA_INTERRUPTED) { + // Prijal sa delimiter, novy ramec zacal skor nez skoncil aktualny, zacne sa s prijmom noveho ramca + continue; + } else { + retcode = r; + break; + } + } + + if (retcode == FRAME_OK) { + retcode = frame_verify_data_checksum(frame); + } + + return retcode; +} + +yup_retcode_t +frame_receive_header(frame_t * const frame) +{ + return yup_retcode_from_bt_retcode(bt_receive_cobs_data(frame->raw, FRAME_HEADER_BYTES, BT_RECEIVE_COBS_START)); +} + +yup_retcode_t +frame_verify_header_checksum (const frame_t * const frame) +{ + yup_retcode_t retcode = FRAME_OK; + + // Vypocet kontrolneho suctu prijatych dat + // Preskoci sa COBS delimiter (1B) a COBS header (1B) + // Do vypoctu nebudu zahrnute 4 bajty kontrolneho suctu + const uint32_t sum = crc32q(frame->raw, FRAME_HEADER_BYTES - FRAME_CHECKSUM_BYTES); + + // Vypocitany kontrolny sucet sa porovna so suctom v ramci + if (sum != frame_get_header_checksum(frame)) { + retcode = FRAME_BAD_HEADER_CHECKSUM; + } + + return retcode; +} + +yup_retcode_t +frame_receive_data (frame_t * const frame) +{ + const uint8_t data_length = frame_get_data_length(frame); + yup_retcode_t retcode = FRAME_OK; + + // Pri nulovych data sa nic neprijme + if (data_length > 0) { + // Treba prijat naviac 4B kontrolneho suctu + retcode = yup_retcode_from_bt_retcode(bt_receive_cobs_data(frame->raw + FRAME_HEADER_BYTES, + data_length + FRAME_CHECKSUM_BYTES, + BT_RECEIVE_COBS_CONTINUE)); + } + + return retcode; +} + +yup_retcode_t +frame_verify_data_checksum (const frame_t * const frame) +{ + yup_retcode_t retcode = FRAME_OK; + const uint8_t data_length = frame_get_data_length(frame); + + // Ked sme sa dostali az sem, kontrolny sucet hlavicky je OK + // Ak nemame ziadne data, nic sa uz nemusi kontrolovat + if (data_length > 0) { + // Kontrola suctu dat + // Do vypoctu nebudu zahrnute 4 bajty kontrolneho suctu + const uint32_t sum = crc32q(frame->raw + FRAME_HEADER_BYTES, data_length); + + // Vypocitany kontrolny sucet sa porovna so suctom v ramci + if (sum != frame_get_data_checksum(frame)) { + retcode = FRAME_BAD_DATA_CHECKSUM; + } + } + + return retcode; +} + +yup_retcode_t +yup_retcode_from_bt_retcode(bt_retcode_t btr) +{ + yup_retcode_t r = FRAME_RECEIVE_ERROR; + + switch (btr) { + case BT_RECEIVE_TIMEOUT: + r = FRAME_TIMEOUT; + break; + + case BT_RECEIVE_COBS_INTERRUPTED: + r = FRAME_PVT_ERR_DATA_INTERRUPTED; + break; + + case BT_RECEIVE_BAD_ARGUMENT: + case BT_RECEIVE_ERROR: + case BT_RECEIVE_COBS_UNKNOWN_STATE: + r = FRAME_RECEIVE_ERROR; + break; + + case BT_OK: + r = FRAME_OK; + break; + } + + return r; +} + + +// Getter/Setter funkcie +uint8_t +frame_get_protocol_version(const frame_t * const frame) +{ + const uint16_t x = GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_PROTOCOL_VERSION); + return (x & FRAME_MASK_PROTOCOL_VERSION) >> FRAME_BITOFF_PROTOCOL_VERSION; +} + +void +frame_set_protocol_version(frame_t * const frame, uint8_t v) +{ + uint16_t x = GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_PROTOCOL_VERSION); + x &= ~FRAME_MASK_PROTOCOL_VERSION; + x |= (v & 0x0F) << FRAME_BITOFF_PROTOCOL_VERSION; + SET_BYTES_FROM_UINT16_T(frame->raw, FRAME_OFFSET_PROTOCOL_VERSION, x); +} + +void +frame_set_flag_ack(frame_t * const frame) +{ + frame_set_flags(frame, frame_get_flags(frame) | FRAME_FLAG_ACK); +} + +bool +frame_is_flag_ack_set(const frame_t * const frame) +{ + return frame_get_flags(frame) & FRAME_FLAG_ACK; +} + +void +frame_set_flag_rej(frame_t * const frame) +{ + frame_set_flags(frame, frame_get_flags(frame) | FRAME_FLAG_REJ); +} + +bool +frame_is_flag_rej_set(const frame_t * const frame) +{ + return frame_get_flags(frame) & FRAME_FLAG_REJ; +} + +void +frame_set_flag_lor(frame_t * const frame) +{ + frame_set_flags(frame, frame_get_flags(frame) | FRAME_FLAG_LOR); +} + +bool +frame_is_flag_lor_set(const frame_t * const frame) +{ + return frame_get_flags(frame) & FRAME_FLAG_LOR; +} + +uint8_t +frame_get_flags(const frame_t * const frame) +{ + const uint16_t x = GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_FLAGS); + return (x & FRAME_MASK_FLAGS) >> FRAME_BITOFF_FLAGS; +} + +void +frame_set_flags(frame_t * const frame, uint8_t f) +{ + uint16_t x = GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_FLAGS); + x &= ~FRAME_MASK_FLAGS; + x |= (f & 0x0F) << FRAME_BITOFF_FLAGS; + SET_BYTES_FROM_UINT16_T(frame->raw, FRAME_OFFSET_FLAGS, x); +} + +uint8_t +frame_get_data_length(const frame_t * const frame) +{ + const uint16_t x = GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_DATA_LENGTH); + return (x & FRAME_MASK_DATA_LENGTH); +} + +void +frame_set_data_length(frame_t * const frame, uint8_t v) +{ + uint16_t x = GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_DATA_LENGTH); + x &= ~FRAME_MASK_DATA_LENGTH; + x |= v; + SET_BYTES_FROM_UINT16_T(frame->raw, FRAME_OFFSET_DATA_LENGTH, x); +} + +uint16_t +frame_get_relation_id(const frame_t * const frame) +{ + return GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_RELATION_ID); +} + +void +frame_set_relation_id(frame_t * const frame, uint16_t v) +{ + SET_BYTES_FROM_UINT16_T(frame->raw, FRAME_OFFSET_RELATION_ID, v); +} + +uint16_t +frame_get_seq_number(const frame_t * const frame) +{ + return GET_UINT16_T_FROM_BYTES(frame->raw, FRAME_OFFSET_SEQ_NUMBER); +} + +void +frame_set_seq_number(frame_t * const frame, uint16_t v) +{ + SET_BYTES_FROM_UINT16_T(frame->raw, FRAME_OFFSET_SEQ_NUMBER, v); +} + +uint32_t +frame_get_header_checksum(const frame_t * const frame) +{ + return GET_UINT32_T_FROM_BYTES(frame->raw, FRAME_OFFSET_HEADER_CHECKSUM); +} + +void +frame_set_header_checksum(frame_t * const frame) +{ + // Nezapocitavaju sa prve dva bajty COBSu a posledne 4 bajty pre ulozenie kontrolneho suctu + const uint32_t cs = crc32q(frame->raw, FRAME_HEADER_BYTES - FRAME_CHECKSUM_BYTES); + SET_BYTES_FROM_UINT32_T(frame->raw, FRAME_OFFSET_HEADER_CHECKSUM, cs); +} + +void +frame_get_data(const frame_t * const frame, uint8_t * const data, uint8_t * const data_length) +{ + *data_length = frame_get_data_length(frame); + memcpy(data, frame->raw + FRAME_OFFSET_DATA, *data_length); +} + +void +frame_set_data(frame_t * const frame, const uint8_t * const data, uint8_t num) +{ + uint8_t n = (num > FRAME_MAX_DATA_BYTES) ? FRAME_MAX_DATA_BYTES : num; + + frame_set_data_length(frame, n); + + if ((data != NULL) && (n > 0)) { + memcpy(frame->raw + FRAME_OFFSET_DATA, data, n); + } +} + +uint32_t +frame_get_data_checksum(const frame_t * const frame) +{ + uint8_t data_length = frame_get_data_length(frame); + uint32_t x = 0; + // Pole checksum je pripojene len vtedy, ked su pripojene nejake data + if (data_length > 0) { + x = GET_UINT32_T_FROM_BYTES(frame->raw, FRAME_OFFSET_DATA + data_length); + } + return x; +} + +void +frame_set_data_checksum(frame_t * const frame) +{ + const uint8_t dl = frame_get_data_length(frame); + if (dl == 0) { + // Zadne data, nie je k comu pocitat kontrolny sucet + return; + } + + const uint32_t cs = crc32q(frame->raw + FRAME_OFFSET_DATA, dl); + SET_BYTES_FROM_UINT32_T(frame->raw, FRAME_OFFSET_DATA + dl, cs); +} + +uint8_t +frame_get_length(const frame_t * const frame) +{ + const uint8_t dl = frame_get_data_length(frame); + return FRAME_OFFSET_DATA + dl + ((dl > 0) ? FRAME_CHECKSUM_BYTES : 0); +} diff --git a/testing/yup-comm/protocol/frame.h b/testing/yup-comm/protocol/frame.h new file mode 100644 index 0000000..d101968 --- /dev/null +++ b/testing/yup-comm/protocol/frame.h @@ -0,0 +1,56 @@ +/* Author: Jan Sucan */ + +#ifndef FRAME_H_ +#define FRAME_H_ + +#include "return_codes.h" + +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> + +#define FRAME_MAX_BYTES 254 + +#define FRAME_MAX_DATA_BYTES 240 + +typedef struct { + uint8_t raw[FRAME_MAX_BYTES]; +} frame_t; + +void frame_init (frame_t * const frame, uint8_t protocol_version); +yup_retcode_t frame_receive(frame_t * const frame, uint8_t protocol_version); +void frame_send (frame_t * const frame); + +// Protocol version +uint8_t frame_get_protocol_version(const frame_t * const frame); +void frame_set_protocol_version(frame_t * const frame, uint8_t v); +// Flags +void frame_set_flag_ack(frame_t * const frame); +bool frame_is_flag_ack_set(const frame_t * const frame); +void frame_set_flag_rej(frame_t * const frame); +bool frame_is_flag_rej_set(const frame_t * const frame); +void frame_set_flag_lor(frame_t * const frame); +bool frame_is_flag_lor_set(const frame_t * const frame); +// Data length +uint8_t frame_get_data_length(const frame_t * const frame); +void frame_set_data_length(frame_t * const frame, uint8_t v); +// Relation ID +uint16_t frame_get_relation_id(const frame_t * const frame); +void frame_set_relation_id(frame_t * const frame, uint16_t v); +// Seq number +uint16_t frame_get_seq_number(const frame_t * const frame); +void frame_set_seq_number(frame_t * const frame, uint16_t v); +// Header checksum +uint32_t frame_get_header_checksum(const frame_t * const frame); +void frame_set_header_checksum(frame_t * const frame); +// Data +void frame_get_data(const frame_t * const frame, uint8_t * const data, uint8_t * const data_length); +void frame_set_data(frame_t * const frame, const uint8_t * const data, uint8_t num); +// Data checksum +uint32_t frame_get_data_checksum(const frame_t * const frame); +void frame_set_data_checksum(frame_t * const frame); + +// Ostatne +uint8_t frame_get_length(const frame_t * const frame); + +#endif /* FRAME_H_ */ diff --git a/testing/yup-comm/protocol/return_codes.h b/testing/yup-comm/protocol/return_codes.h new file mode 100644 index 0000000..b7858a5 --- /dev/null +++ b/testing/yup-comm/protocol/return_codes.h @@ -0,0 +1,38 @@ +/* Author: Jan Sucan */ + +#ifndef RETURN_CODES_H_ +#define RETURN_CODES_H_ + +#include <limits.h> + +typedef enum { + // Privatne kody nesirene v REJ ramcoch + FRAME_OK = 0x00, + DATA_OK = 0x00, + DATA_ERROR, + FRAME_TIMEOUT, + + // Kody sirene v REJ ramcoch + DATA_STARTING_HAS_NONZERO_SEQ_NUMBER = 0x10, + DATA_RELATION_TIMEOUT, + + DATA_DATA_HAS_NO_PAYLOAD = 0x30, + DATA_DATA_HAS_ACK_FLAG, + DATA_DATA_HAS_REJ_FLAG, + DATA_DATA_RELATION_ID_MISMATCH, + DATA_DATA_SEQ_NUMBER_MISMATCH, + + DATA_ACK_HAS_PAYLOAD = 0x50, + DATA_ACK_HAS_NOT_ACK_FLAG, + DATA_ACK_HAS_LOR_FLAG, + DATA_ACK_HAS_REJ_FLAG, + DATA_ACK_RELATION_ID_MISMATCH, + DATA_ACK_SEQ_NUMBER_MISMATCH, + + FRAME_RECEIVE_ERROR = 0x70, + FRAME_BAD_HEADER_CHECKSUM, + FRAME_BAD_DATA_CHECKSUM, + FRAME_PROTOCOL_VERSION_MISMATCH +} yup_retcode_t; + +#endif /* RETURN_CODES_H_ */
\ No newline at end of file |
