Asynchronous data reading from a barcode scanner over RS232 serial port - c++

I have a bar-code reader which is connected to PC on RS232 serial port. I am writing a C++ code to send command to barcode scanner and get the response back to the PC. Currently program can send data to the device correctly but it is failed to read the response from barcode scanner. In this case once we send a command to barcode reader it will response back with a positive or negative acknowledgement.
e.g:- Send BEEP command.
1. Host(PC) send a BEEP command to barcode scanner
2. Barcode scanner make a beep sound and send the acknowledgement back
to host (PC)
3. Host (PC) read the acknowledgement
in below code first 2 step are working properly but I couldn't write third one correctly. Please somebody help me to correct my source code to read the response from barcode scanner asynchronously.
main.cpp
#include <iostream>
extern "C"
{
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
}
#include "DeviceRS232.h"
#include "Message.h"
int main()
{
unsigned char recvBuffer[257];
unsigned char ledOn[] = {0x05, 0xE7, 0x04, 0x00, 0x0D, 0x00};
unsigned char SSIBuffer[] = {0x00, 0xC6, 0x04, 0x08, 0x11, 0xEE, 0x01};
unsigned char requestRevision[] = {0x00, 0x04, 0xA3, 0x04, 0x00};
unsigned char sendBeep[] = {0x00, 0xE6, 0x04, 0x00, 0x05};
Message beepCommand(sendBeep, sizeof(sendBeep)/sizeof(sendBeep[0]));
std::cout << "*********************************************************" << std::endl << std::endl;
DeviceRS232 dev_rs232;
dev_rs232.setDefaultAttributes();
dev_rs232.openSerialPort();
// Send BEEP command several times.
std::cout << "---Start sending beep---" << std::endl;
for(int x=0; x<1; x++)
{
int sizeSent = dev_rs232.sendDataBuffer(beepCommand.getCommandData(), beepCommand.getLen());
if( sizeSent > 0)
{
std::cout << "Data sent: " << sizeSent << std::endl;
}
memset(recvBuffer, 0, sizeof(recvBuffer));
int recvSize = dev_rs232.receiveDataBuffer(recvBuffer, sizeof(recvBuffer));
std::cout << "Date Received, Data: " << recvBuffer << " Size: " << recvSize << std::endl;
sleep(2);
/**
while(true)
{
memset(recvBuffer, 0, sizeof(recvBuffer));
int recvSize = dev_rs232.receiveDataBuffer(recvBuffer, sizeof(recvBuffer));
if(recvSize > 0)
std::cout << "Date Received, Data: " << recvBuffer << " Size: " << recvSize << std::endl;
sleep(2);
}*/
}
std::cout << "---End sending beep-----\n" << std::endl;
dev_rs232.closeSerialPort();
std::cout << "*********************************************************" << std::endl;
return 0;
}
Message.h
#ifndef MESSAGE_H
#define MESSAGE_H
#include <iostream>
#include <string>
#include <numeric>
extern "C"
{
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
}
class Message
{
public:
Message(); // default constructor
virtual ~Message(); // destructor
Message(const std::basic_string<unsigned char> msg) : commandMsg(msg)
{
printf("msg[0]:%x\n", msg[4]);
std::cout << "length: " << commandMsg.length() << std::endl;
//commandMsg[0] = commandMsg.length();
appendChecksum();
};
Message(const unsigned char *msg, int msglen) : commandMsg(msg, msglen)
{
commandMsg[0] = commandMsg.length();
appendChecksum();
};
const unsigned char *getCommandData() const
{
return commandMsg.c_str();
}
int getLen() const
{
return commandMsg.length();
}
protected:
private:
int appendChecksum();
std::basic_string<unsigned char> commandMsg;
};
#endif // MESSAGE_H
Message.cpp
#include "Message.h"
Message::Message()
{
//ctor
}
Message::~Message()
{
//dtor
}
int Message::appendChecksum()
{
int sum = -std::accumulate(commandMsg.begin(), commandMsg.end(), 0);
commandMsg.push_back(0xFF & (sum >> 8));
commandMsg.push_back(0xFF & sum);
}
DeviceRS232.h
#ifndef DEVICERS232_H
#define DEVICERS232_H
extern "C"
{
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdlib.h>
}
#include <string>
#define MAX_SERIAL_PORT_NO 30
class DeviceRS232
{
public:
DeviceRS232();
virtual ~DeviceRS232();
int fdRS232; // file descriptor for the serial port
void setSerialPort(std::string sp);
void setBaudRate(long baud);
void setDataBits(int dataBit);
void setStopBits(int stopBit);
void setNumberOfParityBits(int nparityBits);
void setDefaultAttributes();
long getBaudRate();
std::string getSerialPort();
int openSerialPort();
int readUserConfiguration();
int sendDataBuffer(const unsigned char *dataBuffer, size_t bufferSize);
int receiveDataBuffer(unsigned char *dataBuffer, size_t bufferSize);
void closeSerialPort();
protected:
std::string serialPort; // Serial port like /dev/ttyS0
long baudRate; // Scanner baud rate
int dataBits; // data bits
int stopBits; // stop bits
int numberOfParityBits; // number of parity bits
termios oldSerialPortSetting; // Current values of termios structure for /dev/ttyS0
termios newSerialPortSetting; // new termios attributes for /dev/ttyS0
private:
};
#endif // DEVICERS232_H
DeviceRS232.cpp
#include "DeviceRS232.h"
DeviceRS232::DeviceRS232()
{
//ctor
}
DeviceRS232::~DeviceRS232()
{
//dtor
}
void DeviceRS232::setSerialPort(std::string sp)
{
serialPort = sp;
}
void DeviceRS232::setBaudRate(long baud)
{
baudRate = baud;
}
void DeviceRS232::setDataBits(int dataBit)
{
dataBits = dataBit;
}
void DeviceRS232::setStopBits(int stopBit)
{
stopBits = stopBit;
}
void DeviceRS232::setNumberOfParityBits(int nparityBits)
{
numberOfParityBits = nparityBits;
}
void DeviceRS232::setDefaultAttributes()
{
std::string sp = "/dev/ttyS0";
long baud = 9600;
int dataBit = 1;
int stopBit = 1;
int nparityBits = 0;
setSerialPort(sp);
setBaudRate(baud);
setDataBits(dataBit);
setStopBits(stopBit);
setNumberOfParityBits(nparityBits);
}
long DeviceRS232::getBaudRate()
{
return baudRate;
}
std::string DeviceRS232::getSerialPort()
{
return serialPort;
}
int DeviceRS232::openSerialPort()
{
int fd, baudr, status, portStatus;
setDefaultAttributes();
switch(getBaudRate())
{
case 50 : baudr = B50;
break;
case 75 : baudr = B75;
break;
case 110 : baudr = B110;
break;
case 134 : baudr = B134;
break;
case 150 : baudr = B150;
break;
case 200 : baudr = B200;
break;
case 300 : baudr = B300;
break;
case 600 : baudr = B600;
break;
case 1200 : baudr = B1200;
break;
case 1800 : baudr = B1800;
break;
case 2400 : baudr = B2400;
break;
case 4800 : baudr = B4800;
break;
case 9600 : baudr = B9600;
break;
case 19200 : baudr = B19200;
break;
case 38400 : baudr = B38400;
break;
case 57600 : baudr = B57600;
break;
case 115200 : baudr = B115200;
break;
case 230400 : baudr = B230400;
break;
case 460800 : baudr = B460800;
break;
case 500000 : baudr = B500000;
break;
case 576000 : baudr = B576000;
break;
case 921600 : baudr = B921600;
break;
case 1000000 : baudr = B1000000;
break;
default : printf("invalid baudrate\n");
return(1);
break;
}
// Open serial port
fd = open(getSerialPort().c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1)
{
printf("Unable to open serial port...\n");
perror(getSerialPort().c_str());
return 1;
}
fdRS232 = fd;
fcntl(fdRS232, F_SETFL, FNDELAY);
status = tcgetattr(fdRS232, &oldSerialPortSetting);
if(status == -1)
{
close(fdRS232);
printf("Unable to get serial port attributes...\n");
return 1;
}
memset(&newSerialPortSetting, 0, sizeof(newSerialPortSetting));
newSerialPortSetting.c_cflag = baudr | CS8 | CLOCAL | CREAD; //
newSerialPortSetting.c_iflag = IGNPAR;
newSerialPortSetting.c_oflag = 0;
newSerialPortSetting.c_lflag = 0;
newSerialPortSetting.c_cc[VMIN] = 0;
newSerialPortSetting.c_cc[VTIME] = 0;
status = tcsetattr(fdRS232, TCSANOW, &newSerialPortSetting);
if(status==-1)
{
close(fdRS232);
perror("unable to adjust portsettings ");
return 1;
}
// Get the status of opened serial port
if(ioctl(fdRS232, TIOCMGET, &portStatus) == -1)
{
perror("Unable to get port status");
return 1;
}
// Tern on DTR and RTS
portStatus |= TIOCM_DTR;
portStatus |= TIOCM_RTS;
// Set the status of the port with new DTR, RTS values
if(ioctl(fdRS232, TIOCMSET, &portStatus) == -1)
{
perror("Unable to set port status...");
return 1;
}
return 0;
}
int DeviceRS232::sendDataBuffer(const unsigned char *dataBuffer, size_t bufferSize)
{
return write(fdRS232, dataBuffer, bufferSize);
}
int DeviceRS232::receiveDataBuffer(unsigned char *dataBuffer, size_t bufferSize)
{
/**int recvSize = 0;
recvSize = read(fdRS232, dataBuffer, bufferSize);
return recvSize;*/
unsigned char recvBuffer[255];
unsigned char *ptrChar;
int nBytes;
ptrChar = recvBuffer;
memset(recvBuffer, 0x00, sizeof(recvBuffer));
while((nBytes = read(fdRS232, ptrChar, recvBuffer+sizeof(recvBuffer) - ptrChar -1)) > 0)
{
ptrChar += nBytes;
//printf("while - %d\n", nBytes);
}
//printf("recvBuffer : %x\n", recvBuffer[0]);
//printf("recvBuffer : %x\n", recvBuffer[1]);
//printf("recvBuffer : %x\n", recvBuffer[2]);
//printf("recvBuffer : %x\n", recvBuffer[3]);
//printf("recvBuffer : %x\n", recvBuffer[4]);
dataBuffer = recvBuffer;
return nBytes;
}
void DeviceRS232::closeSerialPort()
{
int portStatus;
if(ioctl(fdRS232, TIOCMGET, &portStatus) == -1)
{
perror("Unable to get the port status");
}
// Tern off DTR and RTS
portStatus &= ~TIOCM_DTR;
portStatus &= ~TIOCM_RTS;
// Set the status of the port with new DTR, RTS values
if(ioctl(fdRS232, TIOCMSET, &portStatus) == -1)
{
perror("Unable to set port status...");
}
close(fdRS232);
}
my bad method is int DeviceRS232::receiveDataBuffer(unsigned char *dataBuffer, size_t bufferSize)
Below is the console output:
*********************************************************
---Start sending beep---
Data sent: 7
Date Received, Data: Size: 0
---End sending beep-----
*********************************************************
Process returned 0 (0x0) execution time : 2.004 s
Press ENTER to continue.

