Problem with connection between C-Program and Arduino DUE

Hello dear Forum

We are two mechanical engineering students, who are working on a 3D-Printer Project. As programing isn't our strenght, we would be very thankfull for some inputs. Our problem is currently the connection between our .C program and the Arduino Due.
The program is built to send Arduino a 'd' and receive a 'R' from Arduino, so it knows that he is ready to receive data. At some point in the sendport() it fails and repeats itself over and over trying to receive a R...
See .C programm for better understanding:

#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <direct.h> // for _getcwd

#define ARDUINOPORT "COM7" // Change to your COM port
#define FALSE 0
#define TRUE 1
#define READ_TIMEOUT_MS 2000

#define PI 3.1415927

char FileName[1000] = ""; //stores the BMP file name

HANDLE hSerial;  // Serial handle for Windows

int plotterSteps = 0; // stores the plotter steps for the picture
char PicturePath[1000]; // stores the directory path for the picture


//+++++++++++++++++++++++ Start clearSerialBuffer ++++++++++++++++++++++++++
// Clears the serial buffer by reading all available data

void clearSerialBuffer() {
    char buff;
    DWORD bytesRead;
    while (ReadFile(hSerial, &buff, 1, &bytesRead, NULL) && bytesRead > 0) {
        printf("Clearing buffer: '%c' (%d)\n", buff, buff);
    }

    if (bytesRead == 0) {
        printf("Buffer cleared.\n");
    } else {
        printf("Failed to clear buffer.\n");
    }
}
//-----------------------nd clearSerialBuffer ----------------------------------

//+++++++++++++++++++++++ Start readport ++++++++++++++++++++++++++
// Checks serial port for incoming Data

char readport(void) { // reads a single byte from the serial port and returns it if data is available
    DWORD bytesRead; // store number of bytes read by ReadFile()
    char buff; // store bytes read from the serial port (temporary)
    LARGE_INTEGER start, now, frequency;

    // Initialize high-resolution timing
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&start);

    // Continuously attempt to read from the serial port until 'R' is received or timeout
    while (1) {
        if (ReadFile(hSerial, &buff, 1, &bytesRead, NULL)) {
            if (bytesRead > 0) {
                if (buff == 'R'|| buff == 'X') {
                    printf("readport received: '%c' (%d)\n", buff, buff);
                    return buff;
                } else if (buff == '\r' || buff == '\n' || buff == 0) {
                    // Ignore unwanted characters
                    printf("readport ignored: '%c' (%d)\n", buff, buff);
                    continue;
                } else {
                    printf("readport received unexpected character: '%c' (%d)\n", buff, buff);
                }
            }
        }
        return 0;  // Return 0 if no data is available

        // Check if the elapsed time has exceeded the timeout
        QueryPerformanceCounter(&now);
        double elapsedTime = (double)(now.QuadPart - start.QuadPart) * 1000.0 / frequency.QuadPart;
        
        if (elapsedTime >= READ_TIMEOUT_MS) {
            printf("readport timouted while waiting for 'R' response.\n");
            return 0;  // Return 0 to indicate a timeout
        }
    }
}
//------------------------ End readport ----------------------------------


//+++++++++++++++++++++++ Start sendport ++++++++++++++++++++++++++
// Sends a single byte of data and waits for Arduinos acknowledgment (R)

