23
23
24
24
#if defined(ESP3DLIB_ENV) && COMMUNICATION_PROTOCOL == SOCKET_SERIAL
25
25
#include < Arduino.h>
26
+ #include " freertos/FreeRTOS.h"
27
+ #include " freertos/semphr.h"
26
28
27
29
#include " ../../core/esp3d_commands.h"
28
30
#include " ../../core/esp3d_message.h"
29
31
#include " serial2socket.h"
30
32
31
33
Serial_2_Socket Serial2Socket;
32
34
33
- Serial_2_Socket::Serial_2_Socket () { end (); }
34
- Serial_2_Socket::~Serial_2_Socket () { end (); }
35
+ Serial_2_Socket::Serial_2_Socket () {
36
+ _rxBufferMutex = (void *)xSemaphoreCreateMutex ();
37
+ if (_rxBufferMutex == NULL ) {
38
+ esp3d_log_e (" Serial2Socket: Failed to create RX mutex" );
39
+ }
40
+
41
+ _txBufferMutex = (void *)xSemaphoreCreateMutex ();
42
+ if (_txBufferMutex == NULL ) {
43
+ esp3d_log_e (" Serial2Socket: Failed to create TX mutex" );
44
+ }
45
+
46
+ end ();
47
+ }
48
+
49
+ Serial_2_Socket::~Serial_2_Socket () {
50
+ if (_rxBufferMutex != NULL ) {
51
+ vSemaphoreDelete ((SemaphoreHandle_t)_rxBufferMutex);
52
+ _rxBufferMutex = NULL ;
53
+ }
54
+
55
+ if (_txBufferMutex != NULL ) {
56
+ vSemaphoreDelete ((SemaphoreHandle_t)_txBufferMutex);
57
+ _txBufferMutex = NULL ;
58
+ }
59
+
60
+ end ();
61
+ }
62
+
35
63
void Serial_2_Socket::begin (long speed) { end (); }
36
64
37
65
void Serial_2_Socket::enable (bool enable) { _started = enable; }
38
66
39
67
void Serial_2_Socket::pause (bool state) {
40
68
_paused = state;
41
69
if (_paused) {
42
- _TXbufferSize = 0 ;
43
- _RXbufferSize = 0 ;
44
- _RXbufferpos = 0 ;
70
+ // Protect TX buffer access with mutex
71
+ if (_txBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_txBufferMutex, pdMS_TO_TICKS (100 )) == pdTRUE) {
72
+ _TXbufferSize = 0 ;
73
+ xSemaphoreGive ((SemaphoreHandle_t)_txBufferMutex);
74
+ } else {
75
+ _TXbufferSize = 0 ;
76
+ }
77
+
78
+ // Protect RX buffer access with mutex
79
+ if (_rxBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_rxBufferMutex, pdMS_TO_TICKS (100 )) == pdTRUE) {
80
+ _RXbufferSize = 0 ;
81
+ _RXbufferpos = 0 ;
82
+ xSemaphoreGive ((SemaphoreHandle_t)_rxBufferMutex);
83
+ } else {
84
+ _RXbufferSize = 0 ;
85
+ _RXbufferpos = 0 ;
86
+ }
45
87
} else {
46
88
_lastflush = millis ();
47
89
}
@@ -50,9 +92,24 @@ void Serial_2_Socket::pause(bool state) {
50
92
bool Serial_2_Socket::isPaused () { return _paused; }
51
93
52
94
void Serial_2_Socket::end () {
53
- _TXbufferSize = 0 ;
54
- _RXbufferSize = 0 ;
55
- _RXbufferpos = 0 ;
95
+ // Protect TX buffer access with mutex
96
+ if (_txBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_txBufferMutex, pdMS_TO_TICKS (100 )) == pdTRUE) {
97
+ _TXbufferSize = 0 ;
98
+ xSemaphoreGive ((SemaphoreHandle_t)_txBufferMutex);
99
+ } else {
100
+ _TXbufferSize = 0 ;
101
+ }
102
+
103
+ // Protect RX buffer access with mutex
104
+ if (_rxBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_rxBufferMutex, pdMS_TO_TICKS (100 )) == pdTRUE) {
105
+ _RXbufferSize = 0 ;
106
+ _RXbufferpos = 0 ;
107
+ xSemaphoreGive ((SemaphoreHandle_t)_rxBufferMutex);
108
+ } else {
109
+ _RXbufferSize = 0 ;
110
+ _RXbufferpos = 0 ;
111
+ }
112
+
56
113
_started = false ;
57
114
_paused = false ;
58
115
_lastflush = millis ();
@@ -70,16 +127,32 @@ bool Serial_2_Socket::started() { return _started; }
70
127
Serial_2_Socket::operator bool () const { return true ; }
71
128
72
129
int Serial_2_Socket::available () {
73
- if (_paused) {
130
+ if (_paused || !_started ) {
74
131
return 0 ;
75
132
}
76
- return _RXbufferSize;
133
+ if (_RXbufferSize == 0 ) {
134
+ return 0 ;
135
+ }
136
+
137
+ // Protect RX buffer access with mutex
138
+ if (_rxBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_rxBufferMutex, pdMS_TO_TICKS (100 )) != pdTRUE) {
139
+ esp3d_log_e (" Serial2Socket: Failed to take mutex for available" );
140
+ return 0 ;
141
+ }
142
+
143
+ int size = _RXbufferSize;
144
+
145
+ if (_rxBufferMutex != NULL ) {
146
+ xSemaphoreGive ((SemaphoreHandle_t)_rxBufferMutex);
147
+ }
148
+ return size;
77
149
}
78
150
79
151
size_t Serial_2_Socket::write (uint8_t c) {
80
152
if (!_started || _paused) {
81
153
return 1 ;
82
154
}
155
+ esp3d_log_d (" Serial2Socket: write one char %c" , c);
83
156
return write (&c, 1 );
84
157
}
85
158
@@ -88,39 +161,81 @@ size_t Serial_2_Socket::write(const uint8_t *buffer, size_t size) {
88
161
esp3d_log (" Serial2Socket: no data, not started or paused" );
89
162
return size;
90
163
}
164
+
165
+ // Take TX buffer mutex once for the entire function
166
+ if (_txBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_txBufferMutex, pdMS_TO_TICKS (100 )) != pdTRUE) {
167
+ esp3d_log_e (" Serial2Socket: Failed to take mutex for write" );
168
+ return 0 ;
169
+ }
170
+
91
171
if (_TXbufferSize == 0 ) {
92
172
_lastflush = millis ();
93
173
}
94
- // send full line
174
+
175
+ // Check if buffer is full and needs flushing
95
176
if (_TXbufferSize + size > S2S_TXBUFFERSIZE) {
96
- flush ();
177
+ esp3d_log_d (" Serial2Socket: buffer full, flush it" );
178
+ flush (false ); // Use flush without mutex since we already have it
97
179
}
98
- // need periodic check to force to flush in case of no end
180
+
181
+ // Add data to buffer and flush on newline
99
182
for (int i = 0 ; i < size; i++) {
100
183
_TXbuffer[_TXbufferSize] = buffer[i];
101
184
_TXbufferSize++;
102
185
if (buffer[i] == (const uint8_t )' \n ' ) {
103
- esp3d_log (" S2S: %s TXSize: %d" , (const char *)_TXbuffer, _TXbufferSize);
104
- flush ();
186
+ esp3d_log_d (" S2S: %s TXSize: %d" , (const char *)_TXbuffer, _TXbufferSize);
187
+ flush (false ); // Use flush without mutex since we already have it
105
188
}
106
189
}
107
- handle_flush ();
190
+
191
+ // Check if we need to flush based on time
192
+ if (_TXbufferSize > 0 && ((millis () - _lastflush) > S2S_FLUSHTIMEOUT)) {
193
+ flush (false ); // Use flush without mutex since we already have it
194
+ }
195
+
196
+ // Release the mutex at the end
197
+ if (_txBufferMutex != NULL ) {
198
+ xSemaphoreGive ((SemaphoreHandle_t)_txBufferMutex);
199
+ }
200
+
108
201
return size;
109
202
}
110
203
111
204
int Serial_2_Socket::peek (void ) {
112
- if (_RXbufferSize > 0 && _started) {
113
- return _RXbuffer[_RXbufferpos];
114
- } else {
205
+ esp3d_log_d (" Serial2Socket: peek first of %d" , _RXbufferSize);
206
+ if (_RXbufferSize <= 0 || !_started) {
115
207
return -1 ;
116
208
}
209
+
210
+ // Protect RX buffer access with mutex
211
+ if (_rxBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_rxBufferMutex, pdMS_TO_TICKS (100 )) != pdTRUE) {
212
+ esp3d_log_e (" Serial2Socket: Failed to take mutex for peek" );
213
+ return -1 ;
214
+ }
215
+
216
+ uint8_t v = _RXbuffer[_RXbufferpos];
217
+
218
+ if (_rxBufferMutex != NULL ) {
219
+ xSemaphoreGive ((SemaphoreHandle_t)_rxBufferMutex);
220
+ }
221
+ return v;
117
222
}
118
223
119
- bool Serial_2_Socket::push (const uint8_t *buffer, size_t size) {
224
+ // Send data to socket output buffer
225
+ bool Serial_2_Socket::push2RX (const uint8_t *buffer, size_t size) {
120
226
if (buffer == NULL || size == 0 || !_started || _paused) {
121
227
return false ;
122
228
}
229
+
230
+ // Protect RX buffer access with mutex
231
+ if (_rxBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_rxBufferMutex, pdMS_TO_TICKS (100 )) != pdTRUE) {
232
+ esp3d_log_e (" Serial2Socket: cannot take mutex for push2RX" );
233
+ return false ;
234
+ }
235
+
123
236
int data_size = size;
237
+ bool success = false ;
238
+ esp3d_log_d (" Serial2Socket: pushing %d chars to buffer" , data_size);
124
239
if ((data_size + _RXbufferSize) <= S2S_RXBUFFERSIZE) {
125
240
int current = _RXbufferpos + _RXbufferSize;
126
241
if (current > S2S_RXBUFFERSIZE) {
@@ -134,24 +249,41 @@ bool Serial_2_Socket::push(const uint8_t *buffer, size_t size) {
134
249
current++;
135
250
}
136
251
_RXbufferSize += size;
137
- _RXbuffer[current] = 0 ;
138
- return true ;
252
+ if (current < S2S_RXBUFFERSIZE) {
253
+ _RXbuffer[current] = 0 ;
254
+ }
255
+ success = true ;
139
256
}
140
- return false ;
257
+
258
+ if (_rxBufferMutex != NULL ) {
259
+ xSemaphoreGive ((SemaphoreHandle_t)_rxBufferMutex);
260
+ }
261
+ return success;
141
262
}
142
263
143
264
int Serial_2_Socket::read (void ) {
144
- if (_RXbufferSize > 0 && _started && !_paused) {
145
- int v = _RXbuffer[_RXbufferpos];
146
- _RXbufferpos++;
147
- if (_RXbufferpos > (S2S_RXBUFFERSIZE - 1 )) {
148
- _RXbufferpos = 0 ;
149
- }
150
- _RXbufferSize--;
151
- return v;
152
- } else {
265
+ if (_RXbufferSize <= 0 || !_started || _paused) {
266
+ return -1 ;
267
+ }
268
+
269
+ // Protect RX buffer access with mutex
270
+ if (_rxBufferMutex != NULL && xSemaphoreTake ((SemaphoreHandle_t)_rxBufferMutex, pdMS_TO_TICKS (100 )) != pdTRUE) {
271
+ esp3d_log_e (" Serial2Socket: Failed to take mutex for read" );
153
272
return -1 ;
154
273
}
274
+
275
+ uint8_t v = _RXbuffer[_RXbufferpos];
276
+ _RXbufferpos++;
277
+ if (_RXbufferpos > (S2S_RXBUFFERSIZE - 1 )) {
278
+ _RXbufferpos = 0 ;
279
+ }
280
+ _RXbufferSize--;
281
+ esp3d_log_d (" Serial2Socket: read one char %c" , v);
282
+
283
+ if (_rxBufferMutex != NULL ) {
284
+ xSemaphoreGive ((SemaphoreHandle_t)_rxBufferMutex);
285
+ }
286
+ return v;
155
287
}
156
288
157
289
void Serial_2_Socket::handle () { handle_flush (); }
@@ -161,27 +293,42 @@ void Serial_2_Socket::handle_flush() {
161
293
if ((_TXbufferSize >= S2S_TXBUFFERSIZE) ||
162
294
((millis () - _lastflush) > S2S_FLUSHTIMEOUT)) {
163
295
esp3d_log (" force socket flush" );
164
- flush ();
296
+ flush (true );
165
297
}
166
298
}
167
299
}
168
- void Serial_2_Socket::flush (void ) {
300
+
301
+ void Serial_2_Socket::flush (bool useMutex) {
302
+
303
+ // Process buffer if there's data and we're not paused
169
304
if (_TXbufferSize > 0 && _started && !_paused) {
305
+ // Protect TX buffer access with mutex if requested
306
+ if (useMutex && _txBufferMutex != NULL ) {
307
+ if (xSemaphoreTake ((SemaphoreHandle_t)_txBufferMutex, pdMS_TO_TICKS (100 )) != pdTRUE) {
308
+ esp3d_log_e (" Serial2Socket: Failed to take mutex for flush" );
309
+ return ;
310
+ }
311
+ }
170
312
ESP3DMessage *msg = esp3d_message_manager.newMsg (
171
313
ESP3DClientType::socket_serial, ESP3DClientType::all_clients, _TXbuffer,
172
314
_TXbufferSize, _auth);
173
- // dispatch command
315
+
316
+ // Reset buffer before processing
317
+ _lastflush = millis ();
318
+ _TXbufferSize = 0 ;
319
+
320
+ // Release mutex if we took it
321
+ if (useMutex && _txBufferMutex != NULL ) {
322
+ xSemaphoreGive ((SemaphoreHandle_t)_txBufferMutex);
323
+ }
324
+
174
325
if (msg) {
175
326
// process command
176
327
msg->type = ESP3DMessageType::unique;
177
328
esp3d_commands.process (msg);
178
329
} else {
179
330
esp3d_log_e (" Cannot create message" );
180
331
}
181
- // refresh timout
182
- _lastflush = millis ();
183
- // reset buffer
184
- _TXbufferSize = 0 ;
185
332
}
186
333
}
187
334
@@ -191,7 +338,8 @@ bool Serial_2_Socket::dispatch(ESP3DMessage *message) {
191
338
return false ;
192
339
}
193
340
if (message->size > 0 && message->data ) {
194
- if (!push (message->data , message->size )) {
341
+ esp3d_log_d (" Serial2Socket: dispatch message %d" , message->size );
342
+ if (!push2RX (message->data , message->size )) {
195
343
esp3d_log_e (" Serial2Socket: cannot push all data" );
196
344
return false ;
197
345
}
0 commit comments