Skip to content

Commit ec08d12

Browse files
authoredSep 21, 2021
Merge pull request #26 from bcmi-labs/data-in-callback
Provide message to be written to prefix/suffix callbacks:
2 parents ad17cde + e55cdb9 commit ec08d12

File tree

3 files changed

+68
-35
lines changed

3 files changed

+68
-35
lines changed
 

‎examples/Threadsafe_Serial_Prefix_Suffix/Threadsafe_Serial_Prefix_Suffix.ino renamed to ‎examples/Threadsafe_Serial_ProtocolWrapping/Threadsafe_Serial_ProtocolWrapping.ino

+43-16
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,59 @@ void loop()
5252
* FUNCTION DEFINITION
5353
**************************************************************************************/
5454

55-
void serial_thread_func()
55+
String nmea_message_prefix(String const & /* msg */)
5656
{
57-
Serial.begin(9600);
57+
return String("$");
58+
}
5859

59-
char const * thread_name = rtos::ThisThread::get_name();
60-
Serial.prefix([thread_name]() -> String
61-
{
62-
char msg[64] = {0};
63-
snprintf(msg, sizeof(msg), "[%05lu] %s ", millis(), thread_name);
64-
return String(msg);
65-
});
66-
Serial.suffix([]() -> String
60+
String nmea_message_suffix(String const & prefix, String const & msg)
61+
{
62+
/* NMEA checksum is calculated over the complete message
63+
* starting with '$' and ending with the end of the message.
64+
*/
65+
byte checksum = 0;
66+
std::for_each(msg.c_str(),
67+
msg.c_str() + msg.length(),
68+
[&checksum](char const c)
6769
{
68-
return String("\r\n");
70+
checksum ^= static_cast<uint8_t>(c);
6971
});
72+
/* Assemble the footer of the NMEA message. */
73+
char footer[16] = {0};
74+
snprintf(footer, sizeof(footer), "*%02X\r\n", checksum);
75+
return String(footer);
76+
}
77+
78+
void serial_thread_func()
79+
{
80+
Serial.begin(9600);
81+
82+
Serial.prefix(nmea_message_prefix);
83+
Serial.suffix(nmea_message_suffix);
7084

7185
for(;;)
7286
{
7387
/* Sleep between 5 and 500 ms */
7488
rtos::ThisThread::sleep_for(rtos::Kernel::Clock::duration_u32(random(5,500)));
75-
/* Print a unbroken log message including thread name and timestamp as a prefix. */
89+
90+
/* Print a fake NMEA GPRMC message:
91+
* $GPRMC,062101.714,A,5001.869,N,01912.114,E,955535.7,116.2,290520,000.0,W*45\r\n
92+
*/
7693
Serial.block();
77-
Serial.print("My ");
78-
Serial.print("unbroken ");
79-
Serial.print("thread-safe ");
80-
Serial.print("message!");
94+
95+
Serial.print("GPRMC,");
96+
Serial.print(millis());
97+
Serial.print(",A,");
98+
Serial.print("5001.869,");
99+
Serial.print("N,");
100+
Serial.print("01912.114,");
101+
Serial.print("E,");
102+
Serial.print("955535.7,");
103+
Serial.print("116.2,");
104+
Serial.print("290520,");
105+
Serial.print("000.0,");
106+
Serial.print("W");
107+
81108
Serial.unblock();
82109
}
83110
}

‎src/serial/SerialDispatcher.cpp

+19-16
Original file line numberDiff line numberDiff line change
@@ -236,36 +236,39 @@ void SerialDispatcher::threadFunc()
236236
if (!d.tx_buffer.available())
237237
return;
238238

239+
/* Retrieve all data stored in the transmit ringbuffer
240+
* and store it into a String for usage by both suffix
241+
* prefix callback functions.
242+
*/
243+
String msg;
244+
while(d.tx_buffer.available())
245+
msg += static_cast<char>(d.tx_buffer.read_char());
246+
239247
/* The prefix callback function allows the
240248
* user to insert a custom message before
241249
* a new message is written to the serial
242250
* driver. This is useful e.g. for wrapping
243251
* protocol (e.g. the 'AT' protocol) or providing
244252
* a timestamp, a log level, ...
245253
*/
254+
String prefix;
246255
if (d.prefix_func)
247-
{
248-
String const prefix_str = d.prefix_func();
249-
_serial.write(prefix_str.c_str());
250-
}
251-
252-
/* Now it's time to actually write the message
253-
* conveyed by the user via Serial.print/println.
254-
*/
255-
while(d.tx_buffer.available())
256-
{
257-
_serial.write(d.tx_buffer.read_char());
258-
}
256+
prefix = d.prefix_func(msg);
259257

260258
/* Similar to the prefix function this callback
261259
* allows the user to specify a specific message
262260
* to be appended to each message, e.g. '\r\n'.
263261
*/
262+
String suffix;
264263
if (d.suffix_func)
265-
{
266-
String const suffix_str = d.suffix_func();
267-
_serial.write(suffix_str.c_str());
268-
}
264+
suffix = d.suffix_func(prefix, msg);
265+
266+
/* Now it's time to actually write the message
267+
* conveyed by the user via Serial.print/println.
268+
*/
269+
_serial.write(prefix.c_str());
270+
_serial.write(msg.c_str());
271+
_serial.write(suffix.c_str());
269272
});
270273
}
271274
}

‎src/serial/SerialDispatcher.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ class SerialDispatcher : public arduino::HardwareSerial
5959
void block();
6060
void unblock();
6161

62-
typedef std::function<String(void)> PrefixInjectorCallbackFunc;
63-
typedef PrefixInjectorCallbackFunc SuffixInjectorCallbackFunc;
62+
typedef std::function<String(String const &)> PrefixInjectorCallbackFunc;
63+
typedef std::function<String(String const &, String const &)> SuffixInjectorCallbackFunc;
6464
void prefix(PrefixInjectorCallbackFunc func);
6565
void suffix(SuffixInjectorCallbackFunc func);
6666

@@ -76,10 +76,13 @@ class SerialDispatcher : public arduino::HardwareSerial
7676
bool _has_tread_started;
7777
bool _terminate_thread;
7878

79+
static int constexpr THREADSAFE_SERIAL_TRANSMIT_RINGBUFFER_SIZE = 128;
80+
typedef arduino::RingBufferN<THREADSAFE_SERIAL_TRANSMIT_RINGBUFFER_SIZE> SerialTransmitRingbuffer;
81+
7982
typedef struct
8083
{
8184
osThreadId_t thread_id;
82-
arduino::RingBuffer tx_buffer;
85+
SerialTransmitRingbuffer tx_buffer;
8386
bool block_tx_buffer;
8487
mbed::SharedPtr<arduino::RingBuffer> rx_buffer; /* Only when a thread has expressed interested to read from serial a receive ringbuffer is allocated. */
8588
PrefixInjectorCallbackFunc prefix_func;

0 commit comments

Comments
 (0)
Please sign in to comment.