diff --git a/CMakeLists.txt b/CMakeLists.txt index 115ebda..2dbc30b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,10 +19,11 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(vegadude + logger.h logger.cpp main.cpp crc.h crc.cpp + device.h device.cpp serialdevice.h serialdevice.cpp - targetproperties.h xmodem.h xmodem.cpp) install(TARGETS vegadude diff --git a/crc.cpp b/crc.cpp index 7f72383..ee4f12c 100644 --- a/crc.cpp +++ b/crc.cpp @@ -13,16 +13,20 @@ #include "crc.h" -uint16_t CRC::generateCRC16CCIT(std::vector bytes) +namespace CRC { - uint16_t final = 0; - for (std::size_t i = 0; i < bytes.size(); i++) + +uint16_t generateCRC16CCITT(std::span bytes) +{ + uint16_t result = 0; + for (auto&& byte : bytes) { // we xor the MSB of result (u16) with the byte -> we get the index (byte value) to fetch. // then we xor the whole result with the existing result - final = (final << 8) ^ CRC::CRC16CCITTable[(((final >> 8) ^ bytes[i]))]; - //final = final ^ crc_table[bytes[i]]; + result = (result << 8) ^ CRC::CRC16CCITTable[(((result >> 8) ^ byte))]; } - return final; + return result; +} + } diff --git a/crc.h b/crc.h index 8ebea25..1c01042 100644 --- a/crc.h +++ b/crc.h @@ -16,49 +16,45 @@ #include #include +#include -class CRC +namespace CRC { -public: - CRC() = delete; +uint16_t generateCRC16CCITT(std::span bytes); - static uint16_t generateCRC16CCIT(std::vector bytes); - -private: - constexpr static uint16_t CRC16CCITTable[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; - -}; +constexpr static uint16_t CRC16CCITTable[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; +} #endif // CRC_H diff --git a/device.cpp b/device.cpp new file mode 100644 index 0000000..21c3589 --- /dev/null +++ b/device.cpp @@ -0,0 +1,14 @@ +#include "device.h" + +Device::Device() +{} + +bool Device::read(unsigned char* bytes) +{ + return read(bytes, 1); +} + +bool Device::write(const unsigned char* bytes) +{ + return write(bytes, 1); +} diff --git a/device.h b/device.h new file mode 100644 index 0000000..3cf5649 --- /dev/null +++ b/device.h @@ -0,0 +1,18 @@ +#ifndef DEVICE_H +#define DEVICE_H + +#include + +class Device +{ +public: + Device(); + + bool read(unsigned char* bytes); + bool write(const unsigned char* bytes); + + virtual bool read(unsigned char* bytes, size_t size) = 0; + virtual bool write(const unsigned char* bytes, size_t size) = 0; +}; + +#endif // DEVICE_H diff --git a/logger.cpp b/logger.cpp new file mode 100644 index 0000000..d9848c8 --- /dev/null +++ b/logger.cpp @@ -0,0 +1,49 @@ +#include + +#include "logger.h" + +#include +#include + +Logger::Logger() + : m_log{false} +{} + +Logger &Logger::get() +{ + static Logger instance; + return instance; +} + +bool Logger::setup(std::string& filePath) +{ + m_stream.open(filePath, std::ofstream::out | std::ofstream::trunc); + + m_log = !m_stream.fail(); + return m_log; +} + +void Logger::close() +{ + get() << NewLine; + + if (m_log) + m_stream.close(); +} + +template +Logger& operator<<(Logger& logger, T text) +{ + std::cerr << text; + if (logger.m_log) logger.m_stream << text; + return logger; +} + +template Logger& operator<<(Logger& logger, size_t); +template Logger& operator<<(Logger& logger, int32_t); +template Logger& operator<<(Logger& logger, bool); +template Logger& operator<<(Logger& logger, char); +template Logger& operator<<(Logger& logger, char*); +template Logger& operator<<(Logger& logger, char const*); +template Logger& operator<<(Logger& logger, std::__cxx11::basic_string, std::allocator>); +template Logger& operator<<(Logger& logger, unsigned short); diff --git a/logger.h b/logger.h new file mode 100644 index 0000000..84c4cc5 --- /dev/null +++ b/logger.h @@ -0,0 +1,28 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include +#include + +class Logger +{ +public: + Logger(); + + static Logger& get(); + bool setup(std::string& filePath); + void close(); + + constexpr static char NewLine {'\n'}; + + template + friend Logger& operator<<(Logger& logger, T text); + +private: + bool m_log; + std::ofstream m_stream; +}; + + +#endif // LOGGER_H diff --git a/main.cpp b/main.cpp index 1fb72ea..f0c6b64 100644 --- a/main.cpp +++ b/main.cpp @@ -28,13 +28,16 @@ #include +#include "logger.h" #include "serialdevice.h" #include "xmodem.h" enum ArgType { + LOG_TO_FILE, BINARY_PATH, TARGET_PATH, + SERIAL_DEVICE_ARIES, SERIAL_PARITY_YES, SERIAL_STOP_BITS, SERIAL_RTS_CTS_YES, @@ -48,7 +51,9 @@ ArgType getArgType(char* const& arg) { using namespace std; - if (!string(arg).compare("-bp") || + if(!string(arg).compare("-o")) + return ArgType::LOG_TO_FILE; + else if (!string(arg).compare("-bp") || !string(arg).compare("--binary-path")) return ArgType::BINARY_PATH; else if (!string(arg).compare("-tp") || @@ -72,74 +77,69 @@ ArgType getArgType(char* const& arg) else if(!string(arg).compare("-sau") || !string(arg).compare("--start-after-upload")) return ArgType::START_AFTER_UPLOAD; + else if(!string(arg).compare("-aries")) + return ArgType::SERIAL_DEVICE_ARIES; return ArgType::INVALID; } void printUsage() { - std::clog << "Usage" << std::endl; + Logger::get() << "Usage." << Logger::NewLine; } -bool validateTargetProperties(const TargetProperties& tp) +bool validateDeviceProperties(const std::string& targetPath, const SerialDevice::DeviceProperties& deviceProperties) { using namespace std; bool valid = true; - if (tp.path.empty()) + if (targetPath.empty()) { - clog << "Target path not specified." << std::endl; + Logger::get() << "Target path not specified." << Logger::NewLine; valid = false; } - if (tp.stopBits == -1) + if (deviceProperties.stopBits == -1) { - clog << "Stop bits not specified." << std::endl; + Logger::get() << "Stop bits not specified." << Logger::NewLine; valid = false; } - else if (tp.stopBits != 1 && tp.stopBits != 2) + else if (deviceProperties.stopBits != 1 && deviceProperties.stopBits != 2) { // FIXME: Investigate: Is this true? - clog << "There can only be 1 or 2 stop bits!" << std::endl; + Logger::get() << "There can only be 1 or 2 stop bits!" << Logger::NewLine; valid = false; } - if (tp.bits == -1) + if (deviceProperties.bits == -1) { - clog << "Bits per byte not specified." << std::endl; + Logger::get() << "Bits per byte not specified." << Logger::NewLine; valid = false; } - else if (!(tp.bits >= 5 && tp.bits <= 8)) + else if (!(deviceProperties.bits >= 5 && deviceProperties.bits <= 8)) { - clog << "There can be 5-8 bits per byte." << std::endl; + Logger::get() << "There can be 5-8 bits per byte." << Logger::NewLine; valid = false; } - if (tp.baud == -1) + if (deviceProperties.baud == -1) { - clog << "Baud rate not specified." << std::endl; + Logger::get() << "Baud rate not specified." << Logger::NewLine; valid = false; } return valid; } -void printTargetProperties(const TargetProperties& tp) +void printDeviceProperties(const SerialDevice::DeviceProperties& deviceProperties) { using namespace std; - clog << "path " << tp.path; - clog << "\nparity " << tp.parity; - clog << "\nstopBits " << tp.stopBits; - clog << "\nrtsCts " << tp.rtsCts; - clog << "\nbits " << tp.bits; - clog << "\nbaud " << tp.baud << std::endl; -} - -void handleError() -{ - std::clog << "Error code : " << errno << std::endl; - std::clog << "Reason: " << strerror(errno); + Logger::get() << "parity " << deviceProperties.parity << Logger::NewLine; + Logger::get() << "stopBits " << deviceProperties.stopBits << Logger::NewLine; + Logger::get() << "rtsCts " << deviceProperties.rtsCts << Logger::NewLine; + Logger::get() << "bits " << deviceProperties.bits << Logger::NewLine; + Logger::get() << "baud " << deviceProperties.baud << Logger::NewLine; } int main(int argc, char** argv) @@ -152,78 +152,125 @@ int main(int argc, char** argv) return -1; } - TargetProperties tp; + SerialDevice::DeviceProperties dp; + std::string targetPath; std::string binaryPath; + std::string logFilePath; + bool startAfterUpload = false; + bool isDevPropsSetManual = false; + bool isDevPropsSetAuto = false; + + for (size_t i = 1; i < argc; i++) { switch (getArgType(argv[i])) { + case ArgType::LOG_TO_FILE: + logFilePath = argv[++i]; + break; case ArgType::BINARY_PATH: binaryPath = argv[++i]; break; case ArgType::TARGET_PATH: - tp.path = argv[++i]; + targetPath = argv[++i]; break; case ArgType::SERIAL_PARITY_YES: - tp.parity = true; + isDevPropsSetManual = true; + dp.parity = true; break; case ArgType::SERIAL_STOP_BITS: - tp.stopBits = std::stoi(argv[++i]); + isDevPropsSetManual = true; + dp.stopBits = std::stoi(argv[++i]); break; case ArgType::SERIAL_RTS_CTS_YES: - tp.rtsCts = true; + isDevPropsSetManual = true; + dp.rtsCts = true; break; case ArgType::SERIAL_BITS: - tp.bits = std::stoi(argv[++i]); + isDevPropsSetManual = true; + dp.bits = std::stoi(argv[++i]); break; case ArgType::SERIAL_BAUD_RATE: - tp.baud = std::stoi(argv[++i]); + isDevPropsSetManual = true; + dp.baud = std::stoi(argv[++i]); break; case ArgType::START_AFTER_UPLOAD: + isDevPropsSetManual = true; startAfterUpload = true; break; + case ArgType::SERIAL_DEVICE_ARIES: + isDevPropsSetAuto = true; + dp = SerialDevice::ARIES; case ArgType::INVALID: - std::clog << "Invalid argument " << argv[i] << std::endl; + Logger::get() << "Invalid argument " << argv[i]; printUsage(); return -1; } } - if (!validateTargetProperties(tp)) return -1; + if (isDevPropsSetAuto && isDevPropsSetManual) + { + Logger::get() << "You cannot use -aries and manually set device properties simultaneously." + << Logger::NewLine; + return -1; + } + + if (!validateDeviceProperties(targetPath, dp)) return -1; + + if (!logFilePath.empty()) + { + if(!Logger::get().setup(logFilePath)) + { + Logger::get() << "Unable to setup logging!" + << Logger::NewLine; + return -1; + } + } if (binaryPath.empty()) { - std::clog << "Binary path not specified." << std::endl; + Logger::get() << "Binary path not specified." << Logger::NewLine; return -1; } - printTargetProperties(tp); - std::clog << "Binary Path: " << binaryPath << std::endl; + if (isDevPropsSetAuto) + { + dp = SerialDevice::ARIES; + } + + printDeviceProperties(dp); + + Logger::get() << "Device Path: " << targetPath << Logger::NewLine; + Logger::get() << "Binary Path: " << binaryPath << Logger::NewLine; - SerialDevice device{std::make_shared(tp)}; + SerialDevice device{targetPath, dp}; - SerialDevice::Response devResponse = device.open(); - if (devResponse != SerialDevice::Response::SUCCESS) + if (!device.open()) { - std::clog << "Failed to setup device. Exit with code : " << devResponse << std::endl; + Logger::get() << "Failed to setup serial device!" + << Logger::NewLine << device.errorStr() + << Logger::NewLine; return -1; } - XModem modem{std::make_unique(device), 128}; + XModem modem{device, 128}; - XModem::Response modemResponse = modem.upload(binaryPath, startAfterUpload); - - if (modemResponse != XModem::Response::SUCCESS) + if (!modem.upload(binaryPath, startAfterUpload)) { - std::clog << "Failed to upload file. Exit with code : " << modemResponse << std::endl; + Logger::get() << "Failed to upload file!" + << Logger::NewLine + << ((modem.error() == XModem::Error::DEVICE_RELATED) ? device.errorStr() : modem.errorStr()) + << Logger::NewLine; return -1; } - std::clog << "Successfully uploaded!" << std::endl; + Logger::get() << "Successfully uploaded!"; + + Logger::get().close(); return 0; } diff --git a/serialdevice.cpp b/serialdevice.cpp index 00d4c46..23c170a 100644 --- a/serialdevice.cpp +++ b/serialdevice.cpp @@ -13,110 +13,146 @@ #include "serialdevice.h" -SerialDevice::SerialDevice(std::shared_ptr targetProperties) - : m_targetProperties{targetProperties}, - m_linuxFD{-1} +SerialDevice::SerialDevice(const std::filesystem::path& devicePath, const DeviceProperties& deviceProperties) + : m_devicePath{devicePath}, + m_deviceProperties{deviceProperties}, + m_linuxFD{-1}, + m_error{Error::NONE} {} -SerialDevice::Response SerialDevice::open() +const SerialDevice::Error &SerialDevice::error() { -#ifdef __linux - return openLinux(); -#endif - return Response::NOT_SUPPORTED; -} - -SerialDevice::Response SerialDevice::close() -{ -#ifdef __linux - return closeLinux(); -#endif - return Response::NOT_SUPPORTED; + return m_error; } -const int &SerialDevice::linuxFD() +std::string SerialDevice::errorStr() { - return m_linuxFD; -} + switch (m_error) + { + case NONE: + return "None"; + case FAILED_TO_OPEN_DEVICE: + return "Failed to open device"; + case FAILED_TO_GET_FD_ATTRS: + return "Failed to get file descriptor attributes"; + case FAILED_TO_SET_FD_ATTRS: + return "Failed to set file descriptor attributes"; + case NOT_SUPPORTED: + return "Operation not supported"; + case READ_FAILED: + return "Read failed"; + case WRITE_FAILED: + return "Write failed"; + case DEVICE_NOT_OPEN: + return "Device not open"; + } -SerialDevice::Response SerialDevice::read(void *byte) -{ - return read(byte, 1); + return std::format("Unknown error {}", static_cast(m_error)); } -SerialDevice::Response SerialDevice::read(void* bytes, - size_t bytesLen) +bool SerialDevice::read(unsigned char *bytes, size_t size) { #ifdef __linux - return (m_linuxFD == -1) ? - Response::ERROR_DEVICE_NOT_OPEN : - (::read(m_linuxFD, bytes, bytesLen) < 0) ? - Response::ERROR_READ_FAILED : - Response::SUCCESS; + if (m_linuxFD == -1) + { + m_error = Error::DEVICE_NOT_OPEN; + return false; + } + else + { + if (::read(m_linuxFD, bytes, size) != -1) + { + m_error = Error::NONE; + return true; + } + else + { + m_error = Error::READ_FAILED; + return false; + } + } #endif - return Response::NOT_SUPPORTED; + m_error = Error::NOT_SUPPORTED; + return false; } -SerialDevice::Response SerialDevice::write(const void *byte) +bool SerialDevice::write(const unsigned char *bytes, size_t size) { - return write(byte, 1); +#ifdef __linux + if (m_linuxFD == -1) + { + m_error = Error::DEVICE_NOT_OPEN; + return false; + } + else + { + if (::write(m_linuxFD, bytes, size) == size) + { + m_error = Error::NONE; + return true; + } + else + { + m_error = Error::WRITE_FAILED; + return false; + } + } +#endif + m_error = Error::NOT_SUPPORTED; + return false; } -SerialDevice::Response SerialDevice::write(const void* bytes, - size_t bytesLen) +bool SerialDevice::open() { #ifdef __linux - return (m_linuxFD == -1) ? - Response::ERROR_DEVICE_NOT_OPEN : - (::write(m_linuxFD, bytes, bytesLen) < 0) ? - Response::ERROR_WRITE_FAILED : - Response::SUCCESS; + return openLinux(); #endif - return Response::NOT_SUPPORTED; + m_error = Error::NOT_SUPPORTED; + return false; } -template -SerialDevice::Response SerialDevice::write(std::vector &vector) +bool SerialDevice::close() { #ifdef __linux - return (m_linuxFD == -1) ? - Response::ERROR_DEVICE_NOT_OPEN : - (::write(m_linuxFD, vector.data(), vector.size()) < 0) ? - Response::ERROR_WRITE_FAILED : - Response::SUCCESS; + return closeLinux(); #endif - return Response::NOT_SUPPORTED; + m_error = Error::NOT_SUPPORTED; + return false; } -template SerialDevice::Response SerialDevice - ::write(std::vector &vector); +const int &SerialDevice::linuxFD() +{ + return m_linuxFD; +} -SerialDevice::Response SerialDevice::openLinux() +bool SerialDevice::openLinux() { - m_linuxFD = ::open(m_targetProperties->path.c_str(), - O_RDWR | O_NOCTTY); + m_linuxFD = ::open(m_devicePath.c_str(), + O_RDWR | O_NOCTTY); if (m_linuxFD < 0) { - return Response::ERROR_FAILED_TO_OPEN_DEVICE; + m_error = Error::FAILED_TO_OPEN_DEVICE; + return false; } struct termios tty; if (ioctl(m_linuxFD, TCGETS, &tty) < 0) { - return Response::ERROR_FAILED_TO_GET_FD_ATTRS; + m_error = Error::FAILED_TO_GET_FD_ATTRS; + return false; } // Parity - if (m_targetProperties->parity) + if ( m_deviceProperties.parity) tty.c_cflag |= PARENB; else tty.c_cflag &= ~PARENB; // Stop Bit - if (m_targetProperties->stopBits == 1) + if ( m_deviceProperties.stopBits == 1) tty.c_cflag &= ~CSTOPB; else tty.c_cflag |= CSTOPB; @@ -124,18 +160,18 @@ SerialDevice::Response SerialDevice::openLinux() //Bits per byte tty.c_cflag &= ~CSIZE; - if (m_targetProperties->bits == 5) + if ( m_deviceProperties.bits == 5) tty.c_cflag |= CS5; - else if (m_targetProperties->bits == 6) + else if ( m_deviceProperties.bits == 6) tty.c_cflag |= CS6; - else if (m_targetProperties->bits == 7) + else if ( m_deviceProperties.bits == 7) tty.c_cflag |= CS7; - else if (m_targetProperties->bits == 8) + else if ( m_deviceProperties.bits == 8) tty.c_cflag |= CS8; // RTS/CTS - if (m_targetProperties->rtsCts) + if ( m_deviceProperties.rtsCts) tty.c_cflag |= CRTSCTS; else tty.c_cflag &= ~CRTSCTS; @@ -188,16 +224,30 @@ SerialDevice::Response SerialDevice::openLinux() cfsetispeed(&tty, B115200); cfsetospeed(&tty, B115200); - - return (ioctl(m_linuxFD, TCSETS, &tty) < 0) ? - ERROR_FAILED_TO_SET_FD_ATTRS : - SUCCESS; + if (!ioctl(m_linuxFD, TCSETS, &tty)) + { + m_error = Error::NONE; + return true; + } + else + { + m_error = Error::FAILED_TO_SET_FD_ATTRS; + return false; + } } -SerialDevice::Response SerialDevice::closeLinux() +bool SerialDevice::closeLinux() { ioctl(m_linuxFD, TCFLSH, 2); - return (::close(m_linuxFD) < 0) ? - ERROR_FAILED_TO_SET_FD_ATTRS : - SUCCESS; + + if (!::close(m_linuxFD)) + { + m_error = Error::NONE; + return true; + } + else + { + m_error = Error::FAILED_TO_SET_FD_ATTRS; + return false; + } } diff --git a/serialdevice.h b/serialdevice.h index f5762a8..2cd0f71 100644 --- a/serialdevice.h +++ b/serialdevice.h @@ -1,7 +1,20 @@ +/* + * Copyright (C) 2023 Debayan Sutradhar (rnayabed) (debayansutradhar3@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #ifndef SERIALDEVICE_H #define SERIALDEVICE_H -#include "targetproperties.h" +#include #include #include #include @@ -10,60 +23,62 @@ #include #include #include - #include #include - #include -/* - * Copyright (C) 2023 Debayan Sutradhar (rnayabed) (debayansutradhar3@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - #include - #include -class SerialDevice +#include "device.h" + +class SerialDevice : public Device { public: - enum Response + enum Error { - SUCCESS, - ERROR_FAILED_TO_OPEN_DEVICE, - ERROR_FAILED_TO_GET_FD_ATTRS, - ERROR_FAILED_TO_SET_FD_ATTRS, + NONE, + FAILED_TO_OPEN_DEVICE, + FAILED_TO_GET_FD_ATTRS, + FAILED_TO_SET_FD_ATTRS, NOT_SUPPORTED, - ERROR_READ_FAILED, - ERROR_WRITE_FAILED, - ERROR_DEVICE_NOT_OPEN + READ_FAILED, + WRITE_FAILED, + DEVICE_NOT_OPEN }; - SerialDevice(std::shared_ptr targetProperties); - Response open(); - Response close(); + struct DeviceProperties + { + bool parity = false; + int32_t stopBits = -1; + bool rtsCts = false; + int32_t bits = -1; + int32_t baud = -1; + }; + + constexpr static DeviceProperties ARIES{false, 1, false, 8, 115200}; + + SerialDevice(const std::filesystem::path& devicePath, const DeviceProperties& deviceProperties); + + const Error& error(); + std::string errorStr(); + + bool read(unsigned char* bytes, size_t size); + bool write(const unsigned char* bytes, size_t size); + + bool open(); + bool close(); const int& linuxFD(); - Response read(void* byte); - Response read(void* bytes, size_t bytesLen); - Response write(const void* byte); - Response write(const void* bytes, size_t bytesLen); - template Response write(std::vector& vector); private: - Response openLinux(); - Response closeLinux(); + Error m_error; + + bool openLinux(); + bool closeLinux(); int m_linuxFD; - std::shared_ptr m_targetProperties; + const std::filesystem::path& m_devicePath; + const DeviceProperties& m_deviceProperties; }; #endif // SERIALDEVICE_H diff --git a/targetproperties.h b/targetproperties.h deleted file mode 100644 index 9577193..0000000 --- a/targetproperties.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2023 Debayan Sutradhar (rnayabed) (debayansutradhar3@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef TARGETPROPERTIES_H -#define TARGETPROPERTIES_H - -#include - -struct TargetProperties -{ - std::string path; - bool parity = false; - int32_t stopBits = -1; - bool rtsCts = false; - int32_t bits = -1; - int32_t baud = -1; -}; - -#endif // TARGETPROPERTIES_H diff --git a/xmodem.cpp b/xmodem.cpp index 43ee869..97904bf 100644 --- a/xmodem.cpp +++ b/xmodem.cpp @@ -16,12 +16,40 @@ #include #include +#include +#include -XModem::XModem(std::unique_ptr serialDevice, const size_t &blockSize) - : m_serialDevice{std::move(serialDevice)}, m_blockSize{blockSize} +#include "logger.h" + +XModem::XModem(Device& device, const size_t &blockSize) + : m_device{device}, + m_blockSize{blockSize}, + m_error{Error::NONE} {} -XModem::Response XModem::upload(const std::string &filePath, const bool& startAfterUpload) +const XModem::Error &XModem::error() +{ + return m_error; +} + +std::string XModem::errorStr() +{ + switch (m_error) + { + case NONE: + return "None"; + case DEVICE_RELATED: + return "Device related error"; + case FILE_OPEN_FAILED: + return "Failed to open file"; + case CANCELLED: + return "Operation cancelled"; + } + + return std::format("Unknown error {}", static_cast(m_error)); +} + +bool XModem::upload(const std::filesystem::path &filePath, const bool& startAfterUpload) { unsigned char blockNumber1 = 1; unsigned char blockNumber2; @@ -33,7 +61,8 @@ XModem::Response XModem::upload(const std::string &filePath, const bool& startAf if(!file.is_open()) { - return XModem::Response::ERROR_FILE_OPEN_FAILED; + m_error = Error::FILE_OPEN_FAILED; + return false; } std::vector fileBlocks(m_blockSize, 0); @@ -42,13 +71,13 @@ XModem::Response XModem::upload(const std::string &filePath, const bool& startAf { unsigned char rb; - if (m_serialDevice->read(&rb) != - SerialDevice::Response::SUCCESS) + if (!m_device.read(&rb)) { - return XModem::Response::ERROR_READ_FAILED; + m_error = Error::DEVICE_RELATED; + return false; } - std::clog << "RECEIVED " << +rb << std::endl; + Logger::get() << "READ: " << +rb << Logger::NewLine; if (rb != XModem::NAK) { @@ -68,7 +97,8 @@ XModem::Response XModem::upload(const std::string &filePath, const bool& startAf } else if (rb == XModem::CAN) { - return XModem::Response::CANCELLED; + m_error = Error::CANCELLED; + return false; } else { @@ -77,12 +107,13 @@ XModem::Response XModem::upload(const std::string &filePath, const bool& startAf if (file.eof()) { - m_serialDevice->write(&EOT); + m_device.write(&EOT, 1); if (startAfterUpload) - m_serialDevice->write(&CR); + m_device.write(&CR, 1); - return XModem::Response::SUCCESS; + m_error = Error::NONE; + return true; } else { @@ -96,25 +127,26 @@ XModem::Response XModem::upload(const std::string &filePath, const bool& startAf } } - m_serialDevice->write(&XModem::SOH); - m_serialDevice->write(&blockNumber1); + m_device.write(&XModem::SOH); + m_device.write(&blockNumber1); blockNumber2 = 255 - blockNumber1; - m_serialDevice->write(&blockNumber2); + m_device.write(&blockNumber2); - m_serialDevice->write(fileBlocks); + m_device.write(fileBlocks.data(), fileBlocks.size()); - uint16_t crc = CRC::generateCRC16CCIT(fileBlocks); + uint16_t crc = CRC::generateCRC16CCITT(fileBlocks); crcBlock[0] = crc >> 8; crcBlock[1] = crc; - m_serialDevice->write(crcBlock, 2); + m_device.write(crcBlock, 2); - std::clog << "CRC " << crc << "; Sent block " << g << std::endl << std::endl; + Logger::get() << "Sent block " << g << Logger::NewLine; } - m_serialDevice->close(); + file.close(); - return XModem::SUCCESS; + m_error = Error::NONE; + return true; } diff --git a/xmodem.h b/xmodem.h index d96eb60..1cec722 100644 --- a/xmodem.h +++ b/xmodem.h @@ -14,28 +14,34 @@ #ifndef XMODEM_H #define XMODEM_H -#include "serialdevice.h" +#include "device.h" #include +#include class XModem { public: - enum Response + enum Error { - SUCCESS, - ERROR_READ_FAILED, - ERROR_FILE_OPEN_FAILED, + NONE, + DEVICE_RELATED, + FILE_OPEN_FAILED, CANCELLED }; - XModem(std::unique_ptr serialDevice, + XModem(Device& device, const size_t& blockSize); - Response upload(const std::string& filePath, const bool& startAfterUpload); + const Error& error(); + std::string errorStr(); + + bool upload(const std::filesystem::path& filePath, const bool& startAfterUpload); private: - std::unique_ptr m_serialDevice; + Error m_error; + + Device& m_device; size_t m_blockSize; constexpr static unsigned char SOH {0x01};