Writing Your Own Serial Port Processing Function Using Callbacks

Handling serial data streams is our bread and butter. In a majority of cases, NetBurner’s serial device platforms are ready for your Serial-to-Ethernet applications right out-of-the-box; however, in applications that require precision serial data timing, additional processing may be needed. In this article, we’ll show you an implementation of callback functions to handle these scenarios.

The Problem

NetBurner serial device platforms are pre-loaded with a buffered interrupt-driven serial port driver, and for most use cases, that is all you need to handle serial communications – straight out of the box. However, there are situations in which you may want to process received serial data in your application. For example, the end of a MODBUS-RTU (MODBUS Remote Terminal Unit) response message is defined as a silent interval or inter-frame delay of at least 3.5 character times (aka. t3.5 or 3.5 char) between successive bytes in the message stream. In applications that require precision serial data timing, this inter-frame delay can cause issues and can be mitigated with additional processing on the receiving end.

The Solution

One solution for applications that require precision timing on the serial stream is to use a callback function with a decrementing timer that resets to a known timing value each time a character is received. When the timer count reaches zero, it generates an interrupt and you know the message frame receipt is complete. Your application can then process the message. NetBurner modules offer a number of timers that can be used for this purpose. The focus of this article will be on the serial interrupt handling.

For this application example to work, a rapid timer reset is essential. Therefore, the key factor is low-latency received character processing to reset or update the timer. Each time a character is received, a serial interrupt occurs and is processed in the serial interrupt service routine. The timer will be reset for each character, and only timeout if the proper gap occurs. You could modify the NetBurner serial port driver code, but a preferred and perhaps lower risk method would be to keep the application-specific code in your project. This can be accomplished with a callback function.

Implementation

The implementation is slightly different between SBL2e-based products and our larger NetBurner platforms such as the SB800 EX (for more detail visit this product comparison table). But in both cases your callback function will be executed in place of the system’s serial driver receive character processing. This means in addition to controlling the timer, your callback function will also need to process the incoming data, since it will no longer be buffered by the NetBurner system. For example, you may want to buffer the incoming characters.

SBL2e Implementation

Note that the serial port must be opened in interrupt mode (not polled mode).

Each time a serial data byte is received it will call your function rather than the system driver. It will happen as soon as the interrupt is serviced, which should be within a few microseconds of when the data byte is received.

There is a complete serial callback example, and Programmable Interval Timer (PIT) example in the ..\nburn\examples\SBL2e folder and is provided after purchase and registration of the device through the support portal. See Appendix A for sample source code.

All Other Platforms

Note that the serial port must be opened in interrupt mode (not polled mode). If you are using a serial port in polled mode, or are uncertain, call the close() function on that serial port and re-open. Anytime an OpenSerial function is called the port will be in interrupt mode.

#include <serialinternal.h>// This function will be called in the ISR for each received serial charactervoid MyReceiveSerialDataCallback(int32_t uartNum, uint8_t dataByte)
{
// Add code to handle received characters// Add code to refresh timer
}
// Open the serial port in the normal way
SimpleOpenSerial(uartNum, baudrate);
// Assign the serial port data handler pointer to your function.
UartData[uartNum].m_pPutCharFunc = MyReceiveSerialDataCallback;

There is a complete serial callback example located at: ..\nburn\examples\StandardStack\serial\SerialReceiveCallback and is provided after purchase and registration of the device through the support portal.

Timer examples are located at ..\nburn\examples\[platform], where [platform] is your specific NetBurner device. See Appendix B for sample source code.