As others have noted, one suspect area is the number of bytes you're sending. Instead of always sending 257 bytes, the barcode reader is probably expecting just the number of bytes in the command and no more.
Also, your code has a number of repeated operations for calculating the checksum at the end of the message. That suggests a class would help streamline the design. Here, then, is a Message class for that purpose:
#include <vector>
#include <numeric>
#include <string>
class Message
{
public:
Message(const std::basic_string<unsigned char> msg) : mymsg(msg) {
mymsg[0] = mymsg.length(); appendChecksum(); };
Message(const unsigned char *msg, int msglen) : mymsg(msg, msglen) {
mymsg[0] = mymsg.length(); appendChecksum(); };
const unsigned char *getData() const { return mymsg.c_str(); }
size_t getLen() const { return mymsg.length(); }
private:
int appendChecksum();
std::basic_string<unsigned char> mymsg;
};
int Message::appendChecksum()
{
int sum = -std::accumulate(mymsg.begin(), mymsg.end(), 0);
mymsg.push_back(0xff & (sum >> 8));
mymsg.push_back(0xff & sum);
return sum;
}
Now within your main routine, you can eliminate several dozen lines of code and use these instead (if you're using C++11):
Message setparams{{0x00, 0xc6, 0x04, 0x08, 0x11, 0xee, 0x01}};
Message beep{{0x00, 0xe6, 0x04, 0x00, 0x05}};
Message getrevision{{0x00, 0xA3, 0x04, 0x00}};
Message ledOn{{0x00, 0xe7, 0x04, 0x00, 0x0d, 0x00}};
If you're not using C++11 (which would be a shame!) you can use this slightly less clean style instead:
unsigned char parms[] = {0x00, 0xc6, 0x04, 0x08, 0x11, 0xee, 0x01};
Message setparams(parms,sizeof(parms)/sizeof(parms[0]));
Note that the first byte is set to zero instead of the length. This is done because the constructor automatically calculates and sets the proper length in that byte just before it calculates and appends the checksum. There are other ways to do this, of course, but I'll leave that to you.
Finally, with your loop, you can now use this line:
int sizeSent = dev_rs232.sendDataBuffer(beep.getData(), beep.getLen());
That may or may not actually solve the problem, but it will assist you to have a cleaner program to start with.
Also, a few pieces of style and design advice:
get out of the habit of using namespace std
use iostream instead of printf
instead of having to call setDefaultAttributes() immediately after creating the device, have the constructor set up sane defaults
eliminate "magic numbers" such as 4096 for the receive buffer size. Instead, use named static const. It will make the program more understandable and maintainable.
consider using an existing library such as boost::asio instead of rolling your own
Good luck!
Edit: Based on your keen (and correct!) observation that the Message constructor doesn't work properly when fed a plain unsigned char *, I've added a second constructor and modified the non C++11 version of the code. Sorry for any inconvenience, and thanks for keeping me honest.

/**
* Receive responses from the decoder
*/
int DeviceRS232::receiveDecodedData(unsigned char *dataBuffer, size_t bufferSize)
{
unsigned char recvBuffer[251];
unsigned char *ptrChar;
int nBytes, portStatus;
int inputBufSize = 0;
ChangeCTS(fdRS232, 0);
ChangeRTS(fdRS232, 0);
while(inputBufSize <= 0)
{
ioctl(fdRS232, FIONREAD, &inputBufSize);
usleep(1);
}
if(inputBufSize > 0)
{
int decodePacketLen = 0;
//unsigned char
memset(recvBuffer, 0x00, sizeof(recvBuffer));
nBytes = 0;
//usleep(100000);
while(nBytes < ((int)recvBuffer[0] + 2))
{
int index = 0;
int recvDataLen = 0;
if(nBytes != 0)
index = nBytes - 1;
recvDataLen = read(fdRS232, &recvBuffer[index], 251);
if(recvDataLen < 0)
{
std::cout << "[INFO#DeviceRS232::receiveDecodedData]File read error: " << strerror(errno) << std::endl;
//sleep(1);
}
nBytes += recvDataLen;
if(nBytes == ((int)recvBuffer[0] + 2))
break;
}
if(recvBuffer[1] == DECODE_DATA)
sendCommandToDecoder(OPCODE_ACK);
std::cout << "[INFO # DeviceRS232::receiveDecodedData]Data Lenght (without CheckSum) : " << (int)recvBuffer[0] << std::endl;
for(int i=0; i<nBytes; i++)
{
std::cout << "recvBuffer[" << i << "]: ";
printf("%x\n", recvBuffer[i]);
}
std::cout << "-----------------------------------" << std::endl;
ChangeRTS(fdRS232, 1);
ChangeCTS(fdRS232, 1);
//sleep(1);
}
//strcpy((char *)dataBuffer, (char *)recvBuffer);
memcpy((char *)dataBuffer, recvBuffer, sizeof(recvBuffer)/sizeof(recvBuffer[0]));
inputBufSize = 0;
return nBytes;
}
/**
* Send commands to the decoder.
*/
int DeviceRS232::sendCommandToDecoder(unsigned int opCode)
{
unsigned char *commandBuffer;
int commandLength;
switch(opCode)
{
case OPCODE_ACK:
{
unsigned char ackString[] = {0x00, 0xD0, 0x04, 0x00};
commandLength = sizeof(ackString);
commandBuffer = ackString;
}
break;
case OPCODE_PARAM_SEND:
{
unsigned char paramSendString[] = {0x00, 0xC6, 0x04, 0x08, 0x00, 0xEE, 0x01};
commandLength = sizeof(paramSendString);
commandBuffer = paramSendString;
}
break;
default:
break;
}
Message msgCommand(commandBuffer, commandLength);
return sendDataBuffer(msgCommand.getCommandData(), msgCommand.getLen());
}
Required constants defined in DeviceRS232.h header file.

Related

I'm trying to get readings from the LIS3DH accelerometer and I'm getting random numbers

I have the LIS3DH accelerometer connected with i2c and when I run the script, which is supposed to print out the x, y, z values I am getting random numbers.
I'm in C++ using the i2c and smbus libraries, which are part of the Linux Kernel.
This is the (datasheet)[https://cdn-shop.adafruit.com/datasheets/LIS3DH.pdf] for the accelerometer.
I have tried changing the addresses of registers.
I tried __s16 instead of __s32.
I'm not sure if I'm missing something that should happen before readings are taken. I don't know if other registers need to be written to. I'm a little in the dark about what exactly is going on in the function in the bottom with the bits and values returned from the registers. I would like to learn.
extern "C" {
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
}
#include <sys/ioctl.h>
#include <fcntl.h> /* For O_RDWR */
#include <unistd.h>
#include <iostream>
using namespace std;
int file;
int adapter_nr = 1;
const char* filename = "/dev/i2c-8";
int initialize_mpu(int file);
__s32 high;
__s32 low;
__s32 value;
int read_raw_data(int file, __u8 addr);
int main() {
file = open(filename, O_RDWR);
if (file < 0) {
exit(1);
}
int addr = 0x18;
if (ioctl(file, I2C_SLAVE, addr) < 0) {
exit(1);
}
__u8 res;
__s32 accel_x;
__s32 accel_y;
__s32 accel_z;
__s32 accel_x_register_high = 0x29;
__s32 accel_y_register_high = 0x2B;
__s32 accel_z_register_high = 0x2D;
char buf[10];
res = i2c_smbus_write_byte_data(file, addr, 0);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* res contains the read word */
}
buf[1] = 0x02;
buf[2] = 0x03;
if (write(file, buf, 3) != 3) {
/* ERROR HANDLING: i2c transaction failed */
}
initialize_mpu(file);
while (1) {
accel_x = read_raw_data(file, accel_x_register_high) / 131.0;
accel_y = read_raw_data(file, accel_y_register_high) / 131.0;
accel_z = read_raw_data(file, accel_z_register_high) / 131.0;
cout << accel_x <<" " << accel_y << " " << accel_z << " " << endl;
usleep(100000);
}
}
int initialize_mpu(int file) {
i2c_smbus_write_byte_data(file, 0x20, 0xA7); //Write A7h into CTRL_REG1; // Turn on the sensor, enable X, Y, Z axes with ODR = 100Hz normal mode.
i2c_smbus_write_byte_data(file, 0x21, 0x09); //Write 09h into CTRL_REG2; // High-pass filter (HPF) enabled
i2c_smbus_write_byte_data(file, 0x22, 0x40); //Write 40h into CTRL_REG3; // ACC AOI1 interrupt signal is routed to INT1 pin.
i2c_smbus_write_byte_data(file, 0x23, 0x00); //Write 00h into CTRL_REG4; // Full Scale = +/-2 g
i2c_smbus_write_byte_data(file, 0x24, 0x08); //Write 08h into CTRL_REG5; // Default value is 00 for no latching. Interrupt signals on INT1 pin is not latched.
// configurations for wakeup and motionless detection
i2c_smbus_write_byte_data(file, 0x32, 0x10); //Write 10h into INT1_THS; // Threshold (THS) = 16LSBs * 15.625mg/LSB = 250mg.
i2c_smbus_write_byte_data(file, 0x33, 0x00); //Write 00h into INT1_DURATION; // Duration = 1LSBs * (1/10Hz) = 0.1s.
//readRegister(); //Dummy read to force the HP filter to set reference acceleration/tilt value
i2c_smbus_write_byte_data(file, 0x30, 0x2A); //Write 2Ah into INT1_CFG; // Enable XLIE, YLIE, ZLIE interrupt generation, OR logic.
}
// Read the data of two 8-bit registers and compile into one 16-bit value
// register_address is the first (high) register, register_address-1 is the low register
// E.g., if the two registers contain the 8-bit values 0x01 and 0x02, this
// function returns the value 0x0102
int read_raw_data(int file, __u8 register_address) {
high = i2c_smbus_read_byte_data(file, register_address);
low = i2c_smbus_read_byte_data(file, register_address-1);
value = (high << 8 | low);
// This converts it from an unsigned 0-63355 value
// to a signed value between -32769 and 32768
if (value > 32768)
value = value - 65536;
return value;
}
I was using initialize_mpu with the wrong register addresses.
There are a few configuration options buried somewhere in this datasheet. I applied one and now I get muh readings.
extern "C" {
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
}
#include <sys/ioctl.h>
#include <fcntl.h> /* For O_RDWR */
#include <unistd.h>
#include <iostream>
using namespace std;
int file;
int adapter_nr = 1;
const char* filename = "/dev/i2c-8";
int initialize_mpu(int file);
__s32 high;
__s32 low;
__s32 value;
int read_raw_data(int file, __u8 addr);
int main() {
file = open(filename, O_RDWR);
if (file < 0) {
exit(1);
}
int addr = 0x18;
if (ioctl(file, I2C_SLAVE, addr) < 0) {
exit(1);
}
__u8 res;
// __s32 whoami;
__s32 accel_x2;
__s32 accel_x;
__s32 accel_y;
__s32 accel_z;
__s32 accel_x_register_high = 0x29;
__s32 accel_y_register_high = 0x2B;
__s32 accel_z_register_high = 0x2D;
res = i2c_smbus_write_byte_data(file, addr, 0);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* res contains the read word */
}
initialize_mpu(file);
while (1) {
accel_x = read_raw_data(file, accel_x_register_high) / 133.0;
accel_y = read_raw_data(file, accel_y_register_high) / 133.0;
accel_z = read_raw_data(file, accel_z_register_high) / 133.0;
cout << accel_x <<" " << accel_y << " " << accel_z << " " << endl;
usleep(150000);
}
}
int initialize_mpu(int file) {
i2c_smbus_write_byte_data(file, 0x20, 0x57);
i2c_smbus_write_byte_data(file, 0x21, 0x00);
i2c_smbus_write_byte_data(file, 0x22, 0x40);
i2c_smbus_write_byte_data(file, 0x23, 0x00);
i2c_smbus_write_byte_data(file, 0x24, 0x08);
i2c_smbus_write_byte_data(file, 0x32, 0x10);
i2c_smbus_write_byte_data(file, 0x33, 0x00);
i2c_smbus_write_byte_data(file, 0x30, 0x0A);
}
// Read the data of two 8-bit registers and compile into one 16-bit value
// register_address is the first (high) register, register_address-1 is the low register
// E.g., if the two registers contain the 8-bit values 0x01 and 0x02, this
// function returns the value 0x0102
int read_raw_data(int file, __u8 register_address) {
high = i2c_smbus_read_byte_data(file, register_address);
low = i2c_smbus_read_byte_data(file, register_address-1);
value = (high << 8 | low);
// This converts it from an unsigned 0-63355 value
// to a signed value between -32769 and 32768
if (value > 32768)
value = value - 65536);
return value;
}

