Skip to content

Commit 79c60d7

Browse files
authored
Merge pull request #639 from LeeLeahy2/array-discard-only
Use an array to discard data, overhead during discard only
2 parents 330d154 + 5c7c6b6 commit 79c60d7

File tree

5 files changed

+243
-15
lines changed

5 files changed

+243
-15
lines changed

Firmware/RTK_Surveyor/Begin.ino

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,11 +599,25 @@ void resetSPI()
599599
// See issue: https://github.com/espressif/arduino-esp32/issues/3386
600600
void beginUART2()
601601
{
602-
ringBuffer = (uint8_t *)malloc(settings.gnssHandlerBufferSize);
603-
if (!ringBuffer)
602+
size_t length;
603+
604+
// Determine the length of data to be retained in the ring buffer
605+
// after discarding the oldest data
606+
length = settings.gnssHandlerBufferSize;
607+
rbOffsetEntries = (length >> 1) / AVERAGE_SENTENCE_LENGTH_IN_BYTES;
608+
length = settings.gnssHandlerBufferSize
609+
+ (rbOffsetEntries * sizeof(RING_BUFFER_OFFSET));
610+
ringBuffer = nullptr;
611+
rbOffsetArray = (RING_BUFFER_OFFSET *)malloc(length);
612+
if (!rbOffsetArray)
613+
{
614+
rbOffsetEntries = 0;
604615
systemPrintln("ERROR: Failed to allocate the ring buffer!");
616+
}
605617
else
606618
{
619+
ringBuffer = (uint8_t *)&rbOffsetArray[rbOffsetEntries];
620+
rbOffsetArray[0] = 0;
607621
if (pinUART2TaskHandle == nullptr)
608622
xTaskCreatePinnedToCore(
609623
pinUART2Task,

Firmware/RTK_Surveyor/PvtClient.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ void pvtClientSetState(uint8_t newState)
251251
}
252252

253253
// Remove previous messages from the ring buffer
254-
void discardPvtClientBytes(RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail, RING_BUFFER_OFFSET discardedBytes)
254+
void discardPvtClientBytes(RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail)
255255
{
256256
if (previousTail < newTail)
257257
{

Firmware/RTK_Surveyor/PvtServer.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ int32_t pvtServerSendData(uint16_t dataHead)
179179
}
180180

181181
// Remove previous messages from the ring buffer
182-
void discardPvtServerBytes(RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail, RING_BUFFER_OFFSET discardedBytes)
182+
void discardPvtServerBytes(RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail)
183183
{
184184
int index;
185185
uint16_t tail;

Firmware/RTK_Surveyor/RTK_Surveyor.ino

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,12 @@ TaskHandle_t btReadTaskHandle =
399399
nullptr; // Store handles so that we can kill them if user goes into WiFi NTRIP Server mode
400400
const int btReadTaskStackSize = 2000;
401401

402+
// Array of start of sentence offsets into the ring buffer
403+
#define AMOUNT_OF_RING_BUFFER_DATA_TO_DISCARD (settings.gnssHandlerBufferSize >> 2)
404+
#define AVERAGE_SENTENCE_LENGTH_IN_BYTES 32
405+
RING_BUFFER_OFFSET * rbOffsetArray;
406+
uint16_t rbOffsetEntries;
407+
402408
uint8_t *ringBuffer; // Buffer for reading from F9P. At 230400bps, 23040 bytes/s. If SD blocks for 250ms, we need 23040
403409
// * 0.25 = 5760 bytes worst case.
404410
TaskHandle_t gnssReadTaskHandle =

Firmware/RTK_Surveyor/Tasks.ino

Lines changed: 219 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ Tasks.ino
3434
3535
------------------------------------------------------------------------------*/
3636

37+
//----------------------------------------
38+
// Macros
39+
//----------------------------------------
40+
41+
#define WRAP_OFFSET(offset, increment, arraySize) \
42+
{ \
43+
offset += increment; \
44+
if (offset >= arraySize) \
45+
offset -= arraySize; \
46+
}
47+
3748
//----------------------------------------
3849
// Constants
3950
//----------------------------------------
@@ -75,6 +86,9 @@ unsigned long lastZedI2CSend; // Timestamp of the last time we sent RTCM ZED ove
7586
static RING_BUFFER_OFFSET btRingBufferTail; // BT Tail advances as it is sent over BT
7687
static RING_BUFFER_OFFSET sdRingBufferTail; // SD Tail advances as it is recorded to SD
7788

89+
// Ring buffer offsets
90+
static uint16_t rbOffsetHead;
91+
7892
//----------------------------------------
7993
// Task routines
8094
//----------------------------------------
@@ -343,7 +357,7 @@ void gnssReadTask(void *e)
343357
}
344358

345359
// Process a complete message incoming from parser
346-
// If we get a complete NMEA/UBX/RTCM sentence, pass on to SD/BT/PVT interfaces
360+
// If we get a complete NMEA/UBX/RTCM message, pass on to SD/BT/PVT interfaces
347361
void processUart1Message(PARSE_STATE *parse, uint8_t type)
348362
{
349363
int32_t bytesToCopy;
@@ -387,13 +401,181 @@ void processUart1Message(PARSE_STATE *parse, uint8_t type)
387401
consumer = (char *)slowConsumer;
388402
if ((bytesToCopy > space) && (!inMainMenu))
389403
{
404+
int32_t bufferedData;
405+
int32_t bytesToDiscard;
406+
int32_t discardedBytes;
407+
int32_t listEnd;
408+
int32_t messageLength;
409+
int32_t offsetBytes;
410+
int32_t previousTail;
411+
int32_t rbOffsetTail;
412+
413+
// Determine the tail of the ring buffer
414+
previousTail = dataHead + space + 1;
415+
if (previousTail >= settings.gnssHandlerBufferSize)
416+
previousTail -= settings.gnssHandlerBufferSize;
417+
418+
/* The rbOffsetArray holds the offsets into the ring buffer of the
419+
* start of each of the parsed messages. A head (rbOffsetHead) and
420+
* tail (rbOffsetTail) offsets are used for this array to insert and
421+
* remove entries. Typically this task only manipulates the head as
422+
* new messages are placed into the ring buffer. The handleGnssDataTask
423+
* normally manipulates the tail as data is removed from the buffer.
424+
* However this task will manipulate the tail under two conditions:
425+
*
426+
* 1. The ring buffer gets full and data must be discarded
427+
*
428+
* 2. The rbOffsetArray is too small to hold all of the message
429+
* offsets for the data in the ring buffer. The array is full
430+
* when (Head + 1) == Tail
431+
*
432+
* Notes:
433+
* The rbOffsetArray is allocated along with the ring buffer in
434+
* Begin.ino
435+
*
436+
* The first entry rbOffsetArray[0] is initialized to zero (0)
437+
* in Begin.ino
438+
*
439+
* The array always has one entry in it containing the head offset
440+
* which contains a valid offset into the ringBuffer, handled below
441+
*
442+
* The empty condition is Tail == Head
443+
*
444+
* The amount of data described by the rbOffsetArray is
445+
* rbOffsetArray[Head] - rbOffsetArray[Tail]
446+
*
447+
* rbOffsetArray ringBuffer
448+
* .-----------------. .-----------------.
449+
* | | | |
450+
* +-----------------+ | |
451+
* Tail --> | Msg 1 Offset |---------->+-----------------+ <-- Tail n
452+
* +-----------------+ | Msg 1 |
453+
* | Msg 2 Offset |--------. | |
454+
* +-----------------+ | | |
455+
* | Msg 3 Offset |------. '->+-----------------+
456+
* +-----------------+ | | Msg 2 |
457+
* Head --> | Head Offset |--. | | |
458+
* +-----------------+ | | | |
459+
* | | | | | |
460+
* +-----------------+ | | | |
461+
* | | | '--->+-----------------+
462+
* +-----------------+ | | Msg 3 |
463+
* | | | | |
464+
* +-----------------+ '------->+-----------------+ <-- dataHead
465+
* | | | |
466+
*/
467+
468+
// Determine the index for the end of the circular ring buffer
469+
// offset list
470+
listEnd = rbOffsetHead;
471+
WRAP_OFFSET(listEnd, 1, rbOffsetEntries);
472+
473+
// Update the tail, walk newest message to oldest message
474+
rbOffsetTail = rbOffsetHead;
475+
bufferedData = 0;
476+
messageLength = 0;
477+
while ((rbOffsetTail != listEnd) && (bufferedData < use))
478+
{
479+
// Determine the amount of data in the ring buffer up until
480+
// either the tail or the end of the rbOffsetArray
481+
//
482+
// | |
483+
// | | Valid, still in ring buffer
484+
// | Newest |
485+
// +-----------+ <-- rbOffsetHead
486+
// | |
487+
// | | free space
488+
// | |
489+
// rbOffsetTail --> +-----------+ <-- bufferedData
490+
// | ring |
491+
// | buffer | <-- used
492+
// | data |
493+
// +-----------+ Valid, still in ring buffer
494+
// | |
495+
//
496+
messageLength = rbOffsetArray[rbOffsetTail];
497+
WRAP_OFFSET(rbOffsetTail, rbOffsetEntries - 1, rbOffsetEntries);
498+
messageLength -= rbOffsetArray[rbOffsetTail];
499+
if (messageLength < 0)
500+
messageLength += settings.gnssHandlerBufferSize;
501+
bufferedData += messageLength;
502+
}
503+
504+
// Account for any data in the ring buffer not described by the array
505+
//
506+
// | |
507+
// +-----------+
508+
// | Oldest |
509+
// | |
510+
// | ring |
511+
// | buffer | <-- used
512+
// | data |
513+
// +-----------+ Valid, still in ring buffer
514+
// | |
515+
// rbOffsetTail --> +-----------+ <-- bufferedData
516+
// | |
517+
// | Newest |
518+
// +-----------+ <-- rbOffsetHead
519+
// | |
520+
//
521+
discardedBytes = 0;
522+
if (bufferedData < use)
523+
discardedBytes = use - bufferedData;
524+
525+
// Writing to the SD card, the network or Bluetooth, a partial
526+
// message may be written leaving the tail pointer mid-message
527+
//
528+
// | |
529+
// rbOffsetTail --> +-----------+
530+
// | Oldest |
531+
// | |
532+
// | ring |
533+
// | buffer | <-- used
534+
// | data | Valid, still in ring buffer
535+
// +-----------+ <--
536+
// | |
537+
// +-----------+
538+
// | |
539+
// | Newest |
540+
// +-----------+ <-- rbOffsetHead
541+
// | |
542+
//
543+
else if (bufferedData > use)
544+
{
545+
// Remove the remaining portion of the oldest entry in the array
546+
discardedBytes = messageLength + use - bufferedData;
547+
WRAP_OFFSET(rbOffsetTail, 1, rbOffsetEntries);
548+
}
549+
550+
// rbOffsetTail now points to the beginning of a message in the
551+
// ring buffer
552+
// Determine the amount of data to discard
553+
bytesToDiscard = discardedBytes;
554+
if (bytesToDiscard < bytesToCopy)
555+
bytesToDiscard = bytesToCopy;
556+
if (bytesToDiscard < AMOUNT_OF_RING_BUFFER_DATA_TO_DISCARD)
557+
bytesToDiscard = AMOUNT_OF_RING_BUFFER_DATA_TO_DISCARD;
558+
559+
// Walk the ring buffer messages from oldest to newest
560+
while ((discardedBytes < bytesToDiscard) && (rbOffsetTail != rbOffsetHead))
561+
{
562+
// Determine the length of the oldest message
563+
WRAP_OFFSET(rbOffsetTail, 1, rbOffsetEntries);
564+
discardedBytes = rbOffsetArray[rbOffsetTail] - previousTail;
565+
if (discardedBytes < 0)
566+
discardedBytes += settings.gnssHandlerBufferSize;
567+
}
568+
569+
// Discard the oldest data from the ring buffer
390570
if (consumer)
391-
systemPrintf("%s is slow, ", consumer);
392-
systemPrintf("%d bytes of %d in use\r\n", use, settings.gnssHandlerBufferSize);
393-
systemPrintf("Ring buffer full: discarding %d bytes\r\n", bytesToCopy);
394-
return;
571+
systemPrintf("Ring buffer full: discarding %d bytes, %s is slow\r\n", discardedBytes, consumer);
572+
else
573+
systemPrintf("Ring buffer full: discarding %d bytes\r\n", discardedBytes);
574+
updateRingBufferTails(previousTail, rbOffsetArray[rbOffsetTail]);
575+
availableHandlerSpace += discardedBytes;
395576
}
396577

578+
// Add another message to the ring buffer
397579
// Account for this message
398580
availableHandlerSpace -= bytesToCopy;
399581

@@ -422,26 +604,51 @@ void processUart1Message(PARSE_STATE *parse, uint8_t type)
422604
dataHead -= settings.gnssHandlerBufferSize;
423605
}
424606

607+
// Add the head offset to the offset array
608+
WRAP_OFFSET(rbOffsetHead, 1, rbOffsetEntries);
609+
rbOffsetArray[rbOffsetHead] = dataHead;
610+
425611
// Display the dataHead offset
426612
if (settings.enablePrintRingBufferOffsets && (!inMainMenu))
427613
systemPrintf("%4d\r\n", dataHead);
428614
}
429615

430616
// Remove previous messages from the ring buffer
431-
void updateRingBufferTails(RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail, RING_BUFFER_OFFSET discardedBytes)
617+
void updateRingBufferTails(RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail)
432618
{
433-
discardRingBufferBytes(&btRingBufferTail, previousTail, newTail, discardedBytes);
434-
discardRingBufferBytes(&sdRingBufferTail, previousTail, newTail, discardedBytes);
435-
discardPvtClientBytes(previousTail, newTail, discardedBytes);
436-
discardPvtServerBytes(previousTail, newTail, discardedBytes);
619+
// Trim any long or medium tails
620+
discardRingBufferBytes(&btRingBufferTail, previousTail, newTail);
621+
discardRingBufferBytes(&sdRingBufferTail, previousTail, newTail);
622+
discardPvtClientBytes(previousTail, newTail);
623+
discardPvtServerBytes(previousTail, newTail);
437624
}
438625

439626
// Remove previous messages from the ring buffer
440-
void discardRingBufferBytes(RING_BUFFER_OFFSET * tail, RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail, RING_BUFFER_OFFSET discardedBytes)
627+
void discardRingBufferBytes(RING_BUFFER_OFFSET * tail, RING_BUFFER_OFFSET previousTail, RING_BUFFER_OFFSET newTail)
441628
{
629+
// The longest tail is being trimmed. Medium length tails may contain
630+
// some data within the region begin trimmed. The shortest tails will
631+
// be trimmed.
632+
//
633+
// Devices that get their tails trimmed, may output a partial message
634+
// prior to the buffer trimming. After the trimming, the tail of the
635+
// ring buffer points to the beginning of a new message.
636+
//
637+
// previousTail newTail
638+
// | |
639+
// Before trimming v Discarded v After trimming
640+
// ----+----------------- ... -----+-- .. ---+-----------+------
641+
// | Partial message | | |
642+
// ----+----------------- ... -----+-- .. ---+-----------+------
643+
// ^ ^ ^
644+
// | | |
645+
// long tail ----' '--- medium tail '-- short tail
646+
//
647+
// Determine if the trimmed data wraps the end of the buffer
442648
if (previousTail < newTail)
443649
{
444650
// No buffer wrap occurred
651+
// Only discard the data from long and medium tails
445652
if ((*tail >= previousTail) && (*tail < newTail))
446653
*tail = newTail;
447654
}
@@ -464,6 +671,7 @@ void handleGnssDataTask(void *e)
464671
bool connected;
465672
uint32_t deltaMillis;
466673
int32_t freeSpace;
674+
uint16_t listEnd;
467675
static uint32_t maxMillis[RBC_MAX];
468676
uint32_t startMillis;
469677
int32_t usedSpace;

0 commit comments

Comments
 (0)