-
Notifications
You must be signed in to change notification settings - Fork 6
/
payload_uart.cpp
215 lines (183 loc) · 6.99 KB
/
payload_uart.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#include "payload_uart.h"
#include "bm_printf.h"
#include "stm32_rtc.h"
#include "uptime.h"
// FreeRTOS Includes
#include "FreeRTOS.h"
#include "semphr.h"
namespace PLUART {
#define USER_BYTE_BUFFER_LEN 2048
// Stream buffer for user bytes
static StreamBufferHandle_t user_byte_stream_buffer = NULL;
static struct {
// This mutex protects the buffer, len, and ready flag
SemaphoreHandle_t mutex;
uint8_t buffer[LPUART1_LINE_BUFF_LEN];
uint16_t len = 0;
bool ready = false;
} _user_line;
// Line termination character
static char terminationCharacter = 0;
// Flag to use lineBuffer or not. If not, user can pull bytes directly from the stream.
static bool _useLineBuffer = true;
// Flag to use xStreamBufferIsFull or not. If not, user can use LineBuffer.
static bool _useByteStreamBuffer = false;
// Process a received byte and store it in a line buffer
static void processLineBufferedRxByte(void *serialHandle, uint8_t byte) {
configASSERT(serialHandle != NULL);
SerialHandle_t *handle = reinterpret_cast<SerialHandle_t *>(serialHandle);
if (_useLineBuffer) {
// This function requires data to be a pointer to a SerialLineBuffer_t
configASSERT(handle->data != NULL);
SerialLineBuffer_t *lineBuffer =
reinterpret_cast<SerialLineBuffer_t *>(handle->data);
// We need a buffer to use!
configASSERT(lineBuffer->buffer != NULL);
lineBuffer->buffer[lineBuffer->idx] = byte;
if (lineBuffer->buffer[lineBuffer->idx] == terminationCharacter) {
// Zero terminate the line
if ((lineBuffer->idx + 1) < lineBuffer->len) {
lineBuffer->buffer[lineBuffer->idx + 1] = 0;
}
if (lineBuffer->lineCallback != NULL) {
lineBuffer->lineCallback(handle, lineBuffer->buffer, lineBuffer->idx);
}
// Reset buffer index
lineBuffer->idx = 0;
// printf("buffer reset!\n");
} else {
lineBuffer->idx++;
// Heavy handed way of dealing with overflow for now
// Later we can just purge the buffer
// TODO - log error and clear buffer instead
configASSERT((lineBuffer->idx + 1) < lineBuffer->len);
}
}
if (_useByteStreamBuffer) {
// Send the byte to the user byte stream buffer, if it is full, reset it first
if (xStreamBufferIsFull(user_byte_stream_buffer) == pdTRUE) {
printf("WARN payload uart user byte stream buffer full!\n");
xStreamBufferReset(user_byte_stream_buffer);
}
xStreamBufferSend(user_byte_stream_buffer, &byte, sizeof(byte), 0);
}
}
// Called everytime we get a 'line' by processLineBufferedRxByte
static void processLine(void *serialHandle, uint8_t *line, size_t len) {
configASSERT(serialHandle != NULL);
configASSERT(line != NULL);
(void)serialHandle;
configASSERT(xSemaphoreTake(_user_line.mutex, portMAX_DELAY) == pdTRUE);
// if the last line has not been read, lets reset the buffer
memset(_user_line.buffer, 0, LPUART1_LINE_BUFF_LEN);
// lets copy over the line to the user mutex protected buffer
memcpy(_user_line.buffer, line, len);
_user_line.len = len;
_user_line.ready = true;
xSemaphoreGive(_user_line.mutex);
}
char getTerminationCharacter() { return terminationCharacter; }
void setTerminationCharacter(char term_char) {
terminationCharacter = term_char;
}
bool getUseLineBuffer() { return _useLineBuffer; }
void setUseLineBuffer(bool enable) {
_useLineBuffer = enable;
}
bool getUseByteStreamBuffer() { return _useByteStreamBuffer; }
void setUseByteStreamBuffer(bool enable) {
_useByteStreamBuffer = enable;
}
bool byteAvailable(void) {
return (!xStreamBufferIsEmpty(user_byte_stream_buffer));
}
bool lineAvailable(void) {
bool rval = false;
configASSERT(xSemaphoreTake(_user_line.mutex, portMAX_DELAY) == pdTRUE);
rval = _user_line.ready;
xSemaphoreGive(_user_line.mutex);
return rval;
}
uint8_t readByte(void) {
uint8_t rval = 0;
xStreamBufferReceive(user_byte_stream_buffer, &rval, sizeof(rval), 0);
return rval;
}
uint16_t readLine(char *buffer, size_t len) {
int16_t rval = 0;
size_t copy_len;
if (len > _user_line.len) {
copy_len = _user_line.len;
} else {
copy_len = len;
}
configASSERT(xSemaphoreTake(_user_line.mutex, portMAX_DELAY) == pdTRUE);
memcpy(buffer, _user_line.buffer, copy_len);
memset(_user_line.buffer, 0, LPUART1_LINE_BUFF_LEN);
_user_line.ready = false;
rval = copy_len;
xSemaphoreGive(_user_line.mutex);
return rval;
}
void write(uint8_t *buffer, size_t len) {
serialWrite(&PLUART::uart_handle, buffer, len);
}
void setBaud(uint32_t new_baud_rate) {
LL_LPUART_SetBaudRate(static_cast<USART_TypeDef *>(uart_handle.device),
LL_RCC_GetLPUARTClockFreq(LL_RCC_LPUART1_CLKSOURCE),
LL_LPUART_PRESCALER_DIV64, new_baud_rate);
}
void enable(void) { serialEnable(&uart_handle); }
// variable definitions
static uint8_t lpUart1Buffer[LPUART1_LINE_BUFF_LEN];
SerialLineBuffer_t lpUART1LineBuffer = {
.buffer = lpUart1Buffer, // pointer to the buffer memory
.idx = 0, // variable to store current index in the buffer
.len = sizeof(lpUart1Buffer), // total size of buffer
.lineCallback =
processLine // lineCallback callback function to call when a line is complete (glued together in the UART handle's byte callback).
};
SerialHandle_t uart_handle = {
.device = LPUART1,
.name = "payload",
.txPin = &PAYLOAD_TX,
.rxPin = &PAYLOAD_RX,
.interruptPin = NULL,
.txStreamBuffer = NULL,
.rxStreamBuffer = NULL,
.txBufferSize = 128,
.rxBufferSize = 2048,
.rxBytesFromISR = serialGenericRxBytesFromISR,
.getTxBytesFromISR = serialGenericGetTxBytesFromISR,
.processByte = processLineBufferedRxByte, // This is where we tell it the callback to call when we get a new byte
.data = &lpUART1LineBuffer, // Pointer to the line buffer this handle should use
.enabled = false,
.flags = 0,
.preTxCb = NULL,
.postTxCb = NULL,
};
BaseType_t init(uint8_t task_priority) {
// Create the stream buffer for the user bytes to be buffered into and read from
user_byte_stream_buffer = xStreamBufferCreate(USER_BYTE_BUFFER_LEN, 1);
configASSERT(user_byte_stream_buffer != NULL);
// Create the mutex used by the payload_uart namespace for users to safely access lines from the payload
_user_line.mutex = xSemaphoreCreateMutex();
configASSERT(_user_line.mutex != NULL);
MX_LPUART1_UART_Init();
// Single byte trigger levels for Rx and Tx for fast response time
uart_handle.txStreamBuffer = xStreamBufferCreate(uart_handle.txBufferSize, 1);
configASSERT(uart_handle.txStreamBuffer != NULL);
uart_handle.rxStreamBuffer = xStreamBufferCreate(uart_handle.rxBufferSize, 1);
configASSERT(uart_handle.rxStreamBuffer != NULL);
BaseType_t rval =
xTaskCreate(serialGenericRxTask, "LPUartRx",
// TODO - verify stack size
2048, &PLUART::uart_handle, task_priority, NULL);
configASSERT(rval == pdTRUE);
return rval;
}
extern "C" void LPUART1_IRQHandler(void) {
configASSERT(&uart_handle);
serialGenericUartIRQHandler(&uart_handle);
}
} // namespace PLUART