应用场景

在工作上经常会遇到需要对接多个外设,如离线语音识别芯片、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;
}


 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