diff options
Diffstat (limited to 'testing/yup-comm/comm')
| -rw-r--r-- | testing/yup-comm/comm/bt.c | 176 | ||||
| -rw-r--r-- | testing/yup-comm/comm/bt.h | 30 | ||||
| -rw-r--r-- | testing/yup-comm/comm/serial_port.c | 144 | ||||
| -rw-r--r-- | testing/yup-comm/comm/serial_port.h | 16 |
4 files changed, 366 insertions, 0 deletions
diff --git a/testing/yup-comm/comm/bt.c b/testing/yup-comm/comm/bt.c new file mode 100644 index 0000000..a0eceb9 --- /dev/null +++ b/testing/yup-comm/comm/bt.c @@ -0,0 +1,176 @@ +/* Author: Jan Sucan */ + +#include "serial_port.h" +#include "bt.h" + +#define COMM_PARAMS_COBS_DELIMITER_CHAR '$' + +typedef enum { + COBS_WAITING_FOR_THE_FIRST_DELIMITER, + COBS_WAITING_FOR_STUFFED_BYTE, + COBS_WAITING_FOR_NON_STUFFED_BYTE +} cobs_state_t; + +static HANDLE bt_serial_port; + +static bt_retcode_t bt_retcode_from_usart_retcode(int ur); + +void +bt_init(HANDLE serial_port) +{ + bt_serial_port = serial_port; +} + +bt_retcode_t +bt_receive_cobs_automaton(uint8_t b, uint8_t * const buf, size_t * const i, bool cobs_continue) +{ + static cobs_state_t cobs_state = COBS_WAITING_FOR_THE_FIRST_DELIMITER; + static uint8_t next_non_stuffed = 0; + static bool interrupted = false; + + bt_retcode_t r = BT_OK; + + if (interrupted) { + // Delimiter bol prijaty v minulom volani tejto funkcie, 'b' je uz nasledujuci bajt + interrupted = false; + // Jeden prazdny priechod nadradenym for cyklom a pokracuje sa v aktualnej funkcii + ++(*i); + } + + // Frame delimiter resetuje stavovy automat a prijem bajtov + if (b == COMM_PARAMS_COBS_DELIMITER_CHAR) { + if (!cobs_continue) { + cobs_state = COBS_WAITING_FOR_STUFFED_BYTE; + *i = 0; + } else { + interrupted = true; + r = BT_RECEIVE_COBS_INTERRUPTED; + } + } else { + switch (cobs_state) { + case COBS_WAITING_FOR_THE_FIRST_DELIMITER: + // Automat deaktivovany, ztial sa neprijal frame delimiter + break; + + case COBS_WAITING_FOR_STUFFED_BYTE: + // Prijal sa stuffovany byte, ziskame pocet nasledujuci nestuffovanych bajtov + next_non_stuffed = (b <= COMM_PARAMS_COBS_DELIMITER_CHAR) ? b : (b - 1); + // COBS header sa nezapisuje do dat, vsetky dalsie stuffovane ano + if (!cobs_continue && (*i > 1)) { + buf[*i - 2] = COMM_PARAMS_COBS_DELIMITER_CHAR; + } else { + buf[*i] = COMM_PARAMS_COBS_DELIMITER_CHAR; + } + cobs_state = (next_non_stuffed == 0) ? COBS_WAITING_FOR_STUFFED_BYTE : COBS_WAITING_FOR_NON_STUFFED_BYTE; + break; + + case COBS_WAITING_FOR_NON_STUFFED_BYTE: + // Prijal sa nestuffovany bajt, nic sa s nim nerobi + --next_non_stuffed; + // Len sa ulozi + buf[*i - ((cobs_continue) ? 0 : 2)] = b; + cobs_state = (next_non_stuffed == 0) ? COBS_WAITING_FOR_STUFFED_BYTE : COBS_WAITING_FOR_NON_STUFFED_BYTE; + break; + + default: + r = BT_RECEIVE_COBS_UNKNOWN_STATE; + break; + } + } + + return r; +} + +bt_retcode_t +bt_receive_cobs_data(uint8_t * const buf, size_t n, bool cobs_continue) +{ + bt_retcode_t r = BT_RECEIVE_BAD_ARGUMENT; + + // Kontrola argumentov + if (buf != NULL) { + size_t i; + // Na zaciatku dat sa prijma navyse COBS frame delimiter (1B) a COBS header (1B) + if (!cobs_continue) { + n += 2; + } + + for (i = 0; i < n; ++i) { + uint8_t b; + const int ur = serial_port_read_byte(bt_serial_port, &b); + + if (ur) { + // Chyba pri prijme bajtu + r = bt_retcode_from_usart_retcode(ur); + break; + } + + const bt_retcode_t ar = bt_receive_cobs_automaton(b, buf, &i, cobs_continue); + + if (ar != BT_OK) { + r = ar; + break; + } + } + + // Uspesny prijem a odsfuttovanie vsetkych bajtov + if (i >= n) { + r = BT_OK; + } + } + + return r; +} + +void +bt_send_cobs_data_block(const uint8_t *const buf, size_t n) +{ + uint8_t comm[2048U]; + unsigned ci = 0; + + // Kontrola argumentov + if (buf == NULL) { + return; + } + // POZOR: neosetrujeme velkost dat, moze dojst k preteceniu hodnot na stuffovanych bajtoch + + // Odosle sa delimiter + comm[ci++] = COMM_PARAMS_COBS_DELIMITER_CHAR; + + uint8_t next_non_stuffed = 0; + size_t send_index = 0 - 1; + + for (size_t i = 0; i <= n; ++i) { + if ((i == n) || (buf[i] == COMM_PARAMS_COBS_DELIMITER_CHAR)) { + comm[ci++] = (next_non_stuffed >= COMM_PARAMS_COBS_DELIMITER_CHAR) ? (next_non_stuffed + 1) : next_non_stuffed; + // Zacne sa odosielat az za virtualnym, alebo realnym stuffovanym bajtom + ++send_index; + // Odoslu sa napocitane bajty + while (next_non_stuffed > 0) { + comm[ci++] = buf[send_index]; + ++send_index; + --next_non_stuffed; + } + } else { + // Pocitaju sa nestuffovane bajty, zatial sa nic neposiela + ++next_non_stuffed; + } + } + + serial_port_write_byte(bt_serial_port, comm, ci); +} + +bt_retcode_t +bt_retcode_from_usart_retcode(int ur) +{ + bt_retcode_t r = BT_RECEIVE_BAD_ARGUMENT; + + if (ur == -2) { + r = BT_RECEIVE_TIMEOUT; + } else if (ur != 0) { + r = BT_RECEIVE_ERROR; + } else { + r = BT_OK; + } + + return r; +} diff --git a/testing/yup-comm/comm/bt.h b/testing/yup-comm/comm/bt.h new file mode 100644 index 0000000..a9df2d5 --- /dev/null +++ b/testing/yup-comm/comm/bt.h @@ -0,0 +1,30 @@ +/* Author: Jan Sucan */ + +#ifndef BT_H_ +#define BT_H_ + +#include <windows.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> +#include <limits.h> + +#define BT_RECEIVE_COBS_START false + +#define BT_RECEIVE_COBS_CONTINUE true + +typedef enum { + BT_RECEIVE_BAD_ARGUMENT = INT_MIN, + BT_RECEIVE_TIMEOUT, + BT_RECEIVE_ERROR, + BT_RECEIVE_COBS_INTERRUPTED, + BT_RECEIVE_COBS_UNKNOWN_STATE, + BT_OK = 0 +} bt_retcode_t; + +void bt_init(HANDLE serial_port); +void bt_close(void); +bt_retcode_t bt_receive_cobs_data(uint8_t * const buf, size_t n, bool cobs_continue); +void bt_send_cobs_data_block(const uint8_t *const buf, size_t n); + +#endif /* BT_H_ */ diff --git a/testing/yup-comm/comm/serial_port.c b/testing/yup-comm/comm/serial_port.c new file mode 100644 index 0000000..da30fab --- /dev/null +++ b/testing/yup-comm/comm/serial_port.c @@ -0,0 +1,144 @@ +/* Author: Jan Sucan */ + +#include <stdio.h> +#include <string.h> + +#include "serial_port.h" + +static HANDLE serial_port_open_port(const char * const portName); +static BOOL serial_port_set_timeouts(HANDLE serial_port, int ms); + +LPSTR +serial_port_get_error(void) +{ + DWORD e = GetLastError(); + if (e == 0) { + return NULL; + } + + LPSTR msgBuff = NULL; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + e, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &msgBuff, + 0, + NULL); + + return msgBuff; +} + +void +serial_port_free_error(LPSTR msg) +{ + LocalFree(msg); +} + +HANDLE +serial_port_open_port(const char * const portName) +{ + HANDLE sp = INVALID_HANDLE_VALUE; + + // Construct Windows serial port name + char sn[16]; + strcpy(sn, "\\\\.\\"); + strcpy(sn + strlen(sn), portName); + // Open serial port + sp = CreateFile(sn, // Port name + GENERIC_READ | GENERIC_WRITE, // Read/Write + 0, // No Sharing + NULL, // No Security + OPEN_EXISTING,// Open existing port only + 0, // Non Overlapped I/O + NULL); // Null for Comm Devices + + return sp; +} + +HANDLE +serial_port_open(const char * const portName) +{ + HANDLE serial_port = serial_port_open_port(portName); + if (serial_port == INVALID_HANDLE_VALUE) { + return INVALID_HANDLE_VALUE; + } + + // Konfiguracia + DCB dcbSerialParams = { 0 }; + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + + if (GetCommState(serial_port, &dcbSerialParams) == 0) { + serial_port_close(serial_port); + return INVALID_HANDLE_VALUE; + } + + dcbSerialParams.BaudRate = CBR_115200; + dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8 + dcbSerialParams.StopBits = ONESTOPBIT;// Setting StopBits = 1 + dcbSerialParams.Parity = NOPARITY; // Setting Parity = None + + if ((SetCommState(serial_port, &dcbSerialParams) == 0) + || (serial_port_set_timeouts(serial_port, 3000U) == 0)) { + serial_port_close(serial_port); + return INVALID_HANDLE_VALUE; + } + + return serial_port; +} + +void +serial_port_close(HANDLE serial_port) +{ + if (serial_port != INVALID_HANDLE_VALUE) { + CloseHandle(serial_port); + serial_port = INVALID_HANDLE_VALUE; + } +} + +BOOL +serial_port_set_timeouts(HANDLE serial_port, int ms) +{ + COMMTIMEOUTS timeouts; + + if (!GetCommTimeouts(serial_port, &timeouts)) { + return FALSE; + } + + timeouts.ReadIntervalTimeout = ms; + timeouts.ReadTotalTimeoutMultiplier = ms; + timeouts.ReadTotalTimeoutConstant = 0; + + timeouts.WriteTotalTimeoutMultiplier = ms; + timeouts.WriteTotalTimeoutConstant = 0; + + if (!SetCommTimeouts(serial_port, &timeouts)) { + return FALSE; + } + + return TRUE; +} + +int +serial_port_write_byte(HANDLE serial_port, uint8_t * const data, unsigned size) +{ + DWORD written = 0; + + if (!WriteFile(serial_port, data, size, &written, NULL)) { + written = 0; + } + + return (written != size) ? -1 : 0; +} + +int +serial_port_read_byte(HANDLE serial_port, uint8_t * const byte) +{ + DWORD read; + + if (!ReadFile(serial_port, byte, sizeof(uint8_t), &read, NULL)) { + return -1; + } + + return (read != 0) ? 0 : -2; +} diff --git a/testing/yup-comm/comm/serial_port.h b/testing/yup-comm/comm/serial_port.h new file mode 100644 index 0000000..db9dfe9 --- /dev/null +++ b/testing/yup-comm/comm/serial_port.h @@ -0,0 +1,16 @@ +/* Author: Jan Sucan */ + +#ifndef SERIAL_PORT_H +#define SERIAL_PORT_H 1 + +#include <windows.h> +#include <stdint.h> + +HANDLE serial_port_open(const char * const portName); +void serial_port_close(HANDLE serial_port); +int serial_port_write_byte(HANDLE serial_port, uint8_t * const data, unsigned size); +int serial_port_read_byte(HANDLE serial_port, uint8_t * const byte); +LPSTR serial_port_get_error(void); +void serial_port_free_error(LPSTR msg); + +#endif |
