2014-03-31 115 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

嗨愛德華:按照指示我修改了代碼,但我原來的問題仍然存在。程序沒有收到來自掃描儀的數據。你能幫我驗證我在這裏用來從掃描儀接收數據的方式嗎? (無論是否正確) –

相關問題