diff --git a/CMakeLists.txt b/CMakeLists.txt index 76b101a..1498816 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12) project(SPI) set(CMAKE_CXX_STANDARD 20) -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -ludev -Da4963_debug") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -ludev -O3 -Da4963_debug") include_directories(.) include_directories(inc) @@ -17,8 +17,8 @@ add_executable(hid main.cpp) find_library(LIBUSB_LIBRARY NAMES usb-1.0) -find_library(LIBEVPP - NAMES libevpp.so) +find_library(UDEV + NAMES libudev.so) find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h @@ -44,32 +44,6 @@ FIND_LIBRARY( ${UDEV_PATH_LIB} ) -IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) - SET(UDEV_FOUND "YES") - execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE) - # retvale is 0 of the condition is "true" so we need to negate the value... - if (UDEV_STABLE) - set(UDEV_STABLE 0) - else (UDEV_STABLE) - set(UDEV_STABLE 1) - endif (UDEV_STABLE) - MESSAGE("udev linked") - message(STATUS "libudev stable: ${UDEV_STABLE}") -ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) - -IF (UDEV_FOUND) - MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") - MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") -ELSE (UDEV_FOUND) - MESSAGE(STATUS "UDev not found.") - MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") - MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") - MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib") - MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") - IF (UDev_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find UDev library") - ENDIF (UDev_FIND_REQUIRED) -ENDIF (UDEV_FOUND) ## Include Directories @@ -91,7 +65,7 @@ include_directories(src/CustomDataTypes) add_subdirectory(src/CustomDataTypes) # LIBEVPP -target_link_libraries(hid src spi usbb inc utils scales a4963 cdt ${LIBUSB_LIBRARY}) +target_link_libraries(hid src spi usbb inc utils scales a4963 cdt ${UDEV} ${LIBUSB_LIBRARY}) #add_executable(SPI # inc/mcp2210_api.c diff --git a/README.md b/README.md index 88bc7f9..1d993da 100644 --- a/README.md +++ b/README.md @@ -1 +1,45 @@ -hid +# Unofficial A4963 Flashing Software + +This is an unofficial free A4963 flashing Software for Linux. + +Used Libaries: + - [nlohmann JSON](https://github.com/nlohmann/json) + - [MCP2210 Linux Libary](https://www.microchip.com/wwwproducts/en/MCP2210) + - [cxxopts](https://github.com/jarro2783/cxxopts/blob/master/include/cxxopts.hpp) + - [spdlog](https://github.com/gabime/spdlog) + +### Build +```sh +$ cd A4963 +$ cmake . +$ make . +``` + +### Commands + +| Plugin | README | +| ------ | ------ | +| -h, --help | Shows all command line arguments | +| -d, --debug | Enables debug output | +| -j, --json [file] | Selects the json file to read from | +| -g, --generate | Generates a default json file on startup, this will take -j location, if existing | +| -f, --force | This will overwrite any exiting settings file. Only possible if -g is specified | +| -c, --client | This will enable interactive client mode | +| -i, --interface [interface] | Select the interface to flash from. Possible values: "mcp" and "atmega" | +| -s, --settings-check | Only check if the settings file syntax is correct. This will **not** flash any data to the chip, even if an interface is specified! | + +#### Examples: +```sh +# Read from config.json and flash with mcp2210 +$ ./hid --json config.json --interface mcp +# same as above +$ ./hid -j config.json -i mcp +# additionally force generate config.json and show debug output +$ ./hid -gfd -j config.json -i mcp +``` + +### Development + +- This Software is written in C++17 +- Currently only tested on gcc +- A Windows build is available in the "Windows" branch. This branch is **not up to date**! If you want to use this software on Windows you can either open a ticket and I'll port it to the newest version if there is enough demand or help me port it by forking the repository and doing a pull-request. diff --git a/main.cpp b/main.cpp index ba31f76..5b7bcf6 100644 --- a/main.cpp +++ b/main.cpp @@ -13,6 +13,7 @@ #include "src/SPI/ATmega32U4SPI.h" #include "src/SPI/SPIBridge.h" #include "inc/json.h" + #ifdef __linux__ #include "mcp2210_api.h" #include "src/SPI/mcp2210_hal.h" @@ -22,7 +23,7 @@ #include "src/Devices/A4963/DeserializeA4963.h" #include "src/utils/scales/UnitScale.h" -int consoleInterface(const std::string& spiDevice); +int consoleInterface(const std::string& spiDevice,const std::string& config); void flashJSON(const std::string& spiDevice, const std::string& filename, bool enable_debug = false); int simpleInput(int min, int max); int serverInterface(const char* spiDevice); @@ -31,7 +32,8 @@ void parseArguments(int argc, char** argv); static inline constexpr int nrOfOptions = 5; void clearInput(); -void loadFromFile(std::shared_ptr& device, const std::string& filename, bool enable_debug = false); +void flashFileFromDevice(std::shared_ptr &device, const std::string &filename, + bool enable_debug = false); void setRegisterVal(std::shared_ptr& device); void showRegisterVal(std::shared_ptr& device); bool generateDefault(bool force = false, const std::string& filename = "config.json"); @@ -94,7 +96,11 @@ void parseArguments(int argc, char** argv) { if(result.count("client") > 0 && result.count("interface") > 0) { auto interface = result["interface"].as(); - consoleInterface(interface); + if(result.count("json") > 0) + consoleInterface(interface,result["json"].as()); + else{ + consoleInterface(interface,"config.json"); + } return; } else if(result.count("client") > 0 && result.count("interface") <= 0) { std::cout << "Missing Parameter: --interface!" << std::endl; @@ -161,8 +167,8 @@ void flashJSON(const std::string& spiDevice, const std::string& filename, bool e return; } } else if(spiDevice == "mcp") { - spi = std::make_shared(); - pin = MCP2210::pin0; + spi = std::make_shared>(); + pin = MCP2210<>::pin0; } else if(spiDevice.empty()) { spi = nullptr; } @@ -171,10 +177,10 @@ void flashJSON(const std::string& spiDevice, const std::string& filename, bool e if(spi) spi->slaveRegister(device, pin); - loadFromFile(device, filename, enable_debug); + flashFileFromDevice(device, filename, enable_debug); } -int consoleInterface(const std::string& spiDevice){ +int consoleInterface(const std::string& spiDevice, const std::string& config){ std::shared_ptr device; std::shared_ptr spi; usb::LibUSBDeviceList deviceList; @@ -190,17 +196,17 @@ int consoleInterface(const std::string& spiDevice){ return 0; } } else { - std::shared_ptr dev = std::make_shared(); + std::shared_ptr> dev = std::make_shared>(); while(!*dev){ std::cout << " device not connected, try again?: y/n" << std::endl; std::string str; - std::cin >> str; + std::getline(std::cin,str); if(str == "y") dev->connect(); else break; } spi = dev; - pin = MCP2210::pin0; + pin = MCP2210<>::pin0; } device = std::make_shared(spi); spi->slaveRegister(device, pin); @@ -210,7 +216,7 @@ int consoleInterface(const std::string& spiDevice){ int choice = simpleInput(1, nrOfOptions); switch (choice) { case 1: { - loadFromFile(device, "config.json"); + flashFileFromDevice(device, config); break; } case 2: { @@ -273,7 +279,7 @@ bool generateDefault(bool force, const std::string& filename){ void setRegisterVal(std::shared_ptr& device){ std::cout << "Enter the name of the register you want to set, or \"exit\" to cancel" << std::endl; std::string str; - NS_A4963::A4963RegisterNames mask; + NS_A4963::A4963RegisterNames mask{}; while(true) { std::getline(std::cin,str); if (str == "exit") break; @@ -297,7 +303,7 @@ void setRegisterVal(std::shared_ptr& device){ } } -void loadFromFile(std::shared_ptr& device, const std::string& filename, bool enable_debug){ +void flashFileFromDevice(std::shared_ptr &device, const std::string &filename, bool enable_debug){ using namespace nlohmann; using namespace NS_A4963; diff --git a/src/CustomDataTypes/Hertz.h b/src/CustomDataTypes/Hertz.h index d529479..936b7db 100644 --- a/src/CustomDataTypes/Hertz.h +++ b/src/CustomDataTypes/Hertz.h @@ -18,7 +18,7 @@ namespace CustomDataTypes::Frequency { using parent_type = SIUnit, Rep, Period>; public: static constexpr std::string_view abr_value = "Hz"; - constexpr explicit Hertz(Rep input) : parent_type{input} {} + constexpr explicit Hertz(Rep input) noexcept : parent_type{input} {} }; using nanohertz = Hertz; @@ -33,51 +33,51 @@ namespace CustomDataTypes::Frequency { using exahertz = Hertz; namespace literals { - constexpr nanohertz operator ""_nHz(unsigned long long element) { + constexpr nanohertz operator ""_nHz(unsigned long long element) noexcept { return nanohertz(static_cast(element)); } - constexpr Hertz operator ""_nHz(long double element) { + constexpr Hertz operator ""_nHz(long double element) noexcept { return Hertz(element); } - constexpr microhertz operator ""_uHz(unsigned long long element) { + constexpr microhertz operator ""_uHz(unsigned long long element) noexcept { return microhertz(static_cast(element)); } - constexpr Hertz operator ""_uHz(long double element) { + constexpr Hertz operator ""_uHz(long double element) noexcept { return Hertz(element); } - constexpr millihertz operator ""_mHz(unsigned long long element) { + constexpr millihertz operator ""_mHz(unsigned long long element) noexcept { return millihertz(static_cast(element)); } - constexpr Hertz operator ""_mHz(long double element) { + constexpr Hertz operator ""_mHz(long double element) noexcept { return Hertz(element); } - constexpr hertz operator ""_Hz(unsigned long long element) { + constexpr hertz operator ""_Hz(unsigned long long element) noexcept { return hertz(static_cast(element)); } - constexpr Hertz operator ""_Hz(long double element) { + constexpr Hertz operator ""_Hz(long double element) noexcept { return Hertz(element); } - constexpr kilohertz operator ""_kHz(unsigned long long element) { + constexpr kilohertz operator ""_kHz(unsigned long long element) noexcept { return kilohertz(static_cast(element)); } - constexpr Hertz operator ""_kHz(long double element) { + constexpr Hertz operator ""_kHz(long double element) noexcept { return Hertz(element); } - constexpr megahertz operator ""_MHz(unsigned long long element) { + constexpr megahertz operator ""_MHz(unsigned long long element) noexcept { return megahertz(static_cast(element)); } - constexpr Hertz operator ""_MHz(long double element) { + constexpr Hertz operator ""_MHz(long double element) noexcept { return Hertz(element); } } diff --git a/src/CustomDataTypes/Percentage.h b/src/CustomDataTypes/Percentage.h index 1a84906..5558a3c 100644 --- a/src/CustomDataTypes/Percentage.h +++ b/src/CustomDataTypes/Percentage.h @@ -4,8 +4,8 @@ #pragma once #include -#include -#include +#include +#include #include namespace CustomDataTypes { @@ -17,34 +17,33 @@ namespace CustomDataTypes { public: static constexpr std::string_view abr_value = "%"; using value_type = accuracy; - constexpr inline Percentage() = default; - constexpr inline explicit Percentage(accuracy percent) : mPercentage(percent){}; + constexpr inline Percentage() noexcept = default; + constexpr inline explicit Percentage(accuracy percent) noexcept : mPercentage(percent){}; constexpr Percentage(Percentage&& other) noexcept : Percentage() { this->swap(other);}; - constexpr inline Percentage(const Percentage& other) : mPercentage(other.mPercentage) {}; - constexpr inline accuracy getPercent() const { return mPercentage; }; - constexpr explicit operator accuracy() const { + constexpr inline Percentage(const Percentage& other) noexcept : mPercentage(other.mPercentage) {}; + constexpr inline accuracy getPercent() const noexcept { return mPercentage; }; + + [[nodiscard]] constexpr value_type get() const noexcept { return mPercentage; } - - template - constexpr explicit operator T() const { + constexpr explicit operator T() const noexcept { static_assert(std::is_arithmetic(), "cannot cast to a non arithmetic type"); return (T)mPercentage; } - constexpr Percentage& set(accuracy percent){mPercentage = percent; return *this;}; - constexpr Percentage& operator+=(const Percentage& other){ + constexpr Percentage& set(accuracy percent) noexcept {mPercentage = percent; return *this;}; + constexpr Percentage& operator+=(const Percentage& other) noexcept { this->mPercentage += other.mPercentage; return *this; } - constexpr Percentage& operator*=(const Percentage& other){ + constexpr Percentage& operator*=(const Percentage& other) noexcept { this->mPercentage = (this->mPercentage*other.mPercentage)/100; return *this; } template - constexpr Percentage& operator*=(const Skalar skalar){ + constexpr Percentage& operator*=(const Skalar skalar) noexcept { static_assert(std::is_arithmetic(), "cannot multiplicate from a non arithmetic type"); if(skalar >= 0) this->mPercentage = mPercentage * skalar; @@ -52,18 +51,18 @@ namespace CustomDataTypes { this->mPercentage = mPercentage * -skalar; return *this; } - constexpr Percentage& operator-=(const Percentage& other){ + constexpr Percentage& operator-=(const Percentage& other) noexcept { if(other.mPercentage <= this->mPercentage) this->mPercentage -= other.mPercentage; else this->mPercentage = 0; return *this; } - constexpr Percentage& operator/=(const Percentage& other){ + constexpr Percentage& operator/=(const Percentage& other) noexcept { this->mPercentage = (this->mPercentage/other.mPercentage)/100; return *this; } template - constexpr Percentage& operator/=(const Skalar skalar){ + constexpr Percentage& operator/=(const Skalar skalar) noexcept { static_assert(std::is_arithmetic(), "cannot divide by a non arithmetic type"); this->mPercentage /= skalar; return *this; @@ -71,21 +70,21 @@ namespace CustomDataTypes { constexpr Percentage& operator~()=delete; - constexpr inline Percentage& swap(Percentage& other){ + constexpr inline Percentage& swap(Percentage& other) noexcept { std::swap(other.mPercentage, this->mPercentage); return *this; } }; namespace literals { - constexpr auto operator"" _percLd(long double percent){ + [[nodiscard]] constexpr auto operator"" _percLd(long double percent){ return Percentage(percent); } constexpr auto operator"" _perc(long double percent){ - return Percentage(percent); + return Percentage(static_cast(percent)); } constexpr auto operator"" _perc(unsigned long long percent){ - return Percentage(percent); + return Percentage(static_cast(percent)); } constexpr auto operator"" _percLd(unsigned long long percent){ return Percentage(percent); @@ -93,82 +92,82 @@ namespace CustomDataTypes { } template - constexpr Percentage operator+(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr Percentage operator+(const Percentage& lhs, const Percentage& rhs) noexcept { Percentage temp{lhs}; temp+=rhs; return temp; } template - constexpr Percentage operator*(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr Percentage operator*(const Percentage& lhs, const Percentage& rhs) noexcept { Percentage temp{lhs}; temp*=rhs; return temp; } template - constexpr Percentage operator*(const Percentage& lhs, const Skalar& rhs){ + [[nodiscard]] constexpr Percentage operator*(const Percentage& lhs, const Skalar& rhs) noexcept { Percentage temp{lhs}; temp*=rhs; return temp; } template - constexpr Percentage operator*(const Skalar& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr Percentage operator*(const Skalar& lhs, const Percentage& rhs) noexcept { Percentage temp{rhs}; temp*=lhs; return temp; } template - constexpr bool operator==(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr bool operator==(const Percentage& lhs, const Percentage& rhs) noexcept { return std::abs(lhs.getPercent() - rhs.getPercent()) < std::numeric_limits::epsilon(); } template - constexpr bool operator!=(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr bool operator!=(const Percentage& lhs, const Percentage& rhs) noexcept { return !(lhs == rhs); } template - constexpr bool operator<=(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr bool operator<=(const Percentage& lhs, const Percentage& rhs) noexcept { return lhs.getPercent() < rhs.getPercent() || lhs == rhs; } template - constexpr bool operator>=(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr bool operator>=(const Percentage& lhs, const Percentage& rhs) noexcept { return lhs.getPercent() > rhs.getPercent() || lhs == rhs; } template - constexpr Percentage operator/(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr Percentage operator/(const Percentage& lhs, const Percentage& rhs) noexcept { Percentage temp{lhs}; temp/=rhs; return temp; } template - constexpr Percentage operator/(const Percentage& lhs, const Skalar rhs){ + [[nodiscard]] constexpr Percentage operator/(const Percentage& lhs, const Skalar rhs) noexcept { Percentage temp{lhs}; temp/=rhs; return temp; } template - constexpr Percentage operator/(const Skalar lhs, const Percentage& rhs){ + [[nodiscard]] constexpr Percentage operator/(const Skalar lhs, const Percentage& rhs) noexcept { Percentage temp{static_cast(lhs)}; temp/=(accuracy) rhs; return temp; } template - constexpr Percentage operator-(const Percentage& lhs, const Percentage& rhs){ + [[nodiscard]] constexpr Percentage operator-(const Percentage& lhs, const Percentage& rhs) noexcept { Percentage temp{lhs}; temp-=rhs; return temp; } template - constexpr void swap(Percentage& lhs, Percentage& rhs){ + constexpr void swap(Percentage& lhs, Percentage& rhs) noexcept { lhs.swap(rhs); } template - constexpr std::ostream &operator<<(std::ostream &os, const Percentage& percentage) { + [[nodiscard]] constexpr std::ostream &operator<<(std::ostream &os, const Percentage& percentage) noexcept { os << percentage.getPercent() << "%"; return os; } diff --git a/src/CustomDataTypes/SIUnit.h b/src/CustomDataTypes/SIUnit.h index 8c57ed3..0304eb2 100644 --- a/src/CustomDataTypes/SIUnit.h +++ b/src/CustomDataTypes/SIUnit.h @@ -40,7 +40,7 @@ namespace CustomDataTypes { return derived_this(); } - constexpr Rep count() const { return internalRepresentation; } + [[nodiscard]] constexpr Rep count() const& noexcept { return internalRepresentation; } constexpr Derived operator+() const { return derived_this(); @@ -58,7 +58,7 @@ namespace CustomDataTypes { } template::value>> - constexpr explicit operator Number() const { + constexpr explicit operator Number() const& { if (internalRepresentation < std::numeric_limits::max()) { return count(); } else { @@ -67,12 +67,12 @@ namespace CustomDataTypes { } template - constexpr bool operator==(const D> &rhs) const { + constexpr bool operator==(const D> &rhs) const& noexcept { return internalRepresentation == convert_value(rhs); } template - constexpr bool operator<(const D> &rhs) const { + constexpr bool operator<(const D> &rhs) const& noexcept { return internalRepresentation < convert_value(rhs); } diff --git a/src/CustomDataTypes/Volt.h b/src/CustomDataTypes/Volt.h index 3ba116f..df9dbda 100644 --- a/src/CustomDataTypes/Volt.h +++ b/src/CustomDataTypes/Volt.h @@ -18,7 +18,7 @@ namespace CustomDataTypes::Electricity { using parent_type = SIUnit, Rep, Period>; public: static constexpr std::string_view abr_value = "V"; - constexpr explicit Volt(Rep input) : parent_type{input} {} + constexpr explicit Volt(Rep input) noexcept : parent_type{input} {} }; using nanovolt = Volt; @@ -29,51 +29,51 @@ namespace CustomDataTypes::Electricity { using megavolt = Volt; namespace literals { - constexpr nanovolt operator ""_nV(unsigned long long element) { + constexpr nanovolt operator ""_nV(unsigned long long element) noexcept { return nanovolt(static_cast(element)); } - constexpr Volt operator ""_nV(long double element) { + constexpr Volt operator ""_nV(long double element) noexcept { return Volt(element); } - constexpr microvolt operator ""_uV(unsigned long long element) { + constexpr microvolt operator ""_uV(unsigned long long element) noexcept { return microvolt(static_cast(element)); } - constexpr Volt operator ""_uV(long double element) { + constexpr Volt operator ""_uV(long double element) noexcept { return Volt(element); } - constexpr millivolt operator ""_mV(unsigned long long element) { + constexpr millivolt operator ""_mV(unsigned long long element) noexcept { return millivolt(static_cast(element)); } - constexpr Volt operator ""_mV(long double element) { + constexpr Volt operator ""_mV(long double element) noexcept { return Volt(element); } - constexpr volt operator ""_V(unsigned long long element) { + constexpr volt operator ""_V(unsigned long long element) noexcept { return volt(static_cast(element)); } - constexpr Volt operator ""_V(long double element) { + constexpr Volt operator ""_V(long double element) noexcept { return Volt(element); } - constexpr kilovolt operator ""_kV(unsigned long long element) { + constexpr kilovolt operator ""_kV(unsigned long long element) noexcept { return kilovolt(static_cast(element)); } - constexpr Volt operator ""_kV(long double element) { + constexpr Volt operator ""_kV(long double element) noexcept { return Volt(element); } - constexpr megavolt operator ""_MV(unsigned long long element) { + constexpr megavolt operator ""_MV(unsigned long long element) noexcept { return megavolt(static_cast(element)); } - constexpr Volt operator ""_MV(long double element) { + constexpr Volt operator ""_MV(long double element) noexcept { return Volt(element); } } diff --git a/src/Devices/A4963/A4963.h b/src/Devices/A4963/A4963.h index 144cf32..de3079d 100644 --- a/src/Devices/A4963/A4963.h +++ b/src/Devices/A4963/A4963.h @@ -140,18 +140,17 @@ namespace NS_A4963 { template(0)> uint16_t A4963::getRuntime(A4963RegisterNames name){ - if (toGet == name){ - return getRegisterEntry(RegisterValues::code,RegisterValues::mask); + if constexpr(static_cast(toGet) >= static_cast(A4963RegisterNames::Run)){ + return A4963::getRegisterEntry(RegisterValues::code,RegisterValues::mask); } else { - return getRuntime(static_cast(toGet)+1)>(name); + if (toGet == name) { + return getRegisterEntry(RegisterValues::code, RegisterValues::mask); + } else { + return getRuntime(static_cast(toGet) + 1)>(name); + } } } - template<> - inline uint16_t A4963::getRuntime(A4963RegisterNames name){ - return A4963::getRegisterEntry(RegisterValues::code,RegisterValues::mask); - } - template< A4963RegisterNames toSet> struct possibleValues { static_assert(!RegisterValues::isRanged, "here is no checked type allowed"); diff --git a/src/Devices/A4963/DeserializeA4963.cpp b/src/Devices/A4963/DeserializeA4963.cpp index c4a6e6c..ebd7539 100644 --- a/src/Devices/A4963/DeserializeA4963.cpp +++ b/src/Devices/A4963/DeserializeA4963.cpp @@ -75,7 +75,7 @@ namespace NS_A4963 { JsonSetter::UnitInfo JsonSetter::parseData(const std::string ®isterValue) { static std::regex unit_regex( - R"(([-+]?[0-9]*\.?[0-9]+)(a|f|p|n|u|m|c|d|D|h|k|M|T|P|E)?([A-Z0-9a-z!"#$%&'()*+,.\/:;<=>?@\[\] ^_`{|}~-]+)?)", + R"(([-+]?[0-9]*\.?[0-9]+)\s?(a|f|p|n|u|m|c|d|D|h|k|M|T|P|E)?([A-Z0-9a-z!"#$%&'()*+,.\/:;<=>?@\[\] ^_`{|}~-]+)?)", std::regex_constants::ECMAScript); std::smatch unit_match; diff --git a/src/Devices/A4963/DeserializeA4963.h b/src/Devices/A4963/DeserializeA4963.h index 694f1ad..88eca6b 100644 --- a/src/Devices/A4963/DeserializeA4963.h +++ b/src/Devices/A4963/DeserializeA4963.h @@ -84,10 +84,10 @@ namespace NS_A4963 { json j; public: struct UnitInfo { - long double data; - char prefix; - std::string unit; - bool succsess; + long double data{}; + char prefix{}; + std::string unit{}; + bool succsess{}; }; static UnitInfo parseData(const std::string& str); @@ -101,9 +101,9 @@ namespace NS_A4963 { getType(const char prefix, const std::string &unit, Rep value) { auto prefixRatio = utils::getRatio(prefix); auto newValue = (value * prefixRatio.first * Period::den) / (prefixRatio.second * Period::num); - if (unit == "V") { + if (unit == CustomDataTypes::Electricity::Volt::abr_value) { return CustomDataTypes::Electricity::Volt{newValue}; - } else if (unit == "Hz") { + } else if (unit == CustomDataTypes::Frequency::Hertz::abr_value) { return CustomDataTypes::Frequency::Hertz{newValue}; } else if (unit == "s") { return std::chrono::duration{newValue}; @@ -122,7 +122,8 @@ namespace NS_A4963 { } template - static auto setIfPeriodic(A4963 &device, double data, const char prefix, const std::string &unit) { + static auto setIfPeriodic(A4963 &device, double data, const char prefix, const std::string &unit) -> std::optional { + static_assert(utils::is_periodic::value); using Rep = typename utils::periodic_info::rep; using Period = typename utils::periodic_info::period; try { @@ -134,10 +135,10 @@ namespace NS_A4963 { } return return_value; } - catch(std::exception& e){ + catch(std::runtime_error& e){ std::cerr << "Invalid Unit \"" << prefix << unit << "\" in register \"" << RegisterValues::name << "\", did you mean \"" << utils::ratio_lookup::abr_value << utils::periodic_printable::name << "\" ?" << std::endl; - return std::optional{}; + return std::nullopt;//std::optional{}; } } @@ -153,7 +154,7 @@ namespace NS_A4963 { } template(0)> - void setRuntime(A4963 &device, A4963RegisterNames toSet, const std::string& registerData) { + void setRuntime(A4963 &device, [[maybe_unused]] A4963RegisterNames toSet, const std::string& registerData) { using namespace utils::printable; if (toSet == N) { if constexpr(RegisterValues::isRanged) { @@ -177,7 +178,7 @@ namespace NS_A4963 { if constexpr (std::is_arithmetic_v) { if (!unit.empty()) { std::cerr << "This register (" << RegisterValues::name - << ") doesn't expect an unit. This might be an error!" << std::endl; + << ") doesn't expect a unit. This might be an error!" << std::endl; } } else { if(unit != type::abr_value) { @@ -213,18 +214,13 @@ namespace NS_A4963 { } } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" - template<> - inline void setRuntime(A4963 &device, A4963RegisterNames toSet, const std::string& registerData) { + inline void setRuntime(A4963 &device, [[maybe_unused]] A4963RegisterNames toSet, const std::string& registerData) { std::cout << "Set the register " << RegisterValues::name << " to " << registerData << std::endl; auto d = static_cast::values>(std::atof(registerData.data())); device.set(d); } -#pragma GCC diagnostic pop - class RegisterStrings { private: template diff --git a/src/SPI/ATmega32U4SPI.cpp b/src/SPI/ATmega32U4SPI.cpp index 7ef8832..9f9fdcf 100644 --- a/src/SPI/ATmega32U4SPI.cpp +++ b/src/SPI/ATmega32U4SPI.cpp @@ -48,10 +48,7 @@ namespace spi { } } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" - gpio::gpioState ATmega32u4SPI::readGPIO(const gpio::GPIOPin& pin) const { -#pragma GCC diagnostic pop + gpio::gpioState ATmega32u4SPI::readGPIO([[maybe_unused]] const gpio::GPIOPin& pin) const { //TODO: make this work return gpio::gpioState::off; } diff --git a/src/SPI/GPIOBridge.h b/src/SPI/GPIOBridge.h index 93d9fe0..38f53bf 100644 --- a/src/SPI/GPIOBridge.h +++ b/src/SPI/GPIOBridge.h @@ -4,7 +4,7 @@ #pragma once -#include +#include namespace gpio { @@ -43,7 +43,7 @@ namespace gpio { virtual ~GPIOBridge() = default; virtual void setGPIODirection(const gpioDirection& direction,const GPIOPin& pin) = 0; virtual void writeGPIO(const gpioState& state,const GPIOPin& pin) = 0; - virtual gpioState readGPIO(const GPIOPin& pin) const = 0; + [[nodiscard]] virtual gpioState readGPIO(const GPIOPin& pin) const = 0; }; } \ No newline at end of file diff --git a/src/SPI/SPIData.h b/src/SPI/SPIData.h index 4c0247b..029bd4b 100644 --- a/src/SPI/SPIData.h +++ b/src/SPI/SPIData.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include "../utils/utils.h" #include #include @@ -26,8 +26,7 @@ namespace spi { return bswap_16(value); else if constexpr (utils::isEqual::value || utils::isEqual::value) return bswap_32(value); - else return bswap_64( - value); + else return bswap_64(value); } class SPI_Exception : public std::exception { @@ -47,27 +46,27 @@ namespace spi { std::vector mData = std::vector(); public: - Data() = default; + Data() noexcept = default; Data(const Data &) = default; - const std::vector &data() { return mData; }; + const std::vector &data() noexcept { return mData; }; - virtual void swap(Data &other) { std::swap(mData, other.mData); }; + virtual void swap(Data &other) noexcept { std::swap(mData, other.mData); }; - inline uint8_t operator[](const uint8_t &index) const { + inline uint8_t operator[](const uint8_t &index) const noexcept { return mData[index]; } - inline uint8_t &operator[](const uint8_t &index) { + inline uint8_t &operator[](const uint8_t &index) noexcept { return mData[index]; } - auto begin() const { + auto begin() const noexcept { return mData.begin(); } - auto end() const { + auto end() const noexcept { return mData.end(); } @@ -100,7 +99,7 @@ namespace spi { inline uint8_t bytesUsed() const { return static_cast(mData.size()); }; - virtual ~Data() = default; + virtual ~Data() noexcept = default; }; enum EndianMode { @@ -110,19 +109,21 @@ namespace spi { template class SPIData : public Data { - std::shared_ptr logger; + static inline std::shared_ptr logger = nullptr; static_assert((numberOfBytes & (numberOfBytes - 1)) == 0, " the number of bytes have to be a pow of 2"); static_assert(numberOfBytes != 0, " 0 means no data, so this is not possible"); public: - SPIData() { + SPIData() noexcept(optimized) { mData.reserve(numberOfBytes); - if constexpr(!optimized) - logger = spdlog::basic_logger_mt("spidata"+std::to_string(numberOfBytes),"spidatalog.txt"); + if constexpr(!optimized) { + if (logger == nullptr) + logger = spdlog::basic_logger_mt("spidata" + std::to_string(numberOfBytes), "spidatalog.txt"); + } }; template - explicit SPIData(T first, args ... ss) : SPIData() { + explicit SPIData(T first, args ... ss) noexcept(optimized) : SPIData() { static constexpr uint8_t bytesSum = (sizeof...(args) + 1) * sizeof(T); static_assert(utils::sameTypes(), "there are different types in the constructor, this is not allowed"); @@ -140,11 +141,14 @@ namespace spi { } template - explicit SPIData(const std::vector &vec) : SPIData() { + explicit SPIData(const std::vector &vec) noexcept(optimized) : SPIData() { static_assert(sizeof(T) <= numberOfBytes, "too much bytes for this data type"); static_assert(std::is_integral::value, "the data type have to be a integral type"); if constexpr(!optimized) - if (vec.size() * sizeof(T) > numberOfBytes) throw SPI_Exception{"too much data for this data type"}; + if (vec.size() * sizeof(T) > numberOfBytes) { + logger->log(spdlog::level::err, " too much data in fill method, max: "+std::to_string(numberOfBytes)+" was: "+std::to_string(vec.size())); + throw SPI_Exception{"too much data for this data type"}; + } for (auto elem : vec) { if constexpr(endian == big_endian) for (uint8_t i = sizeof(T); i > 0; i--) @@ -155,11 +159,11 @@ namespace spi { } } - explicit SPIData(const Data &other) : SPIData() { - mData.insert(std::end(mData), std::begin(other), std::end(other)); + explicit SPIData(const Data &other) noexcept(optimized) : SPIData() { + mData.insert(std::end(mData), other.begin(), other.begin()); } - void fill(const std::vector &vec) override { + void fill(const std::vector &vec) noexcept(optimized) override { if constexpr(!optimized) { if (vec.size() > numberOfBytes) { logger->log(spdlog::level::err, " too much data in fill method, max: "+std::to_string(numberOfBytes)+" was: "+std::to_string(vec.size())); @@ -169,47 +173,55 @@ namespace spi { mData.assign(vec.begin(), vec.end()); } - inline void swap(Data &other) override { + inline void swap(Data &other) noexcept override { other.swap(*this); } - std::unique_ptr create() const override { + std::unique_ptr create() const noexcept(optimized) override { return std::make_unique(); } - explicit operator uint8_t() const override { + explicit operator uint8_t() const noexcept(optimized) override { if constexpr(!optimized) { - logger->log(spdlog::level::err, " data was too much to convert to uint8_t: "+std::to_string(mData.size())); - if (mData.size() > 1) throw SPI_Exception{"SPIData did not fit into a uint8_t type"}; + if (mData.size() > 1) { + logger->log(spdlog::level::err, " data was too much to convert to uint8_t: "+std::to_string(mData.size())); + throw SPI_Exception{"SPIData did not fit into a uint8_t type"}; + } } return mData[0]; } - explicit operator uint16_t() const override { + explicit operator uint16_t() const noexcept(optimized) override { if constexpr(!optimized) { - logger->log(spdlog::level::err, - " data was too much to convert to uint16_t: " + std::to_string(mData.size())); - if (mData.size() > 2) throw SPI_Exception{"SPIData did not fit into a uint16_t type"}; + if (mData.size() > 2) { + logger->log(spdlog::level::err, + " data was too much to convert to uint16_t: " + std::to_string(mData.size())); + throw SPI_Exception{"SPIData did not fit into a uint16_t type"}; + } } uint16_t erg = (mData[1] << 8) | mData[0]; return erg; } - explicit operator uint32_t() const override { + explicit operator uint32_t() const noexcept(optimized) override { if constexpr(!optimized) { - logger->log(spdlog::level::err, - " data was too much to convert to uint32_t: " + std::to_string(mData.size())); - if (mData.size() > 4) throw SPI_Exception{"SPIData did not fit into a uint32_t type"}; + if (mData.size() > 4) { + logger->log(spdlog::level::err, + " data was too much to convert to uint32_t: " + std::to_string(mData.size())); + throw SPI_Exception{"SPIData did not fit into a uint32_t type"}; + } } uint32_t erg = (mData[3] << 24) | (mData[2] << 16) | (mData[1] << 8) | mData[0]; return erg; } - explicit operator uint64_t() const override { + explicit operator uint64_t() const noexcept(optimized) override { if constexpr(!optimized) { - logger->log(spdlog::level::err, - " data was too much to convert to uint64_t: " + std::to_string(mData.size())); - if (mData.size() > 8) throw SPI_Exception{"SPIData did not fit into a uint64_t type"}; + if (mData.size() > 8) { + logger->log(spdlog::level::err, + " data was too much to convert to uint64_t: " + std::to_string(mData.size())); + throw SPI_Exception{"SPIData did not fit into a uint64_t type"}; + } } uint64_t erg = ((uint64_t) (mData[7]) << 56) | ((uint64_t) (mData[6]) << 48) | ((uint64_t) (mData[5]) << 40) | @@ -218,10 +230,10 @@ namespace spi { return erg; } - ~SPIData() override = default; + ~SPIData() noexcept override = default; }; - inline std::ostream &operator<<(std::ostream &os, const Data &data) { + [[nodiscard]] inline std::ostream &operator<<(std::ostream &os, const Data &data) noexcept { uint32_t i = 0; for (auto &elem: data) { os << "data " << i << ": " << std::to_string(elem) << " "; @@ -231,41 +243,41 @@ namespace spi { return os; } - inline void swap(Data &lhs, Data &rhs) { + inline void swap(Data &lhs, Data &rhs) noexcept { lhs.swap(rhs); } inline namespace literals { - inline std::unique_ptr operator ""_spi8(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi8(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi16(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi16(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi32(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi32(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi64(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi64(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi8_big(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi8_big(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi16_big(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi16_big(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi32_big(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi32_big(unsigned long long element) { return std::make_unique>(static_cast(element)); } - inline std::unique_ptr operator ""_spi64_big(unsigned long long element) { + [[nodiscard]] inline std::unique_ptr operator ""_spi64_big(unsigned long long element) { return std::make_unique>(static_cast(element)); } } diff --git a/src/SPI/SPIDevice.cpp b/src/SPI/SPIDevice.cpp index c9ca6f9..9415932 100644 --- a/src/SPI/SPIDevice.cpp +++ b/src/SPI/SPIDevice.cpp @@ -4,10 +4,3 @@ #include "SPIDevice.h" -const gpio::GPIOPin &SPIDevice::getSlavePin() const{ - return slavePin; -} - -void SPIDevice::selectPin(const gpio::GPIOPin &pin){ - slavePin = pin; -} diff --git a/src/SPI/SPIDevice.h b/src/SPI/SPIDevice.h index ed91612..98bb624 100644 --- a/src/SPI/SPIDevice.h +++ b/src/SPI/SPIDevice.h @@ -11,7 +11,11 @@ class SPIDevice : public std::enable_shared_from_this { private: gpio::GPIOPin slavePin; public: - void selectPin(const gpio::GPIOPin& pin); - const gpio::GPIOPin& getSlavePin() const; + constexpr void selectPin(const gpio::GPIOPin& pin) noexcept { + slavePin = pin; + } + [[nodiscard]] constexpr gpio::GPIOPin getSlavePin() const noexcept { + return slavePin; + } }; diff --git a/src/SPI/mcp2210_hal.cpp b/src/SPI/mcp2210_hal.cpp deleted file mode 100644 index 96ebddc..0000000 --- a/src/SPI/mcp2210_hal.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "mcp2210_hal.h" - -MCP2210::MCP2210() { - try { - logger = spdlog::basic_logger_mt("mcplogger", "mcp_log.txt"); - } catch(const spdlog::spdlog_ex &ex) { - std::cerr << "could not create logger: " << ex.what() << std::endl; - } - - //tut: http://www.signal11.us/oss/udev/ - connect(); -} - -MCP2210::~MCP2210() { - delete npath; - close_device(fd); -} - -std::unique_ptr MCP2210::transfer(const spi::Data &input) { - auto tmp = input.create(); - if (*connection) { - uint16_t i = 0; - for(auto data : input) { - txdata[i] = data; - i++; - } - int32_t error = send(static_cast(i)); - for(i = 0; i < input.bytesUsed();i++){ - (*tmp)[i] = rxdata[i]; - } - if (error != ERR_NOERR) { - exceptionHandling(error); - } - } - return tmp; -} - -void MCP2210::writeGPIO(const gpio::gpioState &state, const gpio::GPIOPin &pin) { - if (state == gpio::gpioState::off) { - gpio_write(fd, ~static_cast(pin), static_cast(pin)); - } else { - gpio_write(fd, static_cast(pin), static_cast(pin)); - } -} - -void MCP2210::setGPIODirection(const gpio::gpioDirection &direction, const gpio::GPIOPin &pin) { - if (direction == gpio::gpioDirection::in) { - gpio_direction(fd, 0x01FF, static_cast(pin)); - } else if (direction == gpio::gpioDirection::out) { - gpio_direction(fd, 0x0000, static_cast(pin)); - } -} - -void MCP2210::slaveSelect(const std::shared_ptr& slave) { - auto& pin = slave->getSlavePin(); - if((bool)pin) - writeGPIO(gpio::gpioState::off, pin); - else { - - } -} - -void MCP2210::slaveDeselect(const std::shared_ptr& slave) { - writeGPIO(gpio::gpioState::on, slave->getSlavePin()); -} - -void MCP2210::slaveRegister(const std::shared_ptr& device, const gpio::GPIOPin &pin) { - device->selectPin(pin); -} - -gpio::gpioState MCP2210::readGPIO(const gpio::GPIOPin &pin) const { - int val = 0; - exceptionHandling(gpio_read(fd, &val, static_cast(pin))); - auto erg = val == static_cast(pin) ? gpio::gpioState::on : gpio::gpioState::off; // cannot be null it would cause an exception - return erg; -} - -int32_t MCP2210::send(const uint16_t &dataCount) { - return spi_data_xfer(fd, txdata.data() , rxdata.data() , dataCount, - static_cast(settings.mode), settings.speed, settings.actcsval, settings.idlecsval, settings.gpcsmask, - settings.cs2datadly, settings.data2datadly, settings.data2csdly); -} - -std::vector> -MCP2210::transfer(const std::initializer_list>& spiData) { - if (*connection) { - uint16_t i = 0; - for (const auto& elem: spiData) { - if (i >= SPI_BUF_LEN) break; - auto spicontainer = elem.get(); - for(uint8_t data : *spicontainer) { - txdata[i] = data; - i++; - } - } - int32_t error = send(static_cast(i)); - if (error != ERR_NOERR) exceptionHandling(error); - std::vector> dataOut = std::vector>(i); - for (i = 0; i < spiData.size(); i++) { - if (i >= SPI_BUF_LEN) throw MCPIOException{}; - dataOut.emplace_back(std::make_unique>(rxdata[i])); - } - return dataOut; - } - return std::vector>{}; -} - -void MCP2210::connect() { - if (!(*connection)) { - /* Create the udev object */ - udev = udev_new(); - if (!udev) { - std::cerr << "Can't create udev\n" << std::endl; - logger->log(spdlog::level::err, "udev creation failed"); - exit(1); - } - - /* Create a list of the devices in the 'hidraw' subsystem. */ - enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(enumerate, "hidraw"); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - - udev_list_entry_foreach(dev_list_entry, devices) { - const char *path; - - path = udev_list_entry_get_name(dev_list_entry); - dev = udev_device_new_from_syspath(udev, path); - - npath = udev_device_get_devnode(dev); - - dev = udev_device_get_parent_with_subsystem_devtype( - dev, - "usb", - "usb_device"); - if (!dev) { - exit(1); - } - - if (std::string(udev_device_get_sysattr_value(dev, "idVendor")) == - std::string(deviceinformations::vendor_ID) && - std::string(udev_device_get_sysattr_value(dev, "idProduct")) == std::string(deviceinformations::device_ID)){ - fd = open_device(npath); - std::cout << "device found: " << std::endl; - printf(" VID/PID: %s %s\n", - udev_device_get_sysattr_value(dev, "idVendor"), - udev_device_get_sysattr_value(dev, "idProduct")); - printf(" %s\n %s\n", - udev_device_get_sysattr_value(dev, "manufacturer"), - udev_device_get_sysattr_value(dev, "product")); - printf(" serial: %s\n", - udev_device_get_sysattr_value(dev, "serial")); - } - - udev_device_unref(dev); - } - /* Free the enumerator object */ - udev_enumerate_unref(enumerate); - udev_unref(udev); - - if (fd <= 0) std::cout << "could not detect your device, check the device and try to reconnect." << std::endl; - else { //connection was successful, init the gpios - gpio_setdir(fd, 0); - gpio_setval(fd, 0); - *connection = true; - } - } else { - std::wcerr << "device is already connected" << std::endl; - } - -} - -MCP2210::operator bool() { - return *connection; -} - -void MCP2210::exceptionHandling(int32_t errorCode) const{ - switch (-errorCode) { - case (ERR_NOERR) : - return; - case (10): { - std::cerr << " Write Error " << std::endl; - logger->log(spdlog::level::err, (" Write Error ")); - break; - } - case (20): { - std::cout << " Read Error " << std::endl; - logger->log(spdlog::level::err, (" Read Error ")); - break; - } - case (30): { - std::cout << " Hardware Error " << std::endl; - logger->log(spdlog::level::err, (" Hardware Error ")); - break; - } - case (100): { - std::cout << " Chip Status Error " << std::endl; - logger->log(spdlog::level::err, (" Chip Status Error ")); - break; - } - case (110): { - std::cout << " Get Settings Error " << std::endl; - logger->log(spdlog::level::err, (" Get Settings Error ")); - break; - } - case (120): { - std::cout << " set Settings Error " << std::endl; - logger->log(spdlog::level::err, ("set Settings Error")); - break; - } - case (130): { - std::cout << " Get SPI Settings Error " << std::endl; - logger->log(spdlog::level::err, ( " Get SPI Settings Error " )); - break; - } - case (140): { - std::cout << " set SPI Settings Error " << std::endl; - logger->log(spdlog::level::err, ( " set SPI Settings Error " )); - break; - } - case (150): { - std::cout << " Address out of range Error " << std::endl; - logger->log(spdlog::level::err, (" Address out of range Error ")); - break; - } - case (160): { - std::cout << " Blocked Access Error " << std::endl; - logger->log(spdlog::level::err, (" Blocked Access Error ")); - break; - } - case (170): { - std::cout << " Write GPIO Error " << std::endl; - logger->log(spdlog::level::err, (" Write GPIO Error ")); - break; - } - case (180): { - std::cout << " Read GPIO Error " << std::endl; - logger->log(spdlog::level::err, (" Read GPIO Error ")); - break; - } - case (190): { - std::cout << " set GPIO direction Error " << std::endl; - logger->log(spdlog::level::err, (" set GPIO direction Error ")); - break; - } - default: { - return; - } - } - *connection=false; - close_device(fd); - std::cerr << "device disconnected" << std::endl; -} - -MCP2210::spiSettings MCP2210::getSettings() const { - return settings; -} - -void MCP2210::setSettings(const MCP2210::spiSettings& settings) { - MCP2210::settings = settings; -} \ No newline at end of file diff --git a/src/SPI/mcp2210_hal.h b/src/SPI/mcp2210_hal.h index 9956d6f..da9361f 100644 --- a/src/SPI/mcp2210_hal.h +++ b/src/SPI/mcp2210_hal.h @@ -1,4 +1,5 @@ #pragma once + #include #include #include @@ -10,73 +11,329 @@ #include #include "../../inc/spdlog/spdlog.h" #include "../../inc/spdlog/sinks/basic_file_sink.h" -//#include "USB/LibUSBDevices.h" -struct MCPIOException : public std::exception { - const char* what() const noexcept override { - return "MCPIOException"; - }; -}; -using error_pair = std::pair; +#ifndef linux + static_assert(false, "only linux supported"); +#endif + +using error_pair = std::pair; + +namespace mcp { + struct MCPIOException : public std::exception { + const char *what() const noexcept override { + return "MCPIOException"; + }; + }; -namespace deviceinformations { inline static constexpr const char *vendor_ID = "04d8"; inline static constexpr const char *device_ID = "00de"; -} -class MCP2210 final : public spi::SPIBridge, public gpio::GPIOBridge{ -public: - enum class spiMode : uint16_t{ + enum class spiMode : uint16_t { mode0 = 0, //clock polarity = 0 clock phase = 0 mode1 = 1, //clock polarity = 0 clock phase = 1 mode2 = 2, //clock polarity = 1 clock phase = 0 mode3 = 3 //clock polarity = 1 clock phase = 1 }; - struct spiSettings { - spiMode mode = spiMode::mode0; - uint16_t speed = 20000, //bits per second - actcsval = 0xFFEF, //active chip select value - idlecsval = 0xFFFF, //idle chip select value - gpcsmask = 0x0010, //general purpose chip select? - cs2datadly = 0, //chip select to data delay - data2datadly = 0, // delay between subsequent data bytes - data2csdly = 0; // last data byte to chip select delay + + struct spiSettings { + spiMode mode = spiMode::mode0; + uint16_t speed = 20000, //bits per second + actcsval = 0xFFEF, //active chip select value + idlecsval = 0xFFFF, //idle chip select value + gpcsmask = 0x0010, //general purpose chip select? + cs2datadly = 0, //chip select to data delay + data2datadly = 0, // delay between subsequent data bytes + data2csdly = 0; // last data byte to chip select delay }; + + inline auto defaultSetup = spiSettings{}; +} + +using namespace mcp; +template +class MCP2210 final : public spi::SPIBridge, public gpio::GPIOBridge { private: - const char *npath = nullptr; std::shared_ptr logger; struct udev *udev; struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; - struct udev_device* dev; - spiSettings settings; + struct udev_device *dev; + spiSettings settings = SETTINGS; std::unique_ptr connection = std::make_unique(false); static constexpr int SPI_BUF_LEN = 1024; - std::array txdata{}, rxdata{}; + std::array txdata{}, rxdata{}; int fd = -1; - int32_t send(const uint16_t& dataCount); + [[nodiscard]] int32_t send(const uint16_t dataCount) noexcept { + return spi_data_xfer(fd, txdata.data(), rxdata.data(), dataCount, + static_cast(settings.mode), settings.speed, settings.actcsval, settings.idlecsval, + settings.gpcsmask, + settings.cs2datadly, settings.data2datadly, settings.data2csdly); + } + void exceptionHandling(int32_t errorCode) const noexcept { + switch (-errorCode) { + case (ERR_NOERR) : + return; + case (ERR_WRERR): { + std::cerr << " Write Error " << std::endl; + logger->log(spdlog::level::err, (" Write Error ")); + break; + } + case (ERR_RDERR): { + std::cerr << " Read Error " << std::endl; + logger->log(spdlog::level::err, (" Read Error ")); + break; + } + case (ERR_HWERR): { + std::cerr << " Hardware Error " << std::endl; + logger->log(spdlog::level::err, (" Hardware Error ")); + break; + } + case (ERR_GETCHIPSTATUS): { + std::cerr << " Chip Status Error " << std::endl; + logger->log(spdlog::level::err, (" Chip Status Error ")); + break; + } + case (ERR_GETSETTINGS): { + std::cerr << " Get Settings Error " << std::endl; + logger->log(spdlog::level::err, (" Get Settings Error ")); + break; + } + case (ERR_SETSETTINGS): { + std::cerr << " set Settings Error " << std::endl; + logger->log(spdlog::level::err, ("set Settings Error")); + break; + } + case (ERR_GETSPISETTINGS): { + std::cerr << " Get SPI Settings Error " << std::endl; + logger->log(spdlog::level::err, (" Get SPI Settings Error ")); + break; + } + case (ERR_SETSPISETTINGS): { + std::cerr << " set SPI Settings Error " << std::endl; + logger->log(spdlog::level::err, (" set SPI Settings Error ")); + break; + } + case (ERR_ADDROUTOFRANGE): { + std::cerr << " Address out of range Error " << std::endl; + logger->log(spdlog::level::err, (" Address out of range Error ")); + break; + } + case (ERR_BLOCKEDACCESS): { + std::cerr << " Blocked Access Error " << std::endl; + logger->log(spdlog::level::err, (" Blocked Access Error ")); + break; + } + case (ERR_WRITEGPIO): { + std::cerr << " Write GPIO Error " << std::endl; + logger->log(spdlog::level::err, (" Write GPIO Error ")); + break; + } + case (ERR_READGPIO): { + std::cerr << " Read GPIO Error " << std::endl; + logger->log(spdlog::level::err, (" Read GPIO Error ")); + break; + } + case (ERR_SETGPIODIR): { + std::cerr << " set GPIO direction Error " << std::endl; + logger->log(spdlog::level::err, (" set GPIO direction Error ")); + break; + } + default: { + return; + } + } + *connection = false; + close_device(fd); + std::cerr << "device disconnected" << std::endl; + } public: static constexpr gpio::GPIOPin - pin0 = gpio::GPIOPin(1<<0), pin1 = gpio::GPIOPin(1<<1), pin2 = gpio::GPIOPin(1<<2), pin3 = gpio::GPIOPin(1<<3), - pin4 = gpio::GPIOPin(1<<4), pin5 = gpio::GPIOPin(1<<6), pin6 = gpio::GPIOPin(1<<6), pin7 = gpio::GPIOPin(1<<7); - - spiSettings getSettings() const; - void setSettings(const spiSettings& settings); - explicit MCP2210(); - ~MCP2210() override; - std::unique_ptr transfer(const spi::Data& input) override; - std::vector> transfer(const std::initializer_list>& spiData) override; - void setGPIODirection(const gpio::gpioDirection& direction, const gpio::GPIOPin& pin) override; - void writeGPIO(const gpio::gpioState& state, const gpio::GPIOPin& pin) override; - gpio::gpioState readGPIO(const gpio::GPIOPin& pin) const override; - void slaveSelect(const std::shared_ptr& slave) override; - void slaveDeselect(const std::shared_ptr& slave) override; - void slaveRegister(const std::shared_ptr& device, const gpio::GPIOPin& pin) override; - void exceptionHandling(int32_t errorCode) const; - operator bool(); - void connect(); -}; \ No newline at end of file + pin0 = gpio::GPIOPin(1 << 0), pin1 = gpio::GPIOPin(1 << 1), pin2 = gpio::GPIOPin( + 1 << 2), pin3 = gpio::GPIOPin(1 << 3), + pin4 = gpio::GPIOPin(1 << 4), pin5 = gpio::GPIOPin(1 << 6), pin6 = gpio::GPIOPin( + 1 << 6), pin7 = gpio::GPIOPin(1 << 7); + + [[nodiscard]] spiSettings getSettings() const noexcept { + return settings; + } + + void setSettings(const spiSettings &settings) noexcept { + this->settings = settings; + } + + explicit MCP2210() { + try { + logger = spdlog::basic_logger_mt("mcplogger", "mcp_log.txt"); + } catch (const spdlog::spdlog_ex &ex) { + std::cerr << "could not create logger: " << ex.what() << std::endl; + } + connect(); + } + + ~MCP2210() { + close_device(fd); + } + + std::unique_ptr transfer(const spi::Data &input) override { + auto tmp = input.create(); + if (*connection) { + + uint16_t i = 0; + + for (auto data : input) { + txdata[i] = data; + i++; + } + + int32_t error = send(static_cast(i)); + + for (i = 0; i < input.bytesUsed(); i++) { + (*tmp)[i] = rxdata[i]; + } + exceptionHandling(error); + } + return tmp; + } + + std::vector> + transfer(const std::initializer_list> &spiData) override { + if (*connection) { + uint16_t i = 0; + for (const auto &elem: spiData) { + if (i >= SPI_BUF_LEN) break; + auto spicontainer = elem.get(); + for (uint8_t data : *spicontainer) { + txdata[i] = data; + i++; + } + } + exceptionHandling(send(static_cast(i))); + std::vector> dataOut = std::vector>(i); + for (i = 0; i < spiData.size(); i++) { + if (i >= SPI_BUF_LEN) throw MCPIOException{}; + dataOut.emplace_back(std::make_unique>(rxdata[i])); + } + return dataOut; + } + return std::vector>{}; + } + + void setGPIODirection(const gpio::gpioDirection &direction, const gpio::GPIOPin &pin) override { + int32_t err = 0; + if (direction == gpio::gpioDirection::in) { + err = gpio_direction(fd, 0x01FF, static_cast(pin)); + } else if (direction == gpio::gpioDirection::out) { + err = gpio_direction(fd, 0x0000, static_cast(pin)); + } + exceptionHandling(err); + } + + void writeGPIO(const gpio::gpioState &state, const gpio::GPIOPin &pin) override { + int32_t err = 0; + if (state == gpio::gpioState::off) { + err = gpio_write(fd, ~static_cast(pin), static_cast(pin)); + } else { + err = gpio_write(fd, static_cast(pin), static_cast(pin)); + } + exceptionHandling(err); + } + + [[nodiscard]] gpio::gpioState readGPIO(const gpio::GPIOPin &pin) const override { + int val = 0; + exceptionHandling(gpio_read(fd, &val, static_cast(pin))); + auto erg = val == static_cast(pin) ? gpio::gpioState::on + : gpio::gpioState::off; // cannot be null it would cause an exception + return erg; + } + + void slaveSelect(const std::shared_ptr &slave) override { + writeGPIO(gpio::gpioState::off, slave->getSlavePin()); + } + + void slaveDeselect(const std::shared_ptr &slave) override { + writeGPIO(gpio::gpioState::on, slave->getSlavePin()); + } + + void slaveRegister(const std::shared_ptr &device, const gpio::GPIOPin &pin) override { + device->selectPin(pin); + } + + [[nodiscard]] operator bool() noexcept { + return *connection; + } + + void connect() { + if (!(*connection)) { + /* Create the udev object */ + udev = udev_new(); + if (!udev) { + std::cerr << "Can't create udev\n" << std::endl; + logger->log(spdlog::level::err, "udev creation failed"); + throw MCPIOException(); + } + + /* Create a list of the devices in the 'hidraw' subsystem. */ + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "hidraw"); + udev_enumerate_scan_devices(enumerate); + devices = udev_enumerate_get_list_entry(enumerate); + + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path = nullptr; + const char *npath = nullptr; + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + + npath = udev_device_get_devnode(dev); + + dev = udev_device_get_parent_with_subsystem_devtype( + dev, + "usb", + "usb_device"); + if (!dev) { + std::cerr << "device error" << std::endl; + logger->log(spdlog::level::err, "device error"); + throw MCPIOException(); + } + + if (std::string(udev_device_get_sysattr_value(dev, "idVendor")) == + std::string(mcp::vendor_ID) && + std::string(udev_device_get_sysattr_value(dev, "idProduct")) == + std::string(mcp::device_ID)) { + fd = open_device(npath); + if(fd > 0) { + std::cout << "device found: " << std::endl; + printf(" VID/PID: %s %s\n", + udev_device_get_sysattr_value(dev, "idVendor"), + udev_device_get_sysattr_value(dev, "idProduct")); + printf(" %s\n %s\n", + udev_device_get_sysattr_value(dev, "manufacturer"), + udev_device_get_sysattr_value(dev, "product")); + printf(" serial: %s\n", + udev_device_get_sysattr_value(dev, "serial")); + break; + } + } + + udev_device_unref(dev); + } + /* Free the enumerator object */ + udev_enumerate_unref(enumerate); + udev_unref(udev); + + if (fd <= 0) std::cout << "could not detect your device, check the device and try to reconnect." << std::endl; + else { //connection was successful, init the gpios + gpio_setdir(fd, 0); + gpio_setval(fd, 0); + *connection = true; + } + } else { + std::cerr << "device is already connected" << std::endl; + } + + } +}; diff --git a/src/USB/HIDevice.cpp b/src/USB/HIDevice.cpp index 3ef06ad..cb76399 100644 --- a/src/USB/HIDevice.cpp +++ b/src/USB/HIDevice.cpp @@ -5,7 +5,7 @@ #include #include "HIDevice.h" -std::vector usb::HIDevice::sendData(const std::vector& data) { +std::vector usb::HIDevice::sendData(const std::vector& data) noexcept { if (!isOpen) return {}; diff --git a/src/USB/HIDevice.h b/src/USB/HIDevice.h index 8c3589e..572da69 100644 --- a/src/USB/HIDevice.h +++ b/src/USB/HIDevice.h @@ -11,35 +11,35 @@ namespace usb { class HIDevice : public LibUSBDevice { public: HIDevice(const VendorID& vendorID, const DeviceID& deviceID, libusb_device *device, size_t usbID); - std::vector sendData(const std::vector& data) override; + std::vector sendData(const std::vector& data) noexcept override; private: //(source: http://janaxelson.com/code/generic_hid.c) - static const int CONTROL_REQUEST_TYPE_IN = + static constexpr int CONTROL_REQUEST_TYPE_IN = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE; - static const int CONTROL_REQUEST_TYPE_OUT = + static constexpr int CONTROL_REQUEST_TYPE_OUT = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE; - static const int INTERRUPT_IN_ENDPOINT = 0x81; - static const int INTERRUPT_OUT_ENDPOINT = 0x01; + static constexpr int INTERRUPT_IN_ENDPOINT = 0x81; + static constexpr int INTERRUPT_OUT_ENDPOINT = 0x01; - static const int MAX_INTERRUPT_IN_TRANSFER_SIZE = 8; - static const int MAX_INTERRUPT_OUT_TRANSFER_SIZE = 8; + static constexpr int MAX_INTERRUPT_IN_TRANSFER_SIZE = 8; + static constexpr int MAX_INTERRUPT_OUT_TRANSFER_SIZE = 8; // From the HID spec: - static const int HID_GET_REPORT = 0x01; - static const int HID_SET_REPORT = 0x09; - static const int HID_REPORT_TYPE_INPUT = 0x01; - static const int HID_REPORT_TYPE_OUTPUT = 0x02; - static const int HID_REPORT_TYPE_FEATURE = 0x03; + static constexpr int HID_GET_REPORT = 0x01; + static constexpr int HID_SET_REPORT = 0x09; + static constexpr int HID_REPORT_TYPE_INPUT = 0x01; + static constexpr int HID_REPORT_TYPE_OUTPUT = 0x02; + static constexpr int HID_REPORT_TYPE_FEATURE = 0x03; // With firmware support, transfers can be > the endpoint's max packet size. - static const int MAX_CONTROL_IN_TRANSFER_SIZE = 8; - static const int MAX_CONTROL_OUT_TRANSFER_SIZE = 8; + static constexpr int MAX_CONTROL_IN_TRANSFER_SIZE = 8; + static constexpr int MAX_CONTROL_OUT_TRANSFER_SIZE = 8; - static const int INTERFACE_NUMBER = 0; - static const int TIMEOUT_MS = 5000; + static constexpr int INTERFACE_NUMBER = 0; + static constexpr int TIMEOUT_MS = 5000; }; } diff --git a/src/USB/LibUSBDevices.cpp b/src/USB/LibUSBDevices.cpp index 057c51a..415145e 100644 --- a/src/USB/LibUSBDevices.cpp +++ b/src/USB/LibUSBDevices.cpp @@ -44,9 +44,9 @@ namespace usb { return mDevices; }*/ - const std::optional> - LibUSBDeviceList::findDevice(const VendorID& vendorID, const DeviceID& deviceID) { - for (std::pair> &device : mDevices) { + [[nodiscard]] const std::optional> + LibUSBDeviceList::findDevice(const VendorID& vendorID, const DeviceID& deviceID) const& noexcept { + for (const std::pair>& device : mDevices) { if (device.second->getDeviceID() == deviceID && device.second->getVendorID() == vendorID) { return device.second; } @@ -64,7 +64,4 @@ namespace usb { mDeviceID++; } - size_t LibUSBDeviceList::size() { - return mDevices.size(); - } } \ No newline at end of file diff --git a/src/USB/LibUSBDevices.h b/src/USB/LibUSBDevices.h index 6760c51..6718823 100644 --- a/src/USB/LibUSBDevices.h +++ b/src/USB/LibUSBDevices.h @@ -16,18 +16,28 @@ namespace usb { class LibUSBDeviceList { public: + using devices_t = std::unordered_map>; + using const_iterator = devices_t::const_iterator; + LibUSBDeviceList(); virtual ~LibUSBDeviceList(); - size_t size(); - const std::optional> findDevice(const VendorID& vendorID, const DeviceID& deviceID); + [[nodiscard]] size_t size() const& noexcept { + return mDevices.size(); + } + [[nodiscard]] const std::optional> findDevice(const VendorID& vendorID, const DeviceID& deviceID) const& noexcept; + + const const_iterator begin() const { return mDevices.begin(); } + const const_iterator end() const { return mDevices.end(); } + const const_iterator cbegin() const { return mDevices.cbegin(); } + const const_iterator cend() const { return mDevices.cend(); } private: libusb_context *context = nullptr; libusb_device **list = nullptr; ssize_t device_count = 0; - std::unordered_map> mDevices; + devices_t mDevices; size_t mDeviceID = 0; void addDevice(VendorID vendorID, DeviceID deviceID, libusb_device *device); diff --git a/src/USB/LibUsbDevice.cpp b/src/USB/LibUsbDevice.cpp index 55e6293..4c96aa0 100644 --- a/src/USB/LibUsbDevice.cpp +++ b/src/USB/LibUsbDevice.cpp @@ -19,7 +19,7 @@ namespace usb { mUsbID(usbID){} - LibUSBDevice::~LibUSBDevice() { + LibUSBDevice::~LibUSBDevice() noexcept { _closeDevice(); } @@ -60,7 +60,7 @@ namespace usb { _closeDevice(); } - void LibUSBDevice::_closeDevice() { + void LibUSBDevice::_closeDevice() noexcept { if (isOpen.exchange(false)) { libusb_attach_kernel_driver(handle, 0); libusb_release_interface(handle, 0); diff --git a/src/USB/LibUsbDevice.h b/src/USB/LibUsbDevice.h index 00d1537..afa275f 100644 --- a/src/USB/LibUsbDevice.h +++ b/src/USB/LibUsbDevice.h @@ -15,7 +15,7 @@ namespace usb { class LibUSBDevice { public: LibUSBDevice(const VendorID& vendorID, const DeviceID& deviceID, libusb_device *device, size_t usbID); - virtual ~LibUSBDevice(); + virtual ~LibUSBDevice() noexcept; //There should always only be one device with a given device handle (and it should be managed by the device list)! LibUSBDevice(const LibUSBDevice &other) = delete; LibUSBDevice &operator=(const LibUSBDevice &other) = delete; @@ -28,7 +28,7 @@ namespace usb { virtual std::vector sendData(const std::vector& data); protected: - void _closeDevice(); + void _closeDevice() noexcept; VendorID vendorID; DeviceID deviceID; diff --git a/src/USB/USBUtils.cpp b/src/USB/USBUtils.cpp index 545255e..b5e920c 100644 --- a/src/USB/USBUtils.cpp +++ b/src/USB/USBUtils.cpp @@ -20,10 +20,6 @@ namespace usb { VendorID::VendorID(uint16_t vendorID) noexcept : vendorID(vendorID) {} - uint16_t VendorID::getVendorID() const { - return vendorID; - } - bool VendorID::operator==(const VendorID &rhs) const { return vendorID == rhs.vendorID; } diff --git a/src/USB/USBUtils.h b/src/USB/USBUtils.h index a6b726a..8e2cad6 100644 --- a/src/USB/USBUtils.h +++ b/src/USB/USBUtils.h @@ -26,10 +26,13 @@ namespace usb { class VendorID { public: explicit VendorID(uint16_t vendorID) noexcept; - uint16_t getVendorID() const; bool operator==(const VendorID &rhs) const; bool operator!=(const VendorID &rhs) const; + [[nodiscard]] constexpr uint16_t getVendorID() const noexcept { + return vendorID; + } + private: uint16_t vendorID; }; diff --git a/src/utils/RatioLookup.h b/src/utils/RatioLookup.h index 25f9ec9..d63cc75 100644 --- a/src/utils/RatioLookup.h +++ b/src/utils/RatioLookup.h @@ -114,7 +114,7 @@ namespace utils { static constexpr std::string_view value = "exa"; }; - constexpr std::pair getRatio(const char prefix) { + [[nodiscard]] constexpr std::pair getRatio(const char prefix) { switch (prefix) { case 'a': return {1, 1000000000000000000}; diff --git a/src/utils/scales/UnitScale.h b/src/utils/scales/UnitScale.h index 90ced33..2525560 100644 --- a/src/utils/scales/UnitScale.h +++ b/src/utils/scales/UnitScale.h @@ -43,7 +43,7 @@ class NewUnitScale { const const_iterator end() const { return const_iterator(inverse_functor(max)+stepsize); } template - constexpr std::optional convertValue(const T& value) const { + [[nodiscard]] constexpr std::optional convertValue(const T& value) const noexcept { using namespace utils::printable; //TODO: round value up/down if(utils::approximately_greater_or_equal(value, min) && @@ -69,16 +69,16 @@ class NewUnitScale { } } - constexpr non_ref_type getActualValue(TValueType value) const { + [[nodiscard]] constexpr non_ref_type getActualValue(TValueType value) const noexcept { return non_ref_type{functor(value)}; } - constexpr non_ref_type getMaxValue() const { + [[nodiscard]] constexpr non_ref_type getMaxValue() const noexcept { return max; } - constexpr non_ref_type getMinValue() const { + [[nodiscard]] constexpr non_ref_type getMinValue() const noexcept { return min; } }; diff --git a/src/utils/utils.h b/src/utils/utils.h index 3da1539..d1dadea 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -13,7 +13,7 @@ namespace utils { template - constexpr typename std::make_unsigned::type getFirstSetBitPos(T n) { + [[nodiscard]] constexpr typename std::make_unsigned::type getFirstSetBitPos(T n) noexcept { static_assert(std::numeric_limits::is_integer); return std::log2(n&-n); } @@ -247,7 +247,7 @@ namespace utils { }; template - constexpr bool sameTypes() { + [[nodiscard]] constexpr bool sameTypes() noexcept { if constexpr(sizeof...(T) == 0) return true; else { @@ -301,7 +301,7 @@ namespace utils { struct is_template_same, T> : std::true_type {}; template - inline constexpr bool is_template_same_v = is_template_same::value; + constexpr bool is_template_same_v = is_template_same::value; template struct periodic_printable; @@ -321,19 +321,19 @@ namespace utils { typedef std::remove_cv_t> type; }; - constexpr bool approximately_same(long a, long b) + [[nodiscard]] constexpr auto approximately_same(long a, long b) noexcept { return a == b; } template>> - bool approximately_same(T a, T b) + [[nodiscard]] constexpr bool approximately_same(T a, T b) noexcept { return std::fabs(a - b) <= 1E-13; } template