void sendport(unsigned char ValueToSend) {
    printf("sendport called with ValueToSend: '%c' (%d)\n", ValueToSend, ValueToSend);
    if (ValueToSend == 0) {
        printf("sendport ignored null command.\n");
        return;
    }
    DWORD bytesWritten; // Store number of bytes written by WriteFile()
    LARGE_INTEGER startTime, currentTime, frequency;

    QueryPerformanceFrequency(&frequency);  // Get the high-resolution timer frequency
    QueryPerformanceCounter(&startTime);    // Get the starting time

    if (!WriteFile(hSerial, &ValueToSend, 1, &bytesWritten, NULL)) { 
        printf("write() of value failed!\n");
        return;
    }
    Sleep(100);
    int receivedR = 0; // Flag to track if 'R' was received
    while (1) {
        char response = readport();  // Read a byte from the serial port

        if (response == 'R') {  // Check if the response is 'R'
            QueryPerformanceCounter(&currentTime);  // Get the current time
            double responseTime = (double)(currentTime.QuadPart - startTime.QuadPart) * 1000.0 / frequency.QuadPart;
            printf("Response time for command '%c': %.2f ms\n", ValueToSend, responseTime);
            receivedR = 1;  // Set the flag indicating 'R' was received
            printf("receivedR is now: %d (expected 1)\n", receivedR); // Print the value of receivedR
            break;  // Exit the loop when 'R' is received
        }

        // Clear the serial buffer if the response is not 'R'
        if (receivedR == 1) {
            printf("Response received. Proceeding with next command...\n");
        } else {
            clearSerialBuffer(); // Only clear if necessary
        }

        // Check for timeout
        QueryPerformanceCounter(&currentTime);
        double elapsedTime = (double)(currentTime.QuadPart - startTime.QuadPart) / frequency.QuadPart;
        if (elapsedTime > 2.0) {  // Timeout set to 2 seconds
            printf("Failed to receive 'R' response within timeout for command '%c'.\n", ValueToSend);
            break;  // Exit the loop on timeout
        }
    }
    // If the loop exited because of timeout, ensure no residual looping
    if (receivedR > 1) {
        return;
        printf("Exiting function due to timeout.\n");
        printf("Final value of receivedR: %d\n", receivedR);
    }
}
//------------------------ End sendport ----------------------------------

//+++++++++++++++++++++++ Start openport ++++++++++++++++++++++++++
// - opens the serial port (COM7)
// - configures the serial ports communication settings
// - sets timeout parameters for read and write operations
// - If any step fails (such as opening the port, getting or setting attributes, or setting timeouts), it prints an error message and exits.
void openport(void) {
    hSerial = CreateFile(   // used to open a handle to serial port COM7
        ARDUINOPORT,        // which port to open
        GENERIC_READ | GENERIC_WRITE, // specifies the serial port for reading and writing
        0,              // No sharing with other processes
        NULL,           // Default security setting for the port
        OPEN_EXISTING,  // open port if it exists
        0,              // file attributes (none)
        NULL);          // no template file is used

    if (hSerial == INVALID_HANDLE_VALUE) { // if port could not be opened, CreateFile returns INVALID_HANDLE_VALUE and exits over return
    DWORD error = GetLastError();
    printf("Unable to open port. Error code: %lu\n", error);
    return;
}

    DCB dcbSerialParams = { 0 }; // Device Control Block (contains settings of serial port)
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) { // retrieves currents settings of serial port and stores them in dcbSerialParams
        printf("Couldn't get serial port attributes\n"); // If it fails this will be printed and exits over return
        return;
    }
// setting serial port parameters
    dcbSerialParams.BaudRate = CBR_256000; // sets baud rate to 115200 bits per second
    dcbSerialParams.ByteSize = 8;          // sets number of data bits per byte to 8
    dcbSerialParams.StopBits = ONESTOPBIT; // 1 stop bit will be used to indicate the end of each byte
    dcbSerialParams.Parity = NOPARITY;     // no parity checking
    if (!SetCommState(hSerial, &dcbSerialParams)) { // applies the serial port settings (stored in dcbSerialParams) to the open port
        printf("Couldn't set serial port attributes\n");
        return;                            // if it fails it will exit over return
    }
// set timeouts for read and write operations for serial communication
    COMMTIMEOUTS timeouts = { 0 };               
    timeouts.ReadIntervalTimeout = 100;          // specifies the maximum time (ms) between the arrival of two consecutive bytes
    timeouts.ReadTotalTimeoutConstant = 100;     // a constant timeout for read operations
    timeouts.ReadTotalTimeoutMultiplier = 10;   // a multiplier for read timeouts. this influences the total timeout based on the amount of data being read
    timeouts.WriteTotalTimeoutConstant = 100;    // a constant timeout for write operations
    timeouts.WriteTotalTimeoutMultiplier = 10;  // same multiplier as read timeout
    SetCommTimeouts(hSerial, &timeouts);
}
//------------------------ End openport ----------------------------------


//######################################################################
//################## Main ##############################################
//######################################################################

