linux CAN程式設計(二)----------- can_frame中can_id的資料組織形式及處理
轉載自:https://blog.csdn.net/qwaszx523/article/details/54984544
/**
* struct can_frame - basic CAN frame structure
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
* mapping of the 'data length code' to the real payload length
* @data: CAN frame payload (up to 8 byte)
*/
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
};
can_id定義如下所示,是一個無符號的32位整形數
typedef __u32 canid_t;
can_id資料組織形式如下
/*
* Controller Area Network Identifier structure
*
* bit 0-28 : CAN identifier (11/29 bit)
* bit 29 : error message frame flag (0 = data frame, 1 = error message)
* bit 30 : remote transmission request flag (1 = rtr frame)
* bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
*/
0-28位為識別符號,如果是擴充套件幀,則高11位為標準ID
29位標識是資料幀還是錯誤訊息
30位說明是否是遠端幀
31位說明是標準幀還是擴充套件幀。
以下是在處理can_frame時用到的掩碼和識別符號:
/* special address description flags for the CAN_ID */
#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
#define CAN_ERR_FLAG 0x20000000U /* error message frame */
/* valid bits in CAN ID for frame formats */
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
對can_frame的處理是在mcp251x_hw_tx中進行的,如下:
static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
int tx_buf_idx)
{
struct mcp251x_priv *priv = spi_get_drvdata(spi);
u32 sid, eid, exide, rtr;
u8 buf[SPI_TRANSFER_BUF_LEN];
exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; //取can_id的31位,判斷是標準幀還是擴充套件幀
if (exide)
sid = (frame->can_id & CAN_EFF_MASK) >> 18;//如果是擴充套件幀,can_id的0-28位為ID,其中高11位為標準ID
else
sid = frame->can_id & CAN_SFF_MASK; /* Standard ID */
eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* 是否是遠端幀*/
buf[TXBCTRL_OFF] = INSTRUCTION_LOAD_TXB(tx_buf_idx); //傳送緩衝器控制暫存器地址
buf[TXBSIDH_OFF] = sid >> SIDH_SHIFT; //傳送緩衝器標準ID高8位
//5-7位存放傳送緩衝器低3位,3位存放幀格式,0-1位存放擴充套件識別符號低18位的高兩位(16-17)
buf[TXBSIDL_OFF] = ((sid & SIDL_SID_MASK) << SIDL_SID_SHIFT) | (exide << SIDL_EXIDE_SHIFT) | ((eid >> SIDL_EID_SHIFT) & SIDL_EID_MASK);
buf[TXBEID8_OFF] = GET_BYTE(eid, 1); //存放擴充套件識別符號低18位的8-15位
buf[TXBEID0_OFF] = GET_BYTE(eid, 0); //擴充套件識別符號低18位的低8位(0-7)
buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc; //6位存放遠端幀識別符號,0-3存放資料長度碼
memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);//拷貝要傳送的資料
mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);
/* use INSTRUCTION_RTS, to avoid "repeated frame problem" */
priv->spi_tx_buf[0] = INSTRUCTION_RTS(1 << tx_buf_idx);
mcp251x_spi_trans(priv->spi, 1);
}
static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
int buf_idx)
{
struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (mcp251x_is_2510(spi)) {
int i, len;
for (i = 1; i < RXBDAT_OFF; i++)
buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
len = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);
for (; i < (RXBDAT_OFF + len); i++)
buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
} else {
priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
}
}
---------------------
作者:qwaszx523
來源:CSDN
原文:https://blog.csdn.net/qwaszx523/article/details/54984544
版權宣告:本文為博主原創文章,轉載請附上博文連結!