diff --git a/Makefile b/Makefile index 1a612d9..a768db8 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ BUILD_DIR := build DEBUG := FALSE # Objects and executable -OBJS := $(addprefix $(BUILD_DIR)/, main.o pipeline.o segfilter.o StateManager.o IdlingState.o ProcessingState.o IOBridge.o UART.o ThreadLogger.o LoggingLevel.o ) +OBJS := $(addprefix $(BUILD_DIR)/, main.o pipeline.o StateManager.o IdlingState.o ProcessingState.o segfilter.o IOBridge.o UART.o Reader.o ThreadLogger.o LoggingLevel.o ) TARGET := $(BUILD_DIR)/pipeline LIB := tensorflow @@ -26,9 +26,9 @@ ifeq ($(LIB),nvinfer) endif # Compiler flags -CFLAGS := -Wall -Werror -Wpedantic +CFLAGS := -Wall -Werror -Wpedantic -std=c++17 -fopenmp -LINKERFLAGS := -lstdc++ -lpthread +LINKERFLAGS := -lstdc++ -lpthread # Conditionally add leak sanitizer ifeq ($(LEAK),TRUE) @@ -95,7 +95,9 @@ $(BUILD_DIR)/LoggingLevel.o: $(SRC_DIR)/utils/LoggingLevel.cpp $(SRC_DIR)/utils/ @mkdir -p $(@D) $(CC) $(CFLAGS) -c $(SRC_DIR)/utils/LoggingLevel.cpp -o $@ - +$(BUILD_DIR)/Reader.o: $(SRC_DIR)/utils/Reader.cpp $(SRC_DIR)/utils/Reader.hpp + @mkdir -p $(@D) + $(CC) $(CFLAGS) -c $(SRC_DIR)/utils/Reader.cpp -o $@ diff --git a/src/bridge/UART.cpp b/src/bridge/UART.cpp index 0049b63..ccc632b 100644 --- a/src/bridge/UART.cpp +++ b/src/bridge/UART.cpp @@ -6,9 +6,9 @@ UartIO::UartIO(ThreadLogger *logger) // SETUP SERIAL WORLD struct termios port_options; // Create the structure - + uartId = open(uart_target, O_RDWR | O_NOCTTY); tcgetattr(uartId, &port_options); // Get the current attributes of the Serial port - + //------------------------------------------------ // OPEN THE UART //------------------------------------------------ @@ -24,7 +24,8 @@ UartIO::UartIO(ThreadLogger *logger) // Caution: VMIN and VTIME flags are ignored if O_NONBLOCK flag is set. // O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.uartId = open("/dev/ttyTHS1", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode - uartId = open(uart_target, O_RDWR | O_NOCTTY); + + tcflush(uartId, TCIFLUSH); tcflush(uartId, TCIOFLUSH); diff --git a/src/filter/IFilter.hpp b/src/filter/IFilter.hpp index 472efd7..4e933a4 100644 --- a/src/filter/IFilter.hpp +++ b/src/filter/IFilter.hpp @@ -5,6 +5,6 @@ class IFilter { public: virtual ~IFilter() {} - virtual void doProcessing(unsigned char* image, int width, int height, int channels) = 0; + virtual int * doProcessing(unsigned char* image, int width, int height, int channels) = 0; virtual void doDecision() = 0; }; diff --git a/src/filter/segfilter.cpp b/src/filter/segfilter.cpp index c30b073..ea4bc52 100644 --- a/src/filter/segfilter.cpp +++ b/src/filter/segfilter.cpp @@ -3,8 +3,8 @@ -void SegFilter::doProcessing(unsigned char* image, int width, int height, int channels) { - SegFilter::model -> predict(image, width, height, channels); +int * SegFilter::doProcessing(unsigned char* image, int width, int height, int channels) { + return SegFilter::model -> predict(image, width, height, channels); } void SegFilter::doDecision() { @@ -14,7 +14,7 @@ void SegFilter::doDecision() { SegFilter::SegFilter(const char *modelPath,ThreadLogger * logger) { logger -> log("Mounting segmentation filter..."); - IModel * model = new TFLiteModel(logger); + IModel * model = new TensorRTModel(logger); model -> loadModel(modelPath); SegFilter::model = model; diff --git a/src/filter/segfilter.hpp b/src/filter/segfilter.hpp index a144f34..dfc42ce 100644 --- a/src/filter/segfilter.hpp +++ b/src/filter/segfilter.hpp @@ -2,7 +2,7 @@ #define SEG_FILTER_H #include "IFilter.hpp" -#include "../model/TFLiteModel.hpp" +#include "../model/TensorRTModel.hpp" #include #include "../utils/ThreadLogger.hpp" @@ -14,7 +14,7 @@ class SegFilter: public IFilter{ public: SegFilter(const char *modelPath,ThreadLogger * logger); ~SegFilter(); - virtual void doProcessing(unsigned char* image, int width, int height, int channels); + virtual int * doProcessing(unsigned char* image, int width, int height, int channels); virtual void doDecision(); }; diff --git a/src/model/IModel.hpp b/src/model/IModel.hpp index 24d4f75..5fdbddf 100644 --- a/src/model/IModel.hpp +++ b/src/model/IModel.hpp @@ -7,5 +7,5 @@ class IModel public: virtual ~IModel() {} virtual void loadModel(const char *modelPath) = 0; - virtual void predict(unsigned char* image, int height, int width, int channels) = 0; + virtual int * predict(unsigned char* image, int height, int width, int channels) = 0; }; \ No newline at end of file diff --git a/src/model/TFLiteModel.cpp b/src/model/TFLiteModel.cpp index a08aaae..a2c3bec 100644 --- a/src/model/TFLiteModel.cpp +++ b/src/model/TFLiteModel.cpp @@ -43,7 +43,7 @@ void TFLiteModel::loadModel(const char *modelPath) TF_DeleteBuffer(model_buffer); } -void TFLiteModel::predict(unsigned char *image, int height, int width, int channels) +int * TFLiteModel::predict(unsigned char *image, int height, int width, int channels) { TFLiteModel::logger -> log("Performing inference"); @@ -51,7 +51,7 @@ void TFLiteModel::predict(unsigned char *image, int height, int width, int chann { LoggingLevelWrapper level(LoggingLevel::ERROR); TFLiteModel::logger -> log(level, "Graph not initialized"); - return; + return nullptr; } // Set input tensor TF_DataType dtype = TF_UINT8; @@ -69,13 +69,13 @@ void TFLiteModel::predict(unsigned char *image, int height, int width, int chann { LoggingLevelWrapper level(LoggingLevel::ERROR); TFLiteModel::logger -> log(level,"TF object session not initialized"); - return; + return nullptr; } if (status == nullptr) { LoggingLevelWrapper level(LoggingLevel::ERROR); TFLiteModel::logger -> log(level,"TF object status not initialized"); - return; + return nullptr; } this -> logger -> log("Running session"); @@ -85,7 +85,7 @@ void TFLiteModel::predict(unsigned char *image, int height, int width, int chann this -> logger -> log("Session run"); if (input_tensor) TF_DeleteTensor(input_tensor); - + return nullptr; } void TFLiteModel::deallocator(void *data, size_t length, void *arg) { diff --git a/src/model/TFLiteModel.hpp b/src/model/TFLiteModel.hpp index 0202d05..1394594 100644 --- a/src/model/TFLiteModel.hpp +++ b/src/model/TFLiteModel.hpp @@ -22,7 +22,7 @@ class TFLiteModel : public IModel{ TFLiteModel(ThreadLogger * logger); virtual ~TFLiteModel(); virtual void loadModel(const char *modelPath); - virtual void predict(unsigned char* image, int height, int width, int channels); + virtual int * predict(unsigned char* image, int height, int width, int channels); }; #endif // MODEL_HPP \ No newline at end of file diff --git a/src/model/TensorRTModel.cpp b/src/model/TensorRTModel.cpp index fb2f35b..8705d83 100644 --- a/src/model/TensorRTModel.cpp +++ b/src/model/TensorRTModel.cpp @@ -3,8 +3,9 @@ class Logger : public nvinfer1::ILogger { ThreadLogger *logger; - - public:void setLogger(ThreadLogger *logger) + +public: + void setLogger(ThreadLogger *logger) { Logger::logger = logger; } @@ -90,12 +91,12 @@ void TensorRTModel::loadModel(const char *modelPath) } } -void TensorRTModel::predict(unsigned char *image, int height, int width, int channels) +int *TensorRTModel::predict(unsigned char *image, int height, int width, int channels) { if (engine == nullptr) { this->logger->log("Engine not initialized\n"); - return; + return nullptr; } this->logger->log("Performing TensorRT inference...\n"); // Allocate GPU memory for the input and output buffers @@ -117,12 +118,32 @@ void TensorRTModel::predict(unsigned char *image, int height, int width, int cha float *cpu_output = new float[height * width * 7]; cudaMemcpy(cpu_output, gpu_output, sizeof(float) * height * width * 7, cudaMemcpyDeviceToHost); - // Clean up - //! TODO: This is possibly the image output from the model so it has to be returned - delete[] cpu_output; - cudaFree(gpu_input); cudaFree(gpu_output); + + int *max_indices = new int[height * width]; delete context; + + // Parallelized post-processing using OpenMP + #pragma omp parallel for + for (int i = 0; i < height * width; ++i) + { + float max_value = cpu_output[i * 7]; + int max_index = 0; + for (int j = 1; j < 7; ++j) + { + if (cpu_output[i * 7 + j] > max_value) + { + max_value = cpu_output[i * 7 + j]; + max_index = j; + } + } + max_indices[i] = max_index; + } + // Clean up + //! TODO: This is possibly the image output from the model so it has to be returned + + this->logger->log("TensorRT inference done!\n"); + return max_indices; } \ No newline at end of file diff --git a/src/model/TensorRTModel.hpp b/src/model/TensorRTModel.hpp index f750523..991aa5b 100644 --- a/src/model/TensorRTModel.hpp +++ b/src/model/TensorRTModel.hpp @@ -21,7 +21,7 @@ class TensorRTModel : public IModel{ TensorRTModel(ThreadLogger * logger); virtual ~TensorRTModel(); virtual void loadModel(const char *modelPath); - virtual void predict(unsigned char* image, int height, int width, int channels); + virtual int * predict(unsigned char* image, int height, int width, int channels); }; #endif // TENSORRTMODEL_HPP diff --git a/src/pipeline.cpp b/src/pipeline.cpp index 9b27938..51eaf18 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -6,7 +6,7 @@ Pipeline::Pipeline(){ this->logger = new ThreadLogger(); logger->log("Starting system pipeline..."); this->stateManager = new StateManager(logger); - this->stateManager->transitionTo(new IdlingState()); + this->stateManager->transitionTo(new ProcessingState()); this->ioBridge = new IOBridge(logger, stateManager); stateManager -> pushShutdown([this](){this -> stop();}); } diff --git a/src/state/ProcessingState.cpp b/src/state/ProcessingState.cpp index b1d5d0c..417d5a6 100644 --- a/src/state/ProcessingState.cpp +++ b/src/state/ProcessingState.cpp @@ -1,19 +1,55 @@ #include "ProcessingState.hpp" -#define STB_IMAGE_IMPLEMENTATION +// #define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_RESIZE_IMPLEMENTATION +#include "../stb_files/stb_image_resize.h" #include "../stb_files/stb_image.h" using namespace std; +unsigned char* cropImageToSquare(unsigned char* imgData, int width, int height, int channels) { + int newDim = std::min(width, height); + unsigned char* newImgData = new unsigned char[newDim * newDim * channels]; + + int xOffset = (width - newDim) / 2; + int yOffset = (height - newDim) / 2; + + for (int y = 0; y < newDim; ++y) { + for (int x = 0; x < newDim; ++x) { + for (int c = 0; c < channels; ++c) { + int oldIndex = ((y + yOffset) * width + (x + xOffset)) * channels + c; + int newIndex = (y * newDim + x) * channels + c; + newImgData[newIndex] = imgData[oldIndex]; + } + } + } + + return newImgData; +} -ProcessingState::ProcessingState(){ +unsigned char* resizeImage(unsigned char* imgData, int width, int height, int channels, int newWidth, int newHeight) { + unsigned char* resizedImgData = new unsigned char[newWidth * newHeight * channels]; + stbir_resize_uint8(imgData, width, height, 0, resizedImgData, newWidth, newHeight, 0, channels); + return resizedImgData; +} + + + +ProcessingState::ProcessingState(){ + this -> progress = 0; } ProcessingState::~ProcessingState(){ + this -> reader -> unmountDrive(); + delete ProcessingState::segFilter; + delete ProcessingState::reader; ProcessingState::logger -> log("System exiting processing state"); + } + + std::string ProcessingState::getName(){ return "Processing state"; } @@ -23,39 +59,94 @@ int ProcessingState::getStateCode(){ } int ProcessingState::runStateProcess(){ + this -> progress = 1; ProcessingState::logger->log("System entered processing state..."); // IO reading - int width, height, channels; - unsigned char* image = stbi_load("1499_sat.jpg", &width, &height, &channels, 0); - if (image == nullptr) { - // Process the image + if(!this -> reader -> isMounted()){ + this -> reader -> mountDrive(); + } + + if (this -> reader -> isMounted()){ + this -> logger -> log("USB drive mounted successfully"); + } else { LoggingLevelWrapper level(LoggingLevel::ERROR); - this->logger->log(level,"Error loading image: ", stbi_failure_reason()); + this -> logger -> log(level,"USB drive failed to mount"); + usleep(1000000); //1 second idle + return 1; + } + + this -> progress = 2; + + if (!this -> reader -> isAvailable()){ + LoggingLevelWrapper level(LoggingLevel::WARNING); + this -> logger -> log(level,"No files are availabe to process"); + usleep(1000000); //1 second idle + return 2; + } + + std::tuple imageTuple = this -> reader -> read(); + + this -> progress = 3; + + unsigned char* image = std::get<0>(imageTuple); + if (image == nullptr){ + LoggingLevelWrapper level(LoggingLevel::ERROR); + this -> logger -> log(level,"Error reading image"); this->logger->log("Skipping processing stage..."); + usleep(1000000); //1 second idle return 1; } + int width = std::get<1>(imageTuple); + int height = std::get<2>(imageTuple); + int channels = std::get<3>(imageTuple); + + // cut image to 1:1 ratio + + unsigned char* croppedImage = cropImageToSquare(image, width, height, channels); + stbi_image_free(image); + + // Resize image to 512x512x3 + + int targetWidth = 512; + int targetHeight = 512; + + unsigned char* resizedImage = resizeImage(croppedImage, width, height, channels, targetWidth, targetHeight); + delete croppedImage; + + + this -> progress = 4; + // int width, height, channels; + // unsigned char* image = stbi_load("1499_sat.jpg", &width, &height, &channels, 0); + //! for some reason this function prints the data incorrectly //! however the data itself is correct this->logger->log("Loaded image with a width of %d px, a height of %d px and %d channels",width,height,channels); // data processing - SegFilter segfilter("model.engine",this -> logger); - segfilter.doProcessing(image, width, height, channels); - segfilter.doDecision(); + + int * output = this -> segFilter -> doProcessing(resizedImage, width, height, channels); + this -> progress = 5; + this -> segFilter -> doDecision(); + this -> progress = 6; ProcessingState::logger -> log("Processing done"); // image compression - + //! due to time constraints this part is not implemented // IO writing - - if (image != nullptr){ - stbi_image_free(image); + + // freeing data + delete[] output; + if (resizedImage != nullptr){ + delete resizedImage; } - - + this -> reader -> removeLoaded(); + this -> progress = 7; return 0; } void ProcessingState::setLogger(ThreadLogger * logger){ ProcessingState::logger = logger; + ProcessingState::segFilter = new SegFilter("model.engine",this -> logger); + ProcessingState::reader = new Reader(this -> logger); logger->log("Processing state initialized...\n"); -} \ No newline at end of file + +} diff --git a/src/state/ProcessingState.hpp b/src/state/ProcessingState.hpp index 5440072..6dcbb09 100644 --- a/src/state/ProcessingState.hpp +++ b/src/state/ProcessingState.hpp @@ -4,20 +4,28 @@ #include "../filter/segfilter.hpp" #include "../utils/ThreadLogger.hpp" #include "../utils/LoggingLevel.hpp" +#include "../utils/Reader.hpp" +#include +#include #ifndef PROCESSING_STATE_HPP #define PROCESSING_STATE_HPP -class ProcessingState : public IState { +class ProcessingState : public IState +{ private: - ThreadLogger * logger; + ThreadLogger *logger; + SegFilter *segFilter; + Reader *reader; + int progress; + public: ProcessingState(); virtual ~ProcessingState(); virtual std::string getName(); virtual int runStateProcess(); virtual int getStateCode(); - virtual void setLogger(ThreadLogger * logger); + virtual void setLogger(ThreadLogger *logger); }; #endif // PROCESSING_STATE_HPP \ No newline at end of file diff --git a/src/state/StateManager.cpp b/src/state/StateManager.cpp index 1a33141..a9a3063 100644 --- a/src/state/StateManager.cpp +++ b/src/state/StateManager.cpp @@ -1,88 +1,109 @@ #include "StateManager.hpp" - -StateManager::StateManager(ThreadLogger * logger) { +StateManager::StateManager(ThreadLogger *logger) +{ StateManager::logger = logger; StateManager::stateMutex = new std::mutex(); StateManager::state = nullptr; - StateManager::logger -> log("State manager initialized..."); + StateManager::logger->log("State manager initialized..."); StateManager::transitioned = false; StateManager::shutdownQueue = new std::queue>(); } -StateManager::~StateManager() { +StateManager::~StateManager() +{ delete StateManager::state; delete StateManager::stateMutex; - if (StateManager::requestedState != nullptr){ + if (StateManager::requestedState != nullptr) + { delete StateManager::requestedState; } delete StateManager::shutdownQueue; } -IState * StateManager::getState() { +IState *StateManager::getState() +{ return StateManager::state; } -IState * StateManager::getRequestedState() { +IState *StateManager::getRequestedState() +{ std::lock_guard guard(*StateManager::stateMutex); return StateManager::requestedState; } -void StateManager::setTransitionState(bool transitioned){ +void StateManager::setTransitionState(bool transitioned) +{ std::lock_guard guard(*StateManager::stateMutex); StateManager::transitioned = transitioned; } -bool StateManager::getTransitionState(){ +bool StateManager::getTransitionState() +{ std::lock_guard guard(*StateManager::stateMutex); return StateManager::transitioned; } -int StateManager::getStateCode(){ +int StateManager::getStateCode() +{ + std::lock_guard guard(*StateManager::stateMutex); + + if (StateManager::state == nullptr) + { + return -1; + } return StateManager::state->getStateCode(); } -void StateManager::requestState(IState * state) { - // sets requested state +void StateManager::requestState(IState *state) +{ + // sets requested state std::lock_guard guard(*StateManager::stateMutex); StateManager::requestedState = state; - } -void StateManager::transitionTo(IState * state) { +void StateManager::transitionTo(IState *state) +{ // frees previous state - if (state == nullptr){ + std::lock_guard guard(*StateManager::stateMutex); + if (state == nullptr) + { LoggingLevelWrapper level(LoggingLevel::ERROR); - StateManager::logger -> log(level,"cannot transition to null state!"); + StateManager::logger->log(level, "cannot transition to null state!"); return; } - if (StateManager::state != nullptr){ + if (StateManager::state != nullptr) + { delete StateManager::state; } - StateManager::logger -> log("Transitioning to %s" , state -> getName().c_str()); - + StateManager::logger->log("Transitioning to %s", state->getName().c_str()); // sets new state StateManager::state = state; - StateManager::state -> setLogger(StateManager::logger); - if (StateManager::state -> getName() == "StopState"){ + StateManager::state->setLogger(StateManager::logger); + + if (StateManager::state->getName() == "StopState") + { StateManager::shutdown(); } - } -void StateManager::runStateProcess() { +void StateManager::runStateProcess() +{ // runs state process - StateManager::state -> runStateProcess(); + + StateManager::state->runStateProcess(); } -void StateManager::pushShutdown(std::function shutdownFunction){ +void StateManager::pushShutdown(std::function shutdownFunction) +{ std::lock_guard guard(*StateManager::stateMutex); - StateManager::shutdownQueue -> push(shutdownFunction); + StateManager::shutdownQueue->push(shutdownFunction); } -void StateManager::shutdown(){ - std::lock_guard guard(*StateManager::stateMutex); - while (!StateManager::shutdownQueue -> empty()){ - StateManager::shutdownQueue -> front()(); - StateManager::shutdownQueue -> pop(); +void StateManager::shutdown() +{ + while (!StateManager::shutdownQueue->empty()) + { + StateManager::shutdownQueue->front()(); + StateManager::shutdownQueue->pop(); } } \ No newline at end of file diff --git a/src/utils/Reader.cpp b/src/utils/Reader.cpp new file mode 100644 index 0000000..3ad6fc4 --- /dev/null +++ b/src/utils/Reader.cpp @@ -0,0 +1,157 @@ +#include "Reader.hpp" + +#define STB_IMAGE_IMPLEMENTATION + +#include "../stb_files/stb_image.h" +using namespace std; +Reader::Reader(ThreadLogger * logger){ + Reader::logger = logger; + Reader::usbDevice = "/dev/sda1"; + Reader::mountPoint = "/media/usbdrive"; + Reader::subFolder = "/DCIM/Photo"; + +} + +Reader::~Reader(){ + Reader::logger->log("Reader destroyed"); +} + +int Reader::mountDrive(){ + // Identify the USB drive (usually /dev/sda1, /dev/sdb1, etc.) + + + // Create the mount point directory + std::string mkdirCmd = "sudo mkdir -p " + this -> mountPoint; + system(mkdirCmd.c_str()); + + // Mount the USB drive + std::string mountCmd = "sudo mount " + this -> usbDevice + " " + this -> mountPoint; + int result = system(mountCmd.c_str()); + + if (result == 0) { + Reader::logger->log("USB drive mounted successfully at %s", this -> mountPoint.c_str()); + } else { + Reader::logger->log("Failed to mount USB drive."); + } + return result; +} + +int Reader::unmountDrive(){ + + // Unmount the USB drive + std::string unmountCmd = "sudo umount " + this -> mountPoint; + int unmountResult = system(unmountCmd.c_str()); + + if (unmountResult == 0) { + Reader::logger->log("USB drive unmounted successfully from %s", this -> mountPoint.c_str()); + } else { + Reader::logger->log("Failed to unmount USB drive."); + } + + return unmountResult; +} + +bool Reader::isMounted(){ + std::ifstream mountsFile("/proc/mounts"); + std::string line; + + if (!mountsFile.is_open()) { + std::cerr << "Failed to open /proc/mounts" << std::endl; + return false; + } + + while (getline(mountsFile, line)) { + if (line.find(this -> usbDevice) != std::string::npos && line.find(this -> mountPoint) != std::string::npos) { + this -> logger -> log("USB drive is mounted"); + return true; + } + } + this -> logger -> log("USB drive is not mounted"); + return false; +} + +//Maybe obsolete and not going to be needed. +//Further testing is required. +int Reader::isAvailable(){ + const auto existingDir = this -> mountPoint + this -> subFolder; // Should exist in file system. + int counter = 0; + this -> logger -> log("Checking for files to read from %s", existingDir.c_str()); + for (const auto& entry : std::filesystem::directory_iterator(existingDir)) { + std::string path = entry.path().string(); + counter++; + } + if (counter == 0){ + Reader::logger->log("No files to read"); + return 0; + } + + return counter; +} + +std::tuple Reader::read(){ + const auto existingDir = this -> mountPoint+ this -> subFolder; // Should exist in file system. + Reader::logger -> log("%s", existingDir.c_str()); + if (!fs::exists(existingDir) || !fs::is_directory(existingDir)) { + Reader::logger->log("Read target is not mounted"); + return std::make_tuple(nullptr, 0, 0, 0); + } + + Reader::logger->log("Read target is mounted for reading"); + int counter = 0; + // read the first file + int width, height, channels; + //log number of files in directory + Reader::logger->log("Found %d files in directory", Reader::isAvailable()); + for (const auto& entry : std::filesystem::directory_iterator(existingDir)) { + std::string path = entry.path().string(); + unsigned char * image = stbi_load(path.c_str(), &width, &height, &channels, 0); + if (image == nullptr) { + // Process the image + LoggingLevelWrapper level(LoggingLevel::ERROR); + this->logger->log(level,"Error loading image: ", stbi_failure_reason()); + this->logger->log("Skipping processing stage..."); + return std::make_tuple(nullptr, 0, 0, 0); + } + this -> lastLoaded = path; + this -> logger -> log("Loaded image with a width of %d px, a height of %d px and %d channels",width,height,channels); + return std::make_tuple(image, width, height, channels); + } + + if (counter == 0){ + Reader::logger->log("No files to read"); + return std::make_tuple(nullptr, 0, 0, 0); + } + + return std::make_tuple(nullptr, 0, 0, 0); +} + +void Reader::removeLoaded(){ + if (this -> lastLoaded != ""){ + if (fs::remove(this -> lastLoaded)) { + std::cout << "File deleted successfully.\n"; + } else { + std::cout << "Error deleting the file.\n"; + } + } + this -> lastLoaded = ""; +} + + + +// int main(){ +// ThreadLogger * logger = new ThreadLogger(); +// Reader * reader = new Reader(logger); +// if (reader->isMounted()){ +// reader->unmountDrive(); +// } +// reader->mountDrive(); +// reader->isAvailable(); +// auto image = reader->read(); +// if (image != nullptr){ +// stbi_image_free(image); +// } +// reader->unmountDrive(); +// delete reader; +// delete logger; +// return 0; +// } diff --git a/src/utils/Reader.hpp b/src/utils/Reader.hpp new file mode 100644 index 0000000..b1133a8 --- /dev/null +++ b/src/utils/Reader.hpp @@ -0,0 +1,36 @@ +#include "ThreadLogger.hpp" +#include +#include +#include +#include +#include + +#ifndef READER_HPP +#define READER_HPP +namespace fs = std::filesystem; + + +class Reader { +public: + Reader(ThreadLogger * logger); + ~Reader(); + int mountDrive(); + int unmountDrive(); + bool isMounted(); + int isAvailable(); + void removeLoaded(); + std::tuple read(); + + +private: + ThreadLogger * logger; + std::string mountPoint; + std::string subFolder; + std::string usbDevice; + std::string lastLoaded = ""; + +}; + + + +#endif // READER_HPP \ No newline at end of file diff --git a/src/utils/ThreadLogger.cpp b/src/utils/ThreadLogger.cpp index 79fe3c7..2fbb217 100644 --- a/src/utils/ThreadLogger.cpp +++ b/src/utils/ThreadLogger.cpp @@ -28,23 +28,20 @@ ThreadLogger::~ThreadLogger() std::cout << "Logger thread terminated" << std::endl; } -void ThreadLogger::log(LoggingLevelWrapper loggingLevel,const char *format, ...) -{ - - va_list args; - va_start(args, format); +void ThreadLogger::insertLog(LoggingLevelWrapper loggingLevel,const char *format,va_list args){ + // Determine the length of the formatted string int length = vsnprintf(NULL, 0, format, args); - va_end(args); // end variable argument list + // Allocate a buffer to hold the formatted string char *buffer = new char[length + 1]; - va_start(args, format); // start variable argument list again + // Format the string into the buffer vsnprintf(buffer, length + 1, format, args); - va_end(args); // end variable argument list + // Get the current date and time time_t currentTime = time(nullptr); struct tm *timeinfo = localtime(¤tTime); @@ -77,16 +74,20 @@ void ThreadLogger::log(LoggingLevelWrapper loggingLevel,const char *format, ...) va_end(args); } +void ThreadLogger::log(LoggingLevelWrapper loggingLevel,const char *format, ...) +{ + va_list args; + va_start(args, format); + ThreadLogger::insertLog(loggingLevel,format, args); + va_end(args); + +} + void ThreadLogger::log(const char *format, ...){ va_list args; va_start(args, format); LoggingLevelWrapper defaultLoggingLevel(LoggingLevel::INFO); - - va_list args_copy; - va_copy(args_copy, args); - ThreadLogger::log(defaultLoggingLevel, format, args_copy); - va_end(args_copy); - + ThreadLogger::insertLog(defaultLoggingLevel, format, args); va_end(args); } diff --git a/src/utils/ThreadLogger.hpp b/src/utils/ThreadLogger.hpp index b252bc8..1c1c643 100644 --- a/src/utils/ThreadLogger.hpp +++ b/src/utils/ThreadLogger.hpp @@ -20,7 +20,7 @@ class ThreadLogger { void logMessage(); std::thread logThread; bool stopLogger; - + void insertLog(LoggingLevelWrapper LoggingLevel,const char* format, va_list args); public: ThreadLogger(); ~ThreadLogger();