Windows API to Arduino Serial write works once but sends corrupted data when the same message is rewritten

I am using a third party WinAPI-based Serial library (SerialPort) in a C++ program to command a LED strip (iLED and pixel color), but it turns out it only seems to work for one command - if I send the same command a second time, the color of that pixel takes another random colour and for some reason the first LED turns on too with a random colour.
Here is a link to a video of what happens when the simplified code below is run, i.e. when pixel 3, 5 and 7 are commanded over and over to be red, green, and blue respectively.
https://drive.google.com/file/d/1RRAshnhPz96YGJtmETy3vuGi25QjxqJz/view?usp=drivesdk
I suspected the Serial.read() weren't synchronised so I added a start byte but it didn't seem to work either, that's what the code below does.
What is happening ?
SerialPort.h (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#ifndef SERIALPORT_H
#define SERIALPORT_H
#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class SerialPort
{
private:
HANDLE handler;
bool connected;
COMSTAT status;
DWORD errors;
public:
SerialPort(char const *portName, unsigned long baudrate);
~SerialPort();
int readSerialPort(char *buffer, unsigned int buf_size);
bool writeSerialPort(char *buffer, unsigned int buf_size);
bool isConnected();
};
#endif // SERIALPORT_H
SerialPort.cpp (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#include "serialport.h"
SerialPort::SerialPort(char const *portName, unsigned long baudrate)
{
this->connected = false;
this->handler = CreateFileA(static_cast<LPCSTR>(portName),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (this->handler == INVALID_HANDLE_VALUE){
if (GetLastError() == ERROR_FILE_NOT_FOUND){
printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else {
DCB dcbSerialParameters = {0};
if (!GetCommState(this->handler, &dcbSerialParameters)) {
printf("failed to get current serial parameters");
}
else {
dcbSerialParameters.BaudRate = baudrate;
dcbSerialParameters.ByteSize = 8;
dcbSerialParameters.StopBits = ONESTOPBIT;
dcbSerialParameters.Parity = NOPARITY;
dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(handler, &dcbSerialParameters))
{
printf("ALERT: could not set Serial port parameters\n");
}
else {
this->connected = true;
PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
SerialPort::~SerialPort()
{
if (this->connected){
this->connected = false;
CloseHandle(this->handler);
}
}
int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesRead;
unsigned int toRead;
ClearCommError(this->handler, &this->errors, &this->status);
if (this->status.cbInQue > 0){
if (this->status.cbInQue > buf_size){
toRead = buf_size;
}
else toRead = this->status.cbInQue;
}
if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;
return 0;
}
bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesSend;
if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
ClearCommError(this->handler, &this->errors, &this->status);
return false;
}
else return true;
}
bool SerialPort::isConnected()
{
return this->connected;
}
main.cpp
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM3", 115200);
while(1) {
unsigned char buffer[] = {255,3, 254, 0, 0};
serial.writeSerialPort((char*)buffer, 4);
unsigned char buffer2[] = {255,5, 0, 254, 0};
serial.writeSerialPort((char*)buffer2, 4);
unsigned char buffer3[] = {255,7, 0, 0, 254};
serial.writeSerialPort((char*)buffer3, 4);
}
return 0;
}
Arduino firmware
#include <FastLED.h>
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
CRGB leds[N_LEDS] = {0};
void setup() {
FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, N_LEDS); //I don't know why the colours are BRG on this strip
FastLED.show();
Serial.begin(BAUDRATE);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
if(buf[0] < N_LEDS) { //Valid ID
leds[buf[0]] = CRGB(buf[1],buf[2],buf[3]); //Update LED state in internal representation
FastLED.show(); //Refresh LEDs based on internal representation
}
}
}
Note that the LED strip seems to work properly on its own, since I successfully tested moving at constant speed a single pixel.
The LED strip itself is the easiest debug route I have since I didn't manage to make readSerialPort() work yet and the COM port is hogged by the program so I can't get a handle on it (can we sniff that somehow?).
I test serial.writeSerialPort on Windows 10 desktop with Arduino Uno. It works for me.
The following is the code I used:
On windows:
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM4", 115200);
while (1) {
unsigned char buffer[] = { 255,3, 254, 0, 0 };
serial.writeSerialPort((char*)buffer, 5);
unsigned char buffer2[] = { 255,5, 0, 254, 0 };
serial.writeSerialPort((char*)buffer2, 5);
unsigned char buffer3[] = { 255,7, 0, 0, 254 };
serial.writeSerialPort((char*)buffer3, 5);
}
return 0;
}
On Arduino:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
void setup() {
Serial.begin(BAUDRATE);
mySerial.begin(BAUDRATE);
mySerial.println("Start reading.");
delay(5000);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
mySerial.print(buf[i]);
mySerial.print(",");
}
mySerial.print("\r\n");
//Serial.write("Read complete!");
}
}
I print the received data on Arduino:
I notice that the printed data messed up when the Windows sends fast as you did in the while(1) without delay. So try adding a delay between two writes to see if it works.
Add also note the problem as #paddy pointed out.
I didn't manage to make readSerialPort() work yet
Set unsigned int toRead = buf_size; in SerialPort.cpp works for me. Use the following code to read:
unsigned char readBuffer[20] = {};
serial.readSerialPort((char*)readBuffer, 20);
printf((char*)readBuffer);
printf("\n");
Read from Arduino result:

How to manage concurrence reading from a file descripter using multiple boost::thread objests. (boost threads management)

I am writing an application for a bar-code reader and I have several methods to execute synchronously. As an initial point I am going to read data from the device concurrently. Below is my scenario.
Environment
OS: CENTOS 6.3 (LINUX)
Boost: 1.41
Always waiting for decoded data (bar-code scanned data) from device
Send Acknowledgement for received decoded data
Meanwhile send requests to device
and get response or acknowledgement from the device
for data reading purpose I have 2 methods and I have 1 method to send commands to the decoder. I am trying with boost::thread examples from internet and still I couldn't get a good idea to handle the scenario. Below is a sample codes from my application. Please advise me for thread management in situations like this.
I am using OOP approach below are the methods from DeviceRS232.cpp class
// Open and set attributes for serial port
int DeviceRS232::openSerialPort()
{
int fd, baudr, status, portStatus;
setDefaultAttributes();
switch(getBaudRate())
{
case 50 : baudr = B50;
break;
case 75 : baudr = B75;
break;
case 110 : baudr = B110;
break;
case 134 : baudr = B134;
break;
case 150 : baudr = B150;
break;
case 200 : baudr = B200;
break;
case 300 : baudr = B300;
break;
case 600 : baudr = B600;
break;
case 1200 : baudr = B1200;
break;
case 1800 : baudr = B1800;
break;
case 2400 : baudr = B2400;
break;
case 4800 : baudr = B4800;
break;
case 9600 : baudr = B9600;
break;
case 19200 : baudr = B19200;
break;
case 38400 : baudr = B38400;
break;
case 57600 : baudr = B57600;
break;
case 115200 : baudr = B115200;
break;
case 230400 : baudr = B230400;
break;
case 460800 : baudr = B460800;
break;
case 500000 : baudr = B500000;
break;
case 576000 : baudr = B576000;
break;
case 921600 : baudr = B921600;
break;
case 1000000 : baudr = B1000000;
break;
default : printf("invalid baudrate\n");
return(1);
break;
}
// Open serial port
fd = open(getSerialPort().c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1)
{
printf("Unable to open serial port...\n");
perror(getSerialPort().c_str());
return 1;
}
fdRS232 = fd;
fcntl(fdRS232, F_SETFL, FNDELAY);
status = tcgetattr(fdRS232, &oldSerialPortSetting);
if(status == -1)
{
close(fdRS232);
printf("Unable to get serial port attributes...\n");
return 1;
}
memset(&newSerialPortSetting, 0, sizeof(newSerialPortSetting));
newSerialPortSetting.c_cflag = baudr | CS8 | CLOCAL | CREAD | CRTSCTS; // | CRTSCTS
newSerialPortSetting.c_iflag = IGNPAR;
newSerialPortSetting.c_oflag = 0;
newSerialPortSetting.c_lflag = 0;
newSerialPortSetting.c_cc[VMIN] = 0;
newSerialPortSetting.c_cc[VTIME] = 0;
ChangeCTS(fdRS232, 0);
ChangeRTS(fdRS232, 0);
return 0;
}
// send data to the decoder
int DeviceRS232::sendDataBuffer(const unsigned char *dataBuffer, size_t bufferSize)
{
int sentSize;
ChangeRTS(fdRS232, 1);
ChangeCTS(fdRS232, 1);
while(true)
{
sentSize = write(fdRS232, dataBuffer, bufferSize);
if(sentSize > 0)
break;
}
hasCommandSent = true;
sleep(1);
return sentSize;
}
// Receive response from the decoder
int DeviceRS232::receiveDataBuffer(unsigned char *dataBuffer, size_t bufferSize)
{
unsigned char recvBuffer[251];
unsigned char *ptrChar;
int nBytes, portStatus;
int inputBufSize = 0;
ChangeCTS(fdRS232, 0);
ChangeRTS(fdRS232, 0);
while(inputBufSize <= 0)
{
ioctl(fdRS232, FIONREAD, &inputBufSize);
usleep(1);
}
//TEST PURPOSES
//sleep(1);
if(inputBufSize > 0)
{
memset(recvBuffer, 0x00, sizeof(recvBuffer));
nBytes = read(fdRS232, recvBuffer, 251);
if(nBytes < 0)
{
printf("Unable to receive data...\n");
perror("/dev/ttyS0");
}
std::cout << "RECV Length: " << nBytes << std::endl;
for(int i=0; i<nBytes; i++)
{
std::cout << "recvBuffer[" << (int)i << "]: ";
printf("%x\n", recvBuffer[i]);
}
std::cout << "-----------------------------------" << std::endl;
//ChangeRTS(fdRS232, 1);
//sleep(1);
}
strcpy((char *)dataBuffer, (char *)recvBuffer);
inputBufSize = 0;
return nBytes;
}
// Receive decoded data from decoder.
int DeviceRS232::receiveDecodedData(unsigned char *dataBuffer, size_t bufferSize)
{
unsigned char recvBuffer[251];
unsigned char *ptrChar;
int nBytes, portStatus;
int inputBufSize = 0;
ChangeCTS(fdRS232, 0);
ChangeRTS(fdRS232, 0);
while(inputBufSize <= 0)
{
ioctl(fdRS232, FIONREAD, &inputBufSize);
usleep(1);
}
// TEST PURPOSES
//sleep(1);
if(inputBufSize > 0)
{
int decodePacketLen;
//unsigned char
memset(recvBuffer, 0x00, sizeof(recvBuffer));
nBytes = 0;
while(nBytes < ((int)recvBuffer[0] + 2))
{
int index = 0;
if(nBytes != 0)
index = nBytes - 1;
nBytes += read(fdRS232, &recvBuffer[index], 251);
if(nBytes == ((int)recvBuffer[0] + 2))
break;
}
std::cout << "RECV Length: " << (int)recvBuffer[0] << std::endl;
for(int i=0; i<nBytes; i++)
{
std::cout << "recvBuffer[" << (int)i << "]: ";
printf("%x\n", recvBuffer[i]);
}
std::cout << "-----------------------------------" << std::endl;
//ChangeRTS(fdRS232, 1);
//ChangeCTS(fdRS232, 1);
//sleep(1);
}
//strcpy((char *)dataBuffer, (char *)recvBuffer);
memcpy((char *)dataBuffer, recvBuffer, sizeof(recvBuffer)/sizeof(recvBuffer[0]));
inputBufSize = 0;
return nBytes;
}
// Method I am going to use for concurrent reading
void DeviceRS232::startReadTread()
{
boost::thread *dataReader1, *dataReader2;
dataReader1 = new boost::thread(boost::bind(&DeviceRS232::decodedDataReadThread, this));
dataReader2 = new boost::thread(boost::bind(&DeviceRS232::commandResponseReadThread, this));
dataReader2->join();
}
// Finally I am hoping to create and call to thread handling method from main method.
int main()
{
DeviceRS232 dev_rs232;
dev_rs232.setDefaultAttributes();
dev_rs232.openSerialPort();
dev_rs232.startReadTread();
return 0;
}
I can upload the complete program for further reference.
You can more easily achieve what John Zwinck mentions by using Boost Asio's serial communications options.
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/overview/serial_ports.html
This has the magic benefit of making your code portable
Serial ports are available on all POSIX platforms. For Windows, serial ports are only available at compile time when the I/O completion port backend is used (which is the default). A program may test for the macro BOOST_ASIO_HAS_SERIAL_PORT to determine whether they are supported.
Rather than spin-waiting in a separate thread to read data, you should use an event-based solution like select(), epoll(), WaitForMultipleEvents, etc. That way you can avoid wasting a CPU core for reading, and avoid mutexes, and get woken up exactly when data is available to read.

Send data to a barcode scanner over RS232 serial port

I have a bar-code scanner which is connecting through RS232 serial port. I need to write a program to connect this device with the PC and transmit data. I already wrote some basic methods to initialize a communication link and tried to test by sending a BEEP command to the device but it is not beeping as expected. So I think there is something wrong with my source code. Please somebody help me complete the source code. Below is the written source code
01)DeviceRS232.h
#ifndef DEVICERS232_H
#define DEVICERS232_H
extern "C"
{
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
}
#include <string>
#define MAX_SERIAL_PORT_NO 30
class DeviceRS232
{
public:
DeviceRS232();
virtual ~DeviceRS232();
int fdRS232; // file descriptor for the serial port
void setSerialPort(std::string sp);
void setBaudRate(long baud);
void setDataBits(int dataBit);
void setStopBits(int stopBit);
void setNumberOfParityBits(int nparityBits);
void setDefaultAttributes();
long getBaudRate();
std::string getSerialPort();
int openSerialPort();
int readUserConfiguration();
int sendDataBuffer(const unsigned char *dataBuffer, size_t bufferSize);
void closeSerialPort();
protected:
std::string serialPort; // Serial port like /dev/ttyS0
long baudRate; // Scanner baud rate
int dataBits; // data bits
int stopBits; // stop bits
int numberOfParityBits; // number of parity bits
termios oldSerialPortSetting; // Current values of termios structure for /dev/ttyS0
termios newSerialPortSetting; // new termios attributes for /dev/ttyS0
private:
};
#endif // DEVICERS232_H
2) DeviceRS232.cpp
#include "DeviceRS232.h"
DeviceRS232::DeviceRS232()
{
//ctor
}
DeviceRS232::~DeviceRS232()
{
//dtor
}
void DeviceRS232::setSerialPort(std::string sp)
{
serialPort = sp;
}
void DeviceRS232::setBaudRate(long baud)
{
baudRate = baud;
}
void DeviceRS232::setDataBits(int dataBit)
{
dataBits = dataBit;
}
void DeviceRS232::setStopBits(int stopBit)
{
stopBits = stopBit;
}
void DeviceRS232::setNumberOfParityBits(int nparityBits)
{
numberOfParityBits = nparityBits;
}
void DeviceRS232::setDefaultAttributes()
{
std::string sp = "/dev/ttyS0";
long baud = 9600;
int dataBit = 1;
int stopBit = 1;
int nparityBits = 0;
setSerialPort(sp);
setBaudRate(baud);
setDataBits(dataBit);
setStopBits(stopBit);
setNumberOfParityBits(nparityBits);
}
long DeviceRS232::getBaudRate()
{
return baudRate;
}
std::string DeviceRS232::getSerialPort()
{
return serialPort;
}
int DeviceRS232::openSerialPort()
{
int fd, baudr, status, portStatus;
setDefaultAttributes();
switch(getBaudRate())
{
case 50 : baudr = B50;
break;
case 75 : baudr = B75;
break;
case 110 : baudr = B110;
break;
case 134 : baudr = B134;
break;
case 150 : baudr = B150;
break;
case 200 : baudr = B200;
break;
case 300 : baudr = B300;
break;
case 600 : baudr = B600;
break;
case 1200 : baudr = B1200;
break;
case 1800 : baudr = B1800;
break;
case 2400 : baudr = B2400;
break;
case 4800 : baudr = B4800;
break;
case 9600 : baudr = B9600;
break;
case 19200 : baudr = B19200;
break;
case 38400 : baudr = B38400;
break;
case 57600 : baudr = B57600;
break;
case 115200 : baudr = B115200;
break;
case 230400 : baudr = B230400;
break;
case 460800 : baudr = B460800;
break;
case 500000 : baudr = B500000;
break;
case 576000 : baudr = B576000;
break;
case 921600 : baudr = B921600;
break;
case 1000000 : baudr = B1000000;
break;
default : printf("invalid baudrate\n");
return(1);
break;
}
// Open serial port
fd = open(getSerialPort().c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1)
{
printf("Unable to open serial port...\n");
return 1;
}
fdRS232 = fd;
status = tcgetattr(fdRS232, &oldSerialPortSetting);
if(status == -1)
{
close(fdRS232);
printf("Unable to get serial port attributes...\n");
return 1;
}
memset(&newSerialPortSetting, 0, sizeof(newSerialPortSetting));
newSerialPortSetting.c_cflag = baudr | CS8 | CLOCAL | CREAD; //
newSerialPortSetting.c_iflag = IGNPAR;
newSerialPortSetting.c_oflag = 0;
newSerialPortSetting.c_lflag = 0;
newSerialPortSetting.c_cc[VMIN] = 0;
newSerialPortSetting.c_cc[VTIME] = 0;
status = tcsetattr(fdRS232, TCSANOW, &newSerialPortSetting);
if(status==-1)
{
close(fdRS232);
perror("unable to adjust portsettings ");
return 1;
}
// Get the status of opened serial port
if(ioctl(fdRS232, TIOCMGET, &portStatus) == -1)
{
perror("Unable to get port status");
return 1;
}
// Tern on DTR and RTS
portStatus |= TIOCM_DTR;
portStatus |= TIOCM_RTS;
// Set the status of the port with new DTR, RTS values
if(ioctl(fdRS232, TIOCMSET, &portStatus) == -1)
{
perror("Unable to set port status...");
return 1;
}
return 0;
}
int DeviceRS232::sendDataBuffer(const unsigned char *dataBuffer, size_t bufferSize)
{
return write(fdRS232, dataBuffer, bufferSize);
}
void DeviceRS232::closeSerialPort()
{
int portStatus;
if(ioctl(fdRS232, TIOCMGET, &portStatus) == -1)
{
perror("Unable to get the port status");
}
// Tern off DTR and RTS
portStatus &= ~TIOCM_DTR;
portStatus &= ~TIOCM_RTS;
// Set the status of the port with new DTR, RTS values
if(ioctl(fdRS232, TIOCMSET, &portStatus) == -1)
{
perror("Unable to set port status...");
}
close(fdRS232);
}
3) main.cpp
#include <iostream>
extern "C"
{
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
}
#include "DeviceRS232.h"
using namespace std;
int main()
{
//char sendBuffer[4096] = " ";
unsigned char sendBeep[] = {0x05, 0xE6, 0x04, 0x00, 0x0D, 0x00, 0x00};
unsigned char ledOn[] = {0x05, 0xE7, 0x04, 0x00, 0x0D, 0x00};
unsigned char val[7];
cout << "********************** RS232 - SSI **********************" << endl << endl;
DeviceRS232 dev_rs232;
dev_rs232.setDefaultAttributes();
dev_rs232.openSerialPort();
//----------------------------------------------------
//for(int x=0; x<10; x++)
//{
// dev_rs232.sendDataBuffer(sendBeep, sizeof(sendBeep));
//}
//----------------------------------------------------
int sizeSent = dev_rs232.sendDataBuffer(sendBeep, sizeof(sendBeep));
if( sizeSent > 0)
{
printf("Data sent: %d...\n", sizeSent);
}
sleep(10);
dev_rs232.closeSerialPort();
cout << "*********************************************************" << endl;
return 0;
}
unsigned char sendBeep[] = {0x05, 0xE6, 0x04, 0x00, 0x0D, 0x00, 0x00}; is written considering the bar-device's serial port communication protocol specification.
(Edited to add the output)
Out put:
********************** RS232 - SSI **********************
Data sent: 7...
*********************************************************
Process returned 0 (0x0) execution time : 10.006 s
Press ENTER to continue.
All helps and suggestions are welcome. Thanks.
#include <iostream>
extern "C"
{
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
}
#include "DeviceRS232.h"
using namespace std;
int main()
{
unsigned char sendBuffer[4096] = "Test test test...";
unsigned char sendBeep[] = {0x05, 0xE6, 0x04, 0x00, 0x11, 0x46, 0x00};
unsigned char ledOn[] = {0x05, 0xE7, 0x04, 0x00, 0x0D, 0x00};
unsigned char val[7];
//-------------------------------------------------------------------------
unsigned char commonBuffer[257];
int iChecksum;
int i;
commonBuffer[ 1 ] = (unsigned char)0xC6;
commonBuffer[ 2 ] = (unsigned char)0x04;
commonBuffer[ 3 ] = (unsigned char)0x08; // Permanant Chnage
commonBuffer[ 4 ] = (unsigned char)0x11; // Beep after setting. FF for No Beep
commonBuffer[ 5 ] = (unsigned char)0xEE; // Decorder parameter to set (238)
commonBuffer[ 6 ] = (unsigned char)0x01; // Value to set
commonBuffer[ 0 ] = (unsigned char)0x07; // Length
iChecksum = 0;
for (i = 0; i < 7; i++)
{
iChecksum += commonBuffer[i];
}
commonBuffer[i++] = (char)(((-iChecksum) >> 8) & 0xFF); // Add Checksum into the command
commonBuffer[i++] = (char)((-iChecksum) & 0xFF);
//-------------------------------------------------------------------------
cout << "********************** RS232 - SSI **********************" << endl << endl;
DeviceRS232 dev_rs232;
dev_rs232.setDefaultAttributes();
dev_rs232.openSerialPort();
//----------------------------------------------------
//for(int x=0; x<10; x++)
//{
// dev_rs232.sendDataBuffer(sendBeep, sizeof(sendBeep));
//}
//----------------------------------------------------
int sizeSent = dev_rs232.sendDataBuffer(commonBuffer, sizeof(commonBuffer));
if( sizeSent > 0)
{
printf("Data sent: %d...\n", sizeSent);
}
sleep(1);
dev_rs232.closeSerialPort();
cout << "*********************************************************" << endl;
return 0;
}

linux writing string value as hex to serial

here's my problem
i have a string with hex value such as
std::string str ="8C000002008E"
and i want to write this as hex to serial out by using the
write()
I have a sony Display which i want to control with.
Passing a
unsigned char test[6] = {0x8c, 0x00, 0x00, 0x02, 0x00, 08E};
to the write method works.
But i dont know how to convert the string to such a char array especially that the size of the char array has to be calculated on runtime.
Thanks for your help.
Here is my full code
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <fcntl.h>
#include <termios.h>
#include <sstream>
using namespace std;
#define TERM_DEVICE "/dev/ttyUSB0"
#define TERM_SPEED "B9600"
int main() {
std::string teststr = "8C000002008E";
int fd, old_flags;
ssize_t length;
char buffer[16];
struct termios term_attr;
fd_set input_fdset;
if ((fd = open(TERM_DEVICE, O_RDWR)) == -1)
{
perror("terminal: Can't open device " TERM_DEVICE);
return(1);
}
/* RS232 konfigurieren */
if (tcgetattr(fd, &term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
return(1);
}
cfsetispeed(&term_attr, B9600);
cfsetospeed(&term_attr, B9600);
term_attr.c_cflag &= ~PARENB;
term_attr.c_cflag &= CS8;
term_attr.c_cflag &= CSIZE;
term_attr.c_cflag &= CSTOPB;
term_attr.c_iflag = 0;
term_attr.c_oflag = OPOST | ONLCR;
term_attr.c_lflag = 0;
if (tcsetattr(fd, TCSAFLUSH, &term_attr) != 0)
perror("terminal: tcsetattr() failed");
if (tcgetattr(STDIN_FILENO, &term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
return(1);
}
old_flags = term_attr.c_lflag;
term_attr.c_lflag &= ~(ICANON | ECHO);
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_attr) != 0)
perror("terminal: tcsetattr() failed");
while (1)
{
FD_ZERO(&input_fdset);
FD_SET(STDIN_FILENO, &input_fdset);
FD_SET(fd, &input_fdset);
if (select(fd+1, &input_fdset, NULL, NULL, NULL) == -1)
perror("terminal: select() failed");
unsigned char test[6] = {0x8c, 0x00, 0x00, 0x02, 0x00, 0x8E};
if (FD_ISSET(STDIN_FILENO, &input_fdset)){
if ((length = read(STDIN_FILENO, buffer, 16)) == -1)
perror("terminal: read() failed");
else
if (buffer[0] == '\33')
break;
else{
write(fd, test , sizeof(test));
}
}
if (FD_ISSET(fd, &input_fdset))
{
if ((length = read(fd, buffer, 16)) == -1)
perror("terminal: read() failed");
else
cout << std::hex << buffer<< endl;
}
}
term_attr.c_lflag = old_flags;
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_attr) != 0)
perror("terminal: tcsetattr() failed");
printf("Aborted.\n");
close(fd);
return 0;
}
If the problem is only one of converting the string to a char array, you can try the following:
#include <iostream>
#include <sstream>
int main(int argc, char **argv)
{
const std::string str ="8C000002008E";
// count the number of character pairs (i.e. bytes) in the string
// and dynamically allocate an array of the required size
const int numBytes = str.size() / 2;
unsigned char* bytes = new unsigned char[numBytes];
for (int i = 0; i < numBytes; ++i)
{
// grab two characters from the string...
std::string twoChars = str.substr(2 * i, 2);
// ...and convert them to an integer using a stringstream
int byte;
std::stringstream ss(twoChars);
ss >> std::hex >> byte;
// store the result in our char array
bytes[i] = byte;
}
//
// do something with the byte array here
//
// deallocate array before exiting
delete[] bytes;
}
Please note that this assumes that the initial string always contains an even number of characters. Some extra code would be needed for handling input strings of an odd size.
Probably fast solution I can't offer to you, but you may try this:
std::string str ="8C000002008E"
std::vector<unsigned char> vect;
vect.resize(str.length() / 2);
for (size_t i = 0; i < str.length(); ++i)
{
vect[i] = str[2*i] - ('0' - 7 * (str[2*i] >= '9')); //it is possible to optimize this
vect[i] <<= 4;
vect[i] = str[2*i+1] - ('0' - 7 * (str[2*i+1] >= '9')); //it is possible to optimize this
}
Didn't tried that, but should work, however, code is really not optimized, I have left this part for yourself.
Also this assumes that the initial string always contains an even number of characters.