您好,登錄后才能下訂單哦!
在SylixOS中CAN報文的傳輸框圖如圖 11所示。
圖 11 SylixOS CAN報文傳輸框圖
(注:此文檔承接之前的文檔編寫,之前文檔中詳細介紹過的報文,傳輸結(jié)構(gòu)體在此文檔中不做詳細介紹。)
在SylixOS中CAN報文的傳輸不是底層和上層應(yīng)用的直接傳輸。而是在底層和應(yīng)用層中間加了一層系統(tǒng)緩存隊列。所有收發(fā)的CAN報文都要先經(jīng)過一個系統(tǒng)緩存機制傳輸?shù)秸嬲{(diào)用到它的地方。
SylixOS中CAN報文是以消息隊列的方式進行緩存的,程序清單 21是向消息隊列中寫入一幀CAN報文的具體實現(xiàn)。
程序清單 21從緩存中讀取一幀CAN報文
/********************************************************************************************************* ** 函數(shù)名稱: __canITx ** 功能描述: 從發(fā)送緩沖區(qū)中讀出一個數(shù)據(jù) ** 輸 入 : ** pcanDev CAN 設(shè)備 ** pcanframe 指向待讀出的數(shù)據(jù) ** 輸 出 : ERROR_NONE or PX_ERROR ** 全局變量: ** 調(diào)用模塊: *********************************************************************************************************/ static INT __canITx (__CAN_DEV *pcanDev, PCAN_FRAME pcanframe) { INTREG iregInterLevel; INT iTemp = 0; if (!pcanDev || !pcanframe) { return (PX_ERROR); } iTemp = __canReadQueue(pcanDev, pcanDev->CAN_pcanqSendQueue, pcanframe, 1); /* 從發(fā)送隊列中讀取一幀數(shù)據(jù) */ LW_SPIN_LOCK_QUICK(&pcanDev->CAN_slLock, &iregInterLevel); if (iTemp <= 0) { pcanDev->CAN_canstatWriteState.CANSTAT_bBufEmpty = LW_TRUE; /* 發(fā)送隊列空 */ } LW_SPIN_UNLOCK_QUICK(&pcanDev->CAN_slLock, iregInterLevel); API_SemaphoreBPost(pcanDev->CAN_ulSendSemB); /* 釋放信號量 */ SEL_WAKE_UP_ALL(&pcanDev->CAN_selwulList, SELWRITE); /* 釋放所有等待寫的線程 */ return ((iTemp) ? (ERROR_NONE) : (PX_ERROR)); }
上層應(yīng)用向底層傳輸一幀CAN報文的時候也是通過系統(tǒng)緩存,向系統(tǒng)緩存中寫入一幀CAN報文的具體實現(xiàn)如程序清單 22所示。
程序清單 22向緩存中寫入一幀CAN報文
/********************************************************************************************************* ** 函數(shù)名稱: __canIRx ** 功能描述: 向接收緩沖區(qū)中寫入一個數(shù)據(jù) ** 輸 入 : ** pcanDev CAN 設(shè)備 ** pcanframe 指向待寫入的數(shù)據(jù) ** 輸 出 : ERROR_NONE or PX_ERROR ** 全局變量: ** 調(diào)用模塊: *********************************************************************************************************/ static INT __canIRx (__CAN_DEV *pcanDev, PCAN_FRAME pcanframe) { INT iTemp = 0; if (!pcanDev || !pcanframe) { return (PX_ERROR); } iTemp = __canWriteQueue(pcanDev, pcanDev->CAN_pcanqRecvQueue, pcanframe, 1); /* 往接收隊列中寫入一幀數(shù)據(jù) */ API_SemaphoreBPost(pcanDev->CAN_ulRcvSemB); /* 釋放信號量 */ SEL_WAKE_UP_ALL(&pcanDev->CAN_selwulList, SELREAD); /* select() 激活 */ return ((iTemp) ? (ERROR_NONE) : (PX_ERROR)); }
第一步:如程序清單 31所示,在應(yīng)用層創(chuàng)建一個線程,打開一個CAN設(shè)備。
程序清單 31打開CAN設(shè)備
iFd = open(devname, O_RDWR, 0666); if (iFd < 0) { printf("failed to open %s!\n", devname); return (LW_NULL); }
第二步:如程序清單 32所示,填充一個CAN報文結(jié)構(gòu)體。
程序清單 32填充CAN報文
CAN_FRAME canframe; canframe.CAN_bExtId = LW_FALSE; canframe.CAN_bRtr = LW_FALSE; canframe.CAN_ucLen = CAN_MAX_DATA; lib_memcpy((CHAR *)canframe.CAN_ucData, "01234567", CAN_MAX_DATA); canframe.CAN_uiId = 0;
第三步:如程序清單 33所示,調(diào)用write函數(shù)向系統(tǒng)TX緩存隊列中寫入一幀CAN報文,再調(diào)用ioctl函數(shù)實現(xiàn)底層傳輸。
程序清單 33填充發(fā)送緩存
stLen = write(iFd, &canframe, sizeof(CAN_FRAME)); ioctl(iFd, CAN_DEV_STARTUP, 0); case CAN_DEV_STARTUP: __flexcanStartup(pCanchan); break;
第四步:如程序清單 34所示,最終調(diào)用到底層傳輸函數(shù)。從系統(tǒng)隊列中讀取一幀CAN報文后對設(shè)備寄存器進行相關(guān)操作將消息傳輸?shù)娇偩€上。
程序清單 34底層starup函數(shù)
/********************************************************************************************************* ** 函數(shù)名稱: __flexcanStartup ** 功能描述: 啟動數(shù)據(jù)發(fā)送 ** 輸 入 : pCanchan 通道對象 ** 輸 出 : NONE ** 全局變量: ** 調(diào)用模塊: *********************************************************************************************************/ static INT __flexcanStartup (CAN_CHAN *pCanchan) { FLEXCAN_CHAN *pChannel = container_of(pCanchan, FLEXCAN_CHAN, CANCH_canchan); CAN_FRAME canFrame; INT iCount; if (!pChannel->CANCH_pcbGetTx) { return (PX_ERROR); } while (pChannel->CANCH_pcbGetTx(pChannel->CANCH_pvGetTxArg, /* 從發(fā)送緩沖區(qū)中讀取數(shù)據(jù)發(fā)送 */ &canFrame) == ERROR_NONE) { __flexcanSend(pChannel, &canFrame); } return (ERROR_NONE); }
注:如果想要發(fā)送多幀CAN報文,在寫入操作結(jié)束后需要加等待,以確保所有的CAN報文都成功寫入系統(tǒng)緩存隊列中。
第一步:底層如果接收到CAN報文以后,會觸發(fā)一次中斷,在中斷服務(wù)函數(shù)中所做的事就是判斷狀態(tài)標(biāo)志位置,如果是接收中斷,就把接收到的CAN報文通過回調(diào)函數(shù)寫入,系統(tǒng)緩存隊列中,具體實現(xiàn)如程序清單 35所示。
程序清單 35 CAN底層中斷服務(wù)函數(shù)
/********************************************************************************************************* ** 函數(shù)名稱: __flexcanIrq ** 功能描述: can 中斷服務(wù)程序 ** 輸 入 : pChannel 通道對象 ** ulVector 中斷向量號 ** 輸 出 : ERROR CODE ** 全局變量: ** 調(diào)用模塊: *********************************************************************************************************/ static irqreturn_t __flexcanIrq (PVOID pvArg, ULONG ulVector) { FLEXCAN_CHAN *pChannel; UINT32 uiIflag1, uiEsr, uiValue; CAN_FRAME canframe; can_debug("[CAN]irq\r\n"); pChannel = (FLEXCAN_CHAN *)pvArg; uiIflag1 = CAN_READ(FLEXCAN_IFLAG1); uiEsr = CAN_READ(FLEXCAN_ESR1); uiValue = CAN_READ(FLEXCAN_CTRL1); uiValue &= ~(FLEXCAN_CTRL1_ERR_ALL); CAN_WRITE(FLEXCAN_CTRL1, uiValue); CAN_WRITE(FLEXCAN_IMASK1, 0); if (uiEsr & FLEXCAN_ESR1_ERR_ALL) { can_debug("There is something wrong!\n"); CAN_READ(FLEXCAN_ESR1); CAN_WRITE(FLEXCAN_ESR1, FLEXCAN_ESR1_ERR_ALL); } if (uiEsr & FLEXCAN_ESR1_RX) { if (uiIflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) { CAN_WRITE(FLEXCAN_IMASK1, FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE); memset(&canframe, 0, sizeof(CAN_FRAME)); __flexcanRecv(pChannel, &canframe); if (pChannel->CANCH_pcbPutRcv(pChannel->CANCH_pvPutRcvArg, &canframe) != ERROR_NONE) { pChannel->CANCH_pcbSetBusState(pChannel->CANCH_pvSetBusStateArg, CAN_DEV_BUS_RXBUFF_OVERRUN); } } } if (uiIflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) { can_debug("FIFO overflow\n"); CAN_WRITE(FLEXCAN_IFLAG1, FLEXCAN_IFLAG_RX_FIFO_OVERFLOW); } CAN_WRITE(FLEXCAN_IMASK1, FLEXCAN_IFLAG_DEFAULT); return (LW_IRQ_HANDLED); }
第二步:在應(yīng)用程序中創(chuàng)建一個線程,在線程中所做的事情就是不間斷得讀取系統(tǒng)緩存的消息隊列。如果緩存不為空,就讀取里面的CAN報文,并打印,具體操作如程序清單 36所示。
程序清單 36 CAN應(yīng)用層讀取緩存
while (1) { stLen = read(iFd, &canframe, sizeof(STR_CANMSG_T)); stFrameNum = stLen / sizeof(STR_CANMSG_T); if (stFrameNum != 1) { printf("failed to recv can frame, abort recving!\n"); break; } else { sprintf(cFramInfo, "id=%d, len=%d, data=%02x %02x %02x %02x %02x %02x %02x %02x\n", canframe.Id, (INT)canframe.DLC, canframe.Data[0], canframe.Data[1], canframe.Data[2], canframe.Data[3], canframe.Data[4], canframe.Data[5], canframe.Data[6], canframe.Data[7]); printf(cFramInfo); } }
CAN報文傳輸流程,到此結(jié)束。
內(nèi)部交流文檔,若發(fā)現(xiàn)相關(guān)錯誤或者建議,請及時聯(lián)系文檔創(chuàng)建者進行修訂和更新。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。