├── .gitignore ├── readme.md ├── source ├── J1939_Config.H ├── J1939.H └── J1939.c └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 简述 2 | 1. 源代码下载: 3 | > https://github.com/XeiTongXueFlyMe/J1939 4 | 2. 源代码说明书Web站点:(临时,已准备建站,以后分享更多的汽车通信协议) 5 | > https://xeitongxueflyme.github.io/j1939doc.github.io/ 6 | 3. 技术支持群: 7 | > QQ群:264864184 ,为了节约时间成本,群主可以免费为大家解决最新协议栈问题(老版本,群里也有其他工程师为大家解决,群主不做答) 8 | 9 | # 历史版本变更 10 | 11 | > 版本说明:V a,b,c 12 | 1. a 代表版本号 13 | 2. b 代表稳定的版本号 14 | 3. c 代表基于稳定版本号上功能添加,新的功能不一定稳定 15 | 16 | > 如果是工程使用,建议使用 **V x.x.0** 例如 ***V 1.1.0*** ,***V 2.1.0*** 17 | 18 | ## J1939Socket API Version 2 19 | 20 | Version | date |Description 21 | ------------- | ------------- | ------------- 22 | [V2.1.0] |2018/1/20| Version 2.1 稳定发布版。经过实用性测试,Version 2.1相对Version 1.1做了很大的改进,Version 2.1版本更加的偏向于使用,移植更加的简单,架构和注解更加的规范。API(接口)更加人性化,实用化(感谢许多同行的使用反馈)。 23 | [V2.0.1] |2017/12/8| 地址竞争,动态地址分配等J1939网络功能不能使用,本版本为V2.1.0发布前的测试版本。 24 | 25 | 26 | ## J1939Socket API Version 1 27 | 28 | Version | date | Description 29 | ------------- | ------------- | ------------- 30 | [V1.1.0] | 2017/11/22 | Version 1.1 稳定发布版。\n * 实现了J1939-21文档规定的功能(数据链路层)。\n * 轻量级(可适应低端的MCU)建议低端的MCU采用本版本移植开发。\n * 使用示例参考附带的readme.md和 \n * 移植示例参考 31 | [V1.0.1] | 2017/08/04 | 完善功能,增加对TP(长帧,多组)传输的支持,\n 1.增加非阻塞API调用接口 \n * 使用示例参考附带的readme.md和 \n * 移植示例参考 \n * 本文档不对Version 1 进行阐述。 32 | V1.0.0 | 2017/06/04 | 首个开源版本\n 1.增加双模式(轮询或者中断,逻辑更加简单明了)\n 2.可适应低端的MCU \n 3.支持多任务调用接口(可用于嵌入式系统) 33 | V0.0.1 | 2017/05/04 | 初建工程\n * 易移植(不针对特定的CAN硬件,只要满足CAN2.0B即可) 34 | 35 | [V1.1.0]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/v1.1.0 "V1.1.0下载地址" 36 | [V1.0.1]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/V1.01 "V1.0.1下载地址" 37 | [V2.0.1]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/V2.0.1 "V2.0.1下载地址" 38 | [V2.1.0]: https://github.com/XeiTongXueFlyMe/J1939/releases/tag/V2.1.0 "V2.1.0下载地址" 39 | 40 | -------------------------------------------------------------------------------- /source/J1939_Config.H: -------------------------------------------------------------------------------- 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 | 40 | #ifndef __J1939_Config_H 41 | #define __J1939_Config_H 42 | 43 | #include "J1939.H" 44 | extern CAN_NODE Can_Node; //CAN硬件选择 45 | 46 | 47 | /***************************J1939 地址配置*****************************/ 48 | //设备默认的地址(地址命名是有规定的,参考J1939的附录B 地址和标识符的分配) 49 | #define J1939_STARTING_ADDRESS_1 0x01 50 | #define J1939_STARTING_ADDRESS_2 244 51 | #define J1939_STARTING_ADDRESS_3 247 52 | #define J1939_STARTING_ADDRESS_4 0 53 | 54 | 55 | /******************************J1939功能配置***************************/ 56 | #define J1939_RX_QUEUE_SIZE 3 57 | //当mcu来不及处理消息,接收消息列队是否允许被新的消息覆盖 58 | #define J1939_OVERWRITE_RX_QUEUE J1939_FALSE 59 | #define J1939_TX_QUEUE_SIZE 3 60 | //当mcu来不及处理消息,发送消息列队是否允许被新的消息覆盖 61 | #define J1939_OVERWRITE_TX_QUEUE J1939_FALSE 62 | //是否使用轮询模式(否则使用中断模式) 63 | #define J1939_POLL_ECAN J1939_TRUE 64 | //是否启用软件滤波器 65 | #define J1939SoftwareFilterEn J1939_TRUE 66 | /******************************J1939移植配置函数************************/ 67 | 68 | #define Port_CAN_Transmit(MsgPtr) J1939_CAN_Transmit(MsgPtr) 69 | #define Port_CAN_Receive(MsgPtr) J1939_CAN_Receive(MsgPtr) 70 | #define Port_SetAddressFilter(Address) J1939_SetAddressFilter(Address) 71 | /*不使用中断模式,不对下面的函数进行移植*/ 72 | #if J1939_POLL_ECAN == J1939_FALSE 73 | #define Port_RXinterruptEnable() J1939_RXinterruptEnable() 74 | #define Port_RXinterruptDisable() J1939_RXinterruptDisable() 75 | #define Port_TXinterruptEnable() J1939_TXinterruptEnable() 76 | #define Port_TXinterruptDisable() J1939_TXinterruptDisable() 77 | #define Port_TXinterruptOk() J1939_TXinterruptOk() 78 | #define Port_CAN_identifier_clc() CAN_identifier_clc() 79 | #endif 80 | 81 | /***************************************************************************************/ 82 | 83 | /* 84 | *输入: 85 | *输出: 86 | *说明:基于SAE J1939协议,我们需要CAN控制器提供至少3个滤波器给J1939协议代码。三个滤波器分别配置如下: 87 | 1. 设置滤波器0,只接受广播信息(PF = 240 -255)。 88 | 2. 设置设置滤波器1,2只接受全局地址(J1939_GLOBAL_ADDRESS) 89 | 3. 随着程序的运行,将改变滤波器2,来适应程序逻辑。 90 | J1939_SetAddressFilter() 是用来设置滤波器2的, 函数主要设置PS位(目标地址),其目的是,让控制器 91 | 只接受发送给本设备的消息。 92 | *警告: 滤波器0,1是在CAN驱动里配置,如果对硬件滤波配置不是很熟练,可以使能软件滤波器,#define J1939SoftwareFilterEn 93 | *则可跳过本函数的移植和CAN硬件滤波器的配置,为了J1939协议栈性能最优化,建议只是用硬件滤波。 94 | */ 95 | void J1939_SetAddressFilter(unsigned char Ps_Address) 96 | { 97 | switch (Can_Node) 98 | { 99 | case Select_CAN_NODE_1: 100 | { 101 | break; 102 | } 103 | case Select_CAN_NODE_2: 104 | { 105 | break; 106 | } 107 | case Select_CAN_NODE_3: 108 | { 109 | break; 110 | } 111 | case Select_CAN_NODE_4: 112 | { 113 | break; 114 | } 115 | default : 116 | { 117 | break; 118 | } 119 | } 120 | } 121 | 122 | /* 123 | *输入: *MsgPtr ,协议要发送的消息, 124 | *输出: 125 | *说明: 将数据 从MsgPtr结构体赋值到CAN驱动自带的结构体中 126 | 先将传入函数的MsgPtr中的数据写到CAN的结构体,再调用CAN驱动的发送函数 127 | 默认支持4路CAN硬件的收发。如少于4路,只需配置相应的Can_Node开关代码区, 128 | 其他(Select_CAN_NODE)保持不变。就直接返回(break)。 129 | */ 130 | void J1939_CAN_Transmit(J1939_MESSAGE *MsgPtr) 131 | { 132 | 133 | switch (Can_Node) 134 | { 135 | case Select_CAN_NODE_1: 136 | { 137 | 138 | /*加载第一路CAN硬件的29位ID*/ 139 | 140 | /*CAN硬件加载数据长度*/ 141 | 142 | /*CAN硬件加载数据*/ 143 | 144 | /*CAN硬件加载RTR*/ 145 | 146 | //CAN硬件开始发送数据 147 | 148 | break; 149 | } 150 | case Select_CAN_NODE_2: 151 | { 152 | 153 | /*加载第二路CAN硬件的29位ID*/ 154 | 155 | /*CAN硬件加载数据长度*/ 156 | 157 | /*CAN硬件加载数据*/ 158 | 159 | /*CAN硬件加载RTR*/ 160 | 161 | //CAN硬件开始发送数据 162 | break; 163 | } 164 | case Select_CAN_NODE_3: 165 | { 166 | 167 | /*加载第三路CAN硬件的29位ID*/ 168 | 169 | /*CAN硬件加载数据长度*/ 170 | 171 | /*CAN硬件加载数据*/ 172 | 173 | /*CAN硬件加载RTR*/ 174 | 175 | //CAN硬件开始发送数据 176 | break; 177 | } 178 | case Select_CAN_NODE_4: 179 | { 180 | /*加载第四路CAN硬件的29位ID*/ 181 | 182 | /*CAN硬件加载数据长度*/ 183 | 184 | /*CAN硬件加载数据*/ 185 | 186 | /*CAN硬件加载RTR*/ 187 | 188 | //CAN硬件开始发送数据 189 | break; 190 | } 191 | default : 192 | { 193 | break; 194 | } 195 | } 196 | } 197 | /* 198 | *输入: *MsgPtr 数据要存入的内存的指针 199 | *输出: 1 | 0 200 | *说明: 读取CAN驱动的数据,如果没有数据,返回0 201 | 将CAN中的数据取出,存入J1939_MESSAGE结构体中 202 | 默认支持4路CAN硬件的收发。如少于4路,只需配置相应的Can_Node开关代码区, 203 | 其他(Select_CAN_NODE)保持不变。就直接返回(return 0) 204 | */ 205 | 206 | int J1939_CAN_Receive(J1939_MESSAGE *MsgPtr) 207 | { 208 | 209 | switch (Can_Node) 210 | { 211 | case Select_CAN_NODE_1: 212 | { 213 | if("你的代码")//判断CAN硬件1是否有数据到来 214 | { 215 | //你的代码,从CAN硬件1 中将数据读取后,存入 MsgPtr 216 | return 1; 217 | } 218 | return 0; 219 | break; 220 | } 221 | case Select_CAN_NODE_2: 222 | { 223 | if("你的代码")//判断CAN硬件2是否有数据到来 224 | { 225 | //你的代码,从CAN硬件2 中将数据读取后,存入 MsgPtr 226 | return 1; 227 | } 228 | return 0; 229 | break; 230 | 231 | } 232 | case Select_CAN_NODE_3: 233 | { 234 | if("你的代码")//判断CAN硬件3是否有数据到来 235 | { 236 | //你的代码,从CAN硬件3 中将数据读取后,存入 MsgPtr 237 | return 1; 238 | } 239 | return 0; 240 | break; 241 | 242 | } 243 | case Select_CAN_NODE_4: 244 | { 245 | if("你的代码")//判断CAN硬件4是否有数据到来 246 | { 247 | //你的代码,从CAN硬件4 中将数据读取后,存入 MsgPtr 248 | return 1; 249 | } 250 | return 0; 251 | break; 252 | } 253 | default : 254 | { 255 | return 0;//没有消息 256 | break; 257 | } 258 | } 259 | return 0;//没有消息 260 | } 261 | 262 | /*不使用中断模式,不对下面的函数进行移植*/ 263 | #if J1939_POLL_ECAN == J1939_FALSE 264 | /* 265 | *输入: 266 | *输出: 267 | *说明:使能接受中断 268 | */ 269 | void J1939_RXinterruptEnable() 270 | { 271 | ; 272 | } 273 | /* 274 | *输入: 275 | *输出: 276 | *说明:失能接受中断 277 | */ 278 | void J1939_RXinterruptDisable() 279 | { 280 | ; 281 | } 282 | /* 283 | *输入: 284 | *输出: 285 | *说明:使能发送中断 286 | */ 287 | void J1939_TXinterruptEnable() 288 | { 289 | ; 290 | } 291 | /* 292 | *输入: 293 | *输出: 294 | *说明:失能发送中断 295 | */ 296 | void J1939_TXinterruptDisable() 297 | { 298 | ; 299 | } 300 | /* 301 | *输入: 302 | *输出: 303 | *说明:触发发送中断标致位,当协议栈在中断模式下,要发送消息,将调用此函数 304 | CAN驱动函数,就将直接把消息发送出去,不需要协议在调用任何can驱动函数 305 | */ 306 | void J1939_TXinterruptOk() 307 | { 308 | ; 309 | } 310 | /* 311 | *输入: 312 | *输出: 313 | *说明:清除CAN驱动相关的中断产生标识位,包括(发送中断标志位,接受中断标 314 | 志位,can总线错误标识位) 315 | */ 316 | void CAN_identifier_clc() 317 | { 318 | ; 319 | } 320 | #endif 321 | 322 | #endif 323 | -------------------------------------------------------------------------------- /source/J1939.H: -------------------------------------------------------------------------------- 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 | /** 统一类型定义 46 | * 不同的单片机的编译器, int,short,long 的位数可能不同 47 | * 48 | * 在移植J1939协议栈时,首先应该配置这里 49 | */ 50 | typedef unsigned int j1939_uint32_t; /** < 32位无符号整形*/ 51 | typedef int j1939_int32_t; /** < 32位整形*/ 52 | typedef unsigned short j1939_uint16_t; /** < 16位无符号整形*/ 53 | typedef unsigned char j1939_uint8_t; /** < 8位无符号整形*/ 54 | typedef char j1939_int8_t; /** < 8位无符号整形*/ 55 | #define J1939_NULL 0 56 | 57 | //函数返回代码 58 | #define RC_SUCCESS 0 /**< 成功*/ 59 | #define RC_QUEUEEMPTY 1 /**< 列队为空*/ 60 | #define RC_QUEUEFULL 1 /**< 列队满*/ 61 | #define RC_CANNOTRECEIVE 2 /**< 不能接收*/ 62 | #define RC_CANNOTTRANSMIT 2 /**< 不能传输*/ 63 | #define RC_PARAMERROR 3 /**< 参数错误*/ 64 | 65 | //内部常量 66 | #define J1939_FALSE 0 /**< 代表函数错误返回*/ 67 | #define J1939_TRUE 1 /**< 代表函数正确返回*/ 68 | 69 | // J1939 默认的优先级(参考J1939文档) 70 | #define J1939_CONTROL_PRIORITY 0x03 /**< J1939文档默认的优先级*/ 71 | #define J1939_INFO_PRIORITY 0x06 /**< J1939文档默认的优先级*/ 72 | #define J1939_PROPRIETARY_PRIORITY 0x06 /**< J1939文档默认的优先级*/ 73 | #define J1939_REQUEST_PRIORITY 0x06 /**< J1939文档默认的优先级*/ 74 | #define J1939_ACK_PRIORITY 0x06 /**< J1939文档默认的优先级*/ 75 | #define J1939_TP_CM_PRIORITY 0x07 /**< J1939文档默认的优先级*/ 76 | #define J1939_TP_DT_PRIORITY 0x07 /**< J1939文档默认的优先级*/ 77 | 78 | // J1939 定义的地址 79 | #define J1939_GLOBAL_ADDRESS 255 /**< 全局地址*/ 80 | #define J1939_NULL_ADDRESS 254 /**< 空地址*/ 81 | 82 | //J1939协议栈的PNG请求响应,相关的定义 83 | #define J1939_PF_REQUEST2 201 /**< J1939协议栈的请求 PF */ 84 | #define J1939_PF_TRANSFER 202 /**< J1939协议栈的转移 PF */ 85 | 86 | #define J1939_PF_REQUEST 234 /**< 请求 或 用于握手机制*/ 87 | #define J1939_PF_ACKNOWLEDGMENT 232 /**< 确认请求 或 用于握手机制*/ 88 | 89 | #define J1939_ACK_CONTROL_BYTE 0 /**< 用于TP(长帧数据),代表确认*/ 90 | #define J1939_NACK_CONTROL_BYTE 1 /**< 用于TP(长帧数据),PNG不被支持。否定消息*/ 91 | #define J1939_ACCESS_DENIED_CONTROL_BYTE 2/**< 拒绝访问,但是信息是被支持,暂时不能响应(需要再次发送请求)*/ 92 | #define J1939_CANNOT_RESPOND_CONTROL_BYTE 3/**< 不能做出反应,有空但是接受的缓存不够,或则发送资源被占领,暂时不能响应(需要再次发送请求)*/ 93 | 94 | //TP协议的一些宏定义 95 | #define J1939_PF_DT 235 /**< 协议传输---数据传输 PF*/ 96 | #define J1939_PF_TP_CM 236 /**< 协议传输---链接管理 PF*/ 97 | 98 | //TP的超时时间,单位(ms) 99 | #define J1939_TP_Tr 200 /**< 宏定义TP的超时时间*/ 100 | #define J1939_TP_Th 500 /**< 宏定义TP的超时时间*/ 101 | #define J1939_TP_T1 750 /**< 宏定义TP的超时时间*/ 102 | #define J1939_TP_T2 1250 /**< 宏定义TP的超时时间*/ 103 | #define J1939_TP_T3 1250 /**< 宏定义TP的超时时间*/ 104 | #define J1939_TP_T4 1050 /**< 宏定义TP的超时时间*/ 105 | #define J1939_TP_TIMEOUT_NORMAL 0 /**< 未超时正常*/ 106 | #define J1939_TP_TIMEOUT_ABNORMAL 1 /**< 超时*/ 107 | #define J1939_RTS_CONTROL_BYTE 16 /**< TP.CM_RTS*/ 108 | #define J1939_CTS_CONTROL_BYTE 17 /**< TP.CM_CTS*/ 109 | #define J1939_EOMACK_CONTROL_BYTE 19 /**< 消息应答结束*/ 110 | #define J1939_BAM_CONTROL_BYTE 32 /**< 广播公告消息*/ 111 | #define J1939_CONNABORT_CONTROL_BYTE 255 /**< 连接中断控制字节(放弃连接)*/ 112 | #define J1939_RESERVED_BYTE 0xFF /**< 变量的保留位的值*/ 113 | 114 | //与J1939网络层有关的定义 115 | #define J1939_PGN2_REQ_ADDRESS_CLAIM 0x00 116 | #define J1939_PGN1_REQ_ADDRESS_CLAIM 0xEA 117 | #define J1939_PGN0_REQ_ADDRESS_CLAIM 0x00 118 | 119 | #define J1939_PGN2_COMMANDED_ADDRESS 0x00 120 | #define J1939_PGN1_COMMANDED_ADDRESS 0xFE /**< 命令地址消息*/ 121 | #define J1939_PGN0_COMMANDED_ADDRESS 0xD8 /**< 参考J1939-81 地址命令配置*/ 122 | 123 | #define J1939_PF_ADDRESS_CLAIMED 238 124 | #define J1939_PF_CANNOT_CLAIM_ADDRESS 238 125 | #define J1939_PF_PROPRIETARY_A 239 /**< 专用A*/ 126 | #define J1939_PF_PROPRIETARY_B 255 /**< 专用B*/ 127 | 128 | /**< 是否对TP协议的支持(是否支持长帧(大于8字节的数据)的发送与接受)*/ 129 | #define J1939_TP_RX_TX J1939_TRUE 130 | /**< TP协议的支持的最大接受发送消息长度(最大可配置为1785)*/ 131 | #define J1939_TP_MAX_MESSAGE_LENGTH 240 132 | 133 | /**CAN节点的选择枚举 134 | * 135 | * 默认支持最大4路CAN硬件\n 136 | */ 137 | typedef enum 138 | { 139 | Select_CAN_NODE_Null, /**< 不选择任何CAN硬件*/ 140 | Select_CAN_NODE_1, /**< 选择CAN硬件 1*/ 141 | Select_CAN_NODE_2, /**< 选择CAN硬件 2*/ 142 | Select_CAN_NODE_3, /**< 选择CAN硬件 3*/ 143 | Select_CAN_NODE_4, /**< 选择CAN硬件 4*/ 144 | }CAN_NODE; 145 | 146 | #if J1939_TP_RX_TX 147 | /**TP的状态描述枚举 148 | * 149 | */ 150 | typedef enum 151 | { 152 | J1939_TP_NULL, /**< 长数据传输处于空闲,只有TP系统处于空闲,才能用处理下一个发送,和接受请求*/ 153 | J1939_TP_RX, /**< 长数据传输处于接收*/ 154 | J1939_TP_TX, /**< 长数据传输处于发送*/ 155 | J1939_TP_OSBUSY,/**< 长数据传输处于繁忙,比如刚接受一整段长数据,但是CPU没来得处理,又一个长数据请求到来,为了数据不被覆盖,将状态设为本值*/ 156 | }J1939_TP_State; 157 | /**TP的标志位结构体 158 | * 159 | * 本结构体记录了TP的状态,使用TP发送和接受的CAN硬件编号 160 | */ 161 | typedef struct 162 | { 163 | J1939_TP_State state; /**< TP的连接状态*/ 164 | CAN_NODE TP_RX_CAN_NODE; /**< TP接受请求产生的 CAN硬件编号*/ 165 | CAN_NODE TP_TX_CAN_NODE; /**< TP接受发送产生的 CAN硬件编号*/ 166 | }J1939_TP_Flags; 167 | /**J1939消息对象的结构体 168 | * 169 | * 本结构体实现了 J1939的消息对象 170 | */ 171 | typedef struct 172 | { 173 | j1939_uint32_t PGN ; /**< J1939的消息对象的 PGN*/ 174 | j1939_uint8_t data[J1939_TP_MAX_MESSAGE_LENGTH] ;/**< J1939的消息对象的 数据*/ 175 | j1939_uint16_t byte_count;/**< J1939的消息对象的 数据大小*/ 176 | j1939_uint8_t SA; /**< J1939的消息对象的 目标地址(发送目的地 或 接受来源地)*/ 177 | 178 | } J1939_MESSAGE_T ; 179 | /**J1939消息对象的结构体 180 | * 181 | * 本结构体实现了 J1939的多帧消息对象 182 | */ 183 | typedef struct 184 | { 185 | j1939_uint8_t *data; /**< 缓存区指针*/ 186 | j1939_uint16_t data_num; /**< 缓存区大小*/ 187 | j1939_uint8_t SA; /**< J1939的消息对象的 数据 源地址*/ 188 | j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/ 189 | j1939_uint32_t PGN ; /**< J1939的消息对象的 PGN*/ 190 | }TP_RX_MESSAGE; 191 | /**J1939_TP_Tx_Step枚举 192 | * 193 | * 实现了记录长帧(多帧)传输的TX 的步骤 194 | */ 195 | typedef enum 196 | { 197 | J1939_TP_TX_WAIT, 198 | J1939_TP_TX_CM_START, 199 | J1939_TP_TX_CM_WAIT, 200 | J1939_TP_TX_DT, 201 | J1939_TP_WAIT_ACK, 202 | J1939_TP_TX_ERROR, 203 | J1939_TX_DONE, 204 | }J1939_TP_Tx_Step;//协议的发送步骤 205 | /**J1939_TRANSPORT_TX_INFO 结构体 206 | * 207 | * 实现了长帧传输中产生的临时数据,和一些传输交换数据 208 | */ 209 | typedef struct 210 | { 211 | J1939_MESSAGE_T tp_tx_msg; /**< J1939的消息对象*/ 212 | j1939_uint16_t time; /**< 时间*/ 213 | j1939_uint8_t packet_offset_p; /**< 数据包偏移指针*/ 214 | j1939_uint8_t packets_total; /**< 总共有多少个数据包*/ 215 | j1939_uint8_t packets_request_num; /**< 请求发送的数据包数(接受方准备接受的数据包数)*/ 216 | J1939_TP_Tx_Step state ; /**< 协议的发送步骤*/ 217 | } J1939_TRANSPORT_TX_INFO; 218 | /**J1939_TP_Rx_Step枚举 219 | * 220 | * 实现了记录长帧(多帧)传输的RX 的步骤 221 | */ 222 | typedef enum 223 | { 224 | J1939_TP_RX_WAIT, 225 | J1939_TP_RX_READ_DATA, 226 | J1939_TP_RX_DATA_WAIT, 227 | J1939_TP_RX_ERROR, 228 | J1939_RX_DONE, 229 | }J1939_TP_Rx_Step;//协议的接收步骤 230 | 231 | /**J1939_TRANSPORT_RX_INFO 结构体 232 | * 233 | * 实现了长帧传输中产生的临时数据,和一些传输交换数据 234 | */ 235 | typedef struct 236 | { 237 | J1939_MESSAGE_T tp_rx_msg; /**< J1939的消息对象*/ 238 | j1939_uint8_t osbusy; /**< 此位置1,代表系统繁忙,cpu需要处理其他的事物,直接拒绝一切的链接请求\n 如果正在接受中,此位置1,则会发出链接保持消息帧。*/ 239 | j1939_uint16_t time; /**< 时间*/ 240 | j1939_uint8_t packets_total; /**< 总共有多少个数据包*/ 241 | j1939_uint8_t packets_ok_num;/**< 已经接受的数据包数*/ 242 | J1939_TP_Rx_Step state ; /**< 协议的接受步骤*/ 243 | } J1939_TRANSPORT_RX_INFO; 244 | 245 | #endif //J1939_TP_RX_TX 246 | 247 | /** 248 | * @note 实现Request_PGN 的响应 249 | */ 250 | struct Request_List{ 251 | j1939_uint8_t *data; 252 | j1939_uint16_t lenght; 253 | j1939_uint32_t PGN; 254 | CAN_NODE Can_Node; 255 | void (*update)(); /**< 在函数里需要对data更新,如果不用更新data赋值为J1939_NULL*/ 256 | struct Request_List *next; /**< 链表末尾,需要一直保持J1939_NULL*/ 257 | }; 258 | 259 | // J1939 Data Structures 260 | // J1939_MESSAGE_STRUCT旨在J1939消息块映射到设备的地址映射。 只有字段PDU格式不映射到设备寄存器。 261 | // 结构应该简单地使用PDUFormat和忽视PDUFormat_Top。调整将立即接收和传输之前。 262 | // 注:编译器创建结构从低一点的位置高一些位置,所以可能出现不匹配的设备寄存器。 263 | #define J1939_MSG_LENGTH 9 //消息长度 264 | #define J1939_DATA_LENGTH 8 //数据长度 265 | 266 | /** J1939_MESSAGE_UNION 结构体 267 | * 实现了J1939消息对象 268 | * 269 | * 270 | */ 271 | union J1939_MESSAGE_UNION 272 | { 273 | /** j1939 的 ID 组成结构体 274 | * 275 | */ 276 | struct j1939_PID 277 | { 278 | j1939_uint8_t DataPage : 1; /**< 数据页*/ 279 | j1939_uint8_t Res : 1; /**< Res位*/ 280 | j1939_uint8_t Priority : 3; /**< 优先级*/ 281 | j1939_uint8_t Reserve : 3; /**< 空闲*/ 282 | j1939_uint8_t PDUFormat; /**< PF*/ 283 | j1939_uint8_t PDUSpecific; /**< PS*/ 284 | j1939_uint8_t SourceAddress; /**< SA*/ 285 | j1939_uint8_t DataLength : 4; /**< 数据长度*/ 286 | j1939_uint8_t RTR : 4; /**< RTR位*/ 287 | j1939_uint8_t Data[J1939_DATA_LENGTH]; /**< 数据*/ 288 | j1939_uint32_t PGN :24; /**< 参数群编号*/ 289 | j1939_uint32_t ReservePGN : 8; /**< 空闲*/ 290 | }; 291 | struct j1939_PID Mxe; /**< j1939 的 ID 组成结构体*/ 292 | j1939_uint8_t Array[J1939_MSG_LENGTH + J1939_DATA_LENGTH]; /**< 联合体数组,方便快速处理结构体赋值*/ 293 | }; 294 | 295 | #define GroupExtension PDUSpecific 296 | #define DestinationAddress PDUSpecific 297 | /** 一个宏定义,具体变量名称作用命名 298 | * 299 | */ 300 | typedef union J1939_MESSAGE_UNION J1939_MESSAGE; 301 | 302 | union J1939_FLAGS_UNION 303 | { 304 | struct 305 | { 306 | j1939_uint8_t TransmitMessagesdCover : 1; //发送数据时,J1939协议接受缓存有数据覆盖 307 | j1939_uint8_t ReceivedMessagesdCoverOrDroppedNode : 3; 308 | j1939_uint8_t ReceivedMessagesdCover : 1; //接受数据时,J1939协议接受缓存有数据覆盖 309 | j1939_uint8_t ReceivedMessagesDropped : 1; //接受数据时,J1939协议接受缓存有数据溢出 310 | }; 311 | j1939_uint8_t FlagVal; 312 | }; 313 | 314 | typedef union J1939_FLAGS_UNION J1939_FLAG; 315 | 316 | /********************************************API**************************************************************/ 317 | 318 | //初始化函数 319 | extern void J1939_Initialization( ); 320 | //CAN驱动收发中断入口 321 | extern void J1939_ISR( ); 322 | //心跳函数,定时被调用 323 | extern void J1939_Poll( ); 324 | //读取单帧消息 325 | extern j1939_uint8_t J1939_Read_Message( J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node); 326 | //发送单帧消息 327 | extern j1939_uint8_t J1939_Send_Message( J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node); 328 | //多帧(多组)消息发送函数 (RTS/CTS传输协议) 329 | 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); 330 | //多帧(多组)消息接受函数 (RTS/CTS传输协议) 331 | extern j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node); 332 | //请求获去一个PGN 333 | extern void J1939_Request_PGN(j1939_uint32_t pgn ,j1939_uint8_t DA, CAN_NODE _Can_Node); 334 | //创建一个PGN响应 335 | extern void J1939_Create_Response(j1939_uint8_t data[], j1939_uint16_t dataLenght, j1939_uint32_t PGN, void (*dataUPFun)(), CAN_NODE _Can_Node); 336 | 337 | 338 | #endif //__J1939_H 339 | 340 | 341 | 342 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /source/J1939.c: -------------------------------------------------------------------------------- 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_SOURCE 40 | #define __J1939_SOURCE 41 | #endif 42 | 43 | #include "J1939.H" 44 | #include "J1939_config.H" 45 | 46 | #define J1939_TRUE 1 /**< 代表函数正确返回*/ 47 | #define J1939_FALSE 0 /**< 代表函数错误返回*/ 48 | #define ADDRESS_CLAIM_TX 1 /**< 进入地址竞争发送处理模式*/ 49 | #define ADDRESS_CLAIM_RX 2 /**< 进入地址竞争接受处理模式*/ 50 | 51 | //全局变量。 52 | /** 设备的标称符 53 | * 54 | * 我们需要在"J1939_config.H"中配置 55 | * @note 在初始化中赋值,赋值参考参考1939-81文档 56 | */ 57 | j1939_uint8_t CA_Name[J1939_DATA_LENGTH]; 58 | j1939_uint8_t CommandedAddress; 59 | 60 | j1939_uint8_t J1939_Address; 61 | J1939_FLAG J1939_Flags; 62 | J1939_MESSAGE OneMessage; 63 | CAN_NODE Can_Node; 64 | //节点地址 65 | j1939_uint8_t NodeAddress_1; 66 | j1939_uint8_t NodeAddress_2; 67 | j1939_uint8_t NodeAddress_3; 68 | j1939_uint8_t NodeAddress_4; 69 | //接受列队全局变量(CAN_NODE_1) 70 | j1939_uint8_t RXHead_1; 71 | j1939_uint8_t RXTail_1; 72 | j1939_uint8_t RXQueueCount_1; 73 | J1939_MESSAGE RXQueue_1[J1939_RX_QUEUE_SIZE]; 74 | //发送列队全局变量 (CAN_NODE_1) 75 | j1939_uint8_t TXHead_1; 76 | j1939_uint8_t TXTail_1; 77 | j1939_uint8_t TXQueueCount_1; 78 | J1939_MESSAGE TXQueue_1[J1939_TX_QUEUE_SIZE]; 79 | //接受列队全局变量(CAN_NODE_2) 80 | j1939_uint8_t RXHead_2; 81 | j1939_uint8_t RXTail_2; 82 | j1939_uint8_t RXQueueCount_2; 83 | J1939_MESSAGE RXQueue_2[J1939_RX_QUEUE_SIZE]; 84 | //发送列队全局变量 (CAN_NODE_2) 85 | j1939_uint8_t TXHead_2; 86 | j1939_uint8_t TXTail_2; 87 | j1939_uint8_t TXQueueCount_2; 88 | J1939_MESSAGE TXQueue_2[J1939_TX_QUEUE_SIZE]; 89 | //接受列队全局变量(CAN_NODE_3) 90 | j1939_uint8_t RXHead_3; 91 | j1939_uint8_t RXTail_3; 92 | j1939_uint8_t RXQueueCount_3; 93 | J1939_MESSAGE RXQueue_3[J1939_RX_QUEUE_SIZE]; 94 | //发送列队全局变量 (CAN_NODE_3) 95 | j1939_uint8_t TXHead_3; 96 | j1939_uint8_t TXTail_3; 97 | j1939_uint8_t TXQueueCount_3; 98 | J1939_MESSAGE TXQueue_3[J1939_TX_QUEUE_SIZE]; 99 | //接受列队全局变量(CAN_NODE_4) 100 | j1939_uint8_t RXHead_4; 101 | j1939_uint8_t RXTail_4; 102 | j1939_uint8_t RXQueueCount_4; 103 | J1939_MESSAGE RXQueue_4[J1939_RX_QUEUE_SIZE]; 104 | //发送列队全局变量 (CAN_NODE_4) 105 | j1939_uint8_t TXHead_4; 106 | j1939_uint8_t TXTail_4; 107 | j1939_uint8_t TXQueueCount_4; 108 | J1939_MESSAGE TXQueue_4[J1939_TX_QUEUE_SIZE]; 109 | 110 | struct Request_List REQUEST_LIST; 111 | 112 | #if J1939_TP_RX_TX 113 | //TP协议全局变量 114 | J1939_TP_Flags J1939_TP_Flags_t; 115 | J1939_TRANSPORT_RX_INFO TP_RX_MSG; 116 | J1939_TRANSPORT_TX_INFO TP_TX_MSG; 117 | #endif //J1939_TP_RX_TX 118 | 119 | 120 | static void J1939_ReceiveMessages( void ); 121 | static j1939_uint8_t J1939_TransmitMessages( void ); 122 | 123 | /** 124 | * @note 硬件滤波器2 或 软件滤波器 滤波配置(设置PS段)\n 125 | */ 126 | void SetAddressFilter( j1939_uint8_t Address ) 127 | { 128 | /*软件滤波*/ 129 | #if J1939SoftwareFilterEn == J1939_TRUE 130 | switch (Can_Node) 131 | { 132 | case Select_CAN_NODE_1: 133 | { 134 | NodeAddress_1 = Address; 135 | break; 136 | } 137 | case Select_CAN_NODE_2: 138 | { 139 | NodeAddress_2 = Address; 140 | break; 141 | } 142 | case Select_CAN_NODE_3: 143 | { 144 | NodeAddress_3 = Address; 145 | break; 146 | } 147 | case Select_CAN_NODE_4: 148 | { 149 | NodeAddress_4 = Address; 150 | break; 151 | } 152 | default : 153 | { 154 | break; 155 | } 156 | } 157 | #endif//J1939SoftwareFilterEn 158 | /*硬件滤波*/ 159 | Port_SetAddressFilter(Address); 160 | } 161 | 162 | /** 163 | * @param[in] J1939_MESSAGE * 164 | * @note 发送*MsgPtr的信息,所有的数据字段(比如数据长度、优先级、和源地址)必须已经设置。\n 165 | */ 166 | void SendOneMessage( J1939_MESSAGE *MsgPtr ) 167 | { 168 | //设置消息的最后部分,确保DataLength规范。(参考CAN B2.0) 169 | MsgPtr->Mxe.Res = 0;//参考J1939的数据链路层(SAE J1939-21) 170 | MsgPtr->Mxe.RTR = 0; 171 | if (MsgPtr->Mxe.DataLength > 8) 172 | MsgPtr->Mxe.DataLength = 8; 173 | //发送一帧消息,将 J1939_MESSAGE 中的所有消息加载道can模块自有的结构中 174 | Port_CAN_Transmit(MsgPtr); 175 | } 176 | 177 | /** 178 | * @param[in] MsgPtr 用户要出队的消息 179 | * @param[in] _Can_Node 要出队的CAN硬件编号 180 | * @return RC_SUCCESS 消息出队成功 181 | * @return RC_QUEUEEMPTY 没有消息返回 182 | * @note 从接受队列中读取一个信息到*MsgPtr。如果我们用的是中断,需要将中断失能,在获取接受队列数据时 183 | */ 184 | j1939_uint8_t J1939_DequeueMessage( J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node) 185 | { 186 | j1939_uint8_t _rc = RC_SUCCESS; 187 | 188 | //***************************关接受中断******************************** 189 | #if J1939_POLL_ECAN == J1939_FALSE 190 | Port_RXinterruptDisable(); 191 | #endif 192 | switch (_Can_Node) 193 | { 194 | case Select_CAN_NODE_1: 195 | { 196 | if (RXQueueCount_1 == 0) 197 | { 198 | _rc = RC_QUEUEEMPTY; 199 | } 200 | else 201 | { 202 | *MsgPtr = RXQueue_1[RXHead_1]; 203 | RXHead_1 ++; 204 | if (RXHead_1 >= J1939_RX_QUEUE_SIZE) 205 | RXHead_1 = 0; 206 | RXQueueCount_1 --; 207 | } 208 | break; 209 | } 210 | case Select_CAN_NODE_2: 211 | { 212 | if (RXQueueCount_2 == 0) 213 | { 214 | _rc = RC_QUEUEEMPTY; 215 | } 216 | else 217 | { 218 | *MsgPtr = RXQueue_2[RXHead_2]; 219 | RXHead_2 ++; 220 | if (RXHead_2 >= J1939_RX_QUEUE_SIZE) 221 | RXHead_2 = 0; 222 | RXQueueCount_2 --; 223 | } 224 | break; 225 | } 226 | case Select_CAN_NODE_3: 227 | { 228 | if (RXQueueCount_3 == 0) 229 | { 230 | _rc = RC_QUEUEEMPTY; 231 | } 232 | else 233 | { 234 | *MsgPtr = RXQueue_3[RXHead_3]; 235 | RXHead_3 ++; 236 | if (RXHead_3 >= J1939_RX_QUEUE_SIZE) 237 | RXHead_3 = 0; 238 | RXQueueCount_3 --; 239 | } 240 | break; 241 | } 242 | case Select_CAN_NODE_4: 243 | { 244 | if (RXQueueCount_4 == 0) 245 | { 246 | _rc = RC_QUEUEEMPTY; 247 | } 248 | else 249 | { 250 | *MsgPtr = RXQueue_4[RXHead_4]; 251 | RXHead_4 ++; 252 | if (RXHead_4 >= J1939_RX_QUEUE_SIZE) 253 | RXHead_4 = 0; 254 | RXQueueCount_4 --; 255 | } 256 | break; 257 | } 258 | default : 259 | { 260 | _rc = RC_CANNOTRECEIVE; 261 | break; 262 | } 263 | } 264 | //***************************开接受中断******************************** 265 | #if J1939_POLL_ECAN == J1939_FALSE 266 | Port_RXinterruptEnable(); 267 | #endif 268 | 269 | return _rc; 270 | } 271 | /** 272 | * @param[in] MsgPtr 存储读取消息的缓存 273 | * @param[in] _Can_Node 读取消息的CAN硬件编号(从哪一路CAN读取数据) 274 | * @return RC_SUCCESS 读取消息成功, 275 | * @return RC_QUEUEEMPTY 读取消息不成功,没有消息。 276 | * @note 从接受队列中读取一个信息到*MsgPtr。 277 | */ 278 | j1939_uint8_t J1939_Read_Message( J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node) 279 | { 280 | return J1939_DequeueMessage(MsgPtr,_Can_Node); 281 | } 282 | /** 283 | * @param[in] MsgPtr 用户要入队的消息 284 | * @param[in] _Can_Node 要入队的CAN硬件编号(要选择的使用的CAN硬件编号) 285 | * @return RC_SUCCESS 消息入队成功 286 | * @return RC_QUEUEFULL 发送列队满,消息入队失败 287 | * @return RC_CANNOTTRANSMIT 系统目前不能发送消息 288 | * @note 这段程序,将*MsgPtr放入发送消息列队中\n 289 | 如果信息不能入队或者发送,将有一个相应的返回提示,\n 290 | 如果发送中断被设置(可用),当消息列队后,发送中断被使能 291 | */ 292 | j1939_uint8_t J1939_EnqueueMessage( J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node) 293 | { 294 | j1939_uint8_t _rc = RC_SUCCESS; 295 | 296 | #if J1939_POLL_ECAN == J1939_FALSE 297 | Port_TXinterruptDisable(); 298 | #endif 299 | 300 | if (0) 301 | _rc = RC_CANNOTTRANSMIT; 302 | else 303 | { 304 | switch (_Can_Node) 305 | { 306 | case Select_CAN_NODE_1: 307 | { 308 | if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) || 309 | (TXQueueCount_1 < J1939_TX_QUEUE_SIZE)) 310 | { 311 | if (TXQueueCount_1 < J1939_TX_QUEUE_SIZE) 312 | { 313 | TXQueueCount_1 ++; 314 | TXTail_1 ++; 315 | if (TXTail_1 >= J1939_TX_QUEUE_SIZE) 316 | TXTail_1 = 0; 317 | }else{ 318 | J1939_Flags.TransmitMessagesdCover = 1;//发送数据被覆盖,上一帧数据被覆盖 319 | } 320 | TXQueue_1[TXTail_1] = *MsgPtr; 321 | } 322 | else 323 | _rc = RC_QUEUEFULL; 324 | break; 325 | } 326 | case Select_CAN_NODE_2: 327 | { 328 | if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) || 329 | (TXQueueCount_2 < J1939_TX_QUEUE_SIZE)) 330 | { 331 | if (TXQueueCount_2 < J1939_TX_QUEUE_SIZE) 332 | { 333 | TXQueueCount_2 ++; 334 | TXTail_2 ++; 335 | if (TXTail_2 >= J1939_TX_QUEUE_SIZE) 336 | TXTail_2 = 0; 337 | }else{ 338 | J1939_Flags.TransmitMessagesdCover = 1;//发送数据被覆盖,上一帧数据被覆盖 339 | } 340 | TXQueue_2[TXTail_2] = *MsgPtr; 341 | } 342 | else 343 | _rc = RC_QUEUEFULL; 344 | break; 345 | } 346 | case Select_CAN_NODE_3: 347 | { 348 | if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) || 349 | (TXQueueCount_3 < J1939_TX_QUEUE_SIZE)) 350 | { 351 | if (TXQueueCount_3 < J1939_TX_QUEUE_SIZE) 352 | { 353 | TXQueueCount_3 ++; 354 | TXTail_3 ++; 355 | if (TXTail_3 >= J1939_TX_QUEUE_SIZE) 356 | TXTail_3 = 0; 357 | }else{ 358 | J1939_Flags.TransmitMessagesdCover = 1;//发送数据被覆盖,上一帧数据被覆盖 359 | } 360 | TXQueue_3[TXTail_3] = *MsgPtr; 361 | } 362 | else 363 | _rc = RC_QUEUEFULL; 364 | break; 365 | } 366 | case Select_CAN_NODE_4: 367 | { 368 | if ((J1939_OVERWRITE_TX_QUEUE == J1939_TRUE) || 369 | (TXQueueCount_4 < J1939_TX_QUEUE_SIZE)) 370 | { 371 | if (TXQueueCount_4 < J1939_TX_QUEUE_SIZE) 372 | { 373 | TXQueueCount_4 ++; 374 | TXTail_4 ++; 375 | if (TXTail_4 >= J1939_TX_QUEUE_SIZE) 376 | TXTail_4 = 0; 377 | }else{ 378 | J1939_Flags.TransmitMessagesdCover = 1;//发送数据被覆盖,上一帧数据被覆盖 379 | } 380 | TXQueue_4[TXTail_4] = *MsgPtr; 381 | } 382 | else 383 | _rc = RC_QUEUEFULL; 384 | break; 385 | } 386 | default : 387 | { 388 | break; 389 | } 390 | } 391 | } 392 | 393 | #if J1939_POLL_ECAN == J1939_FALSE 394 | Port_TXinterruptEnable(); 395 | //触发发送中断 396 | Port_TXinterruptOk(); 397 | #endif 398 | return _rc; 399 | } 400 | /** 401 | * @param[in] MsgPtr 存储发送消息的缓存 402 | * @param[in] _Can_Node 发送消息的CAN硬件编号(从哪一路CAN发送数据) 403 | * @return RC_SUCCESS 发送消息成功 404 | * @return RC_QUEUEFULL 发送消息不成功,发送列队满,消息入队失败 405 | * @return RC_CANNOTTRANSMIT 发送消息不成功,系统目前不能发送消息 406 | * @note 如果信息不能入队或者发送,将有一个相应的返回提示,\n 407 | */ 408 | j1939_uint8_t J1939_Send_Message( J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node) 409 | { 410 | return J1939_EnqueueMessage(MsgPtr,_Can_Node); 411 | } 412 | /** 413 | * 414 | * @note 这段代码在系统初始化中被调用,(放在CAN设备初始化之后)\n 415 | 初始化J1939全局变量\n 416 | */ 417 | void J1939_Initialization() 418 | { 419 | /*初始化全局变量*/ 420 | J1939_Flags.FlagVal = 0; //没有声明地址,其他的标识位将被设置为0(复位) 421 | 422 | /*初始化接受和发送列队*/ 423 | TXHead_1 = 0; 424 | TXHead_2 = 0; 425 | TXHead_3 = 0; 426 | TXHead_4 = 0; 427 | TXTail_1 = 0xFF; 428 | TXTail_2 = 0xFF; 429 | TXTail_3 = 0xFF; 430 | TXTail_4 = 0xFF; 431 | RXHead_1 = 0; 432 | RXHead_2 = 0; 433 | RXHead_3 = 0; 434 | RXHead_4 = 0; 435 | RXTail_1 = 0xFF; 436 | RXTail_2 = 0xFF; 437 | RXTail_3 = 0xFF; 438 | RXTail_4 = 0xFF; 439 | TXQueueCount_1 = 0; 440 | TXQueueCount_2 = 0; 441 | TXQueueCount_3 = 0; 442 | TXQueueCount_4 = 0; 443 | RXQueueCount_1 = 0; 444 | RXQueueCount_2 = 0; 445 | RXQueueCount_3 = 0; 446 | RXQueueCount_4 = 0; 447 | /*初始化节点地址*/ 448 | NodeAddress_1 = J1939_STARTING_ADDRESS_1; 449 | NodeAddress_2 = J1939_STARTING_ADDRESS_2; 450 | NodeAddress_3 = J1939_STARTING_ADDRESS_3; 451 | NodeAddress_4 = J1939_STARTING_ADDRESS_4; 452 | /*初始化CAN节点的选择*/ 453 | Can_Node = Select_CAN_NODE_1; 454 | /*初始化请求链表*/ 455 | REQUEST_LIST.PGN = 0; 456 | REQUEST_LIST.data = J1939_NULL; 457 | REQUEST_LIST.update = J1939_NULL; 458 | REQUEST_LIST.lenght = 0; 459 | REQUEST_LIST.Can_Node = Select_CAN_NODE_Null; 460 | REQUEST_LIST.next = J1939_NULL; 461 | /*将TP协议置为空闲*/ 462 | #if J1939_TP_RX_TX 463 | J1939_TP_Flags_t.state = J1939_TP_NULL; 464 | J1939_TP_Flags_t.TP_RX_CAN_NODE = Select_CAN_NODE_Null; 465 | J1939_TP_Flags_t.TP_TX_CAN_NODE = Select_CAN_NODE_Null; 466 | 467 | TP_TX_MSG.packets_request_num = 0; 468 | TP_TX_MSG.packets_total = 0; 469 | TP_TX_MSG.packet_offset_p = 0; 470 | TP_TX_MSG.time = 0; 471 | TP_TX_MSG.state = J1939_TP_TX_WAIT; 472 | 473 | TP_RX_MSG.packets_ok_num = 0; 474 | TP_RX_MSG.packets_total = 0; 475 | TP_RX_MSG.time = 0; 476 | TP_RX_MSG.state = J1939_TP_RX_WAIT; 477 | #endif 478 | } 479 | 480 | /** 481 | * @note 这个函数被调用,当设备产生CAN中断(可能是接受中断,也可能是发送中断)\n 482 | 首先我们要清除中断标识位\n 483 | 然后调用接受或者发送函数。 484 | */ 485 | #if J1939_POLL_ECAN == J1939_FALSE 486 | void J1939_ISR( void ) 487 | { 488 | //判断相关标识位,是接受还是发送 489 | //清除标识位 490 | Port_CAN_identifier_clc(); 491 | //调用相关的处理函数 492 | J1939_ReceiveMessages(); 493 | J1939_TransmitMessages(); 494 | #if J1939_TP_RX_TX 495 | J1939_TP_Poll(); 496 | #endif //J1939_TP_RX_TX 497 | //可能存在因为错误产生中断,直接清除相关的标识位 498 | } 499 | #endif 500 | 501 | /** 502 | * @param[in] ElapsedTime 一个大概的毫秒数,通常设置 5 或 3 503 | * @note 如果我们采用轮询的方式获取信息,这个函数每几个毫秒将被调用一次。\n 504 | 不断的接受消息和发送消息从消息队列中\n 505 | 此外,如果我们正在等待一个地址竞争反应。\n 506 | 如果超时,我们只接收特定的消息(目标地址 = J1939_Address)\n 507 | 508 | 如果设备使用中断,此函数被调用,在调用J1939_Initialization()函数后,因为\n 509 | J1939_Initialization()可能初始化WaitingForAddressClaimContention标识位为1.\n 510 | 511 | 如果接受到命令地址消息,这个函数也必须被调用,以防万一总线要求我们改变地址\n 512 | 513 | 如果使用中断模式,本程序将不会处理接受和发送消息,只处理地址竞争超时。\n 514 | */ 515 | //声明TP轮询函数 516 | void J1939_TP_Poll(); 517 | void J1939_Poll( ) 518 | { 519 | //我们必须调用J1939_ReceiveMessages接受函数,在时间被重置为0之前。 520 | #if J1939_POLL_ECAN == J1939_TRUE 521 | Can_Node = Select_CAN_NODE_1; 522 | J1939_Address = NodeAddress_1; 523 | J1939_ReceiveMessages(); 524 | J1939_TransmitMessages(); 525 | Can_Node = Select_CAN_NODE_2; 526 | J1939_Address = NodeAddress_2; 527 | J1939_ReceiveMessages(); 528 | J1939_TransmitMessages(); 529 | Can_Node = Select_CAN_NODE_3; 530 | J1939_Address = NodeAddress_3; 531 | J1939_ReceiveMessages(); 532 | J1939_TransmitMessages(); 533 | Can_Node = Select_CAN_NODE_4; 534 | J1939_Address = NodeAddress_4; 535 | J1939_ReceiveMessages(); 536 | J1939_TransmitMessages(); 537 | #if J1939_TP_RX_TX 538 | J1939_TP_Poll(); 539 | #endif //J1939_TP_RX_TX 540 | #endif //J1939_POLL_ECAN == J1939_TRUE 541 | } 542 | void J1939_Response(const j1939_uint32_t PGN); 543 | 544 | #if J1939SoftwareFilterEn == J1939_TRUE 545 | 546 | /** 547 | * @return RC_SUCCESS 消息是可以接受 548 | * @return RC_CANNOTTRANSMIT 消息是不可以接受 549 | * @note 软件滤波器\n 550 | * @note 基于SAE J1939协议,我们需要CAN控制器提供至少3个滤波器给J1939协议代码。三个滤波器分别配置如下: 551 | 1. 设置滤波器0,只接受广播信息(PF = 240 -255)。 552 | 2. 设置设置滤波器1,2只接受全局地址(J1939_GLOBAL_ADDRESS) 553 | 3. 随着程序的运行,将改变滤波器2,来适应程序逻辑。 554 | */ 555 | j1939_uint8_t J1939_Messages_Filter(J1939_MESSAGE *MsgPtr) 556 | { 557 | /*滤波器0*/ 558 | if((MsgPtr->Mxe.PDUFormat) >= 240) 559 | { 560 | return RC_SUCCESS; 561 | } 562 | /*滤波器1*/ 563 | if(((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS)) 564 | { 565 | return RC_SUCCESS; 566 | } 567 | /*滤波器2*/ 568 | switch (Can_Node) 569 | { 570 | case Select_CAN_NODE_1: 571 | { 572 | if(((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_1)) 573 | { 574 | return RC_SUCCESS; 575 | } 576 | break; 577 | } 578 | case Select_CAN_NODE_2: 579 | { 580 | if(((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_2)) 581 | { 582 | return RC_SUCCESS; 583 | } 584 | break; 585 | } 586 | case Select_CAN_NODE_3: 587 | { 588 | if(((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_3)) 589 | { 590 | return RC_SUCCESS; 591 | } 592 | break; 593 | } 594 | case Select_CAN_NODE_4: 595 | { 596 | if(((MsgPtr->Mxe.PDUFormat) < 240) && (MsgPtr->Mxe.PDUSpecific == NodeAddress_4)) 597 | { 598 | return RC_SUCCESS; 599 | } 600 | break; 601 | } 602 | default : 603 | { 604 | break; 605 | } 606 | } 607 | return RC_CANNOTTRANSMIT; 608 | } 609 | 610 | #endif //J1939SoftwareFilterEn 611 | 612 | /** 613 | * @note 这段程序被调用,当CAN收发器接受数据(中断 或者 轮询)。\n 614 | 如果一个信息被接受, 它将被调用\n 615 | 如果信息是一个网络管理信息或长帧传输(TP),接受的信息将被加工处理,在这个函数中。\n 616 | 否则, 信息将放置在用户的接收队列。\n 617 | 注意:在这段程序运行期间中断是失能的。\n 618 | */ 619 | void J1939_ReceiveMessages( void ) 620 | { 621 | #if J1939_TP_RX_TX 622 | j1939_uint32_t _pgn = 0; 623 | #endif //J1939_TP_RX_TX 624 | /*从接收缓存中读取信息到OneMessage中,OneMessage是一个全局变量*/ 625 | /*Port_CAN_Receive函数读取到数据返回1,没有数据则返回0*/ 626 | if(Port_CAN_Receive(&OneMessage)) 627 | { 628 | #if J1939SoftwareFilterEn == J1939_TRUE 629 | if(J1939_Messages_Filter(&OneMessage) != RC_SUCCESS) 630 | { 631 | return ; 632 | } 633 | #endif //J1939SoftwareFilterEn 634 | switch( OneMessage.Mxe.PDUFormat) 635 | { 636 | #if J1939_TP_RX_TX 637 | case J1939_PF_TP_CM: //参考J1939-21 TP多帧传输协议 638 | _pgn = (j1939_uint32_t)((OneMessage.Mxe.Data[7]<<16)&0xFF0000) 639 | +(j1939_uint32_t)((OneMessage.Mxe.Data[6]<<8)&0xFF00) 640 | +(j1939_uint32_t)((OneMessage.Mxe.Data[5])&0xFF); 641 | if((J1939_TP_Flags_t.state == J1939_TP_NULL) && (TP_RX_MSG.state == J1939_TP_RX_WAIT)) 642 | { 643 | if(OneMessage.Mxe.Data[0] == 16) 644 | { 645 | J1939_TP_Flags_t.state = J1939_TP_RX; 646 | J1939_TP_Flags_t.TP_RX_CAN_NODE = Can_Node; 647 | 648 | TP_RX_MSG.tp_rx_msg.SA = OneMessage.Mxe.SourceAddress; 649 | TP_RX_MSG.tp_rx_msg.PGN = (j1939_uint32_t)((OneMessage.Mxe.Data[7]<<16)&0xFF0000) 650 | +(j1939_uint32_t)((OneMessage.Mxe.Data[6]<<8)&0xFF00) 651 | +(j1939_uint32_t)((OneMessage.Mxe.Data[5])&0xFF); 652 | /*如果系统繁忙*/ 653 | if(TP_RX_MSG.osbusy) 654 | { 655 | TP_RX_MSG.state = J1939_TP_RX_ERROR; 656 | break; 657 | } 658 | /*判断是否有足够的内存接收数据,如果没有直接,断开连接*/ 659 | if(((j1939_uint32_t)((OneMessage.Mxe.Data[2]<<8)&0xFF00) 660 | +(j1939_uint32_t)((OneMessage.Mxe.Data[1])&0xFF)) > J1939_TP_MAX_MESSAGE_LENGTH) 661 | { 662 | TP_RX_MSG.state = J1939_TP_RX_ERROR; 663 | break; 664 | } 665 | TP_RX_MSG.tp_rx_msg.byte_count = ((j1939_uint32_t)((OneMessage.Mxe.Data[2]<<8)&0xFF00) 666 | +(j1939_uint32_t)((OneMessage.Mxe.Data[1])&0xFF)); 667 | TP_RX_MSG.packets_total = OneMessage.Mxe.Data[3]; 668 | TP_RX_MSG.time = J1939_TP_T2; 669 | TP_RX_MSG.state = J1939_TP_RX_READ_DATA; 670 | break; 671 | } 672 | goto PutInReceiveQueue; 673 | break; 674 | } 675 | if(J1939_TP_Flags_t.state == J1939_TP_TX) 676 | { 677 | /*校验PGN*/ 678 | if (_pgn == TP_TX_MSG.tp_tx_msg.PGN) 679 | { 680 | switch(OneMessage.Mxe.Data[0]) 681 | { 682 | case J1939_RTS_CONTROL_BYTE: 683 | /* 程序运行到这里,说明已经与网络中设备1建立虚拟链接(作为发送端),但是收到设备2的链接请求,并且同一个PGN消息请求*/ 684 | /* 根据J1939-21数据链路层的规定,我们要保持原有的链接,不做任何事,设备2会应为超时自动放弃链接*/ 685 | break; 686 | case J1939_CTS_CONTROL_BYTE: 687 | if((J1939_TP_TX_CM_WAIT == TP_TX_MSG.state) || (J1939_TP_WAIT_ACK == TP_TX_MSG.state)) 688 | { 689 | /* 发送等待保持 */ 690 | if(0x00u == OneMessage.Mxe.Data[1]) 691 | { 692 | /* 刷新等待计数器 */ 693 | TP_TX_MSG.time = J1939_TP_T4; 694 | } 695 | else 696 | { 697 | if((OneMessage.Mxe.Data[2]+OneMessage.Mxe.Data[1]) > (TP_TX_MSG.packets_total+1)) 698 | { 699 | /*请求超出数据包范围*/ 700 | TP_TX_MSG.state = J1939_TP_TX_ERROR; 701 | } 702 | else 703 | { /* response parameter OK */ 704 | TP_TX_MSG.packets_request_num = OneMessage.Mxe.Data[1]; 705 | TP_TX_MSG.packet_offset_p = (j1939_uint8_t)(OneMessage.Mxe.Data[2] - 1); 706 | TP_TX_MSG.state = J1939_TP_TX_DT; 707 | } 708 | 709 | } 710 | } 711 | break; 712 | case J1939_EOMACK_CONTROL_BYTE: 713 | if(J1939_TP_WAIT_ACK == TP_TX_MSG.state) 714 | { 715 | TP_TX_MSG.state = J1939_TX_DONE; 716 | } 717 | //这里可以增加一个对数据的校验 718 | break; 719 | case J1939_CONNABORT_CONTROL_BYTE: 720 | //收到一个放弃连接,什么都不做,协议会在一段延时时间后主动放弃链接 721 | break; 722 | default: 723 | break; 724 | } 725 | } 726 | } 727 | goto PutInReceiveQueue; 728 | break; 729 | #endif//J1939_TP_RX_TX 730 | 731 | #if J1939_TP_RX_TX 732 | case J1939_PF_DT: 733 | if((TP_RX_MSG.state == J1939_TP_RX_DATA_WAIT)&&(TP_RX_MSG.tp_rx_msg.SA == OneMessage.Mxe.SourceAddress)) 734 | { 735 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u]=OneMessage.Mxe.Data[1]; 736 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u+1]=OneMessage.Mxe.Data[2]; 737 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u+2]=OneMessage.Mxe.Data[3]; 738 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u+3]=OneMessage.Mxe.Data[4]; 739 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u+4]=OneMessage.Mxe.Data[5]; 740 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u+5]=OneMessage.Mxe.Data[6]; 741 | TP_RX_MSG.tp_rx_msg.data[(OneMessage.Mxe.Data[0]-1)*7u+6]=OneMessage.Mxe.Data[7]; 742 | /*特殊处理重新接受已接受过的数据包*/ 743 | if((OneMessage.Mxe.Data[0]) > TP_RX_MSG.packets_ok_num) 744 | { 745 | TP_RX_MSG.packets_ok_num++; 746 | } 747 | TP_RX_MSG.time = J1939_TP_T1; 748 | /*判断是否收到偶数个数据包或者读取到最后一个数据包*/ 749 | if((TP_RX_MSG.packets_ok_num%2 == 0) ||(TP_RX_MSG.packets_ok_num == TP_RX_MSG.packets_total)) 750 | { 751 | TP_RX_MSG.state = J1939_TP_RX_READ_DATA; 752 | break ; 753 | } 754 | break ; 755 | } 756 | //程序不可能运行到这,但是我们不能放弃接受的数据包 757 | goto PutInReceiveQueue; 758 | #endif//J1939_TP_RX_TX 759 | case J1939_PF_REQUEST: 760 | /*用OneMessage.Mxe.PGN 来存下被请求的PGN*/ 761 | if(OneMessage.Mxe.Data[1] < 240) 762 | { 763 | OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Mxe.Data[2]<<16)&0x030000) 764 | +(j1939_uint32_t)((OneMessage.Mxe.Data[1]<<8)&0xFF00) 765 | +0x00; 766 | }else{ 767 | OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Mxe.Data[2]<<16)&0x030000) 768 | +(j1939_uint32_t)((OneMessage.Mxe.Data[1]<<8)&0xFF00) 769 | +(j1939_uint32_t)((OneMessage.Mxe.Data[0])&0xFF); 770 | } 771 | J1939_Response(OneMessage.Mxe.PGN); 772 | break; 773 | default: 774 | PutInReceiveQueue: 775 | { 776 | /* 777 | if(OneMessage.Mxe.PDUFormat < 240){ 778 | OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Array[0]<<16)&0x030000) 779 | +(j1939_uint32_t)((OneMessage.Array[1]<<8)&0xFF00) 780 | +0x00; 781 | }else{ 782 | OneMessage.Mxe.PGN = (j1939_uint32_t)((OneMessage.Array[0]<<16)&0x030000) 783 | +(j1939_uint32_t)((OneMessage.Array[1]<<8)&0xFF00) 784 | +(j1939_uint32_t)((OneMessage.Array[2])&0xFF); 785 | } 786 | */ 787 | if(OneMessage.Mxe.PDUFormat < 240){ 788 | OneMessage.Mxe.PGN = (OneMessage.Mxe.Res << 17) 789 | +(OneMessage.Mxe.DataPage << 16) 790 | +(OneMessage.Mxe.PDUFormat << 8); 791 | }else{ 792 | OneMessage.Mxe.PGN = (OneMessage.Mxe.Res << 17) 793 | +(OneMessage.Mxe.DataPage << 16) 794 | +(OneMessage.Mxe.PDUFormat << 8) 795 | + OneMessage.Mxe.PDUSpecific; 796 | } 797 | 798 | switch (Can_Node) 799 | { 800 | case Select_CAN_NODE_1: 801 | { 802 | if ( (J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) || 803 | (RXQueueCount_1 < J1939_RX_QUEUE_SIZE)) 804 | { 805 | if (RXQueueCount_1 < J1939_RX_QUEUE_SIZE) 806 | { 807 | RXQueueCount_1 ++; 808 | RXTail_1 ++; 809 | if (RXTail_1 >= J1939_RX_QUEUE_SIZE) 810 | RXTail_1 = 0; 811 | }else{ 812 | J1939_Flags.ReceivedMessagesdCover = 1; //产生数据覆盖 813 | J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_1; 814 | } 815 | RXQueue_1[RXTail_1] = OneMessage; 816 | } 817 | else 818 | J1939_Flags.ReceivedMessagesDropped = 1; //产生数据溢出 819 | break; 820 | } 821 | case Select_CAN_NODE_2: 822 | { 823 | if ( (J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) || 824 | (RXQueueCount_2 < J1939_RX_QUEUE_SIZE)) 825 | { 826 | if (RXQueueCount_2 < J1939_RX_QUEUE_SIZE) 827 | { 828 | RXQueueCount_2 ++; 829 | RXTail_2 ++; 830 | if (RXTail_2 >= J1939_RX_QUEUE_SIZE) 831 | RXTail_2 = 0; 832 | }else{ 833 | J1939_Flags.ReceivedMessagesdCover = 1; //产生数据覆盖 834 | J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_2; 835 | } 836 | RXQueue_2[RXTail_2] = OneMessage; 837 | } 838 | else 839 | J1939_Flags.ReceivedMessagesDropped = 1; 840 | break; 841 | } 842 | case Select_CAN_NODE_3: 843 | { 844 | if ( (J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) || 845 | (RXQueueCount_3 < J1939_RX_QUEUE_SIZE)) 846 | { 847 | if (RXQueueCount_3 < J1939_RX_QUEUE_SIZE) 848 | { 849 | RXQueueCount_3 ++; 850 | RXTail_3 ++; 851 | if (RXTail_3 >= J1939_RX_QUEUE_SIZE) 852 | RXTail_3 = 0; 853 | }else{ 854 | J1939_Flags.ReceivedMessagesdCover = 1; //产生数据覆盖 855 | J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_3; 856 | } 857 | RXQueue_3[RXTail_3] = OneMessage; 858 | } 859 | else 860 | J1939_Flags.ReceivedMessagesDropped = 1; 861 | break; 862 | } 863 | case Select_CAN_NODE_4: 864 | { 865 | if ( (J1939_OVERWRITE_RX_QUEUE == J1939_TRUE) || 866 | (RXQueueCount_4 < J1939_RX_QUEUE_SIZE)) 867 | { 868 | if (RXQueueCount_4 < J1939_RX_QUEUE_SIZE) 869 | { 870 | RXQueueCount_4 ++; 871 | RXTail_4 ++; 872 | if (RXTail_4 >= J1939_RX_QUEUE_SIZE) 873 | RXTail_4 = 0; 874 | }else{ 875 | J1939_Flags.ReceivedMessagesdCover = 1; //产生数据覆盖 876 | J1939_Flags.ReceivedMessagesdCoverOrDroppedNode = Select_CAN_NODE_4; 877 | } 878 | RXQueue_4[RXTail_4] = OneMessage; 879 | } 880 | else 881 | J1939_Flags.ReceivedMessagesDropped = 1; 882 | break; 883 | } 884 | default : 885 | { 886 | break; 887 | } 888 | } 889 | } 890 | 891 | } 892 | } 893 | 894 | } 895 | 896 | 897 | /** 898 | * @return RC_SUCCESS 信息发送成功 899 | * @return RC_CANNOTTRANSMIT 系统没有发送消息,没有要发送的消息,或错误的CAN设备 900 | * @note 调用这个函数后,如果发送消息列队中有消息就位,则会发送消息 ,如果不能发送消息,相关的错误代码将返回。\n 901 | 程序运行期间,中断是被失能的。 902 | */ 903 | static j1939_uint8_t J1939_TransmitMessages() 904 | { 905 | switch (Can_Node) 906 | { 907 | case Select_CAN_NODE_1: 908 | { 909 | if (TXQueueCount_1 == 0) 910 | { 911 | //如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位) 912 | #if J1939_POLL_ECAN == J1939_FALSE 913 | Port_TXinterruptEnable(); 914 | #endif 915 | return RC_CANNOTTRANSMIT; 916 | } 917 | else 918 | { 919 | while(TXQueueCount_1 > 0) 920 | { 921 | /*确保上次数据发送成功*/ 922 | /**************可增加一个判断函数**************************/ 923 | 924 | TXQueue_1[TXHead_1].Mxe.SourceAddress = NodeAddress_1; 925 | 926 | SendOneMessage( (J1939_MESSAGE *) &(TXQueue_1[TXHead_1]) ); 927 | TXHead_1 ++; 928 | if (TXHead_1 >= J1939_TX_QUEUE_SIZE) 929 | TXHead_1 = 0; 930 | TXQueueCount_1 --; 931 | } 932 | 933 | /*配置了一些标识位,使能中断*/ 934 | #if J1939_POLL_ECAN == J1939_FALSE 935 | Port_TXinterruptEnable(); 936 | #endif 937 | } 938 | break; 939 | } 940 | case Select_CAN_NODE_2: 941 | { 942 | if (TXQueueCount_2 == 0) 943 | { 944 | //如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位) 945 | #if J1939_POLL_ECAN == J1939_FALSE 946 | Port_TXinterruptEnable(); 947 | #endif 948 | return RC_CANNOTTRANSMIT; 949 | } 950 | else 951 | { 952 | 953 | while(TXQueueCount_2 > 0) 954 | { 955 | /*确保上次数据发送成功*/ 956 | /**************可增加一个判断函数**************************/ 957 | 958 | TXQueue_2[TXHead_2].Mxe.SourceAddress = NodeAddress_2; 959 | 960 | SendOneMessage( (J1939_MESSAGE *) &(TXQueue_2[TXHead_2]) ); 961 | TXHead_2 ++; 962 | if (TXHead_2 >= J1939_TX_QUEUE_SIZE) 963 | TXHead_2 = 0; 964 | TXQueueCount_2 --; 965 | } 966 | 967 | /*配置了一些标识位,使能中断*/ 968 | #if J1939_POLL_ECAN == J1939_FALSE 969 | Port_TXinterruptEnable(); 970 | #endif 971 | } 972 | break; 973 | } 974 | case Select_CAN_NODE_3: 975 | { 976 | if (TXQueueCount_3 == 0) 977 | { 978 | //如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位) 979 | #if J1939_POLL_ECAN == J1939_FALSE 980 | Port_TXinterruptEnable(); 981 | #endif 982 | return RC_CANNOTTRANSMIT; 983 | } 984 | else 985 | { 986 | while(TXQueueCount_3 > 0) 987 | { 988 | /*确保上次数据发送成功*/ 989 | /**************可增加一个判断函数**************************/ 990 | 991 | TXQueue_3[TXHead_3].Mxe.SourceAddress = NodeAddress_3; 992 | 993 | SendOneMessage( (J1939_MESSAGE *) &(TXQueue_3[TXHead_3]) ); 994 | TXHead_3 ++; 995 | if (TXHead_3 >= J1939_TX_QUEUE_SIZE) 996 | TXHead_3 = 0; 997 | TXQueueCount_3 --; 998 | } 999 | 1000 | /*配置了一些标识位,使能中断*/ 1001 | #if J1939_POLL_ECAN == J1939_FALSE 1002 | Port_TXinterruptEnable(); 1003 | #endif 1004 | } 1005 | break; 1006 | } 1007 | case Select_CAN_NODE_4: 1008 | { 1009 | if (TXQueueCount_4 == 0) 1010 | { 1011 | //如果没有要发送的消息从发送消息列队中,恢复中断(清空发送标识位) 1012 | #if J1939_POLL_ECAN == J1939_FALSE 1013 | Port_TXinterruptEnable(); 1014 | #endif 1015 | return RC_CANNOTTRANSMIT; 1016 | } 1017 | else 1018 | { 1019 | 1020 | while(TXQueueCount_4 > 0) 1021 | { 1022 | /*确保上次数据发送成功*/ 1023 | /**************可增加一个判断函数**************************/ 1024 | 1025 | TXQueue_4[TXHead_4].Mxe.SourceAddress = NodeAddress_4; 1026 | 1027 | SendOneMessage( (J1939_MESSAGE *) &(TXQueue_4[TXHead_4]) ); 1028 | TXHead_4 ++; 1029 | if (TXHead_4 >= J1939_TX_QUEUE_SIZE) 1030 | TXHead_4 = 0; 1031 | TXQueueCount_4 --; 1032 | } 1033 | 1034 | /*配置了一些标识位,使能中断*/ 1035 | #if J1939_POLL_ECAN == J1939_FALSE 1036 | Port_TXinterruptEnable(); 1037 | #endif 1038 | } 1039 | break; 1040 | } 1041 | default : 1042 | { 1043 | return RC_CANNOTTRANSMIT; 1044 | break; 1045 | } 1046 | } 1047 | 1048 | return RC_SUCCESS; 1049 | } 1050 | #if J1939_TP_RX_TX 1051 | /** 1052 | * @note 发送TP.DT,参考J1939-21 1053 | */ 1054 | void J1939_TP_DT_Packet_send(void) 1055 | { 1056 | J1939_MESSAGE _msg; 1057 | j1939_uint16_t _packet_offset_p; 1058 | j1939_int32_t _i=0; 1059 | _msg.Mxe.Priority = J1939_TP_DT_PRIORITY; 1060 | _msg.Mxe.DataPage =0; 1061 | _msg.Mxe.PDUFormat = J1939_PF_DT; 1062 | _msg.Mxe.DestinationAddress = TP_TX_MSG.tp_tx_msg.SA; 1063 | _msg.Mxe.DataLength = 8; 1064 | 1065 | 1066 | /*获取请求发送的数据包数量*/ 1067 | if(TP_TX_MSG.packets_request_num > 0) 1068 | { 1069 | TP_TX_MSG.packets_request_num--; 1070 | /*获取数据偏移指针*/ 1071 | _packet_offset_p = (j1939_uint16_t)(TP_TX_MSG.packet_offset_p*7u); 1072 | /*加载数据包编号*/ 1073 | _msg.Mxe.Data[0] = (j1939_uint8_t)(1u + TP_TX_MSG.packet_offset_p); 1074 | 1075 | for(_i = 0; _i<7; _i++) 1076 | { 1077 | _msg.Mxe.Data[_i+1] = TP_TX_MSG.tp_tx_msg.data[_packet_offset_p + _i]; 1078 | } 1079 | /*是否是最后一包数据消息*/ 1080 | if(TP_TX_MSG.packet_offset_p == (TP_TX_MSG.packets_total - 1u)) 1081 | { 1082 | /*参数群是否能被填满,是否需要填充,*/ 1083 | if ( _packet_offset_p > TP_TX_MSG.tp_tx_msg.byte_count - 7 ) 1084 | { 1085 | /*计算需要填充的数据数*/ 1086 | _i = TP_TX_MSG.tp_tx_msg.byte_count- _packet_offset_p - 7 ; 1087 | 1088 | for ( ; _i < 0 ; _i++ ) 1089 | { 1090 | /*我们默认J1939的参数群大小为8*/ 1091 | _msg.Mxe.Data[_i+8] = J1939_RESERVED_BYTE ; 1092 | } 1093 | } 1094 | 1095 | 1096 | TP_TX_MSG.packets_request_num = 0; 1097 | TP_TX_MSG.packet_offset_p = 0; 1098 | TP_TX_MSG.time = J1939_TP_T3; 1099 | /* 跳转步骤,等待结束确认或则重新发送数据请求*/ 1100 | TP_TX_MSG.state = J1939_TP_WAIT_ACK; 1101 | } 1102 | else 1103 | { 1104 | /*为下一个数据发送做准备*/ 1105 | TP_TX_MSG.packet_offset_p++; 1106 | TP_TX_MSG.state = J1939_TP_TX_DT; 1107 | } 1108 | 1109 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1110 | J1939_EnqueueMessage(&_msg, Can_Node); 1111 | } 1112 | else 1113 | { 1114 | 1115 | TP_TX_MSG.packets_request_num = 0; 1116 | TP_TX_MSG.packet_offset_p = 0; 1117 | TP_TX_MSG.time = J1939_TP_T3; 1118 | TP_TX_MSG.state = J1939_TP_WAIT_ACK; 1119 | } 1120 | 1121 | } 1122 | /** 1123 | * @note 发送TP。CM-RTS,16,23,4,255,PGN消息,参考J1939-21, 1124 | */ 1125 | void J1939_CM_Start(void) 1126 | { 1127 | j1939_uint32_t pgn_num; 1128 | J1939_MESSAGE _msg; 1129 | 1130 | pgn_num = TP_TX_MSG.tp_tx_msg.PGN; 1131 | 1132 | _msg.Mxe.Priority = J1939_TP_CM_PRIORITY; 1133 | _msg.Mxe.DataPage =0; 1134 | _msg.Mxe.PDUFormat = J1939_PF_TP_CM; 1135 | _msg.Mxe.DestinationAddress = TP_TX_MSG.tp_tx_msg.SA; 1136 | _msg.Mxe.DataLength = 8; 1137 | _msg.Mxe.Data[0] = J1939_RTS_CONTROL_BYTE; 1138 | _msg.Mxe.Data[1] = (j1939_uint8_t) TP_TX_MSG.tp_tx_msg.byte_count ; 1139 | _msg.Mxe.Data[2] = (j1939_uint8_t) ((TP_TX_MSG.tp_tx_msg.byte_count)>>8); 1140 | _msg.Mxe.Data[3] = TP_TX_MSG.packets_total; 1141 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1142 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1143 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1144 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1145 | 1146 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1147 | J1939_EnqueueMessage(&_msg, Can_Node); 1148 | 1149 | /*刷新等待时间,触发下一个步骤()*/ 1150 | TP_TX_MSG.time = J1939_TP_T3; 1151 | TP_TX_MSG.state = J1939_TP_TX_CM_WAIT; 1152 | 1153 | } 1154 | /** 1155 | * @note 中断TP链接 1156 | */ 1157 | void J1939_TP_TX_Abort(void) 1158 | { 1159 | J1939_MESSAGE _msg; 1160 | j1939_uint32_t pgn_num; 1161 | 1162 | pgn_num = TP_TX_MSG.tp_tx_msg.PGN; 1163 | 1164 | _msg.Mxe.Priority = J1939_TP_CM_PRIORITY; 1165 | _msg.Mxe.DataPage =0; 1166 | _msg.Mxe.PDUFormat = J1939_PF_TP_CM; 1167 | _msg.Mxe.DestinationAddress = TP_TX_MSG.tp_tx_msg.SA; 1168 | _msg.Mxe.DataLength = 8; 1169 | _msg.Mxe.Data[0] = J1939_CONNABORT_CONTROL_BYTE; 1170 | _msg.Mxe.Data[1] = J1939_RESERVED_BYTE; 1171 | _msg.Mxe.Data[2] = J1939_RESERVED_BYTE; 1172 | _msg.Mxe.Data[3] = J1939_RESERVED_BYTE; 1173 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1174 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1175 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1176 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1177 | 1178 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1179 | J1939_EnqueueMessage(&_msg, Can_Node); 1180 | /*结束发送*/ 1181 | TP_TX_MSG.state = J1939_TX_DONE; 1182 | 1183 | } 1184 | /** 1185 | * @note 中断TP链接 1186 | */ 1187 | void J1939_TP_RX_Abort(void) 1188 | { 1189 | J1939_MESSAGE _msg; 1190 | j1939_uint32_t pgn_num; 1191 | 1192 | pgn_num = TP_RX_MSG.tp_rx_msg.PGN; 1193 | 1194 | _msg.Mxe.Priority = J1939_TP_CM_PRIORITY; 1195 | _msg.Mxe.DataPage =0; 1196 | _msg.Mxe.PDUFormat = J1939_PF_TP_CM; 1197 | _msg.Mxe.DestinationAddress = TP_RX_MSG.tp_rx_msg.SA; 1198 | _msg.Mxe.DataLength = 8; 1199 | _msg.Mxe.Data[0] = J1939_CONNABORT_CONTROL_BYTE; 1200 | _msg.Mxe.Data[1] = J1939_RESERVED_BYTE; 1201 | _msg.Mxe.Data[2] = J1939_RESERVED_BYTE; 1202 | _msg.Mxe.Data[3] = J1939_RESERVED_BYTE; 1203 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1204 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1205 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1206 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1207 | 1208 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1209 | J1939_EnqueueMessage(&_msg, Can_Node); 1210 | /*结束发送*/ 1211 | TP_RX_MSG.state = J1939_RX_DONE; 1212 | 1213 | } 1214 | /** 1215 | * @note TP的计时器 1216 | */ 1217 | j1939_uint8_t J1939_TP_TX_RefreshCMTimer(j1939_uint16_t dt_ms) 1218 | { 1219 | if((J1939_TP_TX_CM_WAIT == TP_TX_MSG.state)||(J1939_TP_WAIT_ACK == TP_TX_MSG.state)) 1220 | { 1221 | if(TP_TX_MSG.time > dt_ms) 1222 | { 1223 | TP_TX_MSG.time = TP_TX_MSG.time - dt_ms; 1224 | return J1939_TP_TIMEOUT_NORMAL; 1225 | } 1226 | else 1227 | { 1228 | /*超时 */ 1229 | TP_TX_MSG.time = 0u; 1230 | return J1939_TP_TIMEOUT_ABNORMAL; 1231 | } 1232 | 1233 | } 1234 | else 1235 | { 1236 | return J1939_TP_TIMEOUT_NORMAL; 1237 | } 1238 | } 1239 | /** 1240 | * @note TP的计时器 1241 | */ 1242 | j1939_uint8_t J1939_TP_RX_RefreshCMTimer(j1939_uint16_t dt_ms) 1243 | { 1244 | if((J1939_TP_RX_DATA_WAIT == TP_RX_MSG.state)) 1245 | { 1246 | if(TP_RX_MSG.time > dt_ms) 1247 | { 1248 | TP_RX_MSG.time = TP_RX_MSG.time - dt_ms; 1249 | return J1939_TP_TIMEOUT_NORMAL; 1250 | } 1251 | else 1252 | { 1253 | /*超时 */ 1254 | TP_RX_MSG.time = 0u; 1255 | return J1939_TP_TIMEOUT_ABNORMAL; 1256 | } 1257 | 1258 | } 1259 | else 1260 | { 1261 | return J1939_TP_TIMEOUT_NORMAL; 1262 | } 1263 | } 1264 | /** 1265 | * @note 发送读取数据 TP.CM_CTS 和 EndofMsgAck消息。 1266 | */ 1267 | void J1939_read_DT_Packet() 1268 | { 1269 | J1939_MESSAGE _msg; 1270 | j1939_uint32_t pgn_num; 1271 | pgn_num = TP_RX_MSG.tp_rx_msg.PGN; 1272 | 1273 | _msg.Mxe.Priority = J1939_TP_CM_PRIORITY; 1274 | _msg.Mxe.DataPage =0; 1275 | _msg.Mxe.PDUFormat = J1939_PF_TP_CM; 1276 | _msg.Mxe.DestinationAddress = TP_RX_MSG.tp_rx_msg.SA; 1277 | _msg.Mxe.DataLength = 8; 1278 | 1279 | /*如果系统繁忙,保持链接但是不传送消息*/ 1280 | if(TP_RX_MSG.osbusy) 1281 | { 1282 | _msg.Mxe.Data[0] = J1939_CTS_CONTROL_BYTE; 1283 | _msg.Mxe.Data[1] = 0; 1284 | _msg.Mxe.Data[2] = J1939_RESERVED_BYTE; 1285 | _msg.Mxe.Data[3] = J1939_RESERVED_BYTE; 1286 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1287 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1288 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1289 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1290 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1291 | J1939_EnqueueMessage(&_msg, Can_Node); 1292 | return ; 1293 | } 1294 | if(TP_RX_MSG.packets_total > TP_RX_MSG.packets_ok_num) 1295 | { 1296 | /*最后一次响应,如果不足2包数据*/ 1297 | if((TP_RX_MSG.packets_total - TP_RX_MSG.packets_ok_num)==1) 1298 | { 1299 | _msg.Mxe.Data[0] = J1939_CTS_CONTROL_BYTE; 1300 | _msg.Mxe.Data[1] = 1; 1301 | _msg.Mxe.Data[2] = TP_RX_MSG.packets_total; 1302 | _msg.Mxe.Data[3] = J1939_RESERVED_BYTE; 1303 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1304 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1305 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1306 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1307 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1308 | J1939_EnqueueMessage(&_msg, Can_Node); 1309 | TP_RX_MSG.state = J1939_TP_RX_DATA_WAIT; 1310 | return ; 1311 | } 1312 | _msg.Mxe.Data[0] = J1939_CTS_CONTROL_BYTE; 1313 | _msg.Mxe.Data[1] = 2; 1314 | _msg.Mxe.Data[2] = (TP_RX_MSG.packets_ok_num + 1); 1315 | _msg.Mxe.Data[3] = J1939_RESERVED_BYTE; 1316 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1317 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1318 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1319 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1320 | 1321 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1322 | J1939_EnqueueMessage(&_msg, Can_Node); 1323 | TP_RX_MSG.state = J1939_TP_RX_DATA_WAIT; 1324 | return ; 1325 | }else 1326 | { 1327 | /*发送传输正常结束消息,EndofMsgAck*/ 1328 | _msg.Mxe.Data[0] = J1939_EOMACK_CONTROL_BYTE; 1329 | _msg.Mxe.Data[1] = (TP_RX_MSG.tp_rx_msg.byte_count & 0x00ff); 1330 | _msg.Mxe.Data[2] = ((TP_RX_MSG.tp_rx_msg.byte_count >> 8) & 0x00ff); 1331 | _msg.Mxe.Data[3] = TP_RX_MSG.packets_total; 1332 | _msg.Mxe.Data[4] = J1939_RESERVED_BYTE; 1333 | _msg.Mxe.Data[7] = (j1939_uint8_t)((pgn_num>>16) & 0xff); 1334 | _msg.Mxe.Data[6] = (j1939_uint8_t)(pgn_num>>8 & 0xff); 1335 | _msg.Mxe.Data[5] = (j1939_uint8_t)(pgn_num & 0xff); 1336 | /*可能队列已满,发不出去,但是这里不能靠返回值进行无限的死等*/ 1337 | J1939_EnqueueMessage(&_msg, Can_Node); 1338 | TP_RX_MSG.state = J1939_RX_DONE; 1339 | return ; 1340 | } 1341 | } 1342 | /** 1343 | * @note TP协议的心跳,为了满足在总线的计时准确,10ms轮询一次 J1939_TP_TX_RefreshCMTimer(10)\n 1344 | 如果想要更高的分辨率,1ms轮询一次,但是要改下面计时函数 J1939_TP_TX_RefreshCMTimer(1) 1345 | */ 1346 | void J1939_TP_Poll() 1347 | { 1348 | if(J1939_TP_Flags_t.state == J1939_TP_NULL || J1939_TP_Flags_t.state == J1939_TP_OSBUSY) 1349 | { 1350 | return ; 1351 | } 1352 | if(J1939_TP_Flags_t.state == J1939_TP_RX) 1353 | { 1354 | Can_Node = J1939_TP_Flags_t.TP_RX_CAN_NODE; 1355 | switch(TP_RX_MSG.state) 1356 | { 1357 | case J1939_TP_RX_WAIT: 1358 | ; 1359 | break; 1360 | case J1939_TP_RX_READ_DATA: 1361 | /*发送读取数据 TP.CM_CTS 和 EndofMsgAck消息*/ 1362 | J1939_read_DT_Packet(); 1363 | break; 1364 | case J1939_TP_RX_DATA_WAIT: 1365 | /*等待TP.DT帧传输的消息*/ 1366 | if(J1939_TP_TIMEOUT_ABNORMAL == J1939_TP_RX_RefreshCMTimer(10)) 1367 | { 1368 | /* 等待超时,发生连接异常,跳转到异常步骤 */ 1369 | TP_RX_MSG.state = J1939_TP_RX_ERROR; 1370 | } 1371 | break; 1372 | case J1939_TP_RX_ERROR: 1373 | J1939_TP_RX_Abort(); 1374 | J1939_TP_Flags_t.TP_RX_CAN_NODE = Select_CAN_NODE_Null; 1375 | break; 1376 | case J1939_RX_DONE: 1377 | TP_RX_MSG.packets_ok_num = 0; 1378 | TP_RX_MSG.packets_total = 0; 1379 | TP_RX_MSG.time = J1939_TP_T3; 1380 | TP_RX_MSG.state = J1939_TP_RX_WAIT; 1381 | J1939_TP_Flags_t.state = J1939_TP_NULL; 1382 | break; 1383 | default: 1384 | break; 1385 | } 1386 | return ; 1387 | } 1388 | if(J1939_TP_Flags_t.state == J1939_TP_TX) 1389 | { 1390 | Can_Node = J1939_TP_Flags_t.TP_TX_CAN_NODE; 1391 | switch (TP_TX_MSG.state) 1392 | { 1393 | case J1939_TP_TX_WAIT: 1394 | /*没有要发送的数据*/ 1395 | break; 1396 | case J1939_TP_TX_CM_START: 1397 | /*发送TP.CM_RTS帧传输的消息(参考j1939-21)*/ 1398 | J1939_CM_Start(); 1399 | break; 1400 | case J1939_TP_TX_CM_WAIT: 1401 | /*等待TP.CM_CTS帧传输的消息*/ 1402 | if(J1939_TP_TIMEOUT_ABNORMAL == J1939_TP_TX_RefreshCMTimer(10)) 1403 | { 1404 | /* 等待超时,发生连接异常,跳转到异常步骤 */ 1405 | TP_TX_MSG.state = J1939_TP_TX_ERROR; 1406 | } 1407 | break; 1408 | case J1939_TP_TX_DT: 1409 | J1939_TP_DT_Packet_send(); 1410 | break; 1411 | case J1939_TP_WAIT_ACK: 1412 | /*等待TP.EndofMsgACK帧传输的消息*/ 1413 | if(J1939_TP_TIMEOUT_ABNORMAL == J1939_TP_TX_RefreshCMTimer(10)) 1414 | { 1415 | /* 等待超时,发生连接异常,跳转到异常步骤 */ 1416 | TP_TX_MSG.state = J1939_TP_TX_ERROR; 1417 | } 1418 | break; 1419 | case J1939_TP_TX_ERROR: 1420 | J1939_TP_TX_Abort(); 1421 | 1422 | break; 1423 | case J1939_TX_DONE: 1424 | TP_TX_MSG.packets_request_num = 0; 1425 | TP_TX_MSG.packet_offset_p = 0; 1426 | TP_TX_MSG.time = J1939_TP_T3; 1427 | TP_TX_MSG.state = J1939_TP_TX_WAIT; 1428 | J1939_TP_Flags_t.state = J1939_TP_NULL; 1429 | break; 1430 | default: 1431 | //程序不会运行到这里来,可以增加一个调试输出 1432 | break; 1433 | } 1434 | return ; 1435 | } 1436 | } 1437 | 1438 | /**这是一个非阻塞io接口 1439 | * 1440 | * @param[in] PGN TP会话的参数群编号 1441 | * @param[in] SA TP会话的目标地址 1442 | * @param[in] *data TP会话的数据缓存地址 1443 | * @param[in] data_num TP会话的数据大小 1444 | * @param[in] _Can_Node 要入队的CAN硬件编号(要选择的使用的CAN硬件编号) 1445 | * @return RC_SUCCESS 成功打开TP链接,开始进入发送流程 1446 | * @return RC_CANNOTTRANSMIT 不能发送,因为TP协议已经建立虚拟链接,并且未断开 1447 | * @note TP协议的发送函数 1448 | */ 1449 | 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) 1450 | { 1451 | j1939_uint16_t _byte_count =0; 1452 | /*取得发送权限*/ 1453 | if(J1939_TP_Flags_t.state == J1939_TP_NULL) 1454 | { 1455 | J1939_TP_Flags_t.state = J1939_TP_TX; 1456 | J1939_TP_Flags_t.TP_TX_CAN_NODE = _Can_Node; 1457 | }else 1458 | { 1459 | return RC_CANNOTTRANSMIT;//不能发送,因为TP协议已经建立虚拟链接,并且未断开 1460 | } 1461 | 1462 | TP_TX_MSG.tp_tx_msg.PGN = PGN; 1463 | TP_TX_MSG.tp_tx_msg.SA = DA; 1464 | TP_TX_MSG.tp_tx_msg.byte_count = data_num; 1465 | for(_byte_count = 0;_byte_count < data_num;_byte_count++) 1466 | { 1467 | TP_TX_MSG.tp_tx_msg.data[_byte_count] = data[_byte_count]; 1468 | } 1469 | TP_TX_MSG.packet_offset_p = 0; 1470 | TP_TX_MSG.packets_request_num = 0; 1471 | TP_TX_MSG.packets_total = data_num/7; 1472 | if((data_num%7) != 0) 1473 | { 1474 | TP_TX_MSG.packets_total ++; 1475 | } 1476 | TP_TX_MSG.time = J1939_TP_T3; 1477 | //触发开始CM_START 1478 | TP_TX_MSG.state = J1939_TP_TX_CM_START; 1479 | 1480 | 1481 | return RC_SUCCESS; 1482 | } 1483 | 1484 | /** 1485 | * @param[in] msg.data 读取数据的缓存 1486 | * @param[in] msg.data_num 读取数据的缓存大小 1487 | * @param[in] _Can_Node 要入队的CAN硬件编号(要选择的使用的CAN硬件编号) 1488 | * @param[out] msg.SA 数据源地址 1489 | * @param[out] msg.byte_count 数据大小 1490 | * @param[out] msg.PGN 数据参数群编号 1491 | * @return RC_CANNOTRECEIVE 不能接受,TP协议正在接受数据中 1492 | * @return RC_SUCCESS 读取数据成功 1493 | * @note TP的接受函数 , 接受缓存的大小必须大于接受数据的大小,建议初始化缓存大小用 J1939_TP_MAX_MESSAGE_LENGTH\n 1494 | 请正确带入 缓存区的大小,参数错误程序运行有风险 1495 | */ 1496 | j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node) 1497 | { 1498 | j1939_uint16_t _a = 0; 1499 | /*判断是否能读取数据*/ 1500 | if(J1939_TP_Flags_t.state == J1939_TP_NULL && TP_RX_MSG.tp_rx_msg.PGN != 0) 1501 | { 1502 | J1939_TP_Flags_t.state = J1939_TP_OSBUSY; 1503 | }else 1504 | { 1505 | return RC_CANNOTRECEIVE;//不能接受,TP协议正在接受数据中,或没有数据 1506 | } 1507 | //判断是不是要读取那一路CAN数据 1508 | if(_Can_Node != J1939_TP_Flags_t.TP_RX_CAN_NODE) 1509 | { 1510 | /*释放TP接管权限*/ 1511 | if(J1939_TP_Flags_t.state == J1939_TP_OSBUSY) 1512 | { 1513 | J1939_TP_Flags_t.state = J1939_TP_NULL; 1514 | } 1515 | return RC_CANNOTRECEIVE; 1516 | } 1517 | //判断数据缓存够不够 1518 | if((msg->data_num) < TP_RX_MSG.tp_rx_msg.byte_count) 1519 | { 1520 | return RC_CANNOTRECEIVE;//不能接受,缓存区太小 1521 | } 1522 | 1523 | /*获取数据*/ 1524 | for(_a = 0;_a < msg->data_num;_a++) 1525 | { 1526 | msg->data[_a] = TP_RX_MSG.tp_rx_msg.data[_a]; 1527 | } 1528 | /*获取数据 源地址*/ 1529 | msg->SA = TP_RX_MSG.tp_rx_msg.SA; 1530 | /*获取数据的大小*/ 1531 | msg->byte_count = TP_RX_MSG.tp_rx_msg.byte_count; 1532 | /*获取数据PGN*/ 1533 | msg->PGN = TP_RX_MSG.tp_rx_msg.PGN; 1534 | 1535 | /*丢弃读取过的数据*/ 1536 | TP_RX_MSG.tp_rx_msg.byte_count= 0u; 1537 | TP_RX_MSG.tp_rx_msg.PGN = 0; 1538 | 1539 | /*释放TP接管权限*/ 1540 | if(J1939_TP_Flags_t.state == J1939_TP_OSBUSY) 1541 | { 1542 | J1939_TP_Flags_t.state = J1939_TP_NULL; 1543 | } 1544 | 1545 | return RC_SUCCESS; 1546 | } 1547 | /** 1548 | * @param[in] pgn 被请求的参数群 1549 | * @param[in] DA 目标地址(DestinationAddress) 当DA = 0xff表示是全局请求 1550 | * @param[in] _Can_Node 要入队的CAN硬件编号(要选择的使用的CAN硬件编号) 1551 | * @note 请求(从全局范围或则特定目的地的)参数群,请求规则J1939-21的16-17页,有明确的说明 1552 | */ 1553 | void J1939_Request_PGN(j1939_uint32_t pgn ,j1939_uint8_t DA, CAN_NODE _Can_Node) 1554 | { 1555 | J1939_MESSAGE _msg; 1556 | 1557 | _msg.Mxe.DataPage = 0; 1558 | _msg.Mxe.Priority = J1939_REQUEST_PRIORITY; 1559 | _msg.Mxe.DestinationAddress = DA; 1560 | _msg.Mxe.DataLength = 3; 1561 | _msg.Mxe.PDUFormat = J1939_PF_REQUEST; 1562 | _msg.Mxe.Data[0] = (j1939_uint8_t)(pgn & 0x000000FF); 1563 | _msg.Mxe.Data[1] = (j1939_uint8_t)((pgn & 0x0000FF00) >> 8); 1564 | _msg.Mxe.Data[2] = (j1939_uint8_t)((pgn & 0x00FF0000) >> 16); 1565 | 1566 | while (J1939_EnqueueMessage( &_msg, _Can_Node) != RC_SUCCESS); 1567 | } 1568 | /** 1569 | * @param[in] data 需要发送数据的缓存 1570 | * @param[in] dataLenght 发送数据的缓存大小 1571 | * @param[in] PGN 需要发送数据的PGN(参数群编号) 1572 | * @param[in] void (*dataUPFun)() 用于更新缓存data 的函数地址指针 1573 | * @param[in] _Can_Node 要入队的CAN硬件编号(要选择的使用的CAN硬件编号) 1574 | * @note 创建一个PGN 的 请求 对应的 响应\n 如果收到改请求则先运行 REQUEST_LIST.dataUPFun(),在将数据REQUEST_LIST.data发送出去 1575 | * @warning 本函数只能被串行调用,(多线程)并行调用请在函数外加互斥操作 1576 | */ 1577 | void J1939_Create_Response(j1939_uint8_t data[],j1939_uint16_t dataLenght,j1939_uint32_t PGN,void (*dataUPFun)(),CAN_NODE _Can_Node) 1578 | { 1579 | /*查找可用的链表项*/ 1580 | struct Request_List * _requestList = &REQUEST_LIST; 1581 | while(J1939_NULL != _requestList->next) 1582 | { 1583 | _requestList = _requestList->next; 1584 | } 1585 | _requestList->next = (struct Request_List *)malloc(sizeof(struct Request_List)); 1586 | _requestList = _requestList->next; 1587 | 1588 | /*对新的链表项赋值*/ 1589 | _requestList->data = data; 1590 | _requestList->lenght = dataLenght; 1591 | _requestList->PGN = PGN; 1592 | _requestList->update = dataUPFun; 1593 | _requestList->Can_Node = _Can_Node; 1594 | _requestList->next = J1939_NULL; 1595 | 1596 | } 1597 | /** 1598 | * @note 当收到一个PGN请求后,如果有REQUEST_LIST中有相应的PGN,则会自动发送REQUEST_LIST中的PGN。\n 1599 | 如果没有则会发送一个NACK; 本函数的响应逻辑,参考J1939-21 17页表4 1600 | */ 1601 | void J1939_Response(const j1939_uint32_t PGN) 1602 | { 1603 | J1939_MESSAGE _msg; 1604 | 1605 | /*查找可用的链表项*/ 1606 | struct Request_List * _requestList = &REQUEST_LIST; 1607 | while((PGN != _requestList->PGN) || (Can_Node != _requestList->Can_Node)) 1608 | { 1609 | if(_requestList->next == J1939_NULL) 1610 | { 1611 | /*原文档规定 全局请求不被支持时不能响应 NACK*/ 1612 | if(OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS) 1613 | { 1614 | return; 1615 | } 1616 | if((PGN & 0xFF00) >= 0xF000) 1617 | { 1618 | return; 1619 | } 1620 | 1621 | /*没有相应的PGN响应被创建,向总线发送一个NACK*/ 1622 | _msg.Mxe.Priority = J1939_ACK_PRIORITY; 1623 | _msg.Mxe.DataPage = 0; 1624 | _msg.Mxe.PDUFormat = J1939_PF_ACKNOWLEDGMENT; 1625 | _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress; 1626 | _msg.Mxe.DataLength = 8; 1627 | _msg.Mxe.SourceAddress = J1939_Address; 1628 | _msg.Mxe.Data[0] = J1939_NACK_CONTROL_BYTE; 1629 | _msg.Mxe.Data[1] = 0xFF; 1630 | _msg.Mxe.Data[2] = 0xFF; 1631 | _msg.Mxe.Data[3] = 0xFF; 1632 | _msg.Mxe.Data[4] = 0xFF; 1633 | _msg.Mxe.Data[5] = (PGN & 0x0000FF); 1634 | _msg.Mxe.Data[6] = ((PGN >> 8) & 0x0000FF); 1635 | _msg.Mxe.Data[7] = ((PGN >> 16) & 0x0000FF); 1636 | 1637 | SendOneMessage( (J1939_MESSAGE *) &_msg); 1638 | return ; 1639 | }else 1640 | { 1641 | _requestList = _requestList->next; 1642 | } 1643 | } 1644 | 1645 | /*调用dataUPFun()函数,主要用于参数群数据更新*/ 1646 | if(J1939_NULL != _requestList->update) 1647 | { 1648 | _requestList->update(); 1649 | } 1650 | 1651 | /*响应请求*/ 1652 | if(_requestList->lenght > 8) 1653 | { 1654 | /*回一个确认响应多帧(非广播多帧)*/ 1655 | if(RC_SUCCESS != J1939_TP_TX_Message(_requestList->PGN,OneMessage.Mxe.SourceAddress,_requestList->data,_requestList->lenght,Can_Node)) 1656 | { 1657 | /*原文档规定 全局请求不被支持时不能响应 NACK*/ 1658 | if(OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS) 1659 | { 1660 | return; 1661 | } 1662 | 1663 | /*如果长帧发送不成功*/ 1664 | _msg.Mxe.Priority = J1939_ACK_PRIORITY; 1665 | _msg.Mxe.DataPage = 0; 1666 | _msg.Mxe.PDUFormat = J1939_PF_ACKNOWLEDGMENT; 1667 | _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress; 1668 | _msg.Mxe.DataLength = 8; 1669 | _msg.Mxe.SourceAddress = J1939_Address; 1670 | _msg.Mxe.Data[0] = J1939_ACCESS_DENIED_CONTROL_BYTE; 1671 | _msg.Mxe.Data[1] = 0xFF; 1672 | _msg.Mxe.Data[2] = 0xFF; 1673 | _msg.Mxe.Data[3] = 0xFF; 1674 | _msg.Mxe.Data[4] = 0xFF; 1675 | _msg.Mxe.Data[5] = (PGN & 0x0000FF); 1676 | _msg.Mxe.Data[6] = ((PGN >> 8) & 0x0000FF); 1677 | _msg.Mxe.Data[7] = ((PGN >> 16) & 0x0000FF); 1678 | 1679 | SendOneMessage( (J1939_MESSAGE *) &_msg); 1680 | return ; 1681 | } 1682 | 1683 | /*回一个确认响应*/ 1684 | _msg.Mxe.Priority = J1939_ACK_PRIORITY; 1685 | _msg.Mxe.DataPage = 0; 1686 | _msg.Mxe.PDUFormat = J1939_PF_ACKNOWLEDGMENT; 1687 | /*原文档规定 全局请求响应到全局*/ 1688 | if(OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS) 1689 | { 1690 | _msg.Mxe.DestinationAddress = 0XFF; 1691 | }else{ 1692 | _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress; 1693 | } 1694 | _msg.Mxe.DataLength = 8; 1695 | _msg.Mxe.SourceAddress = J1939_Address; 1696 | _msg.Mxe.Data[0] = J1939_ACK_CONTROL_BYTE; 1697 | _msg.Mxe.Data[1] = 0xFF; 1698 | _msg.Mxe.Data[2] = 0xFF; 1699 | _msg.Mxe.Data[3] = 0xFF; 1700 | _msg.Mxe.Data[4] = 0xFF; 1701 | _msg.Mxe.Data[5] = (PGN & 0x0000FF); 1702 | _msg.Mxe.Data[6] = ((PGN >> 8) & 0x0000FF); 1703 | _msg.Mxe.Data[7] = ((PGN >> 16) & 0x0000FF); 1704 | SendOneMessage( (J1939_MESSAGE *) &_msg); 1705 | }else{ 1706 | 1707 | /*回一个确认响应*/ 1708 | _msg.Mxe.Priority = J1939_ACK_PRIORITY; 1709 | _msg.Mxe.DataPage = 0; 1710 | _msg.Mxe.PDUFormat = J1939_PF_ACKNOWLEDGMENT; 1711 | _msg.Mxe.SourceAddress = J1939_Address; 1712 | /*原文档规定 全局请求响应到全局*/ 1713 | if((OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS) || ((PGN & 0xFF00) >= 0xF000)) 1714 | { 1715 | _msg.Mxe.DestinationAddress = 0XFF; 1716 | }else{ 1717 | _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress; 1718 | } 1719 | _msg.Mxe.DataLength = 8; 1720 | _msg.Mxe.SourceAddress = J1939_Address; 1721 | _msg.Mxe.Data[0] = J1939_ACK_CONTROL_BYTE; 1722 | _msg.Mxe.Data[1] = 0xFF; 1723 | _msg.Mxe.Data[2] = 0xFF; 1724 | _msg.Mxe.Data[3] = 0xFF; 1725 | _msg.Mxe.Data[4] = 0xFF; 1726 | _msg.Mxe.Data[5] = (PGN & 0x0000FF); 1727 | _msg.Mxe.Data[6] = ((PGN >> 8) & 0x0000FF); 1728 | _msg.Mxe.Data[7] = ((PGN >> 16) & 0x0000FF); 1729 | SendOneMessage( (J1939_MESSAGE *) &_msg); 1730 | 1731 | /*回一个确认响应单帧*/ 1732 | _msg.Mxe.Priority = J1939_ACK_PRIORITY; 1733 | _msg.Mxe.DataPage = (((_requestList->PGN)>>16) & 0x1); 1734 | _msg.Mxe.PDUFormat = ((_requestList->PGN)>>8) & 0xFF; 1735 | _msg.Mxe.SourceAddress = J1939_Address; 1736 | /*原文档规定 全局请求响应到全局*/ 1737 | if(OneMessage.Mxe.PDUSpecific == J1939_GLOBAL_ADDRESS) 1738 | { 1739 | _msg.Mxe.DestinationAddress = 0XFF; 1740 | }else{ 1741 | _msg.Mxe.DestinationAddress = OneMessage.Mxe.SourceAddress; 1742 | } 1743 | _msg.Mxe.DataLength = _requestList->lenght; 1744 | { 1745 | j1939_uint8_t _i = 0; 1746 | for(_i = 0;_i < (_requestList->lenght);_i++) 1747 | { 1748 | _msg.Mxe.Data[_i] = _requestList->data[_i]; 1749 | } 1750 | for(;_i<8;_i++) 1751 | { 1752 | _msg.Mxe.Data[_i] = 0xFF; 1753 | } 1754 | } 1755 | SendOneMessage( (J1939_MESSAGE *) &_msg); 1756 | } 1757 | } 1758 | #endif 1759 | --------------------------------------------------------------------------------