【编程思想】数据传输的通信接口以及通信协议的解耦设计
应用场景在工作上经常会遇到需要对接多个外设,如离线语音识别芯片、NFC刷卡器芯片等等,这些大部分都是通过UART、SPI等接口进行通信,且具有各自的数据包通信协议。除了通信接口和通信协议(即数据封包解包)有差异外,这些数据处理逻辑都一样,所以可以将数据处理逻辑统一,将通信差异部分抽离出来,分别根据不同的硬件实现。整体框架核心框架部分:IDataStream:数据通信接口定义,用于统一各种通信接口,
应用场景
在工作上经常会遇到需要对接多个外设,如离线语音识别芯片、NFC刷卡器芯片等等,这些大部分都是通过UART、SPI等接口进行通信,且具有各自的数据包通信协议。
除了通信接口和通信协议(即数据封包解包)有差异外,这些数据处理逻辑都一样,所以可以将数据处理逻辑统一,将通信差异部分抽离出来,分别根据不同的硬件要求实现。
整体框架
核心框架部分:
IDataStream:数据通信接口定义,用于统一各种通信接口,如 Serial 串口读写操作,实现数据收发。
IDataCodec:数据编解码接口定义,用于统一各种通信协议的调用接口,如离线识别语言芯片 Ci110x 系列,实现数据封包解包(注意:解码需要采用状态机)。
DataTransfer:依据外部传入的通信接口对象和数据编解码对象,实现数据传输处理的通用逻辑,如数据接收、数据缓存、数据编解码、数据回调,数据发送等。
硬件差异部分:
DataCodecCi110x:Ci110x 芯片的串口通信协议,实现对数据的封包解包。
DataStreamSerial:基于串口通信接口实现的发送接收操作。
设备功能接口:
DevieCi110x:通过创建 DataCodecCi110x、DataStreamSerial 对象,传入 DataTransfer 便可完成基础数据通信,再此基础上进一步封装高层命令,如进入或退出识别模式命令,又如前后端点事件、唤醒事件、音频数据等等具体的高级功能。
这样,主业务逻辑代码无论应对什么外设,都可以完全的复用代码,根据实际场景随意组合 DataStream 和 DataCodec。并且新增的外设,只需要实现 IDataCodec 定义的接口,即可完成数据包编解码部分,若是新增的通信接口,也可按照 IDataStream 定义的接口实现即可。如新增一个 XXXA 设备,设备自有通信协议,使用 Serial 通信接口,那么只需要按照 IDataCodec 定义的接口,实现 XXXA 的通信协议,通信接口复用现有的 DataStreamSerial,即可完成数据通信。
如果发现现有的某个通信协议很完善,支持数据包不定长数据封包解包,在进行大批量数据传输非常稳定,那么在新的项目,如需要与上位机传输音频、图像,都可以直接拿来用,不需要做过多的改动,大大的提高了开发效率。
IDataCodec
IDataCodec 数据编解码接口定义
/**
******************************************************************************
* @文件 IDataCodec.h
* @版本 V1.0.0
* @日期
* @概要 数据编解码接口定义
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#ifndef __IDATA_CODEC_H
#define __IDATA_CODEC_H
#include <cstddef>
class IDataCodec
{
public:
/*************************************************************
* 函数: ~IDataCodec
* 功能: 析构虚函数, 防止内存泄露
* 参数: 无
* 返回值: 无
**************************************************************/
virtual ~IDataCodec() {}
/*************************************************************
* 函数: reset
* 功能: 用于重置解码器状态
* 参数: 无
* 返回值: 无
**************************************************************/
virtual void reset() = 0;
/*************************************************************
* 函数: encode
* 功能: 对数据进行编码
* 参数:
* data: 要编码的数据
* length: 要编码的数据长度
* buffer: 存储编码后的数据缓冲区
* byte: 存储编码后的数据缓冲区大小
*
* 返回值:
* >0: 编码成功, 数据存放在 buffer
* 0: 编码失败, 通常是缓冲区大小不足
**************************************************************/
virtual int encode(const void* data, size_t length, void* buffer, size_t size) = 0;
/*************************************************************
* 函数: decode
* 功能: 对数据进行解码, 内部应使用状态机实现解析
* 参数:
* data: 一字节数据
* buffer: 存放解码后的数据缓冲区
* byte: 存放解码后的数据缓冲区大小
*
* 返回值:
* 0: 正在编码, 中间数据存放在 buffer
* >0: 解码成功, 返回有效数据的长度
* -1: 解码失败, 缓冲区不足
* -2: 解码失败, 数据校验不通过
**************************************************************/
virtual int decode(unsigned char data, void* buffer, size_t size) = 0;
};
#endif
IDataStream
IDataStream 数据通信接口定义
/**
******************************************************************************
* @文件 IDataStream.h
* @版本 V1.0.0
* @日期
* @概要 数据通信接口定义
* @作者 lmx
******************************************************************************
* @注意
*
******************************************************************************
*/
#ifndef __IDATA_STREAM_H
#define __IDATA_STREAM_H
#include <cstddef>
class IDataStream
{
public:
/*************************************************************
* 函数: ~IDataStream
* 功能: 析构虚函数, 防止内存泄露
* 参数: 无
* 返回值: 无
**************************************************************/
virtual ~IDataStream() {};
/*************************************************************
* 函数: isOpen
* 功能: 用于判断数据流是否已经被打开
* 参数: 无
* 返回值:
* true: 数据流已经被打开
* false: 数据流尚未被打开
**************************************************************/
virtual bool isOpen() = 0;
/*************************************************************
* 函数: open
* 功能: 用于打开数据流
* 参数: 无
* 返回值:
* true: 数据流打开成功
* false: 数据流打开失败
**************************************************************/
virtual bool open() = 0;
/*************************************************************
* 函数: recv
* 功能: 用于接收数据流
* 参数:
* buffer: 用于存储数据的缓冲区
* size: 用于指示该缓冲区的大小
* 返回值:
* 0: 没有数据
* -1: 接收数据出错
* >0: 收到有效数据
**************************************************************/
virtual int recv(void* buffer, size_t size) = 0;
/*************************************************************
* 函数: send
* 功能: 用于发送数据流
* 参数:
* data: 指定要发送的数据
* length: 指定要发送数据的长度
* 返回值:
* true: 已成功发送数据
* false: 发送数据出错
**************************************************************/
virtual bool send(const void* data, size_t length) = 0;
/*************************************************************
* 函数: Close
* 功能: 用于关闭数据流
* 参数: 无
* 返回值: 无
**************************************************************/
virtual void close() = 0;
};
#endif
DataCodecCi110x
CI110X 系列芯片数据编解码的实现,此处仅为了演示,不做具体实现。
/**
******************************************************************************
* @文件 DataCodecCi110x.h
* @版本 V1.0.0
* @日期
* @概要 Ci110x 系列芯片数据编解码实现
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#ifndef __DATA_CODEC_CI110X_H
#define __DATA_CODEC_CI110X_H
#include "IDataCodec.h"
class DataCodecCi110x : public IDataCodec
{
public: // 通过 IDataCodec 继承
/*************************************************************
* 函数: reset
* 功能: 用于重置解码器状态
* 参数: 无
* 返回值: 无
**************************************************************/
virtual void reset() override;
/*************************************************************
* 函数: encode
* 功能: 对数据进行编码
* 参数:
* data: 要编码的数据
* length: 要编码的数据长度
* buffer: 存储编码后的数据缓冲区
* byte: 存储编码后的数据缓冲区大小
*
* 返回值:
* >0: 编码成功, 数据存放在 buffer
* 0: 编码失败, 通常是缓冲区大小不足
**************************************************************/
virtual int encode(const void* data, size_t length, void* buffer, size_t size) override;
/*************************************************************
* 函数: decode
* 功能: 对数据进行解码, 内部应使用状态机实现解析
* 参数:
* data: 一字节数据
* buffer: 存放解码后的数据缓冲区
* byte: 存放解码后的数据缓冲区大小
*
* 返回值:
* 0: 正在编码, 中间数据存放在 buffer
* >0: 解码成功, 返回有效数据的长度
* -1: 解码失败, 缓冲区不足
* -2: 解码失败, 数据校验不通过
**************************************************************/
virtual int decode(unsigned char data, void* buffer, size_t size) override;
};
#endif
/**
******************************************************************************
* @文件 DataCodecCi110x.h
* @版本 V1.0.0
* @日期
* @概要 Ci110x 系列芯片数据编解码实现
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#include <iostream>
#include "DataCodecCi110x.h"
void DataCodecCi110x::reset()
{
std::cout << "DataCodecCi110x::reset()..." << std::endl;
}
int DataCodecCi110x::encode(const void* data, size_t length, void* buffer, size_t size)
{
std::cout << "DataCodecCi110x::encode()..." << std::endl;
return 0;
}
int DataCodecCi110x::decode(unsigned char data, void* buffer, size_t size)
{
std::cout << "DataCodecCi110x::decode()..." << std::endl;
return 0;
}
DataStreamSerial
串口读写实现,此处仅为了演示,不做具体实现。
/**
******************************************************************************
* @文件 DataStreamSerial.h
* @版本 V1.0.0
* @日期
* @概要 基于串口通信实现的数据通信功能
* @作者 lmx
******************************************************************************
* @注意
*
******************************************************************************
*/
#ifndef __DATA_STREAM_SERIAL_H
#define __DATA_STREAM_SERIAL_H
#include "IDataStream.h"
class DataStreamSerial : public IDataStream
{
private:
volatile bool bOpen = false; // 为了方便模拟而定义的状态变量
public: // 串口通信特有的配置
/*************************************************************
* 函数: setParameter
* 功能: 用于设置串口参数
* 参数: 无
* 返回值:
* devpath: 串口设备节点
* baudrate: 波特率(默认9600)
* databit: 数据位(默认8)
* stopbit: 停止位(默认1)
**************************************************************/
bool setParameter(const char* devpath, unsigned int baudrate = 9600, int databit = 8, int stopbit = 1);
public: // 通过 IDataStream 继承
/*************************************************************
* 函数: isOpen
* 功能: 用于判断数据流是否已经被打开
* 参数: 无
* 返回值:
* true: 数据流已经被打开
* false: 数据流尚未被打开
**************************************************************/
virtual bool isOpen() override;
/*************************************************************
* 函数: open
* 功能: 用于打开数据流
* 参数: 无
* 返回值:
* true: 数据流打开成功
* false: 数据流打开失败
**************************************************************/
virtual bool open() override;
/*************************************************************
* 函数: recv
* 功能: 用于接收数据流
* 参数:
* buffer: 用于存储数据的缓冲区
* size: 用于指示该缓冲区的大小
* 返回值:
* 0: 没有数据
* -1: 接收数据出错
* >0: 收到有效数据
**************************************************************/
virtual int recv(void* buffer, size_t size) override;
/*************************************************************
* 函数: send
* 功能: 用于发送数据流
* 参数:
* data: 指定要发送的数据
* length: 指定要发送数据的长度
* 返回值:
* true: 已成功发送数据
* false: 发送数据出错
**************************************************************/
virtual bool send(const void* data, size_t length) override;
/*************************************************************
* 函数: Close
* 功能: 用于关闭数据流
* 参数: 无
* 返回值: 无
**************************************************************/
virtual void close() override;
};
#endif
/**
******************************************************************************
* @文件 DataStreamSerial.cpp
* @版本 V1.0.0
* @日期
* @概要 基于串口通信实现的数据通信功能
* @作者 lmx
******************************************************************************
* @注意
*
******************************************************************************
*/
#include <windows.h>
#include <iostream>
#include "DataStreamSerial.h"
bool DataStreamSerial::setParameter(const char* devpath, unsigned int baudrate, int databit, int stopbit)
{
std::cout << "DataStreamSerial::setParameter()..." << std::endl;
return true;
}
bool DataStreamSerial::isOpen()
{
std::cout << "DataStreamSerial::isOpen()..." << std::endl;
return bOpen;
}
bool DataStreamSerial::open()
{
std::cout << "DataStreamSerial::open()..." << std::endl;
bOpen = true;
return bOpen;
}
int DataStreamSerial::recv(void* buffer, size_t size)
{
std::cout << "DataStreamSerial::recv()..." << std::endl;
Sleep(5000);
return 100;
}
bool DataStreamSerial::send(const void* data, size_t length)
{
std::cout << "DataStreamSerial::send()..." << std::endl;
return true;
}
void DataStreamSerial::close()
{
std::cout << "DataStreamSerial::close()..." << std::endl;
bOpen = false;
return;
}
DataTransfer
数据处理的通用逻辑,为了便于理解,这里给出了具体的实现代码。
/**
******************************************************************************
* @文件 DataTransfer.h
* @版本 V1.0.0
* @日期
* @概要 数据传输实现
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#ifndef __DATA_TRANSFER_H
#define __DATA_TRANSFER_H
#include <queue>
#include <mutex>
#include <thread>
#include <cstddef>
#include <functional>
#include <condition_variable>
#include "DataCodec/IDataCodec.h"
#include "DataStream/IDataStream.h"
class DataTransfer
{
public:
// 传输状态定义
typedef enum {
DATA_TRANSFER_STATE_NORMAL = 0, // 传输正常
DATA_TRANSFER_STATE_START = 1, // 传输启动
DATA_TRANSFER_STATE_STOP = 2, // 传输停止
DATA_TRANSFER_STATE_OTHER_ERROR = 3, // 传输失败, 其它错误
DATA_TRANSFER_STATE_VERIFY_ERROR = 4, // 传输失败, 校验错误
DATA_TRANSFER_STATE_MEMORY_ERROR = 5, // 传输失败, 申请内存空间失败
DATA_TRANSFER_STATE_RAWDATA_ERROR = 6, // 传输失败, 原始数据接收错误
}DATA_TRANSFER_STATE_E;
const char* toString(DATA_TRANSFER_STATE_E state); // 传输状态转换为可读性更高的字符串
// 接收到数据通知回调原型
typedef std::function<void(DATA_TRANSFER_STATE_E state, void* pdata, size_t length)> TDataRecvNotice;
private:
std::shared_ptr<IDataStream> pDataStream; // 具体的数据流(可以是网络\串口\USB\I2C等等)
std::shared_ptr<IDataCodec> pDataCodec; // 具体的数据编解码(对应不同的通讯协议)
size_t nConfigBufferSize; // 数据收发缓冲区大小
private:
TDataRecvNotice onDataRecvNotice; // 数据接收状态通知回调
void notice(DATA_TRANSFER_STATE_E state, void* pdata = NULL, size_t length = 0);
private:
void* pSendBuffer; // 发送数据缓冲区
std::mutex mMutexTransfer; // 传输数据互斥体, 实现线程安全
std::queue<uint8_t> mQueueRawData; // 存储原始数据的队列
std::mutex mMutexQueueRawData; // 原始数据队列互斥体, 用于同步接收线程和处理线程
std::condition_variable mCondQueueDataReady; // 用于通知和唤醒处理线程, 表明数据已经就绪
std::thread mThreadRecvRawData; // 原始数据接收线程
std::thread mThreadRecvDataProcess; // 数据解码处理线程
static void onThreadRecvRawData(DataTransfer* pContex);
static void onThreadRecvDataProcess(DataTransfer* pContex);
public:
/*************************************************************
* 函数: DataTransfer
* 功能: 初始化数据传输对象
* 参数:
* pStream: 具体的数据流对象
* pCodec: 具体的数据编解码器
* onNotice: 数据接收通知, 有数据时或传输状态变化时会通过此回调回传
* nBufferSize: 数据缓冲区的大小, 用于指定接收和发送缓冲区
* 返回值: 无
**************************************************************/
DataTransfer(std::shared_ptr<IDataStream> pStream, std::shared_ptr<IDataCodec> pCodec, TDataRecvNotice onNotice, size_t nBufferSize = 2048);
/*************************************************************
* 函数: InitAndStart
* 功能: 初始化并启动数据监听
* 参数: 无
* 返回值: 无
**************************************************************/
bool initAndStart();
/*************************************************************
* 函数: StopAndRelease
* 功能: 停止数据监听并释放相关资源
* 参数: 无
* 返回值: 无
**************************************************************/
bool stopAndRelease();
/*************************************************************
* 函数: Transfer
* 功能: 要传输的数据, 会通过初始化指定的编码器进行编码, 并通过初始化指定的数据流对象发送出去
* 参数:
* pdata: 要发送的数据
* length: 所发送数据的长度
* 返回值: 无
**************************************************************/
bool transfer(const void* pdata, size_t length);
};
#endif
/**
******************************************************************************
* @文件 DataTransfer.cpp
* @版本 V1.0.0
* @日期
* @概要 数据传输
* @作者 lmx
******************************************************************************
* @注意
*
******************************************************************************
*/
#include <stdlib.h>
#include <string.h>
#include "DataTransfer.h"
/*************************************************************
* 函数: DataTransfer
* 功能: 初始化数据传输对象
* 参数:
* pStream: 具体的数据流对象
* pCodec: 具体的数据编解码器
* onNotice: 数据接收通知, 有数据时或传输状态变化时会通过此回调回传
* nBufferSize: 数据缓冲区的大小, 用于指定接收和发送缓冲区
* 返回值: 无
**************************************************************/
DataTransfer::DataTransfer(std::shared_ptr<IDataStream> pStream, std::shared_ptr<IDataCodec> pCodec, TDataRecvNotice onNotice, size_t nBufferSize)
{
pSendBuffer = NULL;
pDataStream = pStream;
pDataCodec = pCodec;
onDataRecvNotice = onNotice;
nConfigBufferSize = nBufferSize;
}
// 接收数据通知
void DataTransfer::notice(DATA_TRANSFER_STATE_E state, void* pdata, size_t length)
{
if (onDataRecvNotice) {
onDataRecvNotice(state, pdata, length);
}
}
// 原始数据接收线程
void DataTransfer::onThreadRecvRawData(DataTransfer* pContex)
{
void* pRecvBuffer = NULL;
int nRecvByte = 0;
// 申请内存空间用于存储原始数据
pRecvBuffer = (void*)malloc(pContex->nConfigBufferSize);
if (NULL == pRecvBuffer) {
pContex->notice(DATA_TRANSFER_STATE_MEMORY_ERROR);
pContex->notice(DATA_TRANSFER_STATE_STOP);
return;
}
while (pContex->pDataStream->isOpen())
{
// 从数据流中接收原始数据
memset(pRecvBuffer, 0, pContex->nConfigBufferSize);
nRecvByte = pContex->pDataStream->recv(pRecvBuffer, pContex->nConfigBufferSize);
if (!pContex->pDataStream->isOpen()) {
break;
}
// 如果出错则通知业务逻辑
if (nRecvByte < 0) {
pContex->notice(DATA_TRANSFER_STATE_RAWDATA_ERROR);
continue;
}
// 将收到的数据, 写入队列
std::unique_lock< std::mutex > lock(pContex->mMutexQueueRawData);
for (int i = 0; i < nRecvByte; i++) {
pContex->mQueueRawData.push(((uint8_t*)pRecvBuffer)[i]);
}
lock.unlock();
// 通知数据解析线程
pContex->mCondQueueDataReady.notify_one();
}
pContex->notice(DATA_TRANSFER_STATE_STOP);
free(pRecvBuffer);
return;
}
// 数据解码线程
void DataTransfer::onThreadRecvDataProcess(DataTransfer* pContex)
{
std::queue<uint8_t> mQueueRawData;
void* pDataBuffer = NULL;
unsigned char data = 0;
int nDecodeByte = 0;
// 用于存储解码出来的数据
pDataBuffer = malloc(pContex->nConfigBufferSize);
if (NULL == pDataBuffer) {
pContex->notice(DATA_TRANSFER_STATE_MEMORY_ERROR);
pContex->notice(DATA_TRANSFER_STATE_STOP);
return;
}
// 进入数据解码流程
pContex->pDataCodec->reset();
while (pContex->pDataStream->isOpen())
{
// 获得锁之后判断数据流是否有效, 无效则需要退出, 避免线程在 wait 之前被 notify_all
std::unique_lock< std::mutex > lock(pContex->mMutexQueueRawData);
if (!pContex->pDataStream->isOpen()) {
break;
}
// 再次确认队列数据中没有数据了, 再进入等待状态, 如果有则意味着解码的过程仍收到数据, 需要继续解码
if (pContex->mQueueRawData.empty()) {
pContex->mCondQueueDataReady.wait(lock);
if (!pContex->pDataStream->isOpen()) { // 被唤醒之后仍需要先判断数据流是否有效, 无效则直接退出循环
break;
}
}
// 拷贝数据及时释放数据锁, 避免影响数据接收线程的实时性
mQueueRawData = pContex->mQueueRawData;
pContex->mQueueRawData = std::queue<uint8_t>();
lock.unlock();
// 开始进行数据解码
while (!mQueueRawData.empty())
{
data = mQueueRawData.front();
mQueueRawData.pop();
// 逐个字节进行解码
nDecodeByte = pContex->pDataCodec->decode(data, pDataBuffer, pContex->nConfigBufferSize);
if (nDecodeByte > 0) {
pContex->notice(DATA_TRANSFER_STATE_NORMAL, pDataBuffer, nDecodeByte);
continue;
}
// 解码的数据超出缓冲区大小
if (-1 == nDecodeByte) {
pContex->notice(DATA_TRANSFER_STATE_MEMORY_ERROR);
continue;
}
// 解码的数据校验不通过
if (-2 == nDecodeByte) {
pContex->notice(DATA_TRANSFER_STATE_VERIFY_ERROR);
continue;
}
// 其它错误
if (nDecodeByte < 0) {
pContex->notice(DATA_TRANSFER_STATE_OTHER_ERROR);
continue;
}
}
}
free(pDataBuffer);
return;
}
// 数据传输
bool DataTransfer::transfer(const void* pdata, size_t length)
{
int nEncodeByte = 0;
bool bSendResult = false;
// 此接口极有可能是被并发调用, 因此需要上锁确保共享缓冲区不被破坏
// 也可以避免同时调用了 StopAndRelease() 接口所引发的异常
mMutexTransfer.lock();
if (pDataStream->isOpen()) {
nEncodeByte = pDataCodec->encode(pdata, length, pSendBuffer, nConfigBufferSize);
if (nEncodeByte) {
bSendResult = pDataStream->send(pSendBuffer, nEncodeByte);
}
}
mMutexTransfer.unlock();
return bSendResult;
}
/*************************************************************
* 函数: InitAndStart
* 功能: 初始化并启动数据监听
* 参数: 无
* 返回值: 无
**************************************************************/
bool DataTransfer::initAndStart()
{
// 参数检查
if (NULL == pDataStream || NULL == pDataCodec || 0 == nConfigBufferSize || pSendBuffer) {
return false;
}
// 打开数据流
if (pDataStream->open() == false) {
return false;
}
// 申请内存空间用于发送数据缓冲区
pSendBuffer = malloc(nConfigBufferSize);
if (NULL == pSendBuffer) {
pDataStream->close();
return false;
}
// 创建数据流处理线程
mThreadRecvRawData = std::thread(onThreadRecvRawData, this);
mThreadRecvDataProcess = std::thread(onThreadRecvDataProcess, this);
notice(DATA_TRANSFER_STATE_START);
return true;
}
/*************************************************************
* 函数: StopAndRelease
* 功能: 停止数据监听并释放相关资源
* 参数: 无
* 返回值: 无
**************************************************************/
bool DataTransfer::stopAndRelease()
{
mMutexTransfer.lock();
if (pDataStream->isOpen())
{
mMutexQueueRawData.lock();
pDataStream->close();
mCondQueueDataReady.notify_all();
mMutexQueueRawData.unlock();
mThreadRecvRawData.join();
mThreadRecvDataProcess.join();
if (pSendBuffer) {
free(pSendBuffer);
pSendBuffer = NULL;
}
}
mMutexTransfer.unlock();
return true;
}
/*************************************************************
* 函数: toString
* 功能: 用于将状态转换为字符串的方式输出
* 参数:
* state: 传入要转换字符串的状态
* 返回值: 无
**************************************************************/
const char* DataTransfer::toString(DATA_TRANSFER_STATE_E state)
{
switch (state)
{
case DATA_TRANSFER_STATE_NORMAL:
return "DATA_TRANSFER_STATE_NORMAL";
case DATA_TRANSFER_STATE_START:
return "DATA_TRANSFER_STATE_START";
case DATA_TRANSFER_STATE_STOP:
return "DATA_TRANSFER_STATE_STOP";
case DATA_TRANSFER_STATE_OTHER_ERROR:
return "DATA_TRANSFER_STATE_OTHER_ERROR";
case DATA_TRANSFER_STATE_VERIFY_ERROR:
return "DATA_TRANSFER_STATE_VERIFY_ERROR";
case DATA_TRANSFER_STATE_MEMORY_ERROR:
return "DATA_TRANSFER_STATE_MEMORY_ERROR";
case DATA_TRANSFER_STATE_RAWDATA_ERROR:
return "DATA_TRANSFER_STATE_RAWDATA_ERROR";
}
return "Undefined String";
}
应用示例
/**
******************************************************************************
* @文件 DeviceCi110x.h
* @版本 V1.0.0
* @日期
* @概要 Ci110x 设备操作接口
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#ifndef __DEVICE_CI110X_H
#define __DEVICE_CI110X_H
#include "../DataTransfer/DataTransfer.h"
#include "../DataTransfer/DataCodec/DataCodecCi110x.h"
#include "../DataTransfer/DataStream/DataStreamSerial.h"
class DeviceCi110x
{
private:
#define DATA_TRANSFER_BUFFER_SIZE (2048)
std::shared_ptr<DataTransfer> spDataTransfer;
void onDataRecvNotice(DataTransfer::DATA_TRANSFER_STATE_E state, void* pdata, size_t length);
public:
bool init(const char* devpath);
void release();
bool setAsrMode(bool en);
};
#endif
/**
******************************************************************************
* @文件 DeviceCi110x.h
* @版本 V1.0.0
* @日期
* @概要 Ci110x 设备操作接口
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#include <iostream>
#include "DeviceCi110x.h"
void DeviceCi110x::onDataRecvNotice(DataTransfer::DATA_TRANSFER_STATE_E state, void* pdata, size_t length)
{
std::cout << "DataTransfer State:" << spDataTransfer->toString(state) << std::endl;
}
bool DeviceCi110x::init(const char* devpath)
{
std::shared_ptr<DataCodecCi110x> pCodecCi110x = std::make_shared<DataCodecCi110x>();
std::shared_ptr<DataStreamSerial> pStreamSerial = std::make_shared<DataStreamSerial>();
DataTransfer::TDataRecvNotice onDataRecvNotice = std::bind(&DeviceCi110x::onDataRecvNotice, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
pStreamSerial->setParameter(devpath, 115200, 8, 1);
spDataTransfer = std::make_shared<DataTransfer>(pStreamSerial, pCodecCi110x, onDataRecvNotice, DATA_TRANSFER_BUFFER_SIZE);
return spDataTransfer->initAndStart();
}
void DeviceCi110x::release()
{
spDataTransfer->stopAndRelease();
}
bool DeviceCi110x::setAsrMode(bool en)
{
const char data[10] = { 0 };
return spDataTransfer->transfer(data, sizeof(data));
}
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <windows.h>
#include <iostream>
#include "Devices/DeviceCi110x.h"
int main()
{
DeviceCi110x mDeviceCi110x;
mDeviceCi110x.init("/dev/ttyS1");
mDeviceCi110x.setAsrMode(true);
Sleep(3000);
mDeviceCi110x.release();
return 0;
}
更多推荐
所有评论(0)