Wrong order of bytes received from serial port - c

I have a device with FPGA which sends data via simple UART. The data is a packet of 32 bytes, baudrate is 115200. I connect them to my laptop via UART-TTL/USB adapter, so in system (Ubuntu 14.04) I can read the data from ttyUSB. I've made a simple application in GTK/C to receive the data, make some math and save results in text file. Everything was working fine until I increased frequency of sending 32 bytes packets from 5 times per second to 100 times per second. The problem is one packet in a dozen or several dozen has wrong order of bytes. I've checked with logic analyzer that my FPGA sends data correctly every time.
For example, FPGA sends packet:
1 2 3 4 5 6 7 8 9
But my application sometimes receives:
1 2 7 3 4 5 6 8 9
I'm using this function to open serial port:
int rs232_open(char *com_name, int baudrate, int databits, char *parity, int stopbits)
{
serial_fd = open(com_name, O_RDWR | O_NOCTTY | O_NDELAY); //open port
if(serial_fd==-1)
{
perror("unable to open comport ");
return 1;
}
error = tcgetattr(serial_fd, &old_settings); //save actual port settings
if(error==-1)
{
close(serial_fd);
perror("unable to read portsettings ");
return 2;
}
memset(&new_settings, 0, sizeof(new_settings));
new_settings.c_iflag = 0; //without in processing
new_settings.c_oflag = 0; //without out processing
new_settings.c_lflag = 0; //without line processing
new_settings.c_cflag = CLOCAL | CREAD; //without flow control, receiver active
switch(baudrate) //baudrate
{
case 9600: new_settings.c_cflag |= B9600; break;
case 19200: new_settings.c_cflag |= B19200; break;
case 38400: new_settings.c_cflag |= B38400; break;
case 115200: new_settings.c_cflag |= B115200; break;
default: return 3; break;
}
switch(databits) //number of data bits
{
case 5: new_settings.c_cflag |= CS5; break;
case 6: new_settings.c_cflag |= CS6; break;
case 7: new_settings.c_cflag |= CS7; break;
case 8: new_settings.c_cflag |= CS8; break;
default: return 3;
}
switch(parity[0]) //parity
{
case 'N': new_settings.c_iflag |= IGNPAR; break;
case 'E': new_settings.c_cflag |= PARENB; break;
case 'O': new_settings.c_cflag |= PARENB | PARODD; break;
default: return 3;
}
switch (stopbits) //stop bits
{
case 1: break; //1 bit
case 2: new_settings.c_cflag |= CSTOPB; break; //2 bits
default: return 3;
}
new_settings.c_cc[VMIN] = 1; //1 received char allows to read
new_settings.c_cc[VTIME] = 0;
tcflush(serial_fd, TCIOFLUSH); //clear port buffers
error = tcsetattr(serial_fd, TCSANOW, &new_settings); //save new settings
if(error==-1)
{
close(serial_fd);
perror("unable to set portsettings ");
return 4;
}
return 0;
}
In my GTK/C application clicking on the "OPEN" button calls above function:
rs232_open("ttyUSB0",115200,8,"N",2);
Then, I create a channel for serial port, set its coding and add a handler for receive event:
int serial_fd; //serial port file descriptor
GIOChannel *serial_ch; //serial port channel
serial_ch = g_io_channel_unix_new(serial_fd); //attach channel to serial port
g_io_add_watch(serial_ch, G_IO_IN, read_channel, NULL); //attach read_channel handler function
Function read_channel() looks like this (frame is a struct with table of chars buffer and integer field byte_number):
gboolean read_channel(GIOChannel *channel, GIOCondition condition, gpointer data)
{
unsigned char i;
gsize bytes_read;
gchar chr;
GString *recdata = g_string_new(NULL);
if(g_io_channel_read_chars(channel, &chr, 1, &bytes_read, NULL) == G_IO_STATUS_NORMAL) //if reading a byte is successful
{
if(bytes_read) //1 byte received
{
//
// here I search for 0x55 0x55 sequence (start tag of 32 bytes packet)
// if start tag is received frame buffer is cleared and byte counter zeroed
//
frame.buffer[frame.byte_number++]=chr; //save received byte to buffer
if(frame.byte_number > BUFFER_SIZE-1) //frame buffer full
{
if(frame.buffer[BUFFER_SIZE-1] == 0x0D) //end tag is correct (0x0D is end tag of my 32 bytes packet)
{
//
// here I convert received data (some int16 numbers)
// and save them in readable form to text file
// also as a string of hex numbers for debugging
//
}
else //end tag not correct
{
//
// here I increase error counter
//
}
for(i=0; i<BUFFER_SIZE; i++) frame.buffer[i]=0; //clear the buffer
frame.byte_number=0; //reset byte counter
}
}
}
return TRUE;
}

