Arduino Asked on December 30, 2021
I am writing EPROM dumper with Arduino UNO and utility program in C and I am using Ubuntu 20.04. The Arduino sketch works fine, but I am having few problems with the utility program. The first problem is that the utility hangs (like in some kind of infinite loop) if I don’t open the serial monitor in Arduino IDE previously, or any other serial communication app (like puTTY). The second problem I have is that the utility also hangs when reading the last bytes which Arduino sends – inspecting the dumped file in hex editor, the last 4-6 bytes are missing. By printing string messages in the function serial_port_read_block_file
, I think that the program hangs up in the read
function.
Thank you in advance and sorry if I understood something wrong configuring the serial communication.
EDIT: Adding switch-case statement for setting the baud rate solved the first problem. The second problem is that I forgot that byte with the value of ‘n’ can be received, and I was just discarding this byte, so at the end I was missing few bytes. Also, I should have checked in the serial_port_read_block_file
function if n>0
, so I don’t access address beyond the scope of the block array (with the statement buffer_cur_pos[-1]
, if n=0
I accessed invalid address).
Conclusion: As @Majenko suggested, I should implement some protocol that will wrap up the data transfer, to distinguish the data from the start/stop conditions. I also changed the code below with the fixes which made the program working (both, in the Arduino sketch and the utility program).
The Arduino sketch:
//74HC595 pins
const int shiftData = 10;
const int shiftClock = 11;
const int shiftLatch = 12;
//ROM data pins (successive)
const int romD0 = 2;
//pgm constants and variables
static const uint16_t BLOCK_SIZE = 256;
uint16_t nBytes = 0;
boolean readMode = false;
void sendAddress(uint16_t addr) {
//first, send the high byte of the address
shiftOut(shiftData, shiftClock, MSBFIRST, addr >> 8);
//then, send the low byte of the address
shiftOut(shiftData, shiftClock, MSBFIRST, addr);
//pulse the shiftLatch pin, to output the address
digitalWrite(shiftLatch, LOW);
digitalWrite(shiftLatch, HIGH);
digitalWrite(shiftLatch, LOW);
}
uint8_t readByte(uint16_t addr) {
uint8_t data = 0;
//send the address
sendAddress(addr);
for (int i = 7; i >= 0; i--)
data = (data << 1) | digitalRead(romD0 + i);
return data;
}
void sendBytes(uint16_t bytes) {
//send the data in blocks with size BLOCK_SIZE
const uint16_t BLOCKS = bytes / BLOCK_SIZE; //number of whole blocks
const uint16_t REMAINDER = bytes % BLOCK_SIZE; //the remaining bytes that don't form a block
uint8_t data[BLOCK_SIZE]; //buffer for block of bytes to be sent
//send the whole blocks
for (uint16_t block = 0; block < BLOCKS; block++) {
for (uint16_t offset = 0; offset < BLOCK_SIZE; offset++) {
data[offset] = readByte(block * BLOCK_SIZE + offset);
}
Serial.write(data, BLOCK_SIZE);
delay(100);
}
//send the remaining bytes
for (uint16_t offset = 0; offset < REMAINDER; offset++) {
data[offset] = readByte(BLOCKS * BLOCK_SIZE + offset);
}
Serial.write(data, REMAINDER);
Serial.write("rn"); //end of transmission
delay(100);
}
void setup() {
pinMode(shiftData, OUTPUT);
pinMode(shiftClock, OUTPUT);
pinMode(shiftLatch, OUTPUT);
for (int i = 0; i < 8; i++)
pinMode(romD0 + i, INPUT);
Serial.begin(57600);
//wait for serial port to connect
while (!Serial) {}
}
void loop() {
while (!Serial.available()) {} //wait until data is available
char c = Serial.read();
delay(100);
switch (c) {
case 'S': //send ready command
Serial.write("> ");
break;
case 'R':
readMode = true;
while ((c = Serial.read()) != 'n') {
nBytes = nBytes * 10 + (c - '0');
}
delay(100);
break;
default:
break;
}
if (readMode) {
sendBytes(nBytes);
}
//reset for next loop
readMode = false;
nBytes = 0;
delay(100);
}
The utility program:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
static const uint16_t BLOCK_SIZE = 256;
static const uint32_t BAUD_RATE = 57600;
void help(void) {
printf(
"rdump - ROM dumpern"
"usage: rdump [OPTIONS]n"
"Options:n"
"-p <serial port> specify serial port of the Arduinon"
"-f <filename> specify output filenamen"
"-s <num bytes> specify the number of bytes to readn"
"-h print this help filen"
);
}
//opening and initializing serial communication
int serial_port_init(const char *port, uint32_t baud) {
//open serial port for read/write, save its file descriptor in fd
int fd = open(port, O_RDWR | O_NOCTTY | O_SYNC);
if(fd == -1) {
fprintf(stderr, "serial_port_init: unable to open %sn", port);
return -1;
}
struct termios options; //serial port options
//get the initial serial port options
if(tcgetattr(fd, &options) < 0) {
fprintf(stderr, "serial_port_init: unable to get terminal optionsn");
return -1;
}
//set the baud rate
cfsetispeed(&options, (speed_t)baud);
cfsetospeed(&options, (speed_t)baud);
options.c_cflag |= (CLOCAL | CREAD); //enable the receiver and block control lines
//set the character size to 8 bits, no parity bit and 1 stop bit (8N1 configuration)
options.c_cflag &= ~PARENB; //no parity
options.c_cflag &= ~CSTOPB; //1 stop bit
options.c_cflag &= ~CSIZE; //bit mask for character size
options.c_cflag |= CS8; //8 bit character size
//disable hardware flow control
options.c_cflag &= ~CRTSCTS;
//configure for non-canonical mode
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG); //disable cannonical mode, echo, erasure, new-line echo, INTR, QUIT and SUSP
options.c_iflag &= ~(IXON | IXOFF | IXANY); //disable software flow control
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); //disable any special handling of received bytes
options.c_oflag &= ~OPOST; // prevent special interpretation of output bytes
options.c_oflag &= ~ONLCR; // prevent conversion of newline to carriage return/line feed
//read returns after 0.5 second timeout
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 5;
serial_port_flush(fd); //flush the serial port
//set the new options for the serial port
if(tcsetattr(fd, TCSANOW, &options) < 0) {
fprintf(stderr, "serial_port_init: unable to set terminal optionsn");
return -1;
}
return fd;
}
//closing the serial communication
void serial_port_close(int fd) {
close(fd);
}
void serial_port_flush(int fd) {
sleep(2);
tcflush(fd, TCIOFLUSH);
}
//check if serial port is ready
int serial_port_ready(int fd) {
uint8_t c[1];
uint8_t prev = 0;
ssize_t n = read(fd, c, 1);
int done = 0;
if(n <= 0) return 0;
prev = c[0];
do {
//printf("%02X", (uint8_t)prev);
n = read(fd, c, 1);
if(n <= 0) return 0;
done = (prev == '>') && (c[0] == ' ');
prev = c[0];
} while(!done);
return 1;
}
//writing to the serial port
ssize_t serial_port_write(int fd, const char *data) {
size_t data_length = strlen(data);
ssize_t n = write(fd, data, data_length);
if(n != data_length) {
fprintf(stderr, "serial_port_write: unable to write the datan");
return -1;
}
return n;
}
//reading block of bytes from the serial port into file
int32_t serial_port_read_block_file(int fd, uint8_t *block, uint16_t block_size, FILE **file) {
uint8_t *block_cur_pos = block;
memset(block, 0, block_size);
ssize_t n;
uint16_t total = 0;
int done = 0;
int try = 0;
static const int TRIES = 5;
//printf("serial_port_read_block_file: started reading block.n");
do {
n = read(fd, block_cur_pos, block_size - (block_cur_pos - block));
if(n == -1) {
fprintf(stderr, "serial_port_read_block_file: unable to read the datan");
return -1;
}
block_cur_pos += n;
total += n;
//print_byte_array(block, block_cur_pos - block + 1);
if(n > 0) {
done = (block_cur_pos[-1] == 'n' && block_cur_pos[-2] == 'r') || (total == block_size);
} else {
try++;
if(try >= TRIES) done = 1;
}
} while(!done);
//printf("serial_port_read_block_file: done reading the required block. Total read: %u bytesn", total);
if(total == 0) return 0;
if(block_cur_pos[-1] == 'n' && block_cur_pos[-2] == 'r') {
total -= 2;
fwrite(block, sizeof(uint8_t), total, *file);
} else {
fwrite(block, sizeof(uint8_t), total, *file);
}
fflush(*file);
//printf("serial_port_read_block_file: done writing the bytes to the file.n");
return total;
}
//reading (bytes) bytes from the serial port into file
int32_t serial_port_read_file(int fd, FILE **file, uint16_t bytes) {
uint8_t *block = (uint8_t*)malloc(BLOCK_SIZE * sizeof(uint8_t));
uint16_t total = 0;
ssize_t n;
do {
n = serial_port_read_block_file(fd, block, BLOCK_SIZE, file);
if(n == -1) {
return -1;
}
total += n;
} while(total < bytes);
free(block);
//printf("Done reading.......n");
return total;
}
int main(int argc, char *argv[]) {
char *port_name = NULL;
char *file_name = NULL;
uint16_t bytes;
//parsing command line arguments
opterr = 0;
char c;
while((c = getopt(argc, argv, "p:f:s:h")) != -1) {
switch(c) {
case 'p':
port_name = strdup(optarg);
break;
case 'f':
file_name = strdup(optarg);
break;
case 's':
bytes = atoi(optarg);
break;
case 'h':
help();
return 0;
break;
default:
fprintf(stderr,
"rdump: invalid option: %cn"
"Try 'rdump -h' for more information.n",
optopt);
return 0;
break;
}
}
//opening serial port communication with the arduino
int port = serial_port_init(port_name, BAUD_RATE);
if(port < 0) {
//fprintf(stderr, "rdump: unable to open port %sn", port_name);
free(port_name);
free(file_name);
return -1;
}
printf("rdump: serial communication to %s opened successfullyn", port_name);
sleep(3); //wait for serial port to be ready
//send command for testing if the serial port is ready
char cmd[20];
cmd[0] = 'S';
cmd[1] = '';
if(serial_port_write(port, cmd) < 0) {
serial_port_close(port);
return -3;
}
//check if serial port is ready
if(!serial_port_ready(port)) {
fprintf(stderr, "rdump: serial port is not ready.n");
serial_port_close(port);
free(port_name);
free(file_name);
return -2;
}
printf("rdump: serial port is readyn");
//send command for reading n bytes
sprintf(cmd, "R%dn", bytes);
if(serial_port_write(port, cmd) < 0) {
serial_port_close(port);
free(port_name);
free(file_name);
return -3;
}
//receive the requested data
FILE *rom = fopen(file_name, "wb");
fsync(fileno(rom));
if(rom == NULL) {
fprintf(stderr, "rdump: unable to create file %sn", file_name);
serial_port_close(port);
free(port_name);
free(file_name);
return -4;
}
printf("rdump: file %s created successfully.n", file_name);
printf("Dumping ROM to file %s...n", file_name);
//uint8_t buffer[10000];
//int n = serial_port_read_block_file(port, buffer, 10000, rom);
//int n = serial_port_read(port, buffer, 10000);
//fwrite(buffer, sizeof(uint8_t), n, rom);
ssize_t dumped_bytes = serial_port_read_file(port, &rom, bytes);
if(dumped_bytes < 0) {
return -5;
}
if(dumped_bytes != bytes) {
fprintf(stderr, "Dumped %zd of %u bytesn", dumped_bytes, bytes);
} else {
printf("Done!n");
}
//close the file, serial port and free the memory
fclose(rom);
serial_port_close(port);
free(port_name);
free(file_name);
//printf("Exiting...n");
return 0;
}
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP