Commit 0b6e6098 authored by Gallacchi Mattia's avatar Gallacchi Mattia
Browse files

First commit

parents
Loading
Loading
Loading
Loading

.gitignore

0 → 100644
+3 −0
Original line number Diff line number Diff line
build/
.vscode/
 No newline at end of file

CMakeLists.txt

0 → 100644
+11 −0
Original line number Diff line number Diff line
cmake_minimum_required(VERSION 3.20)

project(mcp2221a LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD_REQUIRED 11)

include_directories(lib)

add_subdirectory(lib)
add_subdirectory(tests)
 No newline at end of file

README.md

0 → 100644
+69 −0
Original line number Diff line number Diff line
# MCP2221A libraries

Support for user space usage of the [MCP2221A][1] IC from Microchip. 


## Linux

To access the USB device you must add the following rule under */etc/udev/rules.d/* (i.e in a file called mcp2221a.rules) :

```bash
SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00dd", GROUP="plugdev", TAG+="uaccess"
```

You must reboot after this.

To access the I2C devices loaded by the [*mcp2221*][2] kernel driver you must add your user to the *i2c* group:

```bash
sudo usermod -aG i2c $USER
```

You must login again in order for the changes to take effect.

To access the Serial device you must add your user to the *dialout* group:

```bash
sudo usermod -aG dialout $USER
```

You must login again in order for the changes to take effect.

## Dependencies

```bash
sudo apt install -y libi2c-dev
```

## Build

Standard **CMAKE**:

```bash
mkdir build && cd build
cmake ..
make
```

## Try it out

Run the test software found in the tests folder. Expected result is:

```bash
./build/tests/test

Testing serial (115200, 1s): Success
Testing serial (9600, 1s): Success
Testing serial (9600, 0.1s): Success
Testing I2C: Success
```

## TODO

- [ ] Add python library 
- [ ] Add Windows support
- [ ] Add hidapi support

[1]:http://ww1.microchip.com/downloads/en/devicedoc/20005565b.pdf
[2]:https://github.com/torvalds/linux/blob/master/drivers/hid/hid-mcp2221.c
 No newline at end of file

lib/CMakeLists.txt

0 → 100644
+6 −0
Original line number Diff line number Diff line
cmake_minimum_required(VERSION 3.20)

file(GLOB SRC *.cpp)
add_library(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME} i2c)
 No newline at end of file

lib/mcp2221a.h

0 → 100644
+202 −0
Original line number Diff line number Diff line
#pragma once

#include <stdexcept>
#include <vector>
#include <string>

#define MCP2221_NAME        "MCP2221 USB-I2C/UART Combo"

namespace MCP2221A {

    class MCP2221AException : public std::exception {
        private:

        std::string msg_;

        public:

        MCP2221AException(std::string msg) : msg_(msg) {}

        virtual const char* what() const throw()
        {
            return msg_.c_str();
        }
    };

    class I2CMasterException : public MCP2221AException { using MCP2221AException::MCP2221AException; };
    class SerialException : public MCP2221AException { using MCP2221AException::MCP2221AException; };
    class TimeoutException : public MCP2221AException { using MCP2221AException::MCP2221AException; };

    /**
     * @brief I2CMaster class to control the MCP2221A I2C port
     * 
     */
    class I2CMaster {

        private:

        int fd_;
        std::string mcp2221a_path_;
        uint8_t current_slave_addr_;
        std::vector<int> slaves_addr_;

        /**
         * @brief Scan the I2C bus looking for available devices
         * 
         */
        void scan_bus();

        /**
         * @brief Set the slave address
         * 
         * @param addr 7 bit slave address
         * 
         * @throw I2CMasterException if it fails
         */
        void set_slave_address(uint8_t addr);

        /**
         * @brief Not implemented
         * 
         * @param addr 
         * @return true 
         * @return false 
         */
        bool check_slave_connected(uint8_t addr);

        public:

        /**
         * @brief Construct a new I2CMaster object.
         * 
         * @throw I2CMasterException if it fails to open the device. Often this is cause by user rights be sure that your user
         * in the i2c group. This behavior can also be observed just after the device connection cause the driver is loading the
         * device and the rights have not yet been updated.
         * @throw I2CMasterException if device not found or not connected. Connect the usb to your machine.
         */
        I2CMaster();

        /**
         * @brief Destroy the I2CMaster object
         * 
         */
        ~I2CMaster();

        /**
         * @brief Write data to the I2C slave.
         * 
         * @param slave_addr Slave 7-bit address
         * @param data Byte array of data to send
         * @param length Number of bytes to send
         * 
         * @throw I2CMasterException if an error occurs
         */
        void send(uint8_t slave_addr, uint8_t *data, size_t length);

        /**
         * @brief Read data from the I2C slave.
         * 
         * @param slave_addr Slave 7-bit address
         * @param data Buffer to be filled
         * @param length Number of bytes to read
         * 
         * @throw I2CMasterException if an error occurs
         */
        void receive(uint8_t slave_addr, uint8_t *data, size_t length);

        /**
         * @brief Get the slaves addresses found on the I2C bus
         * 
         * @param force_scan Re-scan the bus
         * 
         * @return std::vector<int> Slave addresses. List can be empty if no slave are found
         */
        std::vector<int> get_slaves_addresses(bool force_scan = false);
    };

    /**
     * @brief Serial class to control the MCP2221A UART functionalities
     * 
     */
    class Serial {

        public:

        enum BAUD {
            B_300,
            B_1200,
            B_2400,
            B_4800,
            B_9600,
            B_19200,
            B_38400,
            B_57600,
            B_115200,
            B_230400,
            B_460800
        };
        
        private:
        int fd_;
        std::string port_;
        BAUD baudrate_;
        uint8_t read_timeout_;

        public:
        /**
         * @brief Construct a new Serial. This object gives access to the MCP2221A serial port
         * 
         * @param port Port name. In linux it should be ttyACM<X> where X is a number 0,1,2,etc...
         * @param baudrate Baudrate. Supported baudrates are listed in the BAUD enum
         * 
         * @throw SerialException if something fails.
         */
        Serial(std::string port = "ttyACM0", BAUD baudrate = B_115200);

        /**
         * @brief Destroy the Serial.
         * 
         */
        ~Serial();
        
        /**
         * @brief Write data to the serial port
         * 
         * @param data Byte array of data to send
         * @param length Number of bytes to send
         * 
         * @throw SerialException if an error occurs
         */
        void send(uint8_t *data, size_t length);

        /**
         * @brief Read data from the serial port
         * 
         * @param data Buffer to be filled.
         * @param length Number of bytes to read
         * 
         * @throw SerialException if an error occurs
         * @throw TimeoutException if no data or not enough data is received
         */
        void receive(uint8_t *data, size_t length);

        /**
         * @brief Set the baudrate of the serial port
         * 
         * @param baudrate Serial port baudrate
         * 
         * @throw SerialException if an error occurs
         */
        void set_baudrate(BAUD baudrate);

        /**
         * @brief Set the timeout 
         * 
         * @param timeout Timeout value in deciseconds (0.1s). A value of 0 will be interpreted as no timeout. Max value is 255 or 25.5s
         * 
         * @throw SerialException if an error occurs
         */
        void set_timeout(uint8_t timeout);
    };
}
 No newline at end of file