Skip to main content
Kinematrix provides five distinct serial communication modules, each optimized for specific use cases from simple hardware serial to robust packet protocols.

Available Modules

EnhancedSerial

Production-grade serial with buffering and error handling

HardSerial

Simple hardware serial wrapper for basic communication

SoftSerial

Software serial for additional ports (AVR/ESP8266)

SwapSerial

Custom pin mapping for ESP32/ESP8266

NemaSerial

Packet-based protocol with CRC and acknowledgment

Feature Comparison

FeatureEnhancedSerialHardSerialSoftSerialSwapSerialNemaSerial
BufferingCircular bufferString-basedString-basedString-basedPlatform-adaptive
Error HandlingComprehensiveBasicBasicBasicCRC16 + ACK
PlatformAllAllAVR/ESP8266ESP32/ESP8266All
Pin ConfigFixedFixedCustomCustomFixed
Packet ProtocolNoNoNoNoYes
Data TypesTemplateTemplateTemplateTemplateType-safe

EnhancedSerial

Production-grade serial communication with advanced features including buffering, error handling, and asynchronous operations.

Key Features

  • Circular Buffer: Configurable size with overflow protection
  • Error Handling: Timeout, buffer overflow, invalid data detection
  • Stream Interface: Full Arduino Stream compatibility
  • Echo Mode: Debug mode for monitoring communication
  • Callbacks: Asynchronous data handling with callbacks

Class Definition

lib/modules/communication/wired/serial/enhanced-serial.h
class EnhancedSerial : public Stream {
public:
    enum class Error {
        NONE,
        TIMEOUT,
        BUFFER_OVERFLOW,
        INVALID_DATA,
        MEMORY_ERROR
    };
    
    explicit EnhancedSerial(size_t bufferSize = 2);
    ~EnhancedSerial();
    
    void begin(Stream *_serialPtr, unsigned long timeout = 1000);
    
    // Data operations
    template<typename T>
    void addData(T newData, char separator = ';');
    
    void clearData();
    bool sendData();
    bool sendDataCb(void (*onReceive)(const String &));
    String sendDataCbWaitDataWithTimeout(
        void (*onSend)(const String &) = nullptr,
        unsigned long timeout = 1000,
        int maxRetries = 3,
        bool wdtTimeout = false
    );
    
    // Configuration
    void setEcho(bool enable);
    void setAutoClean(bool enable);
    void setTimeout(unsigned long ms);
    
    // Error handling
    Error getLastError() const;
    String getErrorString() const;
};

Basic Usage

#define ENABLE_MODULE_SERIAL_ENHANCED
#include "Kinematrix.h"

EnhancedSerial enhanced(256);  // 256-byte buffer

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
  
  enhanced.begin(&Serial1, 2000);  // 2-second timeout
  enhanced.setEcho(true);          // Enable debug echo
}

void loop() {
  enhanced.clearData();
  enhanced.addData("TEMP");
  enhanced.addData(25.67);
  enhanced.addData(millis());
  
  if (enhanced.sendData()) {
    Serial.println("Data sent successfully");
  } else {
    Serial.print("Error: ");
    Serial.println(enhanced.getErrorString());
  }
  
  delay(5000);
}

Advanced Features

// Send data and wait for response with retry
void onDataSent(const String &data) {
  Serial.println("Sent: " + data);
}

String response = enhanced.sendDataCbWaitDataWithTimeout(
  onDataSent,
  5000,   // 5-second timeout
  3,      // Max 3 retries
  false   // Don't use WDT timeout
);

if (response.length() > 0) {
  Serial.println("Response: " + response);
}

Data Parsing

// Parse received data
String data = "25.5;60.2;1013.25";

float temp = enhanced.getFloat(data, 0, ";");      // 25.5
float humidity = enhanced.getFloat(data, 1, ";");  // 60.2
float pressure = enhanced.getFloat(data, 2, ";");  // 1013.25

HardSerial

Simple hardware serial wrapper providing basic send/receive functionality.

Basic Usage

#define ENABLE_MODULE_SERIAL_HARD
#include "Kinematrix.h"

HardSerial serial;

void setup() {
  Serial.begin(115200);
  serial.begin(&Serial1, 9600);
}

void loop() {
  serial.clearData();
  serial.addData("Sensor1");
  serial.addData(analogRead(A0));
  serial.sendData();
  delay(1000);
}

Asynchronous Communication

void onDataReceived(const String &data) {
  Serial.println("Received: " + data);
  
  float value = serial.getData(data, 0, (char*)";" );
  String id = serial.getStrData(data, 1, (char*)";");
}

void loop() {
  serial.receiveAsync(500, onDataReceived);
}

SoftSerial

Software serial for additional serial ports on AVR and ESP8266 platforms.
ESP32 Not Supported: SoftSerial is not available on ESP32. Use SwapSerial or additional hardware serial ports instead.

Pin-Based Initialization

#if !defined(ESP32)  // Not available on ESP32

#define ENABLE_MODULE_SERIAL_SOFT
#include "Kinematrix.h"

SoftSerial soft;

void setup() {
  Serial.begin(115200);
  
  // Initialize with RX=10, TX=11, 9600 baud
  soft.begin(10, 11, 9600);
}

void loop() {
  soft.clearData();
  soft.addData("GPS");
  soft.addData("Data");
  soft.sendData();
  delay(1000);
}

#endif

Using SoftwareSerial Object

SoftwareSerial mySerial(10, 11);  // RX, TX
SoftSerial soft;

void setup() {
  soft.begin(&mySerial, 9600);
}

SwapSerial

Hardware serial with custom GPIO pin mapping for ESP32 and ESP8266.
ESP32/ESP8266 Only: This module is only available on ESP32 and ESP8266 platforms with flexible GPIO.

GPIO Pin Options (ESP32)

/*
 * Valid ESP32 GPIO pairs for serial:
 * GPIO32/33, GPIO25/26, GPIO27/14, GPIO13/15
 * GPIO21/22, GPIO17/16
 */

Custom Pin Configuration

#if defined(ESP32) || defined(ESP8266)

#define ENABLE_MODULE_SERIAL_SWAP
#include "Kinematrix.h"

SwapSerial swap;

void setup() {
  Serial.begin(115200);
  
  // Configure Serial2 with custom pins
  swap.begin(
    &Serial2,         // Hardware serial port
    115200,           // Baud rate
    SERIAL_8N1,       // Config (8 data, no parity, 1 stop)
    16,               // RX pin
    17                // TX pin
  );
}

void loop() {
  swap.clearData();
  swap.addData("Custom");
  swap.addData(millis());
  swap.sendData(true, true);  // debug=true, endln=true
  delay(1000);
}

#endif

Timeout Control

void setup() {
  swap.begin(&Serial2, 9600, SERIAL_8N1, 16, 17);
  swap.setTimeOut(5000);  // 5-second timeout
}

NemaSerial

Robust packet-based protocol with NMEA-like structure, CRC error detection, and acknowledgment system.

Protocol Features

  • Binary Packet Protocol: Start/end markers with byte stuffing
  • CRC16 Error Detection: Automatic checksum validation
  • ACK/NAK System: Reliable delivery confirmation
  • JSON Support: ArduinoJson integration for structured data
  • Type-Safe Serialization: int8/16/32, uint8/16/32, float, string, bool
  • Platform-Adaptive Buffers: 64B (AVR), 256B (ESP8266), 512B (ESP32)

Packet Structure

[START][SEQUENCE][COMMAND][LENGTH][DATA...][CRC][END]
  0x7E     1B        1B        2B     0-NB    2B   0x7F

Command Set

lib/modules/communication/wired/serial/nema-serial.h
#define CMD_ACK              0x06  // Acknowledgment
#define CMD_NAK              0x15  // Negative acknowledgment
#define CMD_PING             0x01  // Ping request
#define CMD_DATA             0x02  // Generic data
#define CMD_REGISTER_READ    0x03  // Read register
#define CMD_REGISTER_WRITE   0x04  // Write register
#define CMD_JSON_DATA        0x10  // JSON payload
#define CMD_MIXED_DATA       0x11  // Mixed type data
#define CMD_CUSTOM_START     0x40  // Custom commands start here

Data Types

#define DATA_TYPE_INT8       0x01
#define DATA_TYPE_INT16      0x02
#define DATA_TYPE_INT32      0x03
#define DATA_TYPE_UINT8      0x04
#define DATA_TYPE_UINT16     0x05
#define DATA_TYPE_UINT32     0x06
#define DATA_TYPE_FLOAT      0x07
#define DATA_TYPE_STRING     0x08
#define DATA_TYPE_BOOL       0x09

Basic Packet Communication

#define ENABLE_MODULE_SERIAL_NEMA
#include "Kinematrix.h"

NemaSerial nema;

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
  
  nema.begin(&Serial1, 256);  // 256-byte buffer
  nema.setRequireAck(true);   // Enable acknowledgments
  nema.setMaxRetries(3);      // Retry up to 3 times
  nema.setTimeout(1000);      // 1-second timeout
}

void loop() {
  // Build and send packet
  nema.beginPacket()
      .writeFloat(25.67)        // Temperature
      .writeFloat(60.2)         // Humidity
      .writeString("SENSOR_01") // Device ID
      .writeBool(true)          // Status OK
      .endPacket(CMD_DATA);
  
  delay(5000);
}

Receiving Packets

void onPacketReceived(uint8_t command, uint8_t *data, uint16_t length) {
  Serial.print("Command: 0x");
  Serial.println(command, HEX);
  
  if (command == CMD_DATA) {
    uint16_t index = 0;
    float temp = nema.readFloat(data, &index);
    float humidity = nema.readFloat(data, &index);
    String deviceId = nema.readString(data, &index);
    bool status = nema.readBool(data, &index);
    
    Serial.print("Temperature: ");
    Serial.println(temp);
    Serial.print("Humidity: ");
    Serial.println(humidity);
    Serial.print("Device: ");
    Serial.println(deviceId);
  }
}

void setup() {
  // ... previous setup ...
  nema.setPacketHandler(onPacketReceived);
}

void loop() {
  nema.processIncoming();  // Check for incoming packets
}

JSON Communication

#include <ArduinoJson.h>

void sendJsonData() {
  StaticJsonDocument<200> doc;
  doc["sensor"] = "DHT22";
  doc["temp"] = 25.67;
  doc["humidity"] = 60.2;
  doc["timestamp"] = millis();
  
  nema.sendJson(doc, CMD_JSON_DATA);
}

void onJsonReceived(JsonDocument &doc) {
  const char* sensor = doc["sensor"];
  float temp = doc["temp"];
  float humidity = doc["humidity"];
  
  Serial.print("Sensor: ");
  Serial.println(sensor);
  Serial.print("Temp: ");
  Serial.println(temp);
}

void setup() {
  nema.begin(&Serial1, 512);
  nema.setJsonHandler(onJsonReceived);
}

Debugging and Statistics

void setup() {
  nema.begin(&Serial1, 256);
  nema.setDebugLevel(DEBUG_VERBOSE);  // DEBUG_NONE, DEBUG_ERRORS, DEBUG_INFO, DEBUG_VERBOSE
  nema.setDebugStream(Serial);        // Output debug to Serial
}

void loop() {
  // ... communication ...
  
  // Print statistics every 10 seconds
  static unsigned long lastStats = 0;
  if (millis() - lastStats > 10000) {
    lastStats = millis();
    nema.dumpStats();
  }
}

Error Handling

void onError(uint8_t errorCode) {
  Serial.print("Error: ");
  Serial.println(nema.getErrorString(errorCode));
}

void setup() {
  nema.begin(&Serial1, 256);
  nema.setErrorHandler(onError);
}

// Error codes
// ERR_NONE, ERR_TIMEOUT, ERR_CRC, ERR_LENGTH,
// ERR_COMMAND, ERR_BUFFER_OVERFLOW, ERR_FORMAT,
// ERR_SEQUENCE, ERR_BUSY, ERR_JSON, ERR_MEMORY

Platform-Specific Notes

Available Modules: EnhancedSerial, HardSerial, SwapSerial, NemaSerial
// Multiple hardware serial ports
Serial   // USB (GPIO1/3)
Serial1  // GPIO9/10 (typically flash)
Serial2  // GPIO16/17 (configurable)

// NemaSerial buffer
#define DEFAULT_BUFFER_SIZE 512
#define DEFAULT_CHUNK_SIZE 128

Use Case Selection Guide

  • You need robust error handling
  • Working with high-speed data streams
  • Require buffering to prevent data loss
  • Need timeout detection and retry logic
  • Building production systems
  • Simple point-to-point communication
  • Minimal overhead is required
  • Basic send/receive is sufficient
  • Educational or prototype projects
  • Need multiple serial ports on AVR
  • Hardware serial is unavailable
  • Low-speed communication (<9600 baud)
  • GPS, simple sensors, or debugging
  • Need custom GPIO pins (ESP32/ESP8266)
  • Default pins conflict with other hardware
  • Multiple hardware serial ports required
  • High-speed communication needed
  • Reliability is critical
  • Working in noisy environments
  • Need guaranteed delivery (ACK/NAK)
  • Structured data with type safety
  • JSON communication required
  • Industrial or medical applications

Common Patterns

Request-Response Pattern

// Master sends request
void sendRequest() {
  serial.clearData();
  serial.addData("READ");
  serial.addData("TEMP");
  serial.sendData();
}

// Slave responds
void onRequest(const String &data) {
  String command = serial.getStrData(data, 0, (char*)";");
  
  if (command == "READ") {
    serial.clearData();
    serial.addData("TEMP");
    serial.addData(25.67);
    serial.sendData();
  }
}

Heartbeat Pattern

unsigned long lastHeartbeat = 0;
const unsigned long HEARTBEAT_INTERVAL = 5000;

void loop() {
  if (millis() - lastHeartbeat > HEARTBEAT_INTERVAL) {
    lastHeartbeat = millis();
    
    serial.clearData();
    serial.addData("HEARTBEAT");
    serial.addData(millis() / 1000);  // Uptime
    serial.sendData();
  }
}

Modbus Protocol

Industrial serial protocol with Modbus

I2C Communication

Alternative wired protocol for sensors

Build docs developers (and LLMs) love