Skip to content

Instantly share code, notes, and snippets.

@doevelopper
Created May 9, 2024 12:38
Show Gist options
  • Save doevelopper/16139315f36d3bc1157957ff0341ad17 to your computer and use it in GitHub Desktop.
Save doevelopper/16139315f36d3bc1157957ff0341ad17 to your computer and use it in GitHub Desktop.
I2C, SPI,RS232

In Object-Oriented Programming (OOP) with respect to the SOLID design pattern, you can abstract I2C, SPI, and RS232 communication by creating interfaces (abstract classes) for each communication protocol. The interfaces would define methods for reading and writing data, as well as setting up the communication parameters.Here's an example in C++, using the Boost.Asio library for non-blocking I/O:

#include <boost/asio.hpp>

class I2CInterface 
{
protected: 
    boost::asio::io_context io_context; 
    boost::asio::i2c_base::address address;
public: 
    I2CInterface(boost::asio::i2c_base::address address) 
      : address(address)
        , io_context() 
      {} 
    virtual bool writeBytes(const std::vector<uint8_t>& data) = 0; 
    virtual bool readBytes(std::vector<uint8_t>& buffer) = 0;
};
class SPIInterface 
{
protected: 
    boost::asio::io_context io_context; 
    boost::asio::spi_base::clock_polarity polarity; 
    boost::asio::spi_base::clock_phase phase;
public: 
    SPIInterface(boost::asio::spi_base::clock_polarity polarity, boost::asio::spi_base::clock_phase phase) 
      : polarity(polarity), phase(phase)
      , io_context() {} 
    virtual bool writeBytes(const std::vector<uint8_t>& data) = 0; 
    virtual bool readBytes(std::vector<uint8_t>& buffer) = 0;};

};
class RS232Interface 
{

protected: 
    boost::asio::io_context io_context; 
    int baud_rate;
public: 

    RS232Interface(int baud_rate) : baud_rate(baud_rate), io_context() {} 
    virtual bool writeBytes(const std::vector<uint8_t>& data) = 0; 
    virtual bool readBytes(std::vector<uint8_t>& buffer) = 0;
};

With these interfaces, you can create concrete classes that inherit from I2CInterface, SPIInterface, and RS232Interface and implement the required methods. This design adheres to the SOLID principles:Single Responsibility Principle: Each interface or class handles one type of communication.Open/Closed Principle: You can easily add new communication types by creating new classes that inherit from the existing interfaces.Liskov Substitution Principle: The client code that uses these interfaces can use objects of any subclass without knowing the difference.Interface Segregation Principle: Each interface is small, and only contains methods that are necessary for a particular type of communication.Dependency Inversion Principle: High-level modules should not depend on low-level modules. Both should depend on abstractions.

@doevelopper
Copy link
Author

Here's an example in C++ using Boost.Asio for non-blocking I/O:
```cpp
#include <boost/asio.hpp>
#include <iostream>

// Abstract interface for communication protocols
class Communicator {
public:
    virtual ~Communicator() {}

    // Start the communication protocol
    virtual void start() = 0;

    // Stop the communication protocol
    virtual void stop() = 0;

    // Read data from the communication channel
    virtual int read(int size) = 0;

    // Write data to the communication channel
    virtual void write(const char* data, int size) = 0;
};

// Interface for I2C communication (e.g., using a library like i2c-dev)
class II2CCommunicator : public Communicator {
public:
    II2CCommunicator(boost::asio::io_service& ioService) {}

    void start() override {
        // Initialize the I2C bus
    }

    void stop() override {
        // Stop the I2C bus
    }

    int read(int size) override {
        // Read data from the I2C bus using a library like i2c-dev
        return 0;
    }

    void write(const char* data, int size) override {
        // Write data to the I2C bus using a library like i2c-dev
    }
};

// Interface for SPI communication (e.g., using a library like spi-dev)
class ISPICommunicator : public Communicator {
public:
    ISPICommunicator(boost::asio::io_service& ioService) {}

    void start() override {
        // Initialize the SPI bus
    }

    void stop() override {
        // Stop the SPI bus
    }

    int read(int size) override {
        // Read data from the SPI bus using a library like spi-dev
        return 0;
    }

    void write(const char* data, int size) override {
        // Write data to the SPI bus using a library like spi-dev
    }
};

// Example usage with I2C and SPI communicators
int main() {
    boost::asio::io_service ioService;

    II2CCommunicator i2cComm(ioService);
    ISPICommunicator spiComm(ioService);

    // Start the communication protocols
    i2cComm.start();
    spiComm.start();

    // Read and write data using the communicators
    int bytesRead = i2cComm.read(10);  // Read 10 bytes from I2C bus
    char* writtenData = "Hello, SPI!";
    spiComm.write(writtenData, strlen(writtenData));  // Write a string to SPI bus

    // Stop the communication protocols
    i2cComm.stop();
    spiComm.stop();

    return 0;
}

In this example, we define an abstract Communicator interface that provides methods for starting, stopping, reading, and writing data. We then create concrete implementations of this interface for I2C (II2CCommunicator) and SPI (ISPICommunicator)
communication protocols.

By using interfaces to decouple the application logic from the specific implementation details, we can easily add or modify communication protocols in the future without affecting the rest of the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment