@@ -33,59 +33,202 @@ void F9PSerialWriteTask(void *e)
3333// Task for reading data from the GNSS receiver.
3434void F9PSerialReadTask (void *e)
3535{
36+ int btConnected; // Is the RTK in a state to send Bluetooth data?
37+ int btData; // Amount of buffered Bluetooth data
38+ int length;
39+ static uint8_t rBuffer[SERIAL_SIZE_RX]; // Buffer for reading from F9P to SPP
40+ static uint16_t rBufferBtOffset; // Removal offset for Bluetooth
41+ static uint16_t rBufferFillOffset; // Fill offset for serial data
42+ static uint16_t rBufferSdOffset; // Removal offset for microSD card logging
43+ int s;
44+ int sdData; // Amount of buffered microSD card logging data
45+
3646 while (true )
3747 {
3848 while (serialGNSS.available ())
3949 {
40- int s = serialGNSS.readBytes (rBuffer, sizeof (rBuffer));
50+ if (settings.enableTaskReports == true )
51+ Serial.printf (" SerialReadTask High watermark: %d\n\r " , uxTaskGetStackHighWaterMark (NULL ));
4152
42- // If we are actively survey-in then do not pass NMEA data from ZED to phone
43- if (systemState == STATE_BASE_TEMP_SETTLE || systemState == STATE_BASE_TEMP_SURVEY_STARTED)
53+ // ----------------------------------------------------------------------
54+ // At approximately 3.3K characters/second, a 6K byte buffer should hold
55+ // approximately 2 seconds worth of data. Bluetooth congestion or conflicts
56+ // with the SD card semaphore should clear within this time. At 57600 baud
57+ // the Bluetooth UART is able to send 7200 characters a second. With a 10
58+ // mSec delay this rouitne runs approximately 100 times per second providing
59+ // multiple chances to empty the buffer.
60+ //
61+ // Ring buffer empty when (rBufferFillOffset == rBufferBtOffset) and
62+ // (rBufferFillOffset == rBufferSdOffset)
63+ //
64+ // +---------+
65+ // | |
66+ // | |
67+ // | |
68+ // | |
69+ // +---------+ <-- rBufferFillOffset, rBufferBtOffset, rBufferSdOffset
70+ //
71+ // Ring buffer contains data when (rBufferFillOffset != rBufferBtOffset) or
72+ // (rBufferFillOffset != rBufferSdOffset)
73+ //
74+ // +---------+
75+ // | |
76+ // | |
77+ // | yyyyyyy | <-- rBufferFillOffset
78+ // | xxxxxxx | <-- rBufferBtOffset (1 byte in buffer)
79+ // +---------+ <-- rBufferSdOffset (2 bytes in buffer)
80+ //
81+ // +---------+
82+ // | yyyyyyy | <-- rBufferBtOffset (1 byte in buffer)
83+ // | xxxxxxx | <-- rBufferSdOffset (2 bytes in buffer)
84+ // | |
85+ // | |
86+ // +---------+ <-- rBufferFillOffset
87+ //
88+ // Maximum ring buffer fill is sizeof(rBuffer) - 1
89+ // ----------------------------------------------------------------------
90+
91+ // Determine the amount of Bluetooth data in the buffer
92+ length = sizeof (rBuffer);
93+ btData = 0 ;
94+ btConnected = (bluetoothGetState () == BT_CONNECTED)
95+ && (systemState != STATE_BASE_TEMP_SETTLE)
96+ && (systemState != STATE_BASE_TEMP_SURVEY_STARTED);
97+ if (btConnected)
4498 {
45- // Do nothing
46- taskYIELD ();
99+ btData = rBufferFillOffset - rBufferBtOffset;
100+ if (btData < 0 )
101+ btData += sizeof (rBuffer);
102+ length = sizeof (rBuffer) - btData;
47103 }
48- else if (bluetoothGetState () == BT_CONNECTED)
104+
105+ // Determine the amount of microSD card logging data in the buffer
106+ sdData = 0 ;
107+ if (online.logging )
108+ {
109+ sdData = rBufferFillOffset - rBufferSdOffset;
110+ if (sdData < 0 )
111+ sdData += sizeof (rBuffer);
112+ if (length > (sizeof (rBuffer) - sdData))
113+ length = sizeof (rBuffer) - sdData;
114+ }
115+
116+ // Determine the free bytes in the buffer
117+ // Don't fill the last byte to prevent buffer overflow
118+ if (length)
119+ length -= 1 ;
120+
121+ // Fill the buffer to the end and then start at the beginning
122+ if ((rBufferFillOffset + length) > sizeof (rBuffer))
123+ length = sizeof (rBuffer) - rBufferFillOffset;
124+
125+ // Read more data from the GNSS into the buffer
126+ s = 0 ;
127+ if (length)
128+ s = serialGNSS.readBytes (rBuffer, length);
129+
130+ // Account for the byte read
131+ if (s > 0 )
132+ {
133+ // Set the next fill offset
134+ rBufferFillOffset += s;
135+ if (rBufferFillOffset >= sizeof (rBuffer))
136+ rBufferFillOffset -= sizeof (rBuffer);
137+
138+ // Account for the new data
139+ if (btConnected)
140+ btData += s;
141+ if (online.logging )
142+ sdData += s;
143+ }
144+
145+ // ----------------------------------------------------------------------
146+ // Send data over Bluetooth
147+ // ----------------------------------------------------------------------
148+
149+ // If we are actively survey-in then do not pass NMEA data from ZED to phone
150+ if (!btData)
151+ // Discard the data
152+ rBufferBtOffset = rBufferFillOffset;
153+ else
49154 {
155+ // Fill the buffer to the end and then start at the beginning
156+ length = btData;
157+ if ((rBufferBtOffset + length) > sizeof (rBuffer))
158+ length = sizeof (rBuffer) - rBufferBtOffset;
159+
50160 if ((bluetoothIsCongested () == false ) || (settings.throttleDuringSPPCongestion == false ))
51- {
52161 // Push new data to BT SPP if not congested or not throttling
53- bluetoothWriteBytes (rBuffer, s);
54- }
162+ length = bluetoothWriteBytes (&rBuffer[rBufferBtOffset], length);
55163 else
56164 {
57165 // Don't push data to BT SPP if there is congestion to prevent heap hits.
58- log_d (" Dropped SPP Bytes: %d" , s);
166+ if (btData < (sizeof (rBuffer) - 1 ))
167+ length = 0 ;
168+ else
169+ Serial.printf (" ERROR - Congestion, dropped %d bytes: GNSS --> Bluetooth\r\n " , length);
59170 }
171+
172+ // Account for the sent data or dropped
173+ // Set the next removal offset
174+ rBufferBtOffset += length;
175+ if (rBufferBtOffset >= sizeof (rBuffer))
176+ rBufferBtOffset -= sizeof (rBuffer);
60177 }
61178
62- if (settings.enableTaskReports == true )
63- Serial.printf (" SerialReadTask High watermark: %d\n\r " , uxTaskGetStackHighWaterMark (NULL ));
179+ // ----------------------------------------------------------------------
180+ // Log data to the SD card
181+ // ----------------------------------------------------------------------
64182
65183 // If user wants to log, record to SD
66- if (online.logging == true )
184+ if (!online.logging )
185+ // Discard the data
186+ rBufferSdOffset = rBufferFillOffset;
187+ else
67188 {
68189 // Check if we are inside the max time window for logging
69190 if ((systemTime_minutes - startLogTime_minutes) < settings.maxLogTime_minutes )
70191 {
71- // Attempt to write to file system. This avoids collisions with file writing from other functions like recordSystemSettingsToFile()
192+ // Attempt to gain access to the SD card, avoids collisions with file
193+ // writing from other functions like recordSystemSettingsToFile()
72194 if (xSemaphoreTake (sdCardSemaphore, fatSemaphore_shortWait_ms) == pdPASS)
73195 {
74- ubxFile->write (rBuffer, s);
196+ // Fill the buffer to the end and then start at the beginning
197+ length = sdData;
198+ if ((rBufferSdOffset + length) > sizeof (rBuffer))
199+ length = sizeof (rBuffer) - rBufferSdOffset;
75200
201+ // Write the data to the file
202+ length = ubxFile->write (rBuffer, length);
76203 xSemaphoreGive (sdCardSemaphore);
204+
205+ // Account for the sent data or dropped
206+ rBufferSdOffset += length;
207+ if (rBufferSdOffset >= sizeof (rBuffer))
208+ rBufferSdOffset -= sizeof (rBuffer);
77209 } // End sdCardSemaphore
78210 else
79211 {
80- // Error causing dropped bytes in the log file
81- Serial.printf (" sdCardSemaphore failed to yield, Tasks.ino line %d\r\n " , __LINE__);
212+ // Retry the semaphore a little later if possible
213+ if (sdData == (sizeof (rBuffer) - 1 ))
214+ {
215+ // Error - no more room in the buffer, drop a buffer's worth of data
216+ rBufferSdOffset = rBufferFillOffset;
217+ log_e (" ERROR - sdCardSemaphore failed to yield, Tasks.ino line %d\r\n " , __LINE__);
218+ Serial.printf (" ERROR - Dropped %d bytes: GNSS --> log file\r\n " , sdData);
219+ }
220+ else
221+ log_w (" WARNING - sdCardSemaphore failed to yield, Tasks.ino line %d\r\n " , __LINE__);
82222 }
83223 } // End maxLogTime
84224 } // End logging
85225 } // End Serial.available()
86226
87- delay (1 ); // Poor man's way of feeding WDT. Required to prevent Priority 1 tasks from causing WDT reset
88- taskYIELD ();
227+ // ----------------------------------------------------------------------
228+ // Let other tasks run, prevent watch dog timer (WDT) resets
229+ // ----------------------------------------------------------------------
230+
231+ delay (10 );
89232 }
90233}
91234
0 commit comments