123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- /*********************************************************************
- *
- * J1939 Main Source Code
- *
- *********************************************************************
- *
- * 本程序是由XieTongXueFlyMe对现有的J1939协议文档分析,和对前辈的贡献总结,
- * 写出的一套开源的J1939驱动。
- * 本协议特点:
- * 1.易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可)
- * 2.轻量级(可适应低端的MCU)
- * 3.支持多任务调用接口(可用于嵌入式系统)
- * 4.双模式(轮询或者中断,逻辑更加简单明了)
- * 5.不掉帧(数据采用收发列队缓存)
- *
- * 源代码下载:
- * https://github.com/XeiTongXueFlyMe/J1939
- * 源代码临时手册Web站点:
- * https://xeitongxueflyme.github.io/j1939doc.github.io/
- *
- * Version Date Description
- * -------------------------------------------------------------------
- * v1.0.0 2017/06/04 首个版本 Version 1 测试版发布
- * v1.0.1 2017/08/04 完善功能
- * v1.1.0 2017/11/22 Version 1 稳定发布版
- * v2.0.1 2017/11/24 Version 2 测试版发布
- * v2.0.2 2018/01/03 解决V2.0.1 遗留问题
- * v2.1.0 2018/01/20 Version 2 稳定发布版
- * Author Date changes
- *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *XeiTongXueFlyMe 7/06/04 首个版本
- *XeiTongXueFlyMe 7/08/04 增加对TP的支持
- *XeiTongXueFlyMe 7/11/24 增加对多路CAN硬件的收发,和报文处理
- *XeiTongXueFlyMe 7/11/29 增加请求和响应API
- *XeiTongXueFlyMe 7/12/07 重做TP接受API函数
- *XeiTongXueFlyMe 7/12/08 增加软件滤波器
- *XeiTongXueFlyMe 8/01/03 重做接受发送API,简化协议栈初始化调用逻辑
- **********************************************************************/
- #ifndef __J1939_H
- #define __J1939_H
- /******************************类型声明*********************************/
- #define FALSE 0
- #define TRUE 1
- /** 统一类型定义
- * 不同的单片机的编译器, int,short,long 的位数可能不同
- *
- * 在移植J1939协议栈时,首先应该配置这里
- */
- typedef unsigned int j1939_uint32_t; /** < 32位无符号整形*/
- typedef int j1939_int32_t; /** < 32位整形*/
- typedef unsigned short j1939_uint16_t; /** < 16位无符号整形*/
- typedef unsigned char j1939_uint8_t; /** < 8位无符号整形*/
- typedef char j1939_int8_t; /** < 8位无符号整形*/
- #define J1939_NULL 0
- // 函数返回代码
- #define RC_SUCCESS 0 /**< 成功*/
- #define RC_QUEUEEMPTY 1 /**< 列队为空*/
- #define RC_QUEUEFULL 1 /**< 列队满*/
- #define RC_CANNOTRECEIVE 2 /**< 不能接收*/
- #define RC_CANNOTTRANSMIT 2 /**< 不能传输*/
- #define RC_PARAMERROR 3 /**< 参数错误*/
- // 内部常量
- #define J1939_FALSE 0 /**< 代表函数错误返回*/
- #define J1939_TRUE 1 /**< 代表函数正确返回*/
- // J1939 默认的优先级(参考J1939文档)
- #define J1939_CONTROL_PRIORITY 0x03 /**< J1939文档默认的优先级*/
- #define J1939_INFO_PRIORITY 0x06 /**< J1939文档默认的优先级*/
- #define J1939_PROPRIETARY_PRIORITY 0x06 /**< J1939文档默认的优先级*/
- #define J1939_REQUEST_PRIORITY 0x06 /**< J1939文档默认的优先级*/
- #define J1939_ACK_PRIORITY 0x06 /**< J1939文档默认的优先级*/
- #define J1939_TP_CM_PRIORITY 0x07 /**< J1939文档默认的优先级*/
- #define J1939_TP_DT_PRIORITY 0x07 /**< J1939文档默认的优先级*/
- // J1939 定义的地址
- #define J1939_GLOBAL_ADDRESS 255 /**< 全局地址*/
- #define J1939_NULL_ADDRESS 254 /**< 空地址*/
- // J1939协议栈的PNG请求响应,相关的定义
- #define J1939_PF_REQUEST2 201 /**< J1939协议栈的请求 PF */
- #define J1939_PF_TRANSFER 202 /**< J1939协议栈的转移 PF */
- #define J1939_PF_REQUEST 234 /**< 请求 或 用于握手机制*/
- #define J1939_PF_ACKNOWLEDGMENT 232 /**< 确认请求 或 用于握手机制*/
- #define J1939_ACK_CONTROL_BYTE 0 /**< 用于TP(长帧数据),代表确认*/
- #define J1939_NACK_CONTROL_BYTE 1 /**< 用于TP(长帧数据),PNG不被支持。否定消息*/
- #define J1939_ACCESS_DENIED_CONTROL_BYTE 2 /**< 拒绝访问,但是信息是被支持,暂时不能响应(需要再次发送请求)*/
- #define J1939_CANNOT_RESPOND_CONTROL_BYTE 3 /**< 不能做出反应,有空但是接受的缓存不够,或则发送资源被占领,暂时不能响应(需要再次发送请求)*/
- // TP协议的一些宏定义
- #define J1939_PF_DT 235 /**< 协议传输---数据传输 PF*/
- #define J1939_PF_TP_CM 236 /**< 协议传输---链接管理 PF*/
- // TP的超时时间,单位(ms)
- #define J1939_TP_Tr 200 /**< 宏定义TP的超时时间*/
- #define J1939_TP_Th 500 /**< 宏定义TP的超时时间*/
- #define J1939_TP_T1 750 /**< 宏定义TP的超时时间*/
- #define J1939_TP_T2 1250 /**< 宏定义TP的超时时间*/
- #define J1939_TP_T3 1250 /**< 宏定义TP的超时时间*/
- #define J1939_TP_T4 1050 /**< 宏定义TP的超时时间*/
- #define J1939_TP_TIMEOUT_NORMAL 0 /**< 未超时正常*/
- #define J1939_TP_TIMEOUT_ABNORMAL 1 /**< 超时*/
- #define J1939_RTS_CONTROL_BYTE 16 /**< TP.CM_RTS*/
- #define J1939_CTS_CONTROL_BYTE 17 /**< TP.CM_CTS*/
- #define J1939_EOMACK_CONTROL_BYTE 19 /**< 消息应答结束*/
- #define J1939_BAM_CONTROL_BYTE 32 /**< 广播公告消息*/
- #define J1939_CONNABORT_CONTROL_BYTE 255 /**< 连接中断控制字节(放弃连接)*/
- #define J1939_RESERVED_BYTE 0xFF /**< 变量的保留位的值*/
- // 与J1939网络层有关的定义
- #define J1939_PGN2_REQ_ADDRESS_CLAIM 0x00
- #define J1939_PGN1_REQ_ADDRESS_CLAIM 0xEA
- #define J1939_PGN0_REQ_ADDRESS_CLAIM 0x00
- #define J1939_PGN2_COMMANDED_ADDRESS 0x00
- #define J1939_PGN1_COMMANDED_ADDRESS 0xFE /**< 命令地址消息*/
- #define J1939_PGN0_COMMANDED_ADDRESS 0xD8 /**< 参考J1939-81 地址命令配置*/
- #define J1939_PF_ADDRESS_CLAIMED 238
- #define J1939_PF_CANNOT_CLAIM_ADDRESS 238
- #define J1939_PF_PROPRIETARY_A 239 /**< 专用A*/
- #define J1939_PF_PROPRIETARY_B 255 /**< 专用B*/
- /**< 是否对TP协议的支持(是否支持长帧(大于8字节的数据)的发送与接受)*/
- #define J1939_TP_RX_TX J1939_TRUE
- /**< TP协议的支持的最大接受发送消息长度(最大可配置为1785)*/
- #define J1939_TP_MAX_MESSAGE_LENGTH 240
- /**CAN节点的选择枚举
- *
- * 默认支持最大4路CAN硬件\n
- */
- typedef enum
- {
- Select_CAN_NODE_Null, /**< 不选择任何CAN硬件*/
- Select_CAN_NODE_1, /**< 选择CAN硬件 1*/
- Select_CAN_NODE_2, /**< 选择CAN硬件 2*/
- Select_CAN_NODE_3, /**< 选择CAN硬件 3*/
- Select_CAN_NODE_4, /**< 选择CAN硬件 4*/
- } CAN_NODE;
- #if J1939_TP_RX_TX
- /**TP的状态描述枚举
- *
- */
- typedef enum
- {
- J1939_TP_NULL, /**< 长数据传输处于空闲,只有TP系统处于空闲,才能用处理下一个发送,和接受请求*/
- J1939_TP_RX, /**< 长数据传输处于接收*/
- J1939_TP_TX, /**< 长数据传输处于发送*/
- J1939_TP_OSBUSY, /**< 长数据传输处于繁忙,比如刚接受一整段长数据,但是CPU没来得处理,又一个长数据请求到来,为了数据不被覆盖,将状态设为本值*/
- } J1939_TP_State;
- /**TP的标志位结构体
- *
- * 本结构体记录了TP的状态,使用TP发送和接受的CAN硬件编号
- */
- typedef struct
- {
- J1939_TP_State state; /**< TP的连接状态*/
- CAN_NODE TP_RX_CAN_NODE; /**< TP接受请求产生的 CAN硬件编号*/
- CAN_NODE TP_TX_CAN_NODE; /**< TP接受发送产生的 CAN硬件编号*/
- } J1939_TP_Flags;
- /**J1939消息对象的结构体
- *
- * 本结构体实现了 J1939的消息对象
- */
- typedef struct
- {
- j1939_uint32_t PGN; /**< J1939的消息对象的 PGN*/
- j1939_uint8_t data[J1939_TP_MAX_MESSAGE_LENGTH]; /**< J1939的消息对象的 数据*/
- j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/
- j1939_uint8_t SA; /**< J1939的消息对象的 目标地址(发送目的地 或 接受来源地)*/
- } J1939_MESSAGE_T;
- /**J1939消息对象的结构体
- *
- * 本结构体实现了 J1939的多帧消息对象
- */
- typedef struct
- {
- j1939_uint8_t *data; /**< 缓存区指针*/
- j1939_uint16_t data_num; /**< 缓存区大小*/
- j1939_uint8_t SA; /**< J1939的消息对象的 数据 源地址*/
- j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/
- j1939_uint32_t PGN; /**< J1939的消息对象的 PGN*/
- } TP_RX_MESSAGE;
- /**J1939_TP_Tx_Step枚举
- *
- * 实现了记录长帧(多帧)传输的TX 的步骤
- */
- typedef enum
- {
- J1939_TP_TX_WAIT,
- J1939_TP_TX_CM_START,
- J1939_TP_TX_CM_WAIT,
- J1939_TP_TX_DT,
- J1939_TP_WAIT_ACK,
- J1939_TP_TX_ERROR,
- J1939_TX_DONE,
- } J1939_TP_Tx_Step; // 协议的发送步骤
- /**J1939_TRANSPORT_TX_INFO 结构体
- *
- * 实现了长帧传输中产生的临时数据,和一些传输交换数据
- */
- typedef struct
- {
- J1939_MESSAGE_T tp_tx_msg; /**< J1939的消息对象*/
- j1939_uint16_t time; /**< 时间*/
- j1939_uint8_t packet_offset_p; /**< 数据包偏移指针*/
- j1939_uint8_t packets_total; /**< 总共有多少个数据包*/
- j1939_uint8_t packets_request_num; /**< 请求发送的数据包数(接受方准备接受的数据包数)*/
- J1939_TP_Tx_Step state; /**< 协议的发送步骤*/
- } J1939_TRANSPORT_TX_INFO;
- /**J1939_TP_Rx_Step枚举
- *
- * 实现了记录长帧(多帧)传输的RX 的步骤
- */
- typedef enum
- {
- J1939_TP_RX_WAIT,
- J1939_TP_RX_READ_DATA,
- J1939_TP_RX_DATA_WAIT,
- J1939_TP_RX_ERROR,
- J1939_RX_DONE,
- } J1939_TP_Rx_Step; // 协议的接收步骤
- /**J1939_TRANSPORT_RX_INFO 结构体
- *
- * 实现了长帧传输中产生的临时数据,和一些传输交换数据
- */
- typedef struct
- {
- J1939_MESSAGE_T tp_rx_msg; /**< J1939的消息对象*/
- j1939_uint8_t osbusy; /**< 此位置1,代表系统繁忙,cpu需要处理其他的事物,直接拒绝一切的链接请求\n 如果正在接受中,此位置1,则会发出链接保持消息帧。*/
- j1939_uint16_t time; /**< 时间*/
- j1939_uint8_t packets_total; /**< 总共有多少个数据包*/
- j1939_uint8_t packets_ok_num; /**< 已经接受的数据包数*/
- J1939_TP_Rx_Step state; /**< 协议的接受步骤*/
- } J1939_TRANSPORT_RX_INFO;
- #endif // J1939_TP_RX_TX
- /**
- * @note 实现Request_PGN 的响应
- */
- struct Request_List
- {
- j1939_uint8_t *data;
- j1939_uint16_t lenght;
- j1939_uint32_t PGN;
- CAN_NODE Can_Node;
- void (*update)(); /**< 在函数里需要对data更新,如果不用更新data赋值为J1939_NULL*/
- struct Request_List *next; /**< 链表末尾,需要一直保持J1939_NULL*/
- };
- // J1939 Data Structures
- // J1939_MESSAGE_STRUCT旨在J1939消息块映射到设备的地址映射。 只有字段PDU格式不映射到设备寄存器。
- // 结构应该简单地使用PDUFormat和忽视PDUFormat_Top。调整将立即接收和传输之前。
- // 注:编译器创建结构从低一点的位置高一些位置,所以可能出现不匹配的设备寄存器。
- #define J1939_MSG_LENGTH 9 // 消息长度
- #define J1939_DATA_LENGTH 8 // 数据长度
- /** J1939_MESSAGE_UNION 结构体
- * 实现了J1939消息对象
- *
- *
- */
- union J1939_MESSAGE_UNION
- {
- /** j1939 的 ID 组成结构体
- *
- */
- struct j1939_PID
- {
- j1939_uint8_t DataPage : 1; /**< 数据页*/
- j1939_uint8_t Res : 1; /**< Res位*/
- j1939_uint8_t Priority : 3; /**< 优先级*/
- j1939_uint8_t Reserve : 3; /**< 空闲*/
- j1939_uint8_t PDUFormat; /**< PF*/
- j1939_uint8_t PDUSpecific; /**< PS*/
- j1939_uint8_t SourceAddress; /**< SA*/
- j1939_uint8_t DataLength : 4; /**< 数据长度*/
- j1939_uint8_t RTR : 4; /**< RTR位*/
- j1939_uint8_t Data[J1939_DATA_LENGTH]; /**< 数据*/
- j1939_uint32_t PGN : 24; /**< 参数群编号*/
- j1939_uint32_t ReservePGN : 8; /**< 空闲*/
- };
- struct j1939_PID Mxe; /**< j1939 的 ID 组成结构体*/
- j1939_uint8_t Array[J1939_MSG_LENGTH + J1939_DATA_LENGTH]; /**< 联合体数组,方便快速处理结构体赋值*/
- };
- #define GroupExtension PDUSpecific
- #define DestinationAddress PDUSpecific
- /** 一个宏定义,具体变量名称作用命名
- *
- */
- typedef union J1939_MESSAGE_UNION J1939_MESSAGE;
- union J1939_FLAGS_UNION
- {
- struct
- {
- j1939_uint8_t TransmitMessagesdCover : 1; // 发送数据时,J1939协议接受缓存有数据覆盖
- j1939_uint8_t ReceivedMessagesdCoverOrDroppedNode : 3;
- j1939_uint8_t ReceivedMessagesdCover : 1; // 接受数据时,J1939协议接受缓存有数据覆盖
- j1939_uint8_t ReceivedMessagesDropped : 1; // 接受数据时,J1939协议接受缓存有数据溢出
- };
- j1939_uint8_t FlagVal;
- };
- typedef union J1939_FLAGS_UNION J1939_FLAG;
- /********************************************API**************************************************************/
- // 初始化函数
- extern void J1939_Initialization();
- // CAN驱动收发中断入口
- extern void J1939_ISR();
- // 心跳函数,定时被调用
- extern void J1939_Poll();
- // 读取单帧消息
- extern j1939_uint8_t J1939_Read_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
- // 发送单帧消息
- extern j1939_uint8_t J1939_Send_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
- // 多帧(多组)消息发送函数 (RTS/CTS传输协议)
- extern j1939_int8_t J1939_TP_TX_Message(j1939_uint32_t PGN, j1939_uint8_t DA, j1939_uint8_t *data, j1939_uint16_t data_num, CAN_NODE _Can_Node);
- // 多帧(多组)消息接受函数 (RTS/CTS传输协议)
- extern j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node);
- // 请求获去一个PGN
- extern void J1939_Request_PGN(j1939_uint32_t pgn, j1939_uint8_t DA, CAN_NODE _Can_Node);
- // 创建一个PGN响应
- extern void J1939_Create_Response(j1939_uint8_t data[], j1939_uint16_t dataLenght, j1939_uint32_t PGN, void (*dataUPFun)(), CAN_NODE _Can_Node);
- #endif //__J1939_H
|