Push local changes for complete and functioning probe

This commit is contained in:
Adam Prochazka
2023-05-09 17:36:09 +02:00
parent 836ab547df
commit ea70f82c92
39 changed files with 8678 additions and 50419 deletions

View File

@ -58,6 +58,7 @@
"stop_token": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
"typeinfo": "cpp",
"fstream": "cpp"
}
}

View File

@ -1,3 +1,12 @@
/**
* @file Displayer.cpp
* @brief Source file for the Displayer class.
* @author Adam Prochazka <xproch0f>
*
* This file contains the implementation of the Displayer class which is responsible for
* rendering the images received from the Receiver class.
*/
#include "main.hpp"
#include "Displayer.hpp"
@ -8,10 +17,9 @@ int Displayer::createWindow() {
return 1;
}
window = SDL_CreateWindow("Image Viewer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1920, 1080, SDL_WINDOW_SHOWN);
window = SDL_CreateWindow("Profilometer View", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1920, 1080, SDL_WINDOW_SHOWN);
if (!window) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window: %s", SDL_GetError());
//SDL_Quit();
return 1;
}
@ -23,18 +31,15 @@ int Displayer::renderWindow(){
if (!renderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create renderer: %s", SDL_GetError());
//SDL_DestroyWindow(window);
//SDL_Quit();
return 1;
}
return 0;
}
#define PRINT_BUFFER 0
int Displayer::imageFromVector(std::vector<uint8_t>* img){
#if PRINT_BUFFER
int Displayer::imageFromVector(std::vector<uint8_t>* img, bool printRaw){
if(printRaw){
std::cout << "______________" << std::endl;
for(int i = 0; i<(int)(img)->size(); i++)
@ -44,7 +49,7 @@ int Displayer::imageFromVector(std::vector<uint8_t>* img){
std::cout << std::endl;
std::cout << "______________" << std::endl;
#endif
}
imageRwops = SDL_RWFromMem(img->data(), img->size());
return 0;
@ -52,12 +57,10 @@ int Displayer::imageFromVector(std::vector<uint8_t>* img){
int Displayer::createImageSurface(){
imageSurface = IMG_Load_RW(imageRwops, 0);
if (!imageSurface) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load image: %s", IMG_GetError());
//SDL_DestroyRenderer(renderer);
//SDL_DestroyWindow(window);
//SDL_Quit();
//return 1;
return 1;
}
return 0;
@ -106,13 +109,12 @@ int Displayer::windowDestroy(){
return 0;
}
int Displayer::windowLoop(){
bool quit = false;
while (!quit) {
int Displayer::windowLoop(bool *q){
while (!(*q)) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
*q = true;
}
}
@ -145,8 +147,8 @@ int Displayer::windowLoop(){
}
int Displayer::vectorToTexture(std::vector<uint8_t>* img){
imageFromVector(img);
int Displayer::vectorToTexture(std::vector<uint8_t>* img, bool printRaw){
imageFromVector(img, printRaw);
createImageSurface();
textureFromSurface();
@ -165,5 +167,6 @@ int Displayer::flipThroughTextures(){
flipIdx++;
flipIdx%=2;
}
return 0;
}

View File

@ -1,5 +1,19 @@
/**
* @file Displayer.hpp
* @brief Header file for the Displayer class.
* @author Adam Prochazka <xproch0f>
*
* This file contains the declaration of the Displayer class which is responsible for
* rendering the images received from the Receiver class.
*/
#include "main.hpp"
#define DISPLAYER_HPP
/*!
* \class Displayer
* \brief This class is responsible for displaying image data to user, that includes storing image bytes inside buffer, creating textures from those bytes, rendering UI and updating UI.
*/
class Displayer {
private:
SDL_Window* window;
@ -16,19 +30,63 @@ class Displayer {
std::mutex currentTextureIndexMutex;
public:
/*!
* \brief Create the main SDL window.
* \return 0 on success, 1 on failure.
*/
int createWindow();
/*!
* \brief Render the main SDL window.
* \return 0 on success, 1 on failure.
*/
int renderWindow();
int imageFromVector(std::vector<uint8_t>* img);
/*!
* \brief Copy image data from a vector to an SDL_RWops structure.
* \param[in] img A pointer to the vector containing the image data.
* @param printRaw Bool that indicates weather received byte data should be printed to std::out (for debug).
* \return 0.
*/
int imageFromVector(std::vector<uint8_t>* img, bool printRaw = false);
/*!
* \brief Create an SDL_Surface from the SDL_RWops structure containing image data.
* \return 0 on success, 1 on failure.
*/
int createImageSurface();
/*!
* \brief Create an SDL_Texture from an SDL_Surface and store it to last recently used texture buffer.
* \return 0 on success, 1 on failure.
*/
int textureFromSurface();
int vectorToTexture(std::vector<uint8_t>* img);
/*!
* \brief Convert a vector of image data to an SDL_Texture and store it to laset recently used texture buffer.
* \param[in] img A pointer to the vector containing the image data.
* @param printRaw Bool that indicates weather received byte data should be printed to std::out (for debug).
* \return 0.
*/
int vectorToTexture(std::vector<uint8_t>* img, bool printRaw = false);
/*!
* \brief Destroy the main SDL window, SDL renderer and SDL textures stored in buffers.
* \return 0 on success, 1 on failure.
*/
int windowDestroy();
int windowLoop();
/*!
* \brief Run the main window loop, refresh currently rendered texture buffer with newest one from texture buffers.
* \return 0.
*/
int windowLoop(bool *q);
/*!
* \brief Test function to see if rendering works by infinitelly flipping between two predefined textures.
* \return 0.
*/
int flipThroughTextures();
};

2763
Receiver/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,9 @@ OBJS = $(SRCS:.cpp=.o)
all: main
doc:
doxygen
main: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o main $(LDLIBS)
@ -14,4 +17,4 @@ main: $(OBJS)
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) main
rm -rf $(OBJS) main doc

View File

@ -1,3 +1,12 @@
/**
* @file Receiver.cpp
* @brief Source file for the Receiver class.
* @author Adam Prochazka <xproch0f>
*
* This file contains the implementation of the Receiver class which is responsible for
* managing the serial communication and processing the received data to display images.
*/
#include "Receiver.hpp"
Receiver::Receiver(Displayer *displayerPtr){
@ -8,10 +17,10 @@ void Receiver::printHex(unsigned char value) {
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(value);
}
void Receiver::openStream(){
void Receiver::openStream(char * port){
while(1){
// Open the CDC device file for reading
cdcFile = open("/dev/ttyACM1", O_RDWR | O_NOCTTY);
// Open the CDC device file for reading
cdcFile = open(port, O_RDWR | O_NOCTTY);
if(cdcFile == -1){
std::cerr << "Failed to open CDC device file" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
@ -23,13 +32,18 @@ void Receiver::openStream(){
}
}
void Receiver::closeStream(){
close(cdcFile);
}
int Receiver::initSerial(){
memset(&tty, 0, sizeof(tty));
if (tcgetattr(cdcFile, &tty) != 0) {
std::cerr << "Error in tcgetattr" << std::endl;
return -1;
}
//tcflush(cdcFile, TCIFLUSH);
//CDC communication configuration
cfsetospeed(&tty, B115200);
cfsetispeed(&tty, B115200);
tty.c_cflag |= (CLOCAL | CREAD);
@ -119,49 +133,25 @@ int Receiver::simulateRead(unsigned char (*character)[CDC_FRAME_SIZE]){
}
int Receiver::getDistance(){
uint16_t dist = 0;
int distCorrupted = 1;
unsigned char distanceFrame[12];
int bytesRead = read(cdcFile, distanceFrame, 12);
if(bytesRead == -1){
std::cout<<"ERROR IN READ!!! ";
}
std::cout<<"distance: ";
for(int i=0; i<7; i++){
if(distanceFrame[i] == 0xff && distanceFrame[i+1] == 0x69 && distanceFrame [i+4] == 0xff && distanceFrame[i+5] == 0x69){
dist = (distanceFrame[i+2] << 8 | distanceFrame[i+3]);
std::cout << " - " << static_cast<int>(dist) << " - ";
Receiver::printHex(distanceFrame[i+2]);
std::cout << " ";
Receiver::printHex(distanceFrame[i+3]);
std::cout << std::endl;
distCorrupted = 0;
return 0;
distance = (distanceFrame[i+2] << 8 | distanceFrame[i+3]);
}
}
if(distCorrupted) {
std::cout << "Corrupted :( -> ";
for(int i = 0; i<12; i++) {
Receiver::printHex(distanceFrame[i]);
std::cout << " ";
}
std::cout << std::endl;
}
std::cout << " Distance: " << std::dec << distance << " mm" << std::endl;
return 1;
}
int Receiver::fillBuffer(){
int Receiver::fillBuffer(bool saveToFile){
unsigned char character[CDC_FRAME_SIZE];
std::vector<uint8_t> tempVec{};
@ -187,18 +177,16 @@ int Receiver::fillBuffer(){
Receiver::getDistance();
//////////// SAVE FRAMES TO FILES
/*
std::ofstream outfile(std::to_string(debugFileIdx) + ".jpg", std::ios::out | std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Failed to create file " << debugFileIdx << ".jpg" << std::endl;
return 1;
if(saveToFile){
std::ofstream outfile(std::to_string(debugFileIdx) + "_" + std::to_string(distance) + "_mm" + ".jpg", std::ios::out | std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Failed to create file " << debugFileIdx << ".jpg" << std::endl;
return 1;
}
outfile.write(reinterpret_cast<const char*>(tempVec.data()), tempVec.size());
outfile.close();
debugFileIdx++;
}
outfile.write(reinterpret_cast<const char*>(tempVec.data()), tempVec.size());
outfile.close();
debugFileIdx++;
*/
////////////
currentBufferIndexMutex.lock();
@ -223,22 +211,19 @@ int Receiver::fillBuffer(){
return 1;
}
void Receiver::bufferToDisplay(){
void Receiver::bufferToDisplay(bool printRaw){
currentBufferIndexMutex.lock();
int buffIdx = currentBufferIndex;
currentBufferIndexMutex.unlock();
switch(buffIdx){
case 0:
//std::cout << buffer1.size() << std::endl;
dis->vectorToTexture(&buffer1);
dis->vectorToTexture(&buffer1, printRaw);
break;
case 1:
//std::cout << buffer2.size() << std::endl;
dis->vectorToTexture(&buffer2);
dis->vectorToTexture(&buffer2, printRaw);
break;
case 2:
//std::cout << buffer3.size() << std::endl;
dis->vectorToTexture(&buffer3);
dis->vectorToTexture(&buffer3, printRaw);
break;
default:
std::cout << "error 86" << std::endl;

View File

@ -1,9 +1,23 @@
/**
* @file Receiver.hpp
* @brief Header file for the Receiver class.
* @author Adam Prochazka <xproch0f>
*
* This file contains the declaration of the Receiver class which is responsible for
* managing the serial communication and processing the received data to display images.
*/
#include "main.hpp"
#ifndef DISPLAYER_HPP
#include "Displayer.hpp"
#endif
/**
* @class Receiver
* @brief Handles receiving data from the serial port and buffering the data for the Displayer.
*/
class Receiver{
private:
int cdcFile;
@ -49,27 +63,99 @@ class Receiver{
std::vector<uint8_t> buffer3;
Displayer *dis;
int sequenceEndedFF = 0;
int distance = 0;
int sequenceEndedFF = 0; ///< Flag to indicate if the sequence has ended with 0xFF.
int simulateIdx = 0;
int debugFileIdx = 0;
public:
/**
* @brief Constructor for the Receiver class.
* @param displayerPtr Pointer to the Displayer instance.
*/
Receiver(Displayer *displayerPtr);
void openStream();
/**
* @brief Opens the serial port stream.
* @param port Name of serial port to be openned.
*/
void openStream(char * port);
/**
* @brief Closes the serial port stream.
*/
void closeStream();
/**
* @brief Initializes the serial port settings.
* @return 1 if successful, -1 if an error occurred.
*/
int initSerial();
/**
* @brief Reads data from the CDC device.
* @param[out] character Pointer to the character buffer to store the read data.
* @return 0 if successful, -1 if error occurred.
*/
int readCdcData(unsigned char (*character)[CDC_FRAME_SIZE]);
/**
* @brief Prints char as hexadecimal value with a 0x prefix.
* @param value The char to be printed.
*/
void printHex(unsigned char value);
int fillBuffer();
/**
* @brief Fills the buffer with data from the serial port.
* @param saveToFile Indicates if image data should be saved to file.
* @return 0.
*/
int fillBuffer(bool saveToFile = false);
/**
* @brief Gets the distance data from serial port and print it to std out.
* @return 0 if successful, 1 if error occurred.
*/
int getDistance();
void bufferToDisplay();
/**
* @brief Sends the buffer to the Displayer for rendering.
* @param printRaw Bool that indicates weather received byte data should be printed to std::out (for debug).
*/
void bufferToDisplay(bool printRaw = false);
/**
* @brief Initializes textures in Displayer to default values.
*/
void initTextures();
/**
* @brief Finds a sequence of two characters in the given string.
* @param[in] str Pointer to the input string.
* @param ch1 First character of the sequence to find.
* @param ch2 Second character of the sequence to find.
* @return Index of the first occurrence of the sequence, or -1 if not found.
*/
int findSequence(unsigned char (*str)[CDC_FRAME_SIZE], unsigned char ch1, unsigned char ch2);
/**
* @brief Find index of bytes signalizing start of image.
* @param[in] str Pointer to the input string.
* @return Index of the start of the data sequence, or -1 if not found.
*/
int findStart(unsigned char (*str)[CDC_FRAME_SIZE]);
/**
* @brief Find index of bytes signalizing end of image.
* @param[in] str Pointer to the input string.
* @return Index of the start of the data sequence, or -1 if not found.
*/
int findEnd(unsigned char (*str)[CDC_FRAME_SIZE]);
/**
* @brief Test function to simulate reading from serial port.
* @param[in] str Pointer to the string buffer.
* @return 0.
*/
int simulateRead(unsigned char (*character)[CDC_FRAME_SIZE]);
};

View File

@ -1,3 +1,12 @@
/**
* @file main.cpp
* @brief Source file for the main application.
* @author Adam Prochazka <xproch0f>
*
* This file contains the implementation of the main application, which integrates the Receiver
* and Displayer classes, manages their threads, and handles the overall execution flow.
*/
#include "main.hpp"
#include "Receiver.hpp"
@ -5,13 +14,18 @@
#include "Displayer.hpp"
#endif
int cdcFile;
void readLoop(Receiver ** receiverPtr){
(*receiverPtr)->openStream();
int cdcFile;
bool quit = false;
/**
* @brief Reads and processes data from the serial communication in a loop. - for debug purposes
* @param receiverPtr Pointer to a pointer to the Receiver class instance.
* @param port Serial port to be opened.
*/
void readLoop(Receiver ** receiverPtr, char * port){
(*receiverPtr)->openStream(port);
(*receiverPtr)->initSerial();
while (true) {
while (!quit) {
unsigned char character[CDC_FRAME_SIZE];
(*receiverPtr)->readCdcData(&character);
if((*receiverPtr)->findStart(&character) != -1)
@ -27,28 +41,74 @@ void readLoop(Receiver ** receiverPtr){
close(cdcFile);
}
/**
* @brief Flips through the textures in a separate thread.
* @param displayerPtr Pointer to the Displayer class instance.
*/
void windowFlipThread(Displayer * displayerPtr){
displayerPtr->flipThroughTextures();
}
/**
* @brief Wrapper function to call bufferToDisplay() method of the Receiver instance.
* @param receiverPtr Pointer to a pointer to the Receiver instance.
*/
void WrapperBufferToDisplay(Receiver ** receiverPtr){
(*receiverPtr)->bufferToDisplay();
}
void receiverLoop(Receiver ** receiverPtr){
/**
* @brief Main loop for the Receiver instance.
* @param receiverPtr Pointer to a pointer to the Receiver instance.
*/
void receiverLoop(Receiver ** receiverPtr, bool *q, bool printRaw, bool saveToFile){
std::vector<std::thread> displayThreads;
while(1){
while(!(*q)){
(*receiverPtr)->fillBuffer();
std::thread t2(WrapperBufferToDisplay, receiverPtr);
t2.detach();
(*receiverPtr)->fillBuffer(saveToFile);
(*receiverPtr)->bufferToDisplay(printRaw);
//running in a thread also works, but for simplicity is not used.
//std::thread t2(WrapperBufferToDisplay, receiverPtr);
//t2.detach();
}
}
int main()
int main(int argc, char * argv[])
{
char * port = nullptr;
bool printRaw = false;
bool saveToFile = false;
int opt;
while ((opt = getopt(argc, argv, "p:r:s")) != -1) {
switch (opt) {
case 'p':
port = optarg;
break;
case 'r':
printRaw = true;
break;
case 's':
saveToFile = true;
break;
default:
std::cerr << "Usage: sudo ./main -p <serial_port> [-r to print raw data] [-s to save images]" << std::endl;
std::cerr << "Example: sudo ./main -p /dev/ttyACM0 -r -s" << std::endl;
return 1;
}
}
if (!port) {
std::cerr << "Serial port not specified" << std::endl;
return 1;
}
std::cout << "Serial port: " << port << std::endl;
std::cout << "Print raw data: " << (printRaw ? "true" : "false") << std::endl;
std::cout << "Save images: " << (saveToFile ? "true" : "false") << std::endl;
Displayer dis;
Receiver *rec = new Receiver(&dis);
@ -56,7 +116,7 @@ int main()
dis.createWindow();
dis.renderWindow();
rec->openStream();
rec->openStream(port);
rec->initSerial();
rec->initTextures();
@ -64,13 +124,12 @@ int main()
rec->fillBuffer();
rec->bufferToDisplay();
std::thread t1(receiverLoop, &rec);
dis.windowLoop();
std::thread t1(receiverLoop, &rec, &quit, std::ref(printRaw), std::ref(saveToFile));
t1.detach();
t1.join();
dis.windowLoop(&quit);
rec->closeStream();
readLoop(&rec);
return 0;
}

View File

@ -1,3 +1,11 @@
/**
* @file main.hpp
* @brief Header file for the main application.
* @author Adam Prochazka <xproch0f>
*
* This file contains the includes, definitions, and declarations required for the main application.
*/
#include <iostream>
#include <cstring>
#include <cstdint>

File diff suppressed because it is too large Load Diff