int main(int argc, char **argv) {
    char FullFileName[1000] = ""; // A character array initialized to an empty string, intended to store the full file path of the BMP image file (up to 1000 characters).
    FILE *bmpFile;                // A file pointer used to open and access the BMP file in binary mode.
    char FileInfo[3];             // A character array to store the BMP file identifier (typically "BM" for BMP files) and a null terminator (marks the end of a string).
    long FileSize;                // stores the size of the BMP file in bytes
    long LongTemp;                // A temporary variable used when reading unused sections of the BMP file header.
    long DataOffset;              // stores the offset (in bytes) from the beginning of the file to the start of the pixel data.
    long HeaderSize;              // stores the size of the BMP file header
    long PictureWidth;            // Stores the width of the image in pixels.
    long PictureHeight;           // Stores the height of the image in pixels.
    int IntTemp;                  // A temporary variable used when reading additional fields of the BMP header.
    int ColorDepth;               // Stores the number of bits per pixel (should be 24 for a 24-bit BMP file)
    long CompressionType;         // Stores the compression type; it should be 0 for uncompressed BMP images.
    long PictureSize;             // Stores the size of the pixel data in bytes
    long XPixelPerMeter;          // Stores the horizontal and vertical resolution of the image (pixels per meter)
    long YPixelPerMeter;          
    long ColorNumber;             // Stores the number of colors in the color palette (used mainly for BMP files with color palettes)
    long ColorUsed;               // Stores the number of important colors; this is typically zero in 24-bit BMP files
    unsigned char bitmapData[24][10000]; // a 2D array to store pixel data from the BMP file. It is organized to hold up to 24 rows, each with a width of up to 10,000 pixels

    openport(); // opens serial port to arduino

    printf("\n\nWaiting for 'X' from Arduino (Arduino plugged in?)...\n");

    // Wait for 'X' from Arduino
    char handshakeChar;
    do {
        handshakeChar = readport();
        if (handshakeChar == 'X') {
            printf("Connection to Arduino established.\n");
            break;
        }
        printf("Unexpected character during handshake: '%c' (%d)\n", handshakeChar, handshakeChar);
    } while (1);

    // Wait for 'X' from Arduino
    // while (readport() != 'X');
    // printf("Connection to Arduino established.\n");

    strcpy(FileName, "donut doppelt gross.bmp"); // Image file the program intends to process

    _getcwd(PicturePath, 1000);                  // gets current working directory and stores it in PicturePath
    strcat(PicturePath, "\\pictures");           // subdirectory where the image file is stored
    printf("PicturePath=>%s<\n", PicturePath);   // prints the full path to the PicturePath directory

    if ((bmpFile = fopen(FileName, "rb")) == NULL) { // attempts to open image file in binary read mode (rb)
        printf("File '%s' cannot be opened for reading!\n", FileName);
        return 1;
    }

    fread(&FileInfo, 2, 1, bmpFile);         // reads the first 2 bytes of the BMP file into FileInfo
    fread(&FileSize, 4, 1, bmpFile);         // Reads the next 4 bytes, which store the file size in bytes.
    fread(&LongTemp, 4, 1, bmpFile);         // Reads 4 bytes into LongTemp. This data is reserved and not often used for standard BMPs.
    fread(&DataOffset, 4, 1, bmpFile);       // Reads 4 bytes indicating where the actual pixel data begins.
    fread(&HeaderSize, 4, 1, bmpFile);       // Reads 4 bytes representing the size of the header structure.
    fread(&PictureWidth, 4, 1, bmpFile);     // These read 4 bytes each, storing the width and height of the image in pixels.
    fread(&PictureHeight, 4, 1, bmpFile);    // These read 4 bytes each, storing the width and height of the image in pixels
    fread(&IntTemp, 2, 1, bmpFile);          // Reads 2 bytes for the number of color planes (typically 1 for BMP)
    fread(&ColorDepth, 2, 1, bmpFile);       // Reads 2 bytes representing the bits per pixel (e.g., 24 for 24-bit color).
    fread(&CompressionType, 4, 1, bmpFile);  // Reads 4 bytes that indicate compression type (0 = uncompressed, which is standard for BMP).
    fread(&PictureSize, 4, 1, bmpFile);      // Reads 4 bytes storing the size of the image data (in bytes), not including headers.
    fread(&XPixelPerMeter, 4, 1, bmpFile);   // These read 4 bytes each, representing horizontal and vertical resolution in pixels per meter.
    fread(&YPixelPerMeter, 4, 1, bmpFile);   // These read 4 bytes each, representing horizontal and vertical resolution in pixels per meter.
    fread(&ColorNumber, 4, 1, bmpFile);      // Reads 4 bytes for the number of colors in the palette (if used).
    fread(&ColorUsed, 4, 1, bmpFile);        // Reads 4 bytes for the number of important colors. If zero, all colors are considered important.
// Prints all the fread
    printf("FileInfo=%s\n", FileInfo);
    printf("FileSize=%ld\n", FileSize);
    printf("LongTemp=%ld\n", LongTemp);
    printf("DataOffset=%ld\n", DataOffset);
    printf("HeaderSize=%ld\n", HeaderSize);
    printf("PictureWidth=%ld\n", PictureWidth);
    printf("PictureHeight=%ld\n", PictureHeight);
    printf("IntTemp=%d\n", IntTemp);
    printf("ColorDepth=%d\n", ColorDepth);
    printf("CompressionType=%ld\n", CompressionType);
    printf("PictureSize=%ld\n", PictureSize);
    printf("XPixelPerMeter=%ld\n", XPixelPerMeter);
    printf("YPixelPerMeter=%ld\n", YPixelPerMeter);
    printf("ColorNumber=%ld\n", ColorNumber);
    printf("ColorUsed=%ld\n", ColorUsed);

// prints errors
    if (FileInfo[0] != 'B' || FileInfo[1] != 'M') {
        printf("Wrong Fileinfo (BM)!\n");
        return 1;
    }
    if (ColorDepth != 24) {
        printf("Wrong ColorDepth (24)!\n");
        return 1;
    }
    if (CompressionType != 0) {
        printf("Wrong CompressionType (0)!\n");
        return 1;
    }
    
// This adjustment (also known as "row padding") is essential for reading BMP image data correctly. 
// Without aligning each row to a 4-byte boundary, the data might not appear correctly when processed, leading to misaligned or distorted images.
    fseek(bmpFile, DataOffset, SEEK_SET);

    long PictureWidthFilled = PictureWidth * 3;
    while (PictureWidthFilled % 4 != 0) {
        PictureWidthFilled++;
    }

    printf("PictureWidthFilled = %ld, PictureWidth = %ld\n", PictureWidthFilled, PictureWidth);

    while (!feof(bmpFile)) {
        // Reset buffer to 255 (White)
        for (int i = 0; i < 24; i++) {
            for (int j = 0; j < 10000; j++) {
                bitmapData[i][j] = 255;
            }
        }
        // Read 24 lines into buffer
        for (long j = 0; j < 24; j++) {
            if (!feof(bmpFile)) {
                fread(bitmapData[j], 1, PictureWidthFilled, bmpFile);
            }
            printf("%d\n", 1 << j);
        }

        // Processing data to send...
        for (long k = 0; k < 2; k++) {
            for (long i = 0; i < PictureWidth * 3; i += 3) {
                unsigned char dataToSend1 = 0;
                unsigned char dataToSend2 = 0;
                for (long j = 0; j < 8; j++) {
                    if (bitmapData[j * 2 + k][i] < 127 && bitmapData[j * 2 + k][i + 1] < 127 && bitmapData[j * 2 + k][i + 2] < 127) { // Black dot
                        dataToSend1 += 1 << j;
                    }
                }
                for (long j = 8; j < 12; j++) {
                    if (bitmapData[j * 2 + k][i] < 127 && bitmapData[j * 2 + k][i + 1] < 127 && bitmapData[j * 2 + k][i + 2] < 127) { // Black dot
                        dataToSend2 += 1 << (j - 8);
                    }
                }

                clearSerialBuffer();
                sendport('d');
                sendport(dataToSend1);
                sendport(dataToSend2);
            }
            if (k == 0) {
                sendport('r');  // Return carriage
                sendport('N');  // Forward paper one dot
            } else {
                sendport('r');  // Return carriage
                sendport('n');  // New line
            }
        }
    }

    fclose(bmpFile);
    CloseHandle(hSerial);  // Close the serial port
    return 0;
}

We first thought our Arduino is too fast for our programm, so we checkt our baud rates and also implemented some waiting points in our Arduino IDE. But nothing worked on this side. What can we do, so our program is running step by step and not skipping any of the commands.
Here you have our Arduino programm:

#define LED_1       13
#define SWITCH_01   A0

#define NOZZLE_01     2
#define NOZZLE_02     3
#define NOZZLE_03     4
#define NOZZLE_04     5
#define NOZZLE_05     6
#define NOZZLE_06     7
#define NOZZLE_07     8
#define NOZZLE_08     9
#define NOZZLE_09    10
#define NOZZLE_10    11
#define NOZZLE_11    12
#define NOZZLE_12    A1

#define DIR_X        A2
#define STEP_X       A3
#define DIR_Y        A4
#define STEP_Y       A5

#define STEP_PAUSE       1000
#define COMMAND_PAUSE       5
#define DOT_PAUSE_LONG   1000
#define DOT_PAUSE_SHORT     5

int i;
char comByte = 0;
char dataMode = 0;
long dotWidth = 11;
long lineHeight = 234;
long stepsDone = 0;
long yStepsDone = 0; 

int nozzles[] = {NOZZLE_06, NOZZLE_07, NOZZLE_08, NOZZLE_09, NOZZLE_12, NOZZLE_11, NOZZLE_10, NOZZLE_03, NOZZLE_02, NOZZLE_01, NOZZLE_04, NOZZLE_05};


// Initialize communication through USB
//void establishContact() {
  //while (Serial.available() <= 0) {
    //Serial.print('X');   // send a capital X
    //delay(1000);
  //}
//}


void motorStep(long stepWidth, int dirPin, int stepPin, long stepPause){
  if(stepWidth < 0){
    digitalWrite(dirPin, HIGH);
    stepWidth = -stepWidth;
  }
  else{
    digitalWrite(dirPin, LOW);
  }
  for(long i=0; i<stepWidth; i++){
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(COMMAND_PAUSE);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(stepPause);
  }
}

void makeDot(int nozzle, long dotPause){
  int i = 0;
  digitalWrite(nozzle, HIGH);
  delayMicroseconds(1);
  //for(i=0; i<1; i++);
  digitalWrite(nozzle, LOW);
  delayMicroseconds(dotPause);
}

// the setup routine runs once when you press reset:
void setup(){
  dataMode = 0;
  stepsDone = 0;
  yStepsDone = 0; 

  pinMode(LED_1, OUTPUT);
  pinMode(SWITCH_01, INPUT);
  digitalWrite(SWITCH_01, HIGH); // Activate pull-up resistor

  pinMode(DIR_X, OUTPUT);
  pinMode(STEP_X, OUTPUT);
  pinMode(DIR_Y, OUTPUT);
  pinMode(STEP_Y, OUTPUT);

  for(i=0; i<12; i++){
    pinMode(nozzles[i], OUTPUT);
  }

  motorStep(100, DIR_X, STEP_X, STEP_PAUSE);
  motorStep(-100, DIR_X, STEP_X, STEP_PAUSE);
  motorStep(100, DIR_Y, STEP_Y, STEP_PAUSE);
  motorStep(-100, DIR_Y, STEP_Y, STEP_PAUSE);

  // start serial port at 115200 bps:
  Serial.begin(256000);
  // Clear any lingering data
  while (Serial.available()) {
        Serial.read(); 
  }
  //establishContact();
  Serial.print('X');
}

// the loop routine runs over and over again forever:
void loop() {

  comByte = 0;
  if (Serial.available() > 0) {//if valid, read from serial:
    //get incoming byte:
    char comByte = Serial.read();

    // Serial.print("Received command: ");
    // Serial.print(comByte);
    if (comByte == 'd') {
            // Perform actions specific to 'd' command here

            // Send acknowledgment 'R' for 'd'
            //  Serial.println("Preparing to send 'R'");

            while (Serial.available()) {
              Serial.read(); // Clear lingering data
            }

            delay(10);
            Serial.print('R');  // Send 'R' to signal PC
            delay(1000);
    }

    // Serial.print('R');   // send 'R' to initiate next data from computer

    if(dataMode == 0){

      if(comByte == 'd'){
        dataMode = 1;
      }

      if(comByte == 'r'){// Return line
        motorStep(-stepsDone, DIR_X, STEP_X, STEP_PAUSE/10);
        stepsDone = 0;
      }
      if(comByte == 'n'){// New line
        motorStep(-lineHeight, DIR_Y, STEP_Y, STEP_PAUSE/10);
        //motorStep(-dotWidth, DIR_X, STEP_X, STEP_PAUSE/10);//only why printhead wasn't othogonal
        yStepsDone+=lineHeight;
        stepsDone = 0;
      }
      if(comByte == 'N'){// Forward paper for one dot
        motorStep(-lineHeight/12, DIR_Y, STEP_Y, STEP_PAUSE/10);
        yStepsDone+=lineHeight/12;
        stepsDone = 0;
      }

      if(comByte == 'G') {// Command to return to initial Y position
        motorStep(yStepsDone, DIR_Y, STEP_Y, STEP_PAUSE/10);  // Move back to the start
      }

      if(comByte == 'T'){// Test nozzles
        for(int i = 0; i < 12; i++){
          makeDot(nozzles[i], DOT_PAUSE_LONG);
          delay(2000);
        }
      }

      if(comByte == 't'){// Test nozzles
        for(int i = 0; i < 12; i++){
          for(int j = 0; j < 100; j++){
            makeDot(nozzles[i], DOT_PAUSE_LONG);
            motorStep(dotWidth, DIR_X, STEP_X, DOT_PAUSE_LONG/dotWidth + 10);
          }
        }
        motorStep(-lineHeight, DIR_Y, STEP_Y, STEP_PAUSE/4);
        for(int i = 0; i < 12; i++){
          for(int j = 0; j < 100; j++){
            makeDot(nozzles[i], DOT_PAUSE_LONG);
            motorStep(-dotWidth, DIR_X, STEP_X, DOT_PAUSE_LONG/dotWidth + 10);
          }
        }
      }

      if(comByte == 'x'){
        motorStep(100, DIR_X, STEP_X, STEP_PAUSE);
      }
      if(comByte == 'X'){
        motorStep(-100, DIR_X, STEP_X, STEP_PAUSE);
      }
      if(comByte == 'y'){
        motorStep(100, DIR_Y, STEP_Y, STEP_PAUSE);
      }
      if(comByte == 'Y'){
        motorStep(-100, DIR_Y, STEP_Y, STEP_PAUSE);
      }
    }
    else{
      if(dataMode == 1){
        for(int i = 0; i < 8; i++){
          if(comByte & (1<<i)){
            makeDot(nozzles[i], DOT_PAUSE_SHORT);
          }
        }
      }
      if(dataMode == 2){
        for(int i = 0; i < 4; i++){
          if(comByte & (1<<i)){
            makeDot(nozzles[i+8], DOT_PAUSE_SHORT);
          }
        }
      }
      dataMode++;
      if(dataMode == 3){
        motorStep(dotWidth, DIR_X, STEP_X, DOT_PAUSE_LONG/dotWidth + 10);
        stepsDone+=dotWidth;
        dataMode = 0;
      }
    }

  }//if (Serial.available() > 0){

}

And here is what our command prompt gives us:


We are kinda lost and would really appreciate your help:)
Thank you

Examine very carefully the reasons for all the delays in the Arduino program. Most have no reason for existing.

i see an 'R' on the serial monitor when i run your code an enter a 'd' thru the serial monitor. (i did reduce the bit rate to 9600 because 256000 was not an option).

maybe you just need to set the Arduino bit-rate to 115200 based on the following comment

dcbSerialParams.BaudRate = CBR_256000; // sets baud rate to 115200 bits per second

i'm not familiar with your approach for using the serial interface on the PC. When i've done it, i need to configure the port not to wait for a complete line terminated with a linefeed

You could test each half (PC code, Arduino code) on their own first, just to check you got the serial comms working correctly in each half.

  1. Test Arduino code by connecting its serial that you want to test to a terminal emulator running on your PC.
  2. Test PC code by connecting its serial that you want to test to a terminal emulator running on your PC.