For a project I am working on we're using libserial to communicate with out hardware. the problem with libserial is that when you call read() it returns an unsigned char and readline() returns a string. We're encoding our collected data from four sensors into 32 bit unsigned integer if I do a four unsigned character array some of our sensor data will be broken into pieces across two characters. My question is how would I be able to place all the bits into an unsigned long integer where Char[0] = bits[31:24], Char[1] = bit[23:16], Char[2] = bit[15:8], Char[3] = bit[7:0].

Also if we use the ReadLine() function we would have to place a new line character at the end of it so that the function knows when to stop reading. How would I remove the new line character before I process the bits.

Recommended Answers

All 4 Replies

If I understand you correctly, there are (at least) a couple of possibilities.
You could delare a union which makes both data types available. Read your input into the char array in the order you want, then use the unsigned long for processing.

union
{
    unsigned long theLong;
    unsigned char theChars[4];
} input;

port.Read(input.theChars[3]);
port.Read(input.theChars[2]);
port.Read(input.theChars[1]);
port.Read(input.theChars[0]);

// Do something with input.theLong

Or, you could read each byte into a char, then use bitwise operations to set the appropriate bits in your long int.

unsigned long ulBits = 0;
unsigned char ucInput = 0;

port.Read(ucInput);
ulBits |= (unsigned long)ucInput << 24;

port.Read(ucInput);
ulBits |= (unsigned long)ucInput << 16;

port.Read(ucInput);
ulBits |= (unsigned long)ucInput << 8;

port.Read(ucInput);
ulBits |= (unsigned long)ucInput;

As for ReadLine(), I believe it reads into a string object, so you don't need to worry about handling/removing termination chars. But unless you are only going to expect ascii characters as input, that's not the best idea.

Is this answering your question?

Member Avatar for jencas

Alternatively you can use a union:

union ulong_char4
{
    unsigned long ul;
    unsigned char[4] c4;
}

put the values to c4 and afterwards retrieve the value from ul

Or you could use the std::bitset class.
When you have set all the bits in your bitset, just use the to_ulong() member to convert it to a long.

This is what I have done to test the packing and unpacking of the data. The data will be packed on the data logger device and unpacked on the linux computer after it has been received from the serial port.

#include <iostream>
using namespace std;

struct Data_Logger_output {
	unsigned int speed : 8;
	unsigned int rpm : 14;
	unsigned int fuel : 7;
	unsigned int scene : 3;
};

int main() {

	Data_Logger_output *dataLogger = new Data_Logger_output;
	dataLogger->speed = 150;
	dataLogger->rpm = 10000;
	dataLogger->fuel = 87;
	dataLogger->scene = 0;
	
	unsigned long int output = (dataLogger->scene << 29) | (dataLogger->fuel << 22) | (dataLogger->rpm << 8) | (dataLogger->speed);
	char temp[4];
	temp[0] = (char)output;
	temp[1] = (char)output >> 8;
	temp[2] = (char)output >> 16;
	temp[3] = (char)output >> 24;
	
	string outout = temp;

	cout << outout << endl;
	
	unsigned long int outty = ((unsigned int)outout[3] << 24) | ((unsigned int)outout[2] << 16) | ((unsigned int)outout[1] << 8) | ((unsigned int)outout[0]);

	cout << outty << endl;
	
	unsigned long int Ospeed, Ofuel, Oscene, Orpm;
	Ospeed = outty & 0xFF;
	Orpm = (outty >> 8) & 0x3FFF;
	Ofuel = (outty >> 22) & 0x7F;
	Oscene = (outty >> 29);
	
	cout << "Speed is: " << Ospeed << " MPH," << " rpm is: " << Orpm << " RPM, " << " fuel is: " << Ofuel << "%, " << " scene ID is: " << Oscene << endl;

	return 0;
}

When i run this program I get this:
4294967190
Speed is: 150 MPH, rpm is: 16383 RPM, fuel is: 127%, scene ID is: 7

the speed is returned properly but nothing else is.
here are the bit string compared with one another (ignore the spaces in the string)
got - 111 1111111 11111111111111 10010110
expected - 000 1010111 10011100010000 10010110

for everything other than speed it is setting all the bits to 1

I know this code works perfectly but i wrote this before I realized that libserial returns chars and strings and not unsigned ints

#include <iostream>
using namespace std;

struct Data_Logger_output {
	unsigned int speed : 8;
	unsigned int rpm : 14;
	unsigned int fuel : 7;
	unsigned int scene : 3;
};

int main() {

	Data_Logger_output *dataLogger = new Data_Logger_output;
	dataLogger->speed = 150;
	dataLogger->rpm = 10000;
	dataLogger->fuel = 87;
	dataLogger->scene = 0;
	
	unsigned long int output = (dataLogger->scene << 29) | (dataLogger->fuel << 22) | (dataLogger->rpm << 8) | (dataLogger->speed);
	char temp[4];
	temp[0] = (char)output;
	temp[1] = (char)output >> 8;
	temp[2] = (char)output >> 16;
	temp[3] = (char)output >> 24;
	
	string outout = temp;
	cout << outout << endl;
	
	unsigned long int outty = ((unsigned int)outout[3] << 24) | ((unsigned int)outout[2] << 16) | ((unsigned int)outout[1] << 8) | ((unsigned int)outout[0]);

	cout << outty << endl;
	
	unsigned long int Ospeed, Ofuel, Oscene, Orpm;
	Ospeed = outty & 0xFF;
	Orpm = (outty >> 8) & 0x3FFF;
	Ofuel = (outty >> 22) & 0x7F;
	Oscene = (outty >> 29);
	
	cout << "Speed is: " << Ospeed << " MPH," << " rpm is: " << Orpm << " RPM, " << " fuel is: " << Ofuel << "%, " << " scene ID is: " << Oscene << endl;

	return 0;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.