CAN通信和信号量示例

#include <sys/ioctl.h>
#include <assert.h>
#include <mqueue.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include "ite/itp.h"
#include "project.h"
#include "scene.h"

#define RX_CAN0_PIN				27
#define TX_CAN0_PIN				28

CAN_HANDLE      *can0;
static volatile bool extQuit;
static mqd_t    uiMsgQueue = -1;		//UI更新消息队列
static mqd_t	ctrlMsgQueue = -1;		//下发控制器消息队列
static sem_t	sem;

CAN_FILTEROBJ FilterTable[16] = {	{ true, 0x0, 0x1FFFFFFF, false, false },//FILTER0
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER1
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER2
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER3
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER4
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER5
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER6
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER7
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER8
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER9
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER10
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER11 
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER12
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER13
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER14
									{ false, 0x0, 0x1FFFFFFF, false, false },//FILTER15                                 
};
		
// 接收CAN消息回调
static void CanRxCallback(void *arg1, uint32_t arg2)
{
	sem_post(&sem);
}

// 解析CAN帧
static EBike_Frame ParseFrameData(CAN_RXOBJ _rxObj)
{
	EBike_Frame frame;
	frame.Union_FrameId.frameId = _rxObj.Identifier;
	frame.dataLen = _rxObj.Control.DLC;
	memset(frame.data, 0, DLC_MAX);
	memcpy(frame.data, _rxObj.RXData, frame.dataLen);
	return frame;
}

// 创建CAN接收任务
static void* CanRecvHandle(void* arg)
{
	CAN_RXOBJ _rxObj;

	while (!extQuit)
	{
		sem_wait(&sem);
		if (ithCANRead(can0, &_rxObj) == 0)
		{
			printf("can0 ID[%x]: IDE = %x,DLC = %x, RTR = %x,RTS[0] = %x\n"
				, _rxObj.Identifier, _rxObj.Control.IDE, _rxObj.Control.DLC, _rxObj.Control.RTR, _rxObj.RXRTS[0]);
			printf("data[0-7]=%x %x %x %x %x %x %x %x\n", _rxObj.RXData[0], _rxObj.RXData[1], _rxObj.RXData[2], _rxObj.RXData[3]
				, _rxObj.RXData[4], _rxObj.RXData[5], _rxObj.RXData[6], _rxObj.RXData[7]);

			// 获取Can帧
			EBike_Frame frame = ParseFrameData(_rxObj);
			if (GetUpdateStatus() == true)
			{
				// 用于升级
				if (frame.Union_FrameId.msgTypeId == 0x05)
				{
					// 将数据推送到UI
					ExternalEvent evIn;
					memset(evIn.buf1, 0, EXTERNAL_BUFFER_SIZE);
					memcpy(evIn.buf1, &frame, sizeof(frame));
					SendUiMsgQueueInfo(&evIn);
				}
			}
			else
			{
				// 将数据推送到UI
				ExternalEvent evIn;
				memset(evIn.buf1, 0, EXTERNAL_BUFFER_SIZE);
				memcpy(evIn.buf1, &frame, sizeof(frame));
				SendUiMsgQueueInfo(&evIn);
			}
		}
	}

	ithCANClose(can0);
	free(can0);
	sem_destroy(&sem);
	return NULL;
}

static void* CanSendHandle(void* arg)
{
	CAN_TXOBJ _txObj;
	_txObj.Control.RTR = 0x0;
	_txObj.Control.IDE = 0x1;  // 扩展帧
	_txObj.TBSEL = 0x0;
	_txObj.SingleShot = 0x0;
	_txObj.TTSENSEL = 0x0;

	while (!extQuit)
	{
		ExternalEvent evIn;
		int flag = GetCtrlMsgQueueInfo(&evIn);
		// 获取消息失败
		if (!flag)
		{
			continue;
		}

		EBike_Frame *frame = (EBike_Frame*)evIn.buf1;
		_txObj.Identifier = frame->Union_FrameId.frameId;
		_txObj.Control.DLC = frame->dataLen;

		/*printf("_______FrameId: %x, Len: %d, Data: %x %x %x %x %x %x %x %x\n", frame->Union_FrameId.frameId, frame->dataLen, frame->data[0],
			frame->data[1], frame->data[2], frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]);*/

		// 通过Can发送命令给控制器或者更新UI
		if (ithCANWrite(can0, &_txObj, frame->data))
		{
			printf("can0 write fail, bus busy\n");
		}
	}

	ithCANClose(can0);
	free(can0);
	return NULL;
}

// 创建CAN对象
static void CreateCAN0()
{
	ithCANSetGPIO(0, RX_CAN0_PIN, TX_CAN0_PIN);
	can0 = (CAN_HANDLE *)malloc(sizeof(CAN_HANDLE));
	can0->Instance = 0;
	can0->ADDR = CAN0_BASE_ADDRESS;
	can0->BaudRate = CAN_250K_1M;
	can0->SourceClock = CAN_SRCCLK_60M;
	can0->ProtocolType = protocol_CAN_2_0B;
	can0->ExternalLoopBackMode = false;
	can0->InternalLoopBackMode = false;
	can0->ListenOnlyMode = false;
	can0->TPtr = FilterTable;
	ithCANOpen(can0, (void *)CanRxCallback, (void *)NULL);
}

// 接收到CAN消息,发送消息到Ui消息队列
int SendUiMsgQueueInfo(ExternalEvent* ev)
{
	assert(ev);

	return mq_send(uiMsgQueue, (char*)ev, sizeof(ExternalEvent), 0);
}

//主线程里循环获取UI队列信息
int GetUiMsgQueueInfo(ExternalEvent *ev)
{
	assert(ev);

	if (mq_receive(uiMsgQueue, (char*)ev, sizeof(ExternalEvent), 0) > 0)
		return 1;

	return 0;
}

// 按键下发CAN命令,发送消息到控制器消息队列
int SendCtrlMsgQueueInfo(ExternalEvent* ev)
{
	assert(ev);

	return mq_send(ctrlMsgQueue, (char*)ev, sizeof(ExternalEvent), 0);
}

// CAN消息写处理线程里循环获取控制器队列信息
int GetCtrlMsgQueueInfo(ExternalEvent *ev)
{
	assert(ev);

	if (mq_receive(ctrlMsgQueue, (char*)ev, sizeof(ExternalEvent), 0) > 0)
		return 1;

	return 0;
}

// 外部消息处理初始化
void ExternalInit()
{
	// 创建消息队列
	struct mq_attr qattr;
	qattr.mq_flags = 0;
	qattr.mq_maxmsg = 8;
	qattr.mq_msgsize = sizeof(ExternalEvent);
	uiMsgQueue = mq_open("UI_MsgQueue", O_CREAT | O_NONBLOCK, 0644, &qattr);
	assert(uiMsgQueue != -1);
	ctrlMsgQueue = mq_open("Ctrl_MsgQueue", O_CREAT | O_NONBLOCK, 0644, &qattr);
	assert(ctrlMsgQueue != -1);

	// 初始化信号量
	sem_init(&sem, 0, 0);

	// 创建Can通信对象
	CreateCAN0();
	pthread_attr_t attr;
	static pthread_t MsgRecvTaskId;
	static pthread_t MsgSendTaskId;
	extQuit = false;

	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	pthread_create(&MsgRecvTaskId, &attr, CanRecvHandle, NULL); // 创建CAN接收任务
	pthread_create(&MsgSendTaskId, &attr, CanSendHandle, NULL); // 创建CAN发送任务
}

// 发送CAN命令到控制器
void SendCmdToCtrl(EBike_Frame* frame)
{
	ExternalEvent evIn;
	memset(evIn.buf1, 0, EXTERNAL_BUFFER_SIZE);
	memcpy(evIn.buf1, frame, sizeof(EBike_Frame));
	SendCtrlMsgQueueInfo(&evIn);
}

void ExternalExit(void)
{
	extQuit = true;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值