Related

Can't read from serial port if not opened once with minicom

I have implemented a blocking read from serial port in C. My aim is to have a read which blocks until new data arrives.
Here is how I have implemented the serial pseudo-object (I've removed multithread protections for the code to be clearer).
typedef struct
{
int fd;
se_serial_speed_t speed;
se_serial_parity_t parity;
bool flow_control;
}se_serial_t;
int se_serial_constructor(se_serial_t** self, char* serial_port)
{
int fd;
if(NULL != *self)
{
return ERR_NNULL_PTR;
}
else if(0 != access(serial_port, F_OK))
{
ERRNO("Serial port is not available");
return ERR_ILLEGAL_PARAM;
}
else
{
if(-1 == (fd = open(serial_port, O_RDWR | O_NOCTTY)))
{
ERRNO("Error opening %s in rw mode", serial_port);
return ERR_OFILE_FAIL;
}
else if(NULL == (*self = malloc(sizeof(se_serial_t))))
{
ERROR("Error allocating memory for Serial");
return ERR_MALLOC_FAIL;
}
(*self)->fd = fd;
}
return ERR_OK;
}
int se_serial_configure_interface(se_serial_t* self, se_serial_speed_t speed, se_serial_parity_t parity, bool flow_control)
{
struct termios options;
if(NULL == self)
{
return ERR_NULL_PTR;
}
else
{
if(0 != tcgetattr(self->fd, &options))
{
ERRNO("Unable to get serial port current configuration");
}
if(0 != cfsetospeed(&options, speed))
{
ERRNO("Unable to set serial port output speed");
}
if(0 != cfsetispeed(&options, speed))
{
ERRNO("Unable to set serial port input speed");
}
switch(parity)
{
case SE_SERIAL_PARITY_8N1:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
break;
case SE_SERIAL_PARITY_7E1:
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
break;
case SE_SERIAL_PARITY_7O1:
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
break;
case SE_SERIAL_PARITY_7S1:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
break;
default:
WARNING("Unable to set serial port parity");
break;
}
if(flow_control)
options.c_cflag |= CRTSCTS;
else
options.c_cflag &= ~CRTSCTS;
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 0;
if(0 != tcsetattr(self->fd, TCSANOW, &options))
{
ERRNO("Error configuring serial port");
return ERR_SERIAL_CONF_FAIL;
}
self->speed = speed;
self->parity = parity;
self->flow_control = flow_control;
}
return ERR_OK;
}
int se_serial_read(se_serial_t* self, uint8_t* buffer, int size)
{
int bytes_read = 0;
int ret;
if(NULL == self)
{
return ERR_NULL_PTR;
}
else
{
while(bytes_read < size)
{
if(0 > (ret = read(self->fd, &(buffer[bytes_read]), size - bytes_read)))
{
ERROR("Error reading from %s : %d\n", self->serial_port, ret);
return ERR_RFILE_FAIL;
}
bytes_read += ret;
}
size = bytes_read;
}
return size;
}
The device I'm communicating with send a frame of 11 bytes every second after it has booted.
So I'm receiving frames in an infinite loop after initializing the serial port and I then print them.
se_serial_t* serial = NULL;
uint8_t buffer[1024] = {0};
int ret = 0;
int i;
if(0 > (ret = se_serial_constructor(&serial, "/dev/ttyUSB0")))
{
ERROR("Error creating serial : %d", ret);
return ERR_SERIAL_CREATION_FAIL;
}
else if(0 > (ret = se_serial_configure_interface(serial, SE_SERIAL_SPEED_B115200, SE_SERIAL_PARITY_8N1, false)))
{
ERROR("Error configuring serial interface : %d", ret);
return ERR_SERIAL_CONFIG_FAIL;
}
while(1)
{
if(0 > (ret = se_serial_read(serial, buffer, 11)))
{
ERROR("Error reading from serial : %d", ret);
return ret;
}
else
{
for(i=0;i<ret;i++)
{
printf("%02x ", buffer[i]);
}
printf("\n");
}
}
What is strange with the result I get is that the read blocks forever even if I know that the device is sending frames.
However if I open the port with another program like minicom, I can receive the frames inside of it. Once the port has been opened using minicom and that I have exited it, my program works well until next reboot of my computer.
If I reboot the device, the code blocks until it begins to send frames and receive them well.
I have also tried on a Raspberry Pi 3 to be sure it wasn't a configuration problem on my laptop but I get the same result.
Does anybody has a clue on why I get this behaviour ?
What is strange with the result I get is that the read blocks forever even if I know that the device is sending frames.
...
Once the port has been opened using minicom and that I have exited it, my program works well until next reboot of my computer.
Not strange at all.
That's a clear indication that your program's initialization of the serial terminal is incomplete and depends on a pre-existing initialization to be suitable.
(BTW "strange" is an opinion-based description that conveys no technical information to aid debugging.)
The default mode of the serial terminal is typically canonical mode (for transferring text) after a system boot.
Therefore an (unintentional) canonical read() of a serial terminal will block until a line termination character (e.g. a new-line character or 0x0A) is encountered.
Your program would block forever if the source never sends any line termination character.
You can confirm this by using the stty -F /dev/ttyUSB0 -a command, and find that the icanon attribute has no hyphen preceding it.
Minicom configures the serial terminal for non-canonical mode, which is the mode that your program apparently also expects the serial terminal to operate in.
However your program only configures the termios parameters for baudrate, framing, and flow-control.
It is missing several salient terms for reliable operation of a serial terminal.
If your program requires non-canonical mode, then it must explicitly configure that mode rather than rely on a preexisting configuration.
Since numerous other related attributes should also be set or cleared for non-canonical mode, the macro cfmakeraw() is the simplest edit to your code.
Insert
cfmakeraw(&options);
in between your baudrate and "parity" configuration.
Note that use of a 7-bit data frame will likely cause corruption if the data is not exclusively ASCII text, so supporting those three modes in your program is incongruous.
The other salient omission is enabling the receiver and setting local mode:
options.c_cflag |= (CLOCAL | CREAD);
The device I'm communicating with send a frame of 11 bytes
BTW your use of "frame" in the context of a serial terminal is inappropriate. In asynchronous serial communication each character or byte is framed. Your references to a "frame" would be more appropriately called a message or packet or datagram.

Arduino serial works fine with Debian but hangs with Raspbian

I'm working on a personal home automation project.
On the server side, I have an Arduino Pro Mini with:
a 433 MHz TX module on pin 2
a 433 MHz RX module on pin 3
a DHT22 probe on pin 4 (with 10k pull-up)
a DHT22 probe on pin 5 (with 10k pull-up)
I have two absolutely identical of these modules; one will be the radio relay (and DHT "server") and the other a secondary DHT "server".
When it is linked to my laptop (Debian Wheezy) through an FTDI cable, it can read both local probes and switch my wall plugs on/off thanks to a C program I wrote. I'd like to use it from a Raspberry Pi. But on the Raspberry Pi (with the same FTDI cable on USB), it executes the first command I send and then hangs my terminal, forcing me to use CTRL+C.
Here is the sketch on the Arduino side (header) :
/**
* probe.h
*
* #author David Mézière <...>
*/
/**
* DHT probe result
*
*/
struct Probe {
float temperature;
float humidity;
};
Main file :
/**
* probe.ino
*
* #author David Mézière <...>
*/
#include "probe.h"
/**
* Uses DHT sensor library, from Adafruit.
* #see https://github.com/adafruit/DHT-sensor-library
*/
#include <DHT.h>
/**
* Uses RC Switch library, from sui77.
* #see https://github.com/sui77/rc-switch
*/
#include <RCSwitch.h>
// Pinout definitions
#define TX 2 // 433 MHz transmitter pin number
#define RX 3 // 433 MHz receiver pin number
#define PROBE1 4 // First DHT22 probe pin number
#define PROBE2 5 // Second DHT22 probe pin number
#define LED 13 // On-board status LED pin number
RCSwitch radio = RCSwitch();
// DHT probes definition
DHT dht1(PROBE1, DHT22);
DHT dht2(PROBE2, DHT22);
// Incomming command buffer
byte cmd[9];
/**
* Setup
*
* #return void
*/
void setup()
{
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Serial.begin(9600);
Serial.setTimeout(1000); // doesn't fix the problem
// Attach receiver to interrupt 1, meaning pin 3
radio.enableReceive(1);
radio.enableTransmit(TX);
dht1.begin();
dht2.begin();
// Debug: Internal LED will blink 3 times rapidly to show when a reboot occurs.
for (int i = 0; i < 3; i++) {
digitalWrite(LED, HIGH);
delay(250);
digitalWrite(LED, LOW);
delay(250);
}
}
/**
* Loop
*
* #return void
*/
void loop()
{
if (Serial.available() == 9 && readCommand()) {
// Lights-up internal LED to show when a command has been executed
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
}
}
/**
* Query probe
*
* Query provided [dht] probe until [retry] times for both temperature and humidity.
*
* #param DHT dht Pointer to DHT object
* #param int retry Number of tries
* #return Probe Probe result (float temperature in °C, float humidity in %)
*/
Probe queryProbe(DHT* dht, int retry)
{
Probe probe;
// Query DHT22 probe for temperature, a maximum of [retry] times.
for (int t = 0; t < retry; t++) {
probe.temperature = dht->readTemperature(false);
if (!isnan(probe.temperature)) {
break;
}
delay(50);
}
// Query DHT22 probe for humidity, a maximum of [retry] times.
for (int h = 0; h < retry; h++) {
probe.humidity = dht->readHumidity();
if (!isnan(probe.humidity)) {
break;
}
delay(50);
}
return probe;
}
/**
* Read command
*
* If serial buffer contains 2 bytes, move them to a local buffer and return true. else return false.
*
* #return boolean
*/
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// Calculates the check sum of payload
int sum = cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ cmd[7];
// Checking header and checksum a header of 0xBA 0xB1 means DHT query
if (cmd[0] == 0xBA && cmd[1] == 0xB1 && cmd[8] == sum) {
unsigned int module = cmd[2];
unsigned int probe = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
Probe result;
switch (module) {
case 1:
// Selects the right probe
if (probe == 1) {
result = queryProbe(&dht1, 3);
} else if (probe == 2) {
result = queryProbe(&dht2, 3);
}
// Send status repport to client
Serial.print("1;");
Serial.print(module);
Serial.print(";");
Serial.print(probe);
Serial.print(";");
Serial.print(result.temperature);
Serial.print(";");
Serial.println(result.humidity);
Serial.flush(); // Doesn't fix the problem
break;
}
return true;
// A header of 0xBA 0xB2 means rf wall plugs query
} else if (cmd[0] == 0xBA && cmd[1] == 0xB2 && cmd[8] == sum) {
unsigned int proto = cmd[2];
unsigned int length = cmd[3];
unsigned int value = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
radio.send(value, length);
// Send status repport to client
Serial.print("2;");
Serial.print(proto);
Serial.print(";");
Serial.print(length);
Serial.print(";");
Serial.print(value);
Serial.print(";");
Serial.println("OK");
Serial.flush(); // Doesn't fix the problem
return true;
} else {
Serial.println("KO");
Serial.flush(); // Doesn't fix the problem
return false;
}
}
And on the client side :
/**
* probe.c
*
* #author David Mézière <...>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <getopt.h>
const char* device;
static int module = 0; // uint_8 ?
static int probe = 0; // uint_8 ?
const char* proto;
static int length = 0; // uint_8 ?
static int value = 0; // uint_32 ?
static int verbose = 0; // uint_8 ?
void help()
{
printf("usage:\n");
printf("\n");
printf("probe [options] [arguments]\n");
printf("\n");
printf("options:\n");
printf(" -h|--help: Displays this help and exit\n");
printf(" -v|--verbose: Be more verbose\n");
printf("\n");
printf("arguments:\n");
printf(" -d|--device: string Serial device to use (ex: /dev/ttyUSB0)\n");
printf(" -m|--module: integer DHT22 module to query\n");
printf(" -p|--probe: integer DHT22 probe to query\n");
printf(" -r|--proto: string Radio / IR protocol\n");
printf(" -l|--length: integer Radio / IR value length in bits\n");
printf(" -a|--value: integer Radio / IR value\n");
printf("\n");
printf("examples:\n");
printf(" probe --device /dev/ttyUSB0 --module 1 --probe 1 : Will query first DHT22 probe of first module\n");
printf(" probe --proto radio1 --length 12 --value 5393 : Will send value 5393 on 12 bits over the air using protocol 1\n");
printf(" probe --proto ir11 --length 64 --value 3772793023 : Will send value 3772793023 on 64 bits by infra red using protocol 11\n");
}
void parseArgs(int argc, char **argv)
{
int c;
while (1) {
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"module", required_argument, 0, 'm'},
{"probe", required_argument, 0, 'p'},
{"proto", required_argument, 0, 'r'},
{"length", required_argument, 0, 'l'},
{"value", required_argument, 0, 'a'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, "d:hm:p:v", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) {
break;
}
switch (c) {
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) {
break;
}
printf("option %s", long_options[option_index].name);
if (optarg) {
printf (" with arg %s", optarg);
}
printf("\n");
break;
case 'd':
device = optarg;
break;
case 'h':
help();
exit(0);
break;
case 'm':
module = atoi(optarg);
break;
case 'p':
probe = atoi(optarg);
break;
case 'r':
proto = optarg;
break;
case 'l':
length = atoi(optarg);
break;
case 'a':
value = atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
putchar('\n');
}
if (&device[0] == '\0') {
fprintf(stderr, "--device is mandatory\n");
exit(1);
} else if (verbose) {
printf("Device: %s\n", device);
}
if (verbose) {
printf("Querying probe %i of module %i.\n", probe, module);
}
}
void initSerial(int fd)
{
struct termios toptions;
/* get current serial port settings */
tcgetattr(fd, &toptions);
/* set 9600 baud both ways */
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);
/* 8 bits, no parity, no stop bits */
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
/* Canonical mode */
toptions.c_lflag |= ICANON;
/* commit the serial port settings */
tcsetattr(fd, TCSANOW, &toptions);
}
int main(int argc, char **argv)
{
// Parses command line arguments
parseArgs(argc, argv);
int fd, n, i;
char buf[64] = "temp text";
/* open serial port */
fd = open(device, O_RDWR | O_NOCTTY);
if (verbose) {
printf("Device %s opened as %i\n", device, fd);
}
/*
* Note: Most Arduinos models will reboot upon connection, and they need
* some time for it. I use a pro/mini that doesn't, so i commented it out.
*/
// usleep(3500000);
// Sets the serial port settings (9600 bps, 8 bits, no parity, no stop bits)
initSerial(fd);
/**
* 72 bits
* | Header | Param 1 | Param 2 | Param 3 | sum |
* | 16 b | 8 b | 8 b | 32 b | 8 b |
* Cas 1 : Requête DHT | 0xba 0xb1 | module | 0x00 | sonde | sum |
* Cas 2 : Requête radio | 0xba 0xb2 | proto | length | value | sum |
* Cas 3 : Requête IR | 0xba 0xb3 | proto | length | value | sum |
*/
unsigned char oBuf[9];
// printf("%s\n", proto);
// printf("%i\n", length);
if (module > 0 && probe > 0) {
if (verbose) {
printf("DHT mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB1; // DHT query
oBuf[2] = module;
oBuf[3] = 0x00;
oBuf[4] = (probe >> 24) & 0xFF;
oBuf[5] = (probe >> 16) & 0xFF;
oBuf[6] = (probe >> 8) & 0xFF;
oBuf[7] = probe & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
// sprintf(oBuff, "%c%c%c%c%c%c", 0xba, 0xb1, module, 0x00, probe, sum);
} else if (strcmp((const char*)proto, "radio1") == 0 && length > 0) {
if (verbose) {
printf("Radio mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB2; // Radio query
oBuf[2] = 0x01; // Protocol 1
oBuf[3] = length;
oBuf[4] = (value >> 24) & 0xFF;
oBuf[5] = (value >> 16) & 0xFF;
oBuf[6] = (value >> 8) & 0xFF;
oBuf[7] = value & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
} else {
if (verbose) {
printf("Unknown mode\n");
}
}
/* Send the buffer */
write(fd, oBuf, 9);
/* Receive string from Arduino */
n = read(fd, buf, 64);
/* insert terminating zero in the string */
buf[n] = 0;
if (verbose) {
printf("%i bytes read, buffer contains: %s\n", n, buf);
} else {
printf("%s", buf);
}
return 0;
}
I compile it using just gcc probe.c -o probe.
On Debian, I can use the system as much as I want, it works:
dmeziere#portable2-wlan:~/dev/probe$ gcc probe.c -o probe
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.60;43.10
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
1;1;2;23.60;38.50
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5396
2;1;24;5396;OK
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5393
2;1;24;5393;OK
On Raspbian, the first call works, but the second hangs my terminal and I have to do CTRL+C:
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.90;39.00
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
^C
I found it !
It seems like on Raspbian, the communications were terminated by a NULL character. But not on Debian. And this NULL character was polluting my calculations of incomming buffer length. So i ended up by eventually suppress it on the Arduino side :
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// If sender sends a null character, remove it.
int test = Serial.peek();
if (test == 0x00) {
test = Serial.read();
}
// ...
}

Not able to get the attributes of serial port config

Helo, I have been trying to retrieve the configuration of serial port using tcgetattr and I am able to get the correct values at first instance. When I change the values of corresponding parameters return values I get are repeat of previous returns. If ayone knows please help. I tried this when serial port connection was active and working.
#include<termios.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
char *baudQuery(speed_t speed){
static char SPEED[20];
switch (speed){
case B4800:
strcpy(SPEED, "B4800");
return SPEED;
break;
case B9600:
strcpy(SPEED, "B9600");
return SPEED;
break;
case B19200:
strcpy(SPEED, "B19200");
return SPEED;
break;
case B38400:
strcpy(SPEED, "B38400");
return SPEED;
break;
case B57600:
strcpy(SPEED, "B57600");
return SPEED;
break;
case B115200:
strcpy(SPEED, "B115200");
return SPEED;
break;
default :
strcpy(SPEED, "ERROR");
return SPEED;
}
}
main() {
int fd;
struct termios term;
speed_t speed;
term.c_cflag = B38400 | ~CSIZE | CS5 | PARENB | (~PARODD);
term.c_lflag = ~(ICANON | ECHO | ECHOE);
if((fd = open("/dev/ttyS1",O_RDWR)) <0)
printf("Failed to open file\n");
tcsetattr(fd,TCSANOW,&term);
if (tcgetattr(fd, &term) != 0)
perror("tcgetatt() error");
else {
speed = cfgetospeed(&term);
printf("cfgetispeed() says the speed of stdin is %s\n",
baudQuery(speed));
tcgetattr(fd, &term);
switch(term.c_cflag & CSIZE){
case CS5:
puts("Data Bits = 5");
break;
case CS6:
puts("Data Bits = 6");
break;
case CS7:
puts("Data Bits = 7");
break;
case CS8:
puts("Data Bits = 8");
break;
}
tcgetattr(fd, &term);
if(term.c_cflag & (~PARENB))
puts("No parity is used");
if (term.c_cflag & (PARENB & (~PARODD)) )
puts("Even parity is used");
if (term.c_cflag & (PARODD & PARENB))
puts("Odd parity is used");
//Get the mode (Only part working correct!)
if(term.c_lflag & ICANON)
puts("Mode is canonical");
else
puts("Mode is non canonical");
}
close(fd);
}

Binary data from a serial port in linux using c

I am reading binary data from a serial port on Phidget sbc using Linux to get a command from an application running on a PC. I wrote a test program in VB to read the data into a byte array and convert it to decimal to use it but can’t figure out how to do it in c. I am unable to come up with anything with the research I have done on the internet.
Command sent from PC is 0x0F.
To check if I am getting correct data I read the data and send it back. Here is what I get back. Returned data has a carriage return added to it.
Hex Display 0F00 0000 0D
‘\’ Display \0F\00\00\00\r
Normal display just display a strange character.
This tells me that the data is there that I can use, but can’t figure out to extract the value 0F or 15.
How can I convert the incoming data to use it?
I tried converting the received data using strtol, but it returns 0. I also tried setting the port to raw but it did not make any difference.
unsigned char buffer1[1];
int ReadPort1()
{
int result;
result = read(file1, &buffer1,1);
if(result > 0)
{
WritePort1(buffer1);
sprintf(tempstr, "Port1 data %s %d", buffer1, result);
DisplayText(2,tempstr);
}
return result;
}
Port Open/Setup
void OpenPort1()
{
//file1 = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NONBLOCK);
file1 = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NODELAY);
if(file1 < 0)
printf("Error opening serial port1.\n");
else
{
SetPort(file1, 115200, 8, 1, 0, 1);
port1open = 1;
}
}
void SetPort(int fd, int Baud_Rate, int Data_Bits, int Stop_Bits, int Parity, int raw)
{
long BAUD; // derived baud rate from command line
long DATABITS;
long STOPBITS;
long PARITYON;
long PARITY;
struct termios newtio;
switch (Baud_Rate)
{
case 115200:
BAUD = B115200;
break;
case 38400:
BAUD = B38400;
break;
case 19200:
BAUD = B19200;
break;
case 9600:
BAUD = B9600;
break;
} //end of switch baud_rate
switch (Data_Bits)
{
case 8:
default:
DATABITS = CS8;
break;
case 7:
DATABITS = CS7;
break;
case 6:
DATABITS = CS6;
break;
case 5:
DATABITS = CS5;
break;
} //end of switch data_bits
switch (Stop_Bits)
{
case 1:
default:
STOPBITS = 0;
break;
case 2:
STOPBITS = CSTOPB;
break;
} //end of switch stop bits
switch (Parity)
{
case 0:
default: //none
PARITYON = 0;
PARITY = 0;
break;
case 1: //odd
PARITYON = PARENB;
PARITY = PARODD;
break;
case 2: //even
PARITYON = PARENB;
PARITY = 0;
break;
} //end of switch parity
newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
if(raw == 1)
{
newtio.c_oflag &= ~OPOST;
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
}
else
{
newtio.c_lflag = 0; //ICANON;
newtio.c_oflag = 0;
}
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
}
Are you looking for a hex representation of your data ?
sprintf(tempstr, "Port1 data %s %x", buffer1, buffer1[0]);

Configuring UART1 in lpc 2468

I am working on lpc2468 ARM-based microcontroller. I am not able to configure the UART1 of the controller. Previously I was using UART0 for the same purpose, but due to some changes in hardware now I have to use UART1.
I want to connect GPRS module (SIMCOM 300) to the UART1 of the microcontroller. Here's my code so far:
void init_serial_gprs (void){
PINSEL7 |= 0x0000000F;
U1LCR = 0x00000080;
U1DLL = 0x00000041;
U1DLM = 0x00000000;
U1LCR = 0x03;
VICVectAddr7 = (unsigned)serial1_isr;
VICIntEnable = 1 << 7;
SBUF= U1RBR;
U1IER = 3;
}
void serial1_isr(void) __irq {
volatile char dummy;
volatile UWORD32 IIR1;
/*------------------------------------------------
Repeat while there is at least one interrupt source.
------------------------------------------------*/
while (((IIR1 = U1IIR) & 0x01) == 0)
{
switch (IIR1 & 0x0E)
{
case 0x06: /* Receive Line Status */
dummy = U1LSR; /* Just clear the interrupt source */
break;
case 0x04: /* Receive Data Available */
case 0x0C: /* Character Time-Out */
SBUF= U1RBR;
if(genflag.fl_m_psw || new_st == 0 ||new_st == 0x1f){
if(genflag.gprs_con) receive_data();
else
receive_data_gprs();
}
break;
case 0x02: /* THRE Interrupt */
if(genflag.gprs_con) transfer_data();
else transfer_data_gprs();
dummy = U1LSR;
break;
default:
break;
}
}
VICVectAddr = 0; /* Acknowledge Interrupt */
}
did you try polling the serial port first against a dumb terminal (hyperterm, minicom, putty) to make sure you have the basics then move on to interrupts?

Resources