aboutsummaryrefslogtreecommitdiff
path: root/testing/yup-comm/comm
diff options
context:
space:
mode:
Diffstat (limited to 'testing/yup-comm/comm')
-rw-r--r--testing/yup-comm/comm/bt.c176
-rw-r--r--testing/yup-comm/comm/bt.h30
-rw-r--r--testing/yup-comm/comm/serial_port.c144
-rw-r--r--testing/yup-comm/comm/serial_port.h16
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