armchair_fw/common/uart_common.hpp
jonny_jr9 446c246f43 Add message framing (start, end, escape bytes) to UART
Same functionality as previous commit. But way more stable and clean.
Previous proof of concept approach had issues with random partial or
too large messages due to time based method
Rework send and receive functions to work more stable
- send: encode data with frame (start, end byte)
- receive: read each byte one after the other, assemble message,
  handle actual data in handle function
- add semaphore to write operation to prevent parallel write of
  different data when called from other tasks
2023-08-30 18:17:20 +02:00

122 lines
3.5 KiB
C++

#pragma once
extern "C"
{
#include <stdio.h>
#include <esp_system.h>
#include <esp_event.h>
#include <nvs_flash.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include <string.h>
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "driver/uart.h"
}
#include "types.hpp"
//idea with time gap dropped, replaced with encoding
//#define UART_RECEIVE_DURATION 10
//receive interval may not miss messages but also may not read multiple messages
//has to be significantly smaller than WRITE_MNIN_DELAY but larger than longest message
//semaphore for assuring min delay between sent data
//extern SemaphoreHandle_t uart_semaphoreSend;
//==== parameters message frame ====
#define START_PATTERN 0xAA
#define END_PATTERN 0xBB
#define MAX_MESSAGE_LENGTH 1024
#define ESCAPE_BYTE 0xCC
//min delay after each message (no significant effect)
#define UART_WRITE_MIN_DELAY 50
#define UART_WRITE_WAIT_TIMEOUT 2000
extern bool uart_isInitialized;
//struct for testing uart
typedef struct {
uint32_t timestamp;
int id;
float value;
} uartData_test_t;
//unnecessary, using commands struct directly
typedef struct {
uint32_t timestamp;
motorCommands_t commands;
} uartData_motorCommands_t;
//function that handles receieved messages as byte array
//-> do something with received data
typedef void (*messageHandleFunc_t)(uint8_t *data, int length);
//===== uart_init =====
//should be run once at startup
void uart_init(void);
//===== uart_processReceivedByte =====
//decode received message to byte array (start, stop, escape pattern)
//has to be run for each receibed byte
//runs provided messageHandler function when complete message received
void uart_processReceivedByte(uint8_t data, messageHandleFunc_t messageHandler);
//===== uart_sendBinary =====
//encode byte array to message (start, stop, escape pattern)
//and send it via uart
void uart_sendBinary(uint8_t *data, int length);
//============================
//====== uart_sendStruct =====
//============================
//send and struct via uart
//waits when another struct was sent less than UART_WRITE_MIN_DELAY ago
template <typename T> void uart_sendStruct(T dataStruct) {
static const char * TAG = "uart-common";
//check if uart is initialized
if (!uart_isInitialized){
ESP_LOGE(TAG, "uart not initialized! droping data");
return;
}
uint8_t dataSerial[sizeof(T)];
//struct to serial bytes
memcpy(dataSerial, &dataStruct, sizeof(T));
// //wait for min delay after last write DROPPED
// if (xSemaphoreTake(uart_semaphoreSend, UART_WRITE_WAIT_TIMEOUT / portTICK_PERIOD_MS) == pdTRUE){
// //send bytes
// uart_write_bytes(UART_NUM_1, (const char *)dataSerial, sizeof(T));
// ESP_LOGW(TAG, "sent data struct with len %d", sizeof(T));
// } else ESP_LOGE(TAG, "timeout waiting for uart write semaphore! dropping data");
// //wait min delay before next write is allowed
// vTaskDelay(UART_WRITE_MIN_DELAY / portTICK_PERIOD_MS);
// xSemaphoreGive(uart_semaphoreSend);
uart_sendBinary(dataSerial, sizeof(T));
}
//==============================
//====== serialData2Struct =====
//==============================
//convert serial data (byte array) to given struct and return it
//note check whether serial data length actually matches size of struct is necessary before
template <typename T> T serialData2Struct(uint8_t *dataSerial){
static const char * TAG = "uart-common";
T dataStruct;
memcpy(&dataStruct, dataSerial, sizeof(T));
ESP_LOGI(TAG, "converted serial data len=%d to struct", sizeof(T));
return dataStruct;
}