So I have embedded device based on Raspberry Pi (Modberry) and 4 sensors connected via one USB-hub. These sensors send data all the time via serial port which I have to read and analyze. Data is divided by chunks: 7 bytes each and space between them. First 4 bytes are time and 3 bytes are value which is measured by sensor. Normal values should be about 0 +- 5. Baudrate is 921600. When I read only one sensor, for example "/dev/ttyUSB0", everything is fine but when I start to increase amount of readable sensors things go completely wrong. 4 bytes which represent time are always delivered in correct way and are NEVER wrong but last 3 bytes come with weird values 99% of time and start spamming like this:
[2019-04-22 17:48:02.264] Device: /dev/ttyUSB3, Time: 12226408, Value: 1690
[2019-04-22 17:48:02.265] Device: /dev/ttyUSB2, Time: 12217312, Value: 1690
[2019-04-22 17:48:02.265] Device: /dev/ttyUSB2, Time: 12217316, Value: 1690
Interesting thing is that it doesn't happen 100% of times after restarting application but about 80%.
I made an application also in Python and Java which doesn't have this issue. They are all running on same device. I was trying to run reading every sensors in separate thread but it also didn't help.
I simplified my code a lot and removed all error checks in this chunk.
void openSerial()
{
const int fileDescriptor = ::open(mParams.path.c_str(), O_RDONLY | O_NOCTTY);
termios SerialPortSettings;
SerialPortSettings.c_cflag &= ~PARENB;
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
SerialPortSettings.c_oflag &= ~OPOST;
SerialPortSettings.c_cc[VMIN] = 10;
SerialPortSettings.c_cc[VTIME] = 0;
cfsetispeed(&SerialPortSettings, 921600);
tcsetattr(fileDescriptor, TCSANOW, &SerialPortSettings);
tcflush(fileDescriptor, TCIOFLUSH);
}
static const int BUFFER_SIZE = 256;
void readSerial()
{
char buffer[BUFFER_SIZE + 1] = { 0 };
int count = 0;
count = read(mfd, buffer, BUFFER_SIZE);
std::vector<char> rawBuffer;
for (int i = 0; i < count; i++) {
rawBuffer.push_back(buffer[i]);
}
parse(rawBuffer);
}
void parse(std::vector<char> rawBuffer)
{
auto currentSpace = std::find(rawBuffer.begin(), rawBuffer.end(), ' ');
auto nextSpace = std::find(currentSpace + 1, rawBuffer.end(), ' ');
size_t counter = 0;
while (currentSpace != rawBuffer.end()) {
const int dist = std::distance(currentSpace, nextSpace);
if (dist == 8) {
XD1000Data data;
data.time = parseTime(&(*(currentSpace + TIME_SHIFT)));
data.value = parseValue(&(*(currentSpace + VALUE_SHIFT)));
} else {
printf("packet size error, dist %d, rawBuffer.size %d, counter %d", dist, rawBuffer.size(), counter);
}
counter++;
currentSpace = nextSpace;
nextSpace = std::find(currentSpace + 1, rawBuffer.end(), ' ');
}
rawBuffer.clear();
}
long parseTime(char *buffer)
{
long dest[4];
long time;
parseBuffer<long, 4>(buffer, dest);
time = dest[3] + (dest[2] << 6) + (dest[1] << 12) + (dest[0] << 18);
return time;
}
int parseValue(char *buffer)
{
int dest[3];
int value;
parseBuffer<int, 3>(buffer, dest);
value = dest[2] + (dest[1] << 6) + (dest[0] << 12);
return (short)((value & 0x1000) ? (value | 0xf000) : (value & 0x0fff));
}
template <typename T, size_t size> void parseBuffer(char *buffer, T *dest)
{
for (size_t i = 0; i < size; i++) {
if (isupper(buffer[i]))
dest[i] = buffer[i] - 'A';
else if (islower(buffer[i]))
dest[i] = buffer[i] - 'a' + 26;
else if (isdigit(buffer[i]))
dest[i] = buffer[i] - '0' + 52;
else if (buffer[i] == '+')
dest[i] = 62;
else if (buffer[i] == '/')
dest[i] = 63;
else // error
;
}
}
I'm 100% sure that sensors are not sending this 1690 data, this behaviour is not observed in any other apps with any amount of sensors or even Minicom. And this is how it should actually work and it does some rare times:
Device:/dev/ttyUSB3 14006188 -5
Device:/dev/ttyUSB3 14006192 -6
Device:/dev/ttyUSB3 14006196 -5
Device:/dev/ttyUSB3 14006200 -6
Device:/dev/ttyUSB3 14006204 -5
Device:/dev/ttyUSB3 14006208 -6
Device:/dev/ttyUSB3 14006212 -5
Device:/dev/ttyUSB0 14006152 -1
Device:/dev/ttyUSB0 14006156 -2
Device:/dev/ttyUSB0 14006160 -1
Device:/dev/ttyUSB0 14006164 0
buffer
was null terminated and checkcount
if I were you. – user4581301Java
then it might be useful to show us the coreJava
code than correctly reads the values alongside the equivalentC++
code that fails. Just the reading/decodong code. – Galikparse()
work? – Galiksizeof(long) == 4
. That's not always true, on a 64-bit Linux system thensizeof(long)
is typically equal to8
. – Some programmer dude