2014-03-31 62 views
4

我有一个条形码阅读器,它通过RS232串行端口连接到PC。我正在编写一个C++代码来发送命令给条形码扫描器并将响应回复给PC。目前程序可以正确地向设备发送数据,但是无法从条码扫描器读取响应。在这种情况下,一旦我们向条形码读取器发送命令,它将以肯定或否定确认回应。通过RS232串行端口从条形码扫描器读取异步数据

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 

在下面的代码第一步2步正常工作,但我不能正确写第三个。请有人帮助我纠正我的源代码异步阅读条形码扫描器的响应。

的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); 
} 

我的坏方法是int DeviceRS232::receiveDataBuffer(unsigned char *dataBuffer, size_t bufferSize)

下面是控制台输出:

********************************************************* 

---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. 
+0

您正在向扫描仪发送垃圾邮件,哔哔声命令当然不是257字节长。很不清楚为什么你会期望返回任何东西,条形码扫描仪通常只有当你按下扫描仪上的扫描按钮才会发送一些东西。 –

+2

+1用于提交格式正确的代码。 –

+0

@HansPassant:其实这个条形码设备捆绑了一个协议来做串行通信。协议规范列出了所有命令(所有硬件相关命令,图像扫描命令等)。根据向设备发送命令后的协议规范,它应该使用确认消息进行回复。因此,在向设备发送BEEP命令之后的上述情况下,主机预计会收到肯定或否定确认。我仍处于协议实施的起始阶段。首先,我试图建立沟通的联系。 –

回答

2
/** 
* 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 << "[[email protected]::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()); 
} 

在DeviceRS232.h头文件中定义的常量。

2

正如其他人所指出的,一个可疑区域是你的字节数发送。条形码阅读器可能只需要等待命令中的字节数,而不会再发送257字节。

此外,您的代码有多个重复的操作来计算消息结尾的校验和。这表明一个班会帮助简化设计。那么,这里是一个Message类为该目的:

#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; 
} 

现在你main程序中,可以消除的代码几十行,并利用这些来代替(如果你使用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}}; 

如果你不使用C++ 11(!这将是一种耻辱),您可以使用此略少清新的风格,而不是:

unsigned char parms[] = {0x00, 0xc6, 0x04, 0x08, 0x11, 0xee, 0x01}; 
Message setparams(parms,sizeof(parms)/sizeof(parms[0])); 

注意第一个字节设置为零而不是长度。这是因为构造函数在计算并附加校验和之前自动计算并设置该字节中的适当长度。当然,还有其他方法可以做到这一点,但我会把它留给你。

最后,你的循环,你现在可以使用该行:

int sizeSent = dev_rs232.sendDataBuffer(beep.getData(), beep.getLen()); 

,可能会或可能不会实际解决问题,但它会帮助你有一个更清洁程序开始。

而且,款式和设计咨询了几件:

  1. 走出的using namespace std
  2. 使用iostream代替printf
  3. ,而不必调用setDefaultAttributes()习惯在创建设备后,立即,将构造函数设置为理想默认值
  4. 为接收缓冲区大小消除诸如4096的“幻数”。相反,使用名为static const。它会使程序更易于理解和维护。
  5. 考虑使用如boost::asio,而不是滚动您自己

好运的现有的库!

编辑:(!和正确的)根据您的敏锐的观察到输入纯unsigned char *Message构造函数不能正常工作,我已经添加了第二个构造和修改的非C++ 11版代码。对不便之处感到抱歉,并感谢我保持诚实。

+0

感谢您的宝贵意见我遵循您的建议和重构源代码但是我在为Message类创建对象时遇到了问题一旦创建Message对象,一旦发现NULL(0x00)字符所有下一个连续的元素都将变为null。我的环境不支持C11,并且遵循第二种方法来创建消息对象。例如:实际命令:{0x05,0xe6,0x04,0x00,0x05}创建的对象有{0x05,0xe6,0x04,0x00,0x00} –

+1

好抓!这是我的错误 - 我习惯于使用C++ 11。我会立即更新答案。 – Edward

+0

嗨爱德华:按照指示我修改了代码,但我原来的问题仍然存在。程序没有收到来自扫描仪的数据。你能帮我验证我在这里用来从扫描仪接收数据的方式吗? (无论是否正确) –

相关问题