1——東西方向紅燈;
2——東西方向黃燈;
3——東西方向綠燈;
4—— 避開發送 0x0A的底層卻發送0x0D 0x0A問題
5——南北方向紅燈;
6——南北方向黃燈;
7——南北方向綠燈。
https://blog.csdn.net/qiaoliang328/article/details/6153998 0x0A的底層卻發送0x0D 0x0A問題
按上面博客鏈接修改了,但是並沒有起作用。所以我修改了接線,避開了 0x0A
1 接口頭文件
/**
* @file socket_uart.hpp
* @brief uart socket class
* @author
* @version 1.0.0
* @date 2019-03-27
* @par history:
* | version | date | author | description |
* | ------- | ---- | ------ | ----------- |
* | 1.0.0 | 2019-03-27 | | create |
*/
#ifndef __SOCKET_UART_HPP_INCLUDED__
#define __SOCKET_UART_HPP_INCLUDED__
#include "socket_base.hpp"
namespace com {
class socket_uart_t : public socket_base_t {
public:
socket_uart_t();
~socket_uart_t();
void* get_sock() { return NULL; }
int get_fd();
int setsockopt(sock_option_t opt, const void* val, int len) { return E_NOTIMPL; }
int getsockopt(sock_option_t opt, void *val, int* len) const { return E_NOTIMPL; }
int bind(const std::string& addr);
int unbind(const char* addr);
int connect(const std::string& addr) { return E_NOTIMPL; }
int disconnect(const char* addr) { return E_NOTIMPL; }
void close();
/**
* @brief receive data from socket
* @param[out] buf buffer of received data
* @param[in] len max length of buffer
* @param[out] addr receive address
* @return length of received data
* @retval <0 receive fail
* @retval other length of received data
*/
int recv(void* buf, int len, std::string* addr);
/**
* @brief send data on the socket
* @param[in] buf buffer of send data
* @param[in] len length of buffer
* @param[in] addr send address,if it is empty, the data will be send to the connected address.
* @return length of send data
* @retval <0 send fail
* @retval other length of send data
*/
int send(const void* buf, int len, const std::string* addr);
/**
* @brief receive message from socket
* @param[out] msg received message
* @param[in] addr send address,if it is empty, the data will be send to the connected address.
* @return length of received data
* @retval <0 receive fail
* @retval other length of received data
*/
int recv(socket_msg_t& msg, std::string* addr);
/**
* @brief send msg on the socket
* @param[in] msg send message
* @param[in] addr send address,if it is empty, the data will be send to the connected address.
* @return length of send data
* @retval <0 send fail
* @retval other length of send data
*/
int send(const socket_msg_t& msg, const std::string* addr);
private:
int fd_;
};
}
#endif // __SOCKET_UART_HPP_INCLUDED__
2接口實現文件
/**
* @file socket_uart.cpp
* @brief uart socket class
* @author xxxxxxxxxxx
* @version 1.0.0
* @date 2019-03-27
* @par history:
* | version | date | author | description |
* | ------- | ---- | ------ | ----------- |
* | 1.0.0 | 2019-03-27 | xxxxxx | create |
*/
#include "socket_uart.hpp"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
namespace com {
socket_uart_t::socket_uart_t()
{
fd_ = 0;
}
socket_uart_t::~socket_uart_t()
{
close();
}
int socket_uart_t::get_fd()
{
return fd_;
}
int socket_uart_t::bind(const std::string& addr)
{
std::cout<<"socket_uart_t::bind:"<<std::endl;
int ret = E_OK;
sock_protocol_t prot_type;
std::string name;
int baud = 9600;
int c_flow = 0;
int bits = 8;
char parity = 'N';
int stop = 1;
do
{
if (addr.empty())
{
ret = E_INVAL;
break;
}
// have bound
if (fd_ > 0)
{
ret = E_ALREADY;
break;
}
// parse address
prot_type = parse_addr(addr, name, &baud);
prot_type = SOCK_PROTOCOL_UART;
name="/dev/ttymxc2";
if (SOCK_PROTOCOL_UART != prot_type)
{
ret = E_NOTSUPT;
break;
}
// open uart
ret = open(name.c_str(), O_RDWR|O_NOCTTY|O_NDELAY);
if(-1 == ret)
{
ret = E_OPENFAIL;
break;
}
std::cout<<"open uart fd_ =ret= "<<ret<<std::endl;
fd_ = ret;
// clear the nonblocking flag
//恢復串口狀態爲阻塞,用於等待串口數據的讀入
if(fcntl(fd_, F_SETFL, 0) < 0)
{
ret = socket_error_t::trans_syserr();
break;
}
struct termios options;
// get attribute
if(tcgetattr(fd_,&options) < 0)
{
ret = socket_error_t::trans_syserr();
break;
}
// set the input/output baud rate
switch(baud)
{
case 4800:
cfsetispeed(&options, B4800);
cfsetospeed(&options, B4800);
break;
case 9600:
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
break;
case 19200:
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
break;
case 38400:
cfsetispeed(&options, B38400);
cfsetospeed(&options, B38400);
break;
case 57600:
cfsetispeed(&options, B57600);
cfsetospeed(&options, B38400);
break;
case 115200:
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
break;
default:
ret = E_INVAL;
break;
}
if (ret)
{
break;
}
// set control mode
options.c_cflag |= CLOCAL; // not occupy the serial port
options.c_cflag |= CREAD; // can read data
// set data flow control
switch(c_flow)
{
case 0: //不進行流控制
options.c_cflag &= ~CRTSCTS;
break;
case 1: //進行硬件流控制
options.c_cflag |= CRTSCTS;
break;
case 2: //進行軟件流控制
options.c_cflag |= IXON|IXOFF|IXANY;
break;
default:
ret = E_INVAL;
break;
}
if (ret)
{
break;
}
// set data bits
switch(bits)
{
case 5:
options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
options.c_cflag |= CS8;
break;
default:
ret = E_INVAL;
break;
}
if (ret)
{
break;
}
// set parity bit
switch(parity)
{
/*無奇偶校驗位*/
case 'n':
case 'N':
options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行奇偶校驗
options.c_cflag &= ~INPCK;//INPCK:使奇偶校驗起作用
break;
/*設爲空格,即停止位爲2位*/
case 's':
case 'S':
options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行奇偶校驗
options.c_cflag &= ~CSTOPB;//CSTOPB:使用兩位停止位
break;
/*設置奇校驗*/
case 'o':
case 'O':
options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行奇偶校驗
options.c_cflag |= PARODD;//PARODD:若設置則爲奇校驗,否則爲偶校驗
options.c_cflag |= INPCK;//INPCK:使奇偶校驗起作用
options.c_cflag |= ISTRIP;//ISTRIP:若設置則有效輸入數字被剝離7個字節,否則保留全部8位
break;
/*設置偶校驗*/
case 'e':
case 'E':
options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行奇偶校驗
options.c_cflag &= ~PARODD;//PARODD:若設置則爲奇校驗,否則爲偶校驗
options.c_cflag |= INPCK;//INPCK:使奇偶校驗起作用
options.c_cflag |= ISTRIP;//ISTRIP:若設置則有效輸入數字被剝離7個字節,否則保留全部8位
break;
default:
ret = E_INVAL;
break;
}
if (ret)
{
break;
}
// set stop bit
switch(stop)
{
case 1:
options.c_cflag &= ~CSTOPB;//CSTOPB:停止位爲1
break;
case 2:
options.c_cflag |= CSTOPB;//CSTOPB:使用停止位爲2
break;
default:
ret = E_INVAL;
break;
}
if (ret)
{
break;
}
/*設置輸出模式爲原始輸出*/
//options.c_oflag &= ~OPOST;//OPOST:若設置則按定義的輸出處理,否則所有c_oflag失效
options.c_iflag &= ~(INLCR | ICRNL | IGNCR);//解決發送)0X0A的問題
options.c_oflag &= ~(ONLCR | OCRNL | ONOCR | ONLRET);
/*設置本地模式爲原始模式*/
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/*
*ICANON:允許規範模式進行輸入處理
*ECHO:允許輸入字符的本地回顯
*ECHOE:在接收EPASE時執行Backspace,Space,Backspace組合
*ISIG:允許信號
*/
/*設置等待時間和最小接受字符*/
options.c_cc[VTIME] = 0;//可以在select中設置
options.c_cc[VMIN] = 1;//最少讀取一個字符
/*如果發生數據溢出,只接受數據,但是不進行讀操作*/
tcflush(fd_,TCIFLUSH);
/*激活配置*/
if(tcsetattr(fd_,TCSANOW,&options) < 0)
{
ret = socket_error_t::trans_syserr();
break;
}
} while(0);
if (ret < 0)
{
unbind(NULL);
}
return ret;
}
int socket_uart_t::unbind(const char* addr)
{
if (fd_)
{
::close(fd_);
fd_ = 0;
}
return E_OK;
}
void socket_uart_t::close()
{
unbind(NULL);
}
int socket_uart_t::send(const void* buf, int len, const std::string* addr)
{
int ret = E_OK;
do
{
std::cout<<"socket_uart_t::send begin!"<<std::endl;
if ((NULL == buf) ||
(len <= 0))
{
ret = E_INVAL;
break;
}
std::cout<<"socket_uart_t send fd_: "<<fd_<<std::endl;
if (fd_ <= 0)
{
ret = E_NOTINIT;
break;
}
int left = len;
const char* ptr = (const char*)buf;
std::cout<<"uart data:";
for(int i=0 ; i<8 ; i++)
{
printf("%X ",ptr[i]);
}
std::cout<<std::endl;
while(left > 0)
{
std::cout<<"socket uart write begin..."<<std::endl;
ret = write(fd_, ptr, left);
std::cout<<"socket uart write end ret: "<<ret<<std::endl;
if(ret <= 0)
{
if((ret < 0) &&
(errno == EINTR))
{
ret = 0;
}
else
{
ret = socket_error_t::trans_syserr();
break;
}
}
left -= ret;
ptr += ret;
}
} while(0);
return ret;
}
int socket_uart_t::recv(void* buf, int len, std::string* addr)
{
int ret = E_OK;
do
{
if ((NULL == buf) ||
(len <= 0))
{
ret = E_INVAL;
break;
}
if (fd_ <= 0)
{
ret = E_NOTINIT;
break;
}
ret = read(fd_, buf, len);
if(ret < 0)
{
if(errno == EINTR)//被信號中斷
{
ret = 0;
}
else
{
ret = socket_error_t::trans_syserr();
break;
}
}
} while(0);
return ret;
}
int socket_uart_t::send(const socket_msg_t& msg, const std::string* addr)
{
return send(msg.data(), msg.size(), addr);
}
int socket_uart_t::recv(socket_msg_t& msg, std::string* addr)
{
int ret = E_OK;
do
{
if (fd_ <= 0)
{
ret = E_NOTINIT;
break;
}
char buf[64] = {0};
ret = recv(buf, sizeof(buf), addr);
if (ret > 0)
{
msg.build(buf, ret);
}
} while(0);
return ret;
}
};
上面的接口文件實際測試有用,接下來,編寫代碼來使用接口
1綁定串口
int appi_spat_t::bind_uart(std::string& addr)
{
int ret=E_INVAL;
std::cout<<"bind uart start"<<std::endl;
log_->info("bind_uart start");
ret=socket_uart_.bind(addr);
log_->info("bind_uart ret:%d ",ret);
std::cout<<"bind uart ret:"<<ret<<std::endl;
if(E_INVAL ==ret)
{
log_->error("bind_uart failed!");
}
return ret;
}
2、根據通信協議 組數據包
int appi_spat_t::get_uart_light(int phase1_light,int phase2_light)
{
//根據紅綠燈串口協議組一個串口幀
int ret = E_OK;
uart_rx_data_[0]=0x33;
uart_rx_data_[1]=0x01;
uart_rx_data_[2]=0x16;
uart_rx_data_[3]=0x00;
uart_rx_data_[4]=0x00;
uart_rx_data_[6]=0x08;
if(( TRA_LIGHT_STATE_RED == phase1_light) && //3
(TRA_LIGHT_STATE_GREEN == phase2_light)) //5
{
uart_rx_data_[5]=0x41;//100 0001
uart_rx_data_[7]=0x93;
}
if(( TRA_LIGHT_STATE_RED == phase1_light) && //3
(TRA_LIGHT_STATE_YELLOW == phase2_light)) //7
{
uart_rx_data_[5]=0x21;//010 0001
uart_rx_data_[7]=0x73;
}
if(( TRA_LIGHT_STATE_RED == phase2_light) && //3
(TRA_LIGHT_STATE_GREEN == phase1_light)) //5
{
uart_rx_data_[5]=0x14;//001 0100
uart_rx_data_[7]=0x66;
}
if(( TRA_LIGHT_STATE_RED == phase2_light) && //3
(TRA_LIGHT_STATE_YELLOW == phase1_light)) //7
{
uart_rx_data_[5]=0x12;//001 0010
uart_rx_data_[7]=0x64;
}
if(uart_rx_data_[5] <= 0)
{
log_->error("get_uart_light fault!");
ret = E_FALT;
}
log_->info("get uart light data_: %X",uart_rx_data_[5]);
return ret;
}
組報文的方法二
void appi_spat_t::get_uart_light(int phase1_light,int phase2_light)
{ //根據紅綠燈串口協議組一個串口幀
uart_rx_data_[0]=0x33;
uart_rx_data_[1]=0x01;
uart_rx_data_[2]=0x16;
uart_rx_data_[3]=0x00;
uart_rx_data_[4]=0x00;
uart_rx_data_[6]=0x08;
switch(phase1_light)
{
case TRA_LIGHT_STATE_RED: //3
{
switch(phase2_light)
{
case TRA_LIGHT_STATE_RED:
{
log_->error("get_uart_light fault!");
ret = E_FALT;
break;
}
case TRA_LIGHT_STATE_YELLOW: //7
{
//char buff[]="0X33 0X01 0X16 0X00 0X00 0X11 0X08 0X63";//010 001
uart_rx_data_[5]=0x11;//010 001
uart_rx_data_[7]=0x63;
break;
}
case TRA_LIGHT_STATE_GREEN: //5
{
//char buff[]="0X33 0X01 0X16 0X00 0X00 0X21 0X08 0X73";//100 001
uart_rx_data_[5]=0x21;//100 001
uart_rx_data_[7]=0x73;
break;
}
}
break;
}
case TRA_LIGHT_STATE_YELLOW: //7
{
switch(phase2_light)
{
case TRA_LIGHT_STATE_RED: //3
{
//char buff[]="0X33 0X01 0X16 0X00 0X00 0X0A 0X08 0X5C";//001 010
uart_rx_data_[5]=0x0A;//001 010
uart_rx_data_[7]=0x5C;
break;
}
case TRA_LIGHT_STATE_YELLOW:
{
log_->error("get_uart_light fault!");
ret = E_FALT;
break;
}
case TRA_LIGHT_STATE_GREEN: //5
{
//char buff[]="0X33 0X01 0X16 0X00 0X00 0X22 0X08 0X74";//100 010
uart_rx_data_[5]=0x22;//100 010
uart_rx_data_[7]=0x74;
break;
}
}
break;
}
case TRA_LIGHT_STATE_GREEN: //5
{
switch(phase2_light)
{
case TRA_LIGHT_STATE_RED: //3
{
//char buff[]="0X33 0X01 0X16 0X00 0X00 0X0C 0X08 0X5E";//001 100
uart_rx_data_[5]=0x0C;//001 100
uart_rx_data_[7]=0x5E;
break;
}
case TRA_LIGHT_STATE_YELLOW: //7
{
//char buff[]="0X33 0X01 0X16 0X00 0X00 0X14 0X08 0X66";//010 100
uart_rx_data_[5]=0x14;//010 100
uart_rx_data_[7]=0x66;
break;
}
case TRA_LIGHT_STATE_GREEN:
{
log_->error("get_uart_light fault!");
break;
}
}
break;
}
}
log_->info("get uart light data_: %X",uart_rx_data_[5]);
return ;
}
3、向串口發送
int appi_spat_t::send_uart(const void* buf, int len, const std::string* addr)
{
int ret=E_INVAL;
std::cout<<"socket_uart send"<<std::endl;
ret=socket_uart_.send(buf,len,addr);
std::cout<<"socket_uart send ret: "<<ret<<std::endl;
if(E_INVAL ==ret)
{
log_->error("send_uart failed!");
}
return ret;
}
我並沒有寫發送返回檢查程序,串口發送報文,接收模塊會根據協議返回對應的返回碼,
根據返回碼,可以知道發送的報文是否正確