File transfer over UART

You should be sending the 0x03 after the file data

Hello @benedict.hewson, I am still facing the same issue. Now only filenames are stored in the /home/debian/NEW folder of beaglebone. I opened those files using “cat” and Nano Editor, and all files do not contain any type of data. Means all files are empty.
Please help me solve this issue.

Regards,
Avinash.

  1. C code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

#define UART_BUFFER_SIZE 8192

enum State {
    IDLE,
    FILENAME,
    DATA
};
void receiveAndStoreFilesOverUART(const char *folderPath) {
    int uart_fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
        struct termios uart_config;
    if (uart_fd < 0) {
        perror("Error opening UART port");
        return;
    }
    // Configure UART settings

 if (tcgetattr(uart_fd, &uart_config) < 0) {
        perror("Error getting UART configuration");
        close(uart_fd);
        return;
    }

    // Set baud rate to 9600
    cfsetispeed(&uart_config, B9600);
    cfsetospeed(&uart_config, B9600);

    // Set data format to 8N1 (8 data bits, no parity, 1 stop bit)
    uart_config.c_cflag &= ~PARENB;
    uart_config.c_cflag &= ~CSTOPB;
    uart_config.c_cflag &= ~CSIZE;
    uart_config.c_cflag |= CS8;
 // Disable hardware flow control
    uart_config.c_cflag &= ~CRTSCTS;

    // Enable receiver and local mode
    uart_config.c_cflag |= CREAD | CLOCAL;
    // Set input mode to non-canonical and disable echo
    uart_config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    // Set the minimum number of characters for non-canonical read
    uart_config.c_cc[VMIN] = 1;

    // Set the timeout in deciseconds for non-canonical read
    uart_config.c_cc[VTIME] = 0;

    // Apply UART configuration
    if (tcsetattr(uart_fd, TCSANOW, &uart_config) < 0) {
        perror("Error setting UART configuration");
        close(uart_fd);
        return;
    }


    enum State state = IDLE;
    char filenameBuffer[UART_BUFFER_SIZE];
    char filePath[UART_BUFFER_SIZE + strlen(folderPath) + 1];

    FILE *currentFile = NULL;

    char buffer[UART_BUFFER_SIZE];
    ssize_t bytesRead;
    while ((bytesRead = read(uart_fd, buffer, sizeof(buffer))) > 0) {
        for (int i = 0; i < bytesRead; i++) {
            char byte = buffer[i];

            switch (state) {
                case IDLE:
                    if (byte == 0x01) {
                        state = FILENAME;
                        filenameBuffer[0] = '\0';
 printf("Entering FILENAME state\n");
                    }
                    break;

                case FILENAME:
                    if (byte == 0x02) {
                        state = DATA;
                        printf("Entering DATA state\n");

                        snprintf(filePath, sizeof(filePath), "%s%s", folderPath, filenameBuffer);

                        currentFile = fopen(filePath, "wb");
                        if (currentFile == NULL) {
                            perror("Error opening file for writing");
                            state = IDLE;
                        }
                    } else {
                        strncat(filenameBuffer, &byte, 1);
                    }
                    break;

                case DATA:
                    if (byte == 0x03) {
                        fclose(currentFile);
                        printf("File closed\n");
                        state = IDLE;
                    } else {
                       // fwrite(&byte, 1, 1, currentFile);
                        fwrite(buffer + i, 1, bytesRead - i, currentFile);
                        i = bytesRead;
                    }
                    break;
            }
        }
    }

    if (bytesRead < 0) {
        perror("Error reading from UART");
 }

    close(uart_fd);
    printf("UART port closed\n");
}

int main(void) {
    const char *storageFolderPath = "/home/debian/NEW/";
    receiveAndStoreFilesOverUART(storageFolderPath);

    return 0;
}
 
  1. Transmitting(Windows) side code
import serial
import time

def send_file(serial_port, file_name):
    try:
        # Send start marker (0x01)
        serial_port.write(bytes([0x01]))

        # Send filename
        serial_port.write(file_name.encode())

        # Send filename marker (0x02)
        serial_port.write(bytes([0x02]))

        # Open the file for reading
        with open(f"C:/Users/HP/OneDrive/Desktop/DRS_Database/{file_name}", "rb") as file:
            # Send file data marker (0x03)
            serial_port.write(bytes([0x03]))

            # Send file data
            file_data = file.read()
            serial_port.write(file_data)

        print(f"{file_name} sent successfully.")
    except FileNotFoundError:
        print(f"File {file_name} not found.")

def send_files(serial_port, filenames):
    for file_name in filenames:
        send_file(serial_port, file_name)
        time.sleep(1)  # Add a delay to allow time for the BeagleBone to process the data

    # Send finish marker (0x04) after all files are sent
    serial_port.write(bytes([0x04]))

# Open the serial port for communication
ser = serial.Serial('COM11', 9600)  # COM port and baud rate

# List of file names to send
file_names = ["a1.txt", "a2.txt", "a3.txt", "a4.txt", "a5.txt", "a6.txt"]

# Send files
send_files(ser, file_names)

# Close the serial port
ser.close()

Please take a look on it once.

Again, you have to send the 0x03 after the file data. 0x03 is the end of file marker. If you send it before the file no data will be written.

Hello @benedict.hewson, I am trying to do it. On your side, are both codes working or not?

If working can you please share it with me, because i tried on it lot of times.

Thank you.

Hello @benedict.hewson, Thank you for your support. We are close now. I am sending two files from my PC to beaglebone. Those two files are stored and saved to a specified location in Beaglebone, but a small issue arises: all data transferred from Windows is not stored on the Beaglebone side. Only 39 characters with spaces are stored in both files, and the remaining parts are not.

I will attach both codes; please go through them. It’s a kind request; please help.

  1. Beaglebone side C code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

#define UART_BUFFER_SIZE 12000

void receiveAndStoreFilesOverUART(const char *folderPath) {
  int uart_fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
  struct termios uart_config;
  if (uart_fd < 0) {
    perror("Error opening UART port");
    return;
  }

  // Configure UART settings
    if (tcgetattr(uart_fd, &uart_config) < 0) {
    perror("Error getting UART configuration");
    close(uart_fd);
    return;
  }

  // Set baud rate to 9600
  cfsetispeed(&uart_config, B9600);
  cfsetospeed(&uart_config, B9600);

  // Set data format to 8N1 (8 data bits, no parity, 1 stop bit)
  uart_config.c_cflag &= ~PARENB;
  uart_config.c_cflag &= ~CSTOPB;
  uart_config.c_cflag &= ~CSIZE;
  uart_config.c_cflag |= CS8;

  // Disable hardware flow control
  uart_config.c_cflag &= ~CRTSCTS;

  // Enable receiver and local mode
  uart_config.c_cflag |= CREAD | CLOCAL;
 // Set input mode to non-canonical and disable echo
  uart_config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

  // Set the minimum number of characters for non-canonical read
  uart_config.c_cc[VMIN] = 1;

  // Set the timeout in deciseconds for non-canonical read
  uart_config.c_cc[VTIME] = 0;

  // Apply UART configuration
  if (tcsetattr(uart_fd, TCSANOW, &uart_config) < 0) {
    perror("Error setting UART configuration");
    close(uart_fd);
    return;
  }


  char buffer[UART_BUFFER_SIZE];
  ssize_t bytesRead;
  FILE *currentFile = NULL;
  char currentFileName[UART_BUFFER_SIZE];
  int fileOpen = 0;

  while ((bytesRead = read(uart_fd, buffer, sizeof(buffer))) > 0) {
    for (int i = 0; i < bytesRead; i++) {
      printf("%c", buffer[i]);
     if (buffer[i] == 0x01) { // Start of file marker
        if (fileOpen) {
          fclose(currentFile);
        }
        fileOpen = 1;
        currentFileName[0] = '\0'; // Reset the file name
      } else if (buffer[i] == 0x02) { // End of file name marker
        currentFileName[strlen(currentFileName)] = '\0'; // Null-terminate the file name
        char filePath[UART_BUFFER_SIZE + strlen(folderPath) + strlen(currentFileName) + 1];
        snprintf(filePath, sizeof(filePath), "%s%s", folderPath, currentFileName);
        currentFile = fopen(filePath, "ab"); // Append mode to avoid overwriting
      } else if (buffer[i] == 0x03) { // Start of file data marker
        if (currentFile != NULL) {
 fwrite(&buffer[i + 1], 1, bytesRead - i - 1, currentFile);
          fflush(currentFile); // Flush the file stream
          i = bytesRead; // Move to end of buffer
        }
      } else {
        if (!fileOpen) {
          continue; // Skip data if no file is open
        }
        strncat(currentFileName, &buffer[i], 1);
      }
    }
  }

  if (fileOpen) {
    fclose(currentFile);
  }

  if (bytesRead < 0) {
    perror("Error reading from UART");
  }

  close(uart_fd);
  printf("UART port closed\n");
}

int main(void) {
  const char *storageFolderPath = "/home/debian/BLE/";
  receiveAndStoreFilesOverUART(storageFolderPath);
  return 0;
}

  1. Windows side Python code
import serial
import time

def send_file(serial_port, file_name):
    try:
        # Send start marker (0x01)
        serial_port.write(bytes([0x01]))
        print(f"Sent: 0x01")

        # Send filename
        serial_port.write(file_name.encode())
        print(f"Sent filename: {file_name}")

        # Send filename marker (0x02)
        serial_port.write(bytes([0x02]))
        print("Sent: 0x02")

        # Open the file for reading
        with open(f"C:/Users/HP/OneDrive/Desktop/DRS_Database/{file_name}", "rb") as file:
            # Send file data marker (0x03)
            serial_port.write(bytes([0x03]))
            print("Sent: 0x03")

            # Send file data
            file_data = file.read()
            print(f"File content: {file_data.decode()}")  # Print the content before sending
            print(f"Sent file data ({len(file_data)} bytes)")
            serial_port.write(file_data)

        print(f"{file_name} sent successfully.")
    except FileNotFoundError:
        print(f"File {file_name} not found.")

# Open the serial port for communication
ser = serial.Serial('COM11', 9600)  # COM port and baud rate

# Specify the file names to send
file_names_to_send = ["a1.txt", "a2.txt"]

# Send each specified file
for file_name in file_names_to_send:
    send_file(ser, file_name)
    time.sleep(2)  # Wait for 2 seconds before sending the next file

# Close the serial port
ser.close()

Thank you.

You have lots of potential problems with this code. You really need to sit down and think what is going on.

Firstly you are trying to read 12K. Does the read timeout while waiting for the 12K to fill up ?
What happens with your code if it only returns 50 bytes say ?

What will your code do if that happens ?
What if file data is spread across multiple reads because it is larger than 12K ?
What happens if a file + filename is less than 12K and you read 12K ?
You are appending all data after the filename up to the end of the buffer to the file. What happens if the second filename starts in there somewhere ?

If any of the files you are transmitting is larger than 12K you are likely going to write past the end of currentFileName.

You need to process all data a byte at a time to look for the control markers. You can’t just write out the contents of a buffer to a file.

You need to maintain the state between file reads as a file transfer may take multiple reads.