@小鱼 @3152079070 之前的仓库已无法访问,小鱼串口文件没办法上传附件我直接贴在下面,这个串口文件目前只有串口,没有了tcp、udp等功能,酌情使用。```
proto_utils.cpp
/**
* @brief 文件描述:协议处理工具,打印、crc、转义与反转义
* @author 小鱼 (fishros@foxmail.com)
* @version V1.0.0
* @date 2022-07-17
* @copyright 版权所有:FishBot Open Source Organization
*/
#include "fish_protocol/protocol_util.h"
#include <iostream>
namespace fish_protocol {
using namespace std;
// ------------------------查表法crc8校验-------
static const uint8_t crc8tab[] =
{0x00,0x5e,0xbc,0xe2,0x61,0x3f,0xdd,0x83,0xc2,0x9c,0x7e,0x20,0xa3,0xfd,0x1f,0x41,
0x9d,0xc3,0x21,0x7f,0xfc,0xa2,0x40,0x1e,0x5f,0x01,0xe3,0xbd,0x3e,0x60,0x82,0xdc,
0x23,0x7d,0x9f,0xc1,0x42,0x1c,0xfe,0xa0,0xe1,0xbf,0x5d,0x03,0x80,0xde,0x3c,0x62,
0xbe,0xe0,0x02,0x5c,0xdf,0x81,0x63,0x3d,0x7c,0x22,0xc0,0x9e,0x1d,0x43,0xa1,0xff,
0x46,0x18,0xfa,0xa4,0x27,0x79,0x9b,0xc5,0x84,0xda,0x38,0x66,0xe5,0xbb,0x59,0x07,
0xdb,0x85,0x67,0x39,0xba,0xe4,0x06,0x58,0x19,0x47,0xa5,0xfb,0x78,0x26,0xc4,0x9a,
0x65,0x3b,0xd9,0x87,0x04,0x5a,0xb8,0xe6,0xa7,0xf9,0x1b,0x45,0xc6,0x98,0x7a,0x24,
0xf8,0xa6,0x44,0x1a,0x99,0xc7,0x25,0x7b,0x3a,0x64,0x86,0xd8,0x5b,0x05,0xe7,0xb9,
0x8c,0xd2,0x30,0x6e,0xed,0xb3,0x51,0x0f,0x4e,0x10,0xf2,0xac,0x2f,0x71,0x93,0xcd,
0x11,0x4f,0xad,0xf3,0x70,0x2e,0xcc,0x92,0xd3,0x8d,0x6f,0x31,0xb2,0xec,0x0e,0x50,
0xaf,0xf1,0x13,0x4d,0xce,0x90,0x72,0x2c,0x6d,0x33,0xd1,0x8f,0x0c,0x52,0xb0,0xee,
0x32,0x6c,0x8e,0xd0,0x53,0x0d,0xef,0xb1,0xf0,0xae,0x4c,0x12,0x91,0xcf,0x2d,0x73,
0xca,0x94,0x76,0x28,0xab,0xf5,0x17,0x49,0x08,0x56,0xb4,0xea,0x69,0x37,0xd5,0x8b,
0x57,0x09,0xeb,0xb5,0x36,0x68,0x8a,0xd4,0x95,0xcb,0x29,0x77,0xf4,0xaa,0x48,0x16,
0xe9,0xb7,0x55,0x0b,0x88,0xd6,0x34,0x6a,0x2b,0x75,0x97,0xc9,0x4a,0x14,0xf6,0xa8,
0x74,0x2a,0xc8,0x96,0x15,0x4b,0xa9,0xf7,0xb6,0xe8,0x0a,0x54,0xd7,0x89,0x6b,0x35};
uint8_t getcrc8tab(const uint8_t *buf, int len) {
uint8_t crc = 0x00;
while(len--)
{
crc = crc8tab[crc ^ *buf++];
}
return crc;
}
/****************************
函数功能:直接计算法获得8位循环冗余校验值
入口参数:数组地址、长度
出口参数:校验值
******************************/
uint8_t getCrc8(uint8_t *ptr, uint16_t len)
{
uint8_t crc, i;
crc = 0;
while(len--)
{
crc ^= *ptr++;
for(i = 0; i < 8; i++)
{
if(crc&0x01)
crc=(crc>>1)^0x8C;
else
crc >>= 1;
}
}
return crc;
}
int frame_packing(const uint8_t *buf, uint8_t *frame, uint8_t len, uint8_t func) {
uint8_t cnt = 0;
frame[cnt++] = FIRST_CODE;
frame[cnt++] = func;
frame[cnt++] = len;
for (int i = 0; i < len; i++) {
frame[cnt++] = buf[i];
}
frame[cnt++] = getcrc8tab(buf, len);
frame[cnt++] = END_CODE;
return cnt;
}
int inverse_frame(uint8_t *result, const uint8_t *frame, uint8_t len, uint8_t& func) {
if((frame[0] != FIRST_CODE) || (frame[len - 1] != END_CODE))// 检查帧头帧尾
return 0;
for(int i = 3; i < len-2; i++)
{
result[i - 3] = frame[i];
}
if(getcrc8tab(result, frame[2]) != frame[len - 2])// 检查crc8校验
return 0;
func = frame[1];
return frame[2];
}
} // namespace fish_protocol
serial_protocol.cpp
/**
* @brief 文件描述:待完善
* @author 小鱼 (fishros@foxmail.com)
* @version V1.0.0
* @date 2022-07-24
* @copyright 版权所有:(鱼香ROS)fishros.org.cn
*/
#include "fish_protocol/serial_protocol.h"
namespace serial_protocol {
/// @brief Flush a serial port's buffers.
///
/// @param serial_port Port to flush.
/// @param what Determines the buffers to flush.
/// @param error Set to indicate what error occurred, if any.
void SerialProtocol::flush_serial_port(
boost::asio::serial_port& serial_port,
flush_type what,
boost::system::error_code& error)
{
if (0 == ::tcflush(serial_port.lowest_layer().native_handle(), what))
{
error = boost::system::error_code();
}
else
{
error = boost::system::error_code(errno,
boost::asio::error::get_system_category());
}
}
SerialProtocol::~SerialProtocol()
{
io_service_.stop();
serial_port_.cancel();
serial_port_.close();
}
void SerialProtocol::_initSerialProtocol() {
boost::system::error_code ec;
try
{
serial_port_.open(protocol_config_.serial_address_, ec);
if(!serial_port_.is_open())
throw ec;
}
catch(boost::system::error_code& ec)
{
std::cout << ec.message() << std::endl;
return ;
}
std::cout << "串口已打开:" << protocol_config_.serial_address_ << std::endl;
serial_port_.set_option(spb::baud_rate(protocol_config_.serial_baut_));
serial_port_.set_option(spb::character_size(8));
serial_port_.set_option(spb::stop_bits(spb::stop_bits::one));
serial_port_.set_option(spb::parity(spb::parity::none));
serial_port_.set_option(spb::flow_control(spb::flow_control::none));
boost::thread td(boost::bind(&boost::asio::io_service::run, &io_service_));
_asyncReadSomeData();
}
void SerialProtocol::_recvDataCallback(const boost::system::error_code& error,
size_t bytes_transferred) {
if (bytes_transferred > 0) {
// 回调数据
if(recv_uint8_callback)
{
recv_uint8_callback(recv_data_buffer_, bytes_transferred);
}
}
_asyncReadSomeData();
}
void SerialProtocol::_asyncReadSomeData() {
serial_port_.async_read_some(
boost::asio::buffer(recv_data_buffer_, sizeof(recv_data_buffer_)),
boost::bind(&SerialProtocol::_recvDataCallback, this,
boost::placeholders::_1, boost::placeholders::_2));
}
int SerialProtocol::ProtocolSendString(const std::string& data) {
serial_port_.write_some(boost::asio::buffer(data.data(), data.size()));
return 0;
}
int SerialProtocol::ProtocolSenduint8_t(const std::uint8_t* data, const std::uint8_t len) {
serial_port_.write_some(boost::asio::buffer(data, len));
return 0;
}
void SerialProtocol::SetDataRecvCallback(
std::function<void(const std::uint8_t*, const std::uint8_t)> callback) {
recv_uint8_callback = callback;
}
} // namespace fish_protocol
protocol_util.h
/**
* @brief 文件描述:待完善
* @author 小鱼 (fishros@foxmail.com)
* @version V1.0.0
* @date 2022-07-24
* @copyright 版权所有:(鱼香ROS)fishros.org.cn
*/
#ifndef _FISH_PROTOCOL_PROTO_UTIL_H_
#define _FISH_PROTOCOL_PROTO_UTIL_H_
#include <cstdint>
#include <cstdio>
namespace fish_protocol {
#define FIRST_CODE 0x55
#define END_CODE 0xBB
/**
* @brief 截取指定位数据并赋值
* 小端模式: 高位在前(低内存),低位在后(高内存)
*
*/
#define SET_SUB_BYTES1(target, data) target = (data & 0xFF)
#define SET_SUB_BYTES2(target, data) target |= ((data << 8) & 0xFF00)
/**
* @brief 查表法crc8校验
*
* @param buf 输入数组
* @param len 数组长度
* @return uint8_t
*/
uint8_t getcrc8tab(const uint8_t *buf, int len);
/**
* @brief 直接计算法crc8校验
*
* @param buf 输入数组
* @param len 数组长度
* @return uint8_t
*/
uint8_t getCrc8(const uint8_t *buf, int len);
/**
* @brief 将数据进行转义
*
* @param frame 帧数据
* @param result 结果
* @param len 长度
* @return int 转义完成后新的帧的大小
*/
int frame_packing(const uint8_t *buf, uint8_t *frame, uint8_t len, uint8_t func);
/**
* @brief 将数据帧进行反转义
*
* @param frame 帧数据
* @param result 结果
* @param len 长度
* @return int
*/
int inverse_frame(uint8_t *result, const uint8_t *frame, uint8_t len, uint8_t& func);
} // namespace fish_protocol
#endif // _PROTO_UTILS_H_
serial_protocol.h
/**
* @brief 文件描述:待完善
* @author 小鱼 (fishros@foxmail.com)
* @version V1.0.0
* @date 2022-07-24
* @copyright 版权所有:(鱼香ROS)fishros.org.cn
*/
#ifndef _FISH_PROTOCOL_SERIAL_PROTOCOL_H_
#define _FISH_PROTOCOL_SERIAL_PROTOCOL_H_
#include <unistd.h>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <string>
namespace serial_protocol{
class ProtocolConfig {
public:
// serial
int serial_baut_;
std::string serial_address_;
ProtocolConfig& operator=(const ProtocolConfig& config) {
serial_baut_ = config.serial_baut_;
serial_address_ = config.serial_address_;
return *this;
};
public:
ProtocolConfig(){};
~ProtocolConfig(){};
};
enum flush_type
{
flush_receive = TCIFLUSH,
flush_send = TCOFLUSH,
flush_both = TCIOFLUSH
};
class SerialProtocol{
using spb = boost::asio::serial_port_base;
protected:
std::function<void(const std::uint8_t*, const std::uint8_t)> recv_uint8_callback;
ProtocolConfig protocol_config_;
private:
void _asyncReadSomeData();
void _initSerialProtocol();
void _recvDataCallback(const boost::system::error_code& error,
size_t bytes_transferred);
void flush_serial_port(
boost::asio::serial_port& serial_port,
flush_type what,
boost::system::error_code& error);
public:
SerialProtocol(const ProtocolConfig& protocol_config)
: io_service_(),
serial_port_(io_service_) {
this->protocol_config_ = protocol_config;
_initSerialProtocol();
}
~SerialProtocol();
int ProtocolSendString(const std::string& data);
int ProtocolSenduint8_t(const std::uint8_t* data, const std::uint8_t len);
void SetDataRecvCallback(std::function<void(const std::uint8_t*, const std::uint8_t)> callback);
private:
unsigned char recv_data_buffer_[1024] = {0};
boost::asio::io_service io_service_;
boost::asio::serial_port serial_port_;
};
} // namespace fish_protocol
#endif // _FISH_PROTOCOL_SERIAL_PROTOCOL_H_