recibir - leer puerto serial arduino
La transferencia binaria en el puerto serie cambia el retorno del carro (1)
¡Muchas gracias, funcionó! Nunca supe que existía la opción ICRNL que traduce los avances de línea a retornos de carro. Una vez que establecí eso y otros con
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); //tty is the name of the struct termios
era dorado
He intentado implementar un protocolo de transferencia de archivos en serie primitivo en C la semana pasada y me he encontrado con un problema realmente extraño que parece que no puedo encontrar la solución en línea. Logré transferir datos binarios a través del puerto serie y recibirlos, pero en el proceso, todos los bytes "0D" se convierten en "0A". El siguiente es mi código.
#include <stdlib.h>
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <signal.h>
#include <sys/ioctl.h>
#include <termios.h>
//eventually plan to set up a proper communication protocol
#define ACK 0x01
#define NAK 0x00
int setAttribs (int fd, int speed, int parity);
unsigned char* readFile(char* filename, int* file_size);
int main(void){
//set up ports
int fd = 0, r = 0, i = 0;
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);//sending port
if(fd<0){
perror("open port ttyUSB0 failed");
return -1;
}
setAttribs(fd,1500000,0);
int rd =0, file_size=0, bytes=0;
rd = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NDELAY);//receiving port
setAttribs(rd,1500000,0);
//create file to which the binary data will be written
FILE *newFile;
newFile = fopen("t.bin","wb");
if(newFile<0){
printf("open file failed/n");
return -1;
}
//This character array will hold the file to be transferred
unsigned char* data = ''/0'';
data = readFile("t.odt", &file_size);
ioctl(rd, TCFLSH, &bytes);//port flush which does not seem to work
do{
//write data in 1024 byte chunks
write(fd,data+i,1024);
//wait for write to finish
usleep(8500);
//buffer to hold received bytes
unsigned char buffer[1024];
//ensure buffer is empty
memset(buffer,0,1024);
//read in 1024 byte chunks
read(rd, buffer, 1024);
//printing bytes in the buffer to check for errors
for(r=0;r<1024;r++){
if(r%16==0)
printf("/n");
printf("%02X ", buffer[r]);
}
//write to file in 1024 byte chunks
fwrite(buffer, 1,1024,newFile);
//increase counter
i+=1024;
}while(i<8197);//its an 8088 byte file
printf("Done!/n");
return 0;
}
unsigned char* readFile(char* filename, int* file_size){
unsigned char *buffer = NULL;
int string_size, i;
FILE *handler = fopen(filename, "rb");
if (handler)
{
// Seek the last byte of the file
fseek(handler, 0, SEEK_END);
// Offset from the first to the last byte, or in other words, filesize
string_size = ftell(handler);
printf("File length: %d/n",string_size);
*file_size = string_size;
// go back to the start of the file
rewind(handler);
// Allocate a string that can hold it all
buffer = (unsigned char*) malloc(sizeof(unsigned char) * (string_size + 1) );
// Read it all in one operation
for(i=0;i<string_size;i++){
fread(buffer+i, sizeof(unsigned char),1, handler);
if(i%16==0)
printf("/n");
printf("%02X ",*(buffer+i));
}
// fread doesn''t set it so put a /0 in the last position
// and buffer is now officially a string
// buffer[string_size] = ''/0'';
printf("Finished read/n");
// Always remember to close the file
fclose(handler);
}
return buffer;
}
int setAttribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
fputs("error %d from tcgetattr", stderr);
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as /000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn''t block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
fputs("error %d from tcsetattr", stderr);
}
return 1;
}
Todo lo que hace es escribir en un convertidor USB-Serial en un puerto y leer uno en el otro. Estaba probando con un archivo ODT de 8088 bytes (Hello World) y estaba probando diferentes baudrates y tamaños de bloques de escritura. Después de algunos intentos de prueba y error, descubrí que esta configuración (bloques de 1500000 bps y 1024 bytes) era rápida y relativamente más confiable. Los únicos errores son los que se muestran a continuación.
Bytes transmitidos: 70 6E 67 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49
Bytes recibidos: 70 6E 67 89 50 4E 47 0A 0A 1A 0A 00 00 00 0A 49
Como puede ver, todos los bytes "0D" se cambian a "0A". Intenté baudrates más bajos y tamaños de bloque más pequeños y el problema persiste. Entiendo que son los valores de retorno de carro y de avance de línea respectivamente y que el avance de línea se usa como un valor de control para la comunicación asíncrona en Linux; pero no entiendo por qué eso afectaría los valores de retorno de carro . ¿Hay algún significado especial para el retorno de carro en la comunicación serial? ¿Hay alguna manera de enviar el byte "0D" en ese caso?
TL; DR: la comunicación en serie sin formato hace que los bytes "0D" se reemplacen por "0A". ¿Alguna idea de por qué? Cualquier forma de resolver?