Embedded Expertise

Bus Your Way to Better Embedded Systems

Communication between processes, applications, or even computers is crucial for creating modular and flexible software architectures. But when it comes to implementing this communication, developers are often faced with a multitude of choices—each with its own set of complexities. This article explores how software buses simplify this challenge, making inter-component communication more structured and scalable.

Conventional Communication Methods

Communication between processes or applications is at the core of any modern embedded system. Traditionally, developers have relied on mechanisms like raw sockets, named pipes, or other point-to-point solutions to connect software components.

Young and ambitious software architects are often tempted to build a bespoke communication infrastructure on top of these traditional low-level facilities. However, this frequently results in reinventing the wheel and introduces unnecessary complexity. These methods are cumbersome, as they encourage the proliferation of different link types, require custom handling for each connection, lack scalability, and ultimately make the entire architecture harder to scale and maintain. It’s like building a highway system, but reinventing each piece of asphalt for every new road.

What is a Software Bus?

Enter the software bus—a software component that ensures the connectivity between other components. This structured approach to inter-service communication abstracts away many of the complexities of traditional methods. A bus is essentially a shared communication layer that multiple processes or applications can use, providing a standardized API and simplifying the process of connecting new components. This rationalization brings several advantages:

  • Reduced complexity: Simplifies development by minimizing the need for custom communication code. While the bus exposes a simple communication API, it silently handles underlying complexities such as signaling, notification mechanisms, and other intricate synchronization challenges such as race conditions.

  • Ease of adding new nodes: New components can be integrated seamlessly, often requiring minimal or no modifications to the existing system.

  • Improved maintainability: Standardized communication makes the system easier to maintain and debug. Instead of building new communication paths from scratch, a bus offers a plug-and-play model for software interactions.

Example: A Simple Multi-Process Application

If the notion of software bus is still foggy, let a simple example do the talking.

Consider an embedded application consisting of just two components:

  • Temperature Sensor: Read data from a temperature sensor (or more precisely, from its driver).

  • Display Engine: Acquire the temperature readings and display them on a local screen.

While this simple application could easily be implemented as a single process, let’s explore how it scales when we add more complexity. Consider expanding this simple system with these additional features:

  • Add a speed sensor whose reading can be displayed on the screen along with the temperature;
  • Log the temperature and speed readings in a local database storage;
  • Monitor the operation of the temperature sensor, speed sensor, database storage and display engine, display the results and log them in the database.

This setup is still quite modest with only two data sources and typical logging facilities. Let’s visualize a traditional point-to-point architecture for this expanded system:

This approach quickly becomes complex and difficult to maintain as the system grows. It suffers from:

  • Tight coupling: Components are tightly coupled, making it hard to modify or replace one without affecting others.
  • Scalability issues: Adding new components or features requires significant changes to the existing code.
  • Debugging challenges: Isolating issues can be difficult due to the intricate connections.

A software bus provides a more flexible and scalable solution:

This bus architecture provides the following benefits:

  • Decoupling: The processes don’t need to know each other’s implementation details.

  • Scalability: Additional processes (e.g., debug or alert processes) can easily subscribe to the temperature and speed data without modifying the existing code. Adding a new sensors would be also straightforward—these new processes would publish their data to the same shared bus, and any interested components could subscribe without major changes to the existing architecture.

  • Standardized API: All processes can use a consistent API, simplifying development and reducing errors.

Classification of Software Buses

Software buses come in various forms, each tailored to the specific context and constraints of the system. The choice of bus depends on factors such as system scale, performance requirements, and the type of communication needed. We can attempt to classify software buses along several dimensions:

  • Throughput Metrics:

    • Volume of Data: The amount of data the bus can handle effectively.

    • Speed of Transfer: The rate at which data can be transferred across the bus.

    • Jitter: The variability in time delay for data transfer, which can impact time-sensitive applications.

    • Real-Time Capability: The ability of the bus to meet stringent timing requirements, crucial for real-time embedded systems.

  • Mode of Communication:

    • Synchronous: In synchronous communication—like Remote Procedure Calls (RPC)—one component waits for another to respond, creating a tightly coupled system.

    • Asynchronous: In asynchronous communication, components notify each other without waiting, fostering loose coupling and greater resilience.

  • Scope of Communication:

    • Inter-Process: Communication across the different processes that make up an application.

    • Inter-Application: Communication across the different applications that make up a system.

  • Bus Reach:

    • Local Bus: Integrates multiple processes or applications that run within a single computing domain (e.g., CPU), providing efficient communication and simplifying internal interactions.

    • Distributed Bus: Facilitates communication across multiple devices, typically over a routable network, enabling seamless data exchange between distributed components while maintaining scalability and resilience

What Types of Payloads Can a Software Bus Handle?

Most software buses are payload agnostic: they simply transport data to the point of delivery without concerning themselves with the data’s content. However, there are common types of payloads that are frequently used:

  • Text-Formatted Data: Commonly used formats such as JSON, YAML, or XML are easy to read and understand, making them ideal for human-friendly configuration, logging, or data exchange. These formats are particularly useful when interoperability and readability are priorities. They however need elaborate message builder and parser that may consume precious resources.

  • Binary-Formatted Data: Formats like Protocol Buffers (Protobuf), or MessagePack offer efficient serialization of data into a compact binary format. Binary formats are suitable when performance, minimal bandwidth usage, and faster parsing are important. They are however not human-readable and require specific debug tools.

  • Raw Data: In some cases, the bus conveys raw data, such as a stream of bytes. This can be useful for transferring data like binary blobs, sensor streams, or any data that does not require structured formatting. Raw data is often used in scenarios where speed is critical and additional overhead is undesirable.

  • Command or Control Messages: A bus can also convey specialized command or control messages to trigger specific actions or control states in different components. These messages are often lightweight and may use a combination of text or binary formatting depending on the system’s requirements.

The choice of payload format depends on factors such as the communication overhead, ease of integration, processing requirements, and whether the data needs to be human-readable or optimized for machine parsing.

The Future of Embedded Systems: A Bus-Driven Approach

As we’ve briefly explored, software buses offer a robust and efficient solution for inter-process communication in embedded systems. By adopting this architectural approach, developers can create more modular, scalable, and maintainable systems.

In a coming article, we’ll delve deeper into a sampler of specific bus implementations, examining their strengths, weaknesses, and typical use cases. By understanding these tools and their applications, you can make informed decisions to build cutting-edge, future-proof embedded systems that meet the demands of today’s and tomorrow’s complex technological landscape.