J1939.H 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*********************************************************************
  2. *
  3. * J1939 Main Source Code
  4. *
  5. *********************************************************************
  6. *
  7. * 本程序是由XieTongXueFlyMe对现有的J1939协议文档分析,和对前辈的贡献总结,
  8. * 写出的一套开源的J1939驱动。
  9. * 本协议特点:
  10. * 1.易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可)
  11. * 2.轻量级(可适应低端的MCU)
  12. * 3.支持多任务调用接口(可用于嵌入式系统)
  13. * 4.双模式(轮询或者中断,逻辑更加简单明了)
  14. * 5.不掉帧(数据采用收发列队缓存)
  15. *
  16. * 源代码下载:
  17. * https://github.com/XeiTongXueFlyMe/J1939
  18. * 源代码临时手册Web站点:
  19. * https://xeitongxueflyme.github.io/j1939doc.github.io/
  20. *
  21. * Version Date Description
  22. * -------------------------------------------------------------------
  23. * v1.0.0 2017/06/04 首个版本 Version 1 测试版发布
  24. * v1.0.1 2017/08/04 完善功能
  25. * v1.1.0 2017/11/22 Version 1 稳定发布版
  26. * v2.0.1 2017/11/24 Version 2 测试版发布
  27. * v2.0.2 2018/01/03 解决V2.0.1 遗留问题
  28. * v2.1.0 2018/01/20 Version 2 稳定发布版
  29. * Author Date changes
  30. *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  31. *XeiTongXueFlyMe 7/06/04 首个版本
  32. *XeiTongXueFlyMe 7/08/04 增加对TP的支持
  33. *XeiTongXueFlyMe 7/11/24 增加对多路CAN硬件的收发,和报文处理
  34. *XeiTongXueFlyMe 7/11/29 增加请求和响应API
  35. *XeiTongXueFlyMe 7/12/07 重做TP接受API函数
  36. *XeiTongXueFlyMe 7/12/08 增加软件滤波器
  37. *XeiTongXueFlyMe 8/01/03 重做接受发送API,简化协议栈初始化调用逻辑
  38. **********************************************************************/
  39. #ifndef __J1939_H
  40. #define __J1939_H
  41. /******************************类型声明*********************************/
  42. #define FALSE 0
  43. #define TRUE 1
  44. /** 统一类型定义
  45. * 不同的单片机的编译器, int,short,long 的位数可能不同
  46. *
  47. * 在移植J1939协议栈时,首先应该配置这里
  48. */
  49. typedef unsigned int j1939_uint32_t; /** < 32位无符号整形*/
  50. typedef int j1939_int32_t; /** < 32位整形*/
  51. typedef unsigned short j1939_uint16_t; /** < 16位无符号整形*/
  52. typedef unsigned char j1939_uint8_t; /** < 8位无符号整形*/
  53. typedef char j1939_int8_t; /** < 8位无符号整形*/
  54. #define J1939_NULL 0
  55. // 函数返回代码
  56. #define RC_SUCCESS 0 /**< 成功*/
  57. #define RC_QUEUEEMPTY 1 /**< 列队为空*/
  58. #define RC_QUEUEFULL 1 /**< 列队满*/
  59. #define RC_CANNOTRECEIVE 2 /**< 不能接收*/
  60. #define RC_CANNOTTRANSMIT 2 /**< 不能传输*/
  61. #define RC_PARAMERROR 3 /**< 参数错误*/
  62. // 内部常量
  63. #define J1939_FALSE 0 /**< 代表函数错误返回*/
  64. #define J1939_TRUE 1 /**< 代表函数正确返回*/
  65. // J1939 默认的优先级(参考J1939文档)
  66. #define J1939_CONTROL_PRIORITY 0x03 /**< J1939文档默认的优先级*/
  67. #define J1939_INFO_PRIORITY 0x06 /**< J1939文档默认的优先级*/
  68. #define J1939_PROPRIETARY_PRIORITY 0x06 /**< J1939文档默认的优先级*/
  69. #define J1939_REQUEST_PRIORITY 0x06 /**< J1939文档默认的优先级*/
  70. #define J1939_ACK_PRIORITY 0x06 /**< J1939文档默认的优先级*/
  71. #define J1939_TP_CM_PRIORITY 0x07 /**< J1939文档默认的优先级*/
  72. #define J1939_TP_DT_PRIORITY 0x07 /**< J1939文档默认的优先级*/
  73. // J1939 定义的地址
  74. #define J1939_GLOBAL_ADDRESS 255 /**< 全局地址*/
  75. #define J1939_NULL_ADDRESS 254 /**< 空地址*/
  76. // J1939协议栈的PNG请求响应,相关的定义
  77. #define J1939_PF_REQUEST2 201 /**< J1939协议栈的请求 PF */
  78. #define J1939_PF_TRANSFER 202 /**< J1939协议栈的转移 PF */
  79. #define J1939_PF_REQUEST 234 /**< 请求 或 用于握手机制*/
  80. #define J1939_PF_ACKNOWLEDGMENT 232 /**< 确认请求 或 用于握手机制*/
  81. #define J1939_ACK_CONTROL_BYTE 0 /**< 用于TP(长帧数据),代表确认*/
  82. #define J1939_NACK_CONTROL_BYTE 1 /**< 用于TP(长帧数据),PNG不被支持。否定消息*/
  83. #define J1939_ACCESS_DENIED_CONTROL_BYTE 2 /**< 拒绝访问,但是信息是被支持,暂时不能响应(需要再次发送请求)*/
  84. #define J1939_CANNOT_RESPOND_CONTROL_BYTE 3 /**< 不能做出反应,有空但是接受的缓存不够,或则发送资源被占领,暂时不能响应(需要再次发送请求)*/
  85. // TP协议的一些宏定义
  86. #define J1939_PF_DT 235 /**< 协议传输---数据传输 PF*/
  87. #define J1939_PF_TP_CM 236 /**< 协议传输---链接管理 PF*/
  88. // TP的超时时间,单位(ms)
  89. #define J1939_TP_Tr 200 /**< 宏定义TP的超时时间*/
  90. #define J1939_TP_Th 500 /**< 宏定义TP的超时时间*/
  91. #define J1939_TP_T1 750 /**< 宏定义TP的超时时间*/
  92. #define J1939_TP_T2 1250 /**< 宏定义TP的超时时间*/
  93. #define J1939_TP_T3 1250 /**< 宏定义TP的超时时间*/
  94. #define J1939_TP_T4 1050 /**< 宏定义TP的超时时间*/
  95. #define J1939_TP_TIMEOUT_NORMAL 0 /**< 未超时正常*/
  96. #define J1939_TP_TIMEOUT_ABNORMAL 1 /**< 超时*/
  97. #define J1939_RTS_CONTROL_BYTE 16 /**< TP.CM_RTS*/
  98. #define J1939_CTS_CONTROL_BYTE 17 /**< TP.CM_CTS*/
  99. #define J1939_EOMACK_CONTROL_BYTE 19 /**< 消息应答结束*/
  100. #define J1939_BAM_CONTROL_BYTE 32 /**< 广播公告消息*/
  101. #define J1939_CONNABORT_CONTROL_BYTE 255 /**< 连接中断控制字节(放弃连接)*/
  102. #define J1939_RESERVED_BYTE 0xFF /**< 变量的保留位的值*/
  103. // 与J1939网络层有关的定义
  104. #define J1939_PGN2_REQ_ADDRESS_CLAIM 0x00
  105. #define J1939_PGN1_REQ_ADDRESS_CLAIM 0xEA
  106. #define J1939_PGN0_REQ_ADDRESS_CLAIM 0x00
  107. #define J1939_PGN2_COMMANDED_ADDRESS 0x00
  108. #define J1939_PGN1_COMMANDED_ADDRESS 0xFE /**< 命令地址消息*/
  109. #define J1939_PGN0_COMMANDED_ADDRESS 0xD8 /**< 参考J1939-81 地址命令配置*/
  110. #define J1939_PF_ADDRESS_CLAIMED 238
  111. #define J1939_PF_CANNOT_CLAIM_ADDRESS 238
  112. #define J1939_PF_PROPRIETARY_A 239 /**< 专用A*/
  113. #define J1939_PF_PROPRIETARY_B 255 /**< 专用B*/
  114. /**< 是否对TP协议的支持(是否支持长帧(大于8字节的数据)的发送与接受)*/
  115. #define J1939_TP_RX_TX J1939_TRUE
  116. /**< TP协议的支持的最大接受发送消息长度(最大可配置为1785)*/
  117. #define J1939_TP_MAX_MESSAGE_LENGTH 240
  118. /**CAN节点的选择枚举
  119. *
  120. * 默认支持最大4路CAN硬件\n
  121. */
  122. typedef enum
  123. {
  124. Select_CAN_NODE_Null, /**< 不选择任何CAN硬件*/
  125. Select_CAN_NODE_1, /**< 选择CAN硬件 1*/
  126. Select_CAN_NODE_2, /**< 选择CAN硬件 2*/
  127. Select_CAN_NODE_3, /**< 选择CAN硬件 3*/
  128. Select_CAN_NODE_4, /**< 选择CAN硬件 4*/
  129. } CAN_NODE;
  130. #if J1939_TP_RX_TX
  131. /**TP的状态描述枚举
  132. *
  133. */
  134. typedef enum
  135. {
  136. J1939_TP_NULL, /**< 长数据传输处于空闲,只有TP系统处于空闲,才能用处理下一个发送,和接受请求*/
  137. J1939_TP_RX, /**< 长数据传输处于接收*/
  138. J1939_TP_TX, /**< 长数据传输处于发送*/
  139. J1939_TP_OSBUSY, /**< 长数据传输处于繁忙,比如刚接受一整段长数据,但是CPU没来得处理,又一个长数据请求到来,为了数据不被覆盖,将状态设为本值*/
  140. } J1939_TP_State;
  141. /**TP的标志位结构体
  142. *
  143. * 本结构体记录了TP的状态,使用TP发送和接受的CAN硬件编号
  144. */
  145. typedef struct
  146. {
  147. J1939_TP_State state; /**< TP的连接状态*/
  148. CAN_NODE TP_RX_CAN_NODE; /**< TP接受请求产生的 CAN硬件编号*/
  149. CAN_NODE TP_TX_CAN_NODE; /**< TP接受发送产生的 CAN硬件编号*/
  150. } J1939_TP_Flags;
  151. /**J1939消息对象的结构体
  152. *
  153. * 本结构体实现了 J1939的消息对象
  154. */
  155. typedef struct
  156. {
  157. j1939_uint32_t PGN; /**< J1939的消息对象的 PGN*/
  158. j1939_uint8_t data[J1939_TP_MAX_MESSAGE_LENGTH]; /**< J1939的消息对象的 数据*/
  159. j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/
  160. j1939_uint8_t SA; /**< J1939的消息对象的 目标地址(发送目的地 或 接受来源地)*/
  161. } J1939_MESSAGE_T;
  162. /**J1939消息对象的结构体
  163. *
  164. * 本结构体实现了 J1939的多帧消息对象
  165. */
  166. typedef struct
  167. {
  168. j1939_uint8_t *data; /**< 缓存区指针*/
  169. j1939_uint16_t data_num; /**< 缓存区大小*/
  170. j1939_uint8_t SA; /**< J1939的消息对象的 数据 源地址*/
  171. j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/
  172. j1939_uint32_t PGN; /**< J1939的消息对象的 PGN*/
  173. } TP_RX_MESSAGE;
  174. /**J1939_TP_Tx_Step枚举
  175. *
  176. * 实现了记录长帧(多帧)传输的TX 的步骤
  177. */
  178. typedef enum
  179. {
  180. J1939_TP_TX_WAIT,
  181. J1939_TP_TX_CM_START,
  182. J1939_TP_TX_CM_WAIT,
  183. J1939_TP_TX_DT,
  184. J1939_TP_WAIT_ACK,
  185. J1939_TP_TX_ERROR,
  186. J1939_TX_DONE,
  187. } J1939_TP_Tx_Step; // 协议的发送步骤
  188. /**J1939_TRANSPORT_TX_INFO 结构体
  189. *
  190. * 实现了长帧传输中产生的临时数据,和一些传输交换数据
  191. */
  192. typedef struct
  193. {
  194. J1939_MESSAGE_T tp_tx_msg; /**< J1939的消息对象*/
  195. j1939_uint16_t time; /**< 时间*/
  196. j1939_uint8_t packet_offset_p; /**< 数据包偏移指针*/
  197. j1939_uint8_t packets_total; /**< 总共有多少个数据包*/
  198. j1939_uint8_t packets_request_num; /**< 请求发送的数据包数(接受方准备接受的数据包数)*/
  199. J1939_TP_Tx_Step state; /**< 协议的发送步骤*/
  200. } J1939_TRANSPORT_TX_INFO;
  201. /**J1939_TP_Rx_Step枚举
  202. *
  203. * 实现了记录长帧(多帧)传输的RX 的步骤
  204. */
  205. typedef enum
  206. {
  207. J1939_TP_RX_WAIT,
  208. J1939_TP_RX_READ_DATA,
  209. J1939_TP_RX_DATA_WAIT,
  210. J1939_TP_RX_ERROR,
  211. J1939_RX_DONE,
  212. } J1939_TP_Rx_Step; // 协议的接收步骤
  213. /**J1939_TRANSPORT_RX_INFO 结构体
  214. *
  215. * 实现了长帧传输中产生的临时数据,和一些传输交换数据
  216. */
  217. typedef struct
  218. {
  219. J1939_MESSAGE_T tp_rx_msg; /**< J1939的消息对象*/
  220. j1939_uint8_t osbusy; /**< 此位置1,代表系统繁忙,cpu需要处理其他的事物,直接拒绝一切的链接请求\n 如果正在接受中,此位置1,则会发出链接保持消息帧。*/
  221. j1939_uint16_t time; /**< 时间*/
  222. j1939_uint8_t packets_total; /**< 总共有多少个数据包*/
  223. j1939_uint8_t packets_ok_num; /**< 已经接受的数据包数*/
  224. J1939_TP_Rx_Step state; /**< 协议的接受步骤*/
  225. } J1939_TRANSPORT_RX_INFO;
  226. #endif // J1939_TP_RX_TX
  227. /**
  228. * @note 实现Request_PGN 的响应
  229. */
  230. struct Request_List
  231. {
  232. j1939_uint8_t *data;
  233. j1939_uint16_t lenght;
  234. j1939_uint32_t PGN;
  235. CAN_NODE Can_Node;
  236. void (*update)(); /**< 在函数里需要对data更新,如果不用更新data赋值为J1939_NULL*/
  237. struct Request_List *next; /**< 链表末尾,需要一直保持J1939_NULL*/
  238. };
  239. // J1939 Data Structures
  240. // J1939_MESSAGE_STRUCT旨在J1939消息块映射到设备的地址映射。 只有字段PDU格式不映射到设备寄存器。
  241. // 结构应该简单地使用PDUFormat和忽视PDUFormat_Top。调整将立即接收和传输之前。
  242. // 注:编译器创建结构从低一点的位置高一些位置,所以可能出现不匹配的设备寄存器。
  243. #define J1939_MSG_LENGTH 9 // 消息长度
  244. #define J1939_DATA_LENGTH 8 // 数据长度
  245. /** J1939_MESSAGE_UNION 结构体
  246. * 实现了J1939消息对象
  247. *
  248. *
  249. */
  250. union J1939_MESSAGE_UNION
  251. {
  252. /** j1939 的 ID 组成结构体
  253. *
  254. */
  255. struct j1939_PID
  256. {
  257. j1939_uint8_t DataPage : 1; /**< 数据页*/
  258. j1939_uint8_t Res : 1; /**< Res位*/
  259. j1939_uint8_t Priority : 3; /**< 优先级*/
  260. j1939_uint8_t Reserve : 3; /**< 空闲*/
  261. j1939_uint8_t PDUFormat; /**< PF*/
  262. j1939_uint8_t PDUSpecific; /**< PS*/
  263. j1939_uint8_t SourceAddress; /**< SA*/
  264. j1939_uint8_t DataLength : 4; /**< 数据长度*/
  265. j1939_uint8_t RTR : 4; /**< RTR位*/
  266. j1939_uint8_t Data[J1939_DATA_LENGTH]; /**< 数据*/
  267. j1939_uint32_t PGN : 24; /**< 参数群编号*/
  268. j1939_uint32_t ReservePGN : 8; /**< 空闲*/
  269. };
  270. struct j1939_PID Mxe; /**< j1939 的 ID 组成结构体*/
  271. j1939_uint8_t Array[J1939_MSG_LENGTH + J1939_DATA_LENGTH]; /**< 联合体数组,方便快速处理结构体赋值*/
  272. };
  273. #define GroupExtension PDUSpecific
  274. #define DestinationAddress PDUSpecific
  275. /** 一个宏定义,具体变量名称作用命名
  276. *
  277. */
  278. typedef union J1939_MESSAGE_UNION J1939_MESSAGE;
  279. union J1939_FLAGS_UNION
  280. {
  281. struct
  282. {
  283. j1939_uint8_t TransmitMessagesdCover : 1; // 发送数据时,J1939协议接受缓存有数据覆盖
  284. j1939_uint8_t ReceivedMessagesdCoverOrDroppedNode : 3;
  285. j1939_uint8_t ReceivedMessagesdCover : 1; // 接受数据时,J1939协议接受缓存有数据覆盖
  286. j1939_uint8_t ReceivedMessagesDropped : 1; // 接受数据时,J1939协议接受缓存有数据溢出
  287. };
  288. j1939_uint8_t FlagVal;
  289. };
  290. typedef union J1939_FLAGS_UNION J1939_FLAG;
  291. /********************************************API**************************************************************/
  292. // 初始化函数
  293. extern void J1939_Initialization();
  294. // CAN驱动收发中断入口
  295. extern void J1939_ISR();
  296. // 心跳函数,定时被调用
  297. extern void J1939_Poll();
  298. // 读取单帧消息
  299. extern j1939_uint8_t J1939_Read_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
  300. // 发送单帧消息
  301. extern j1939_uint8_t J1939_Send_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
  302. // 多帧(多组)消息发送函数 (RTS/CTS传输协议)
  303. 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);
  304. // 多帧(多组)消息接受函数 (RTS/CTS传输协议)
  305. extern j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node);
  306. // 请求获去一个PGN
  307. extern void J1939_Request_PGN(j1939_uint32_t pgn, j1939_uint8_t DA, CAN_NODE _Can_Node);
  308. // 创建一个PGN响应
  309. extern void J1939_Create_Response(j1939_uint8_t data[], j1939_uint16_t dataLenght, j1939_uint32_t PGN, void (*dataUPFun)(), CAN_NODE _Can_Node);
  310. #endif //__J1939_H