/*********************************************************************
 *
 *            J1939 Main Source Code
 *
 *********************************************************************
 *
 *	本程序是由XieTongXueFlyMe对现有的J1939协议文档分析，和对前辈的贡献总结,
 * 写出的一套开源的J1939驱动。
 *	本协议特点：
 *		1.易移植（不针对特定的CAN硬件，只要满足CAN2.0B即可）
 *		2.轻量级（可适应低端的MCU）
 *		3.支持多任务调用接口（可用于嵌入式系统）
 *		4.双模式（轮询或者中断，逻辑更加简单明了）
 *		5.不掉帧（数据采用收发列队缓存）
 *
 *  源代码下载：
 *		https://github.com/XeiTongXueFlyMe/J1939
 *  源代码临时手册Web站点：
 *		https://xeitongxueflyme.github.io/j1939doc.github.io/
 *
 * Version     Date        Description
 * -------------------------------------------------------------------
 * v1.0.0     2017/06/04    首个版本 Version 1 测试版发布
 * v1.0.1     2017/08/04    完善功能
 * v1.1.0     2017/11/22    Version 1 稳定发布版
 * v2.0.1     2017/11/24    Version 2 测试版发布
 * v2.0.2     2018/01/03    解决V2.0.1 遗留问题
 * v2.1.0     2018/01/20    Version 2 稳定发布版
 * Author               Date         changes
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *XeiTongXueFlyMe       7/06/04      首个版本
 *XeiTongXueFlyMe       7/08/04      增加对TP的支持
 *XeiTongXueFlyMe       7/11/24      增加对多路CAN硬件的收发，和报文处理
 *XeiTongXueFlyMe       7/11/29      增加请求和响应API
 *XeiTongXueFlyMe       7/12/07      重做TP接受API函数
 *XeiTongXueFlyMe       7/12/08      增加软件滤波器
 *XeiTongXueFlyMe       8/01/03      重做接受发送API，简化协议栈初始化调用逻辑
 **********************************************************************/
#ifndef __J1939_H
#define __J1939_H
/******************************类型声明*********************************/
#define FALSE 0
#define TRUE  1

/** 统一类型定义
 *  不同的单片机的编译器， int,short,long 的位数可能不同
 *
 *  在移植J1939协议栈时，首先应该配置这里
 */
typedef unsigned int   j1939_uint32_t; /** < 32位无符号整形*/
typedef int            j1939_int32_t;  /** < 32位整形*/
typedef unsigned short j1939_uint16_t; /** < 16位无符号整形*/
typedef unsigned char  j1939_uint8_t;  /** < 8位无符号整形*/
typedef char           j1939_int8_t;   /** < 8位无符号整形*/
#define J1939_NULL 0

// 函数返回代码
#define RC_SUCCESS        0 /**< 成功*/
#define RC_QUEUEEMPTY     1 /**< 列队为空*/
#define RC_QUEUEFULL      1 /**< 列队满*/
#define RC_CANNOTRECEIVE  2 /**< 不能接收*/
#define RC_CANNOTTRANSMIT 2 /**< 不能传输*/
#define RC_PARAMERROR     3 /**< 参数错误*/

// 内部常量
#define J1939_FALSE 0 /**< 代表函数错误返回*/
#define J1939_TRUE  1 /**< 代表函数正确返回*/

// J1939 默认的优先级（参考J1939文档）
#define J1939_CONTROL_PRIORITY     0x03 /**< J1939文档默认的优先级*/
#define J1939_INFO_PRIORITY        0x06 /**< J1939文档默认的优先级*/
#define J1939_PROPRIETARY_PRIORITY 0x06 /**< J1939文档默认的优先级*/
#define J1939_REQUEST_PRIORITY     0x06 /**< J1939文档默认的优先级*/
#define J1939_ACK_PRIORITY         0x06 /**< J1939文档默认的优先级*/
#define J1939_TP_CM_PRIORITY       0x07 /**< J1939文档默认的优先级*/
#define J1939_TP_DT_PRIORITY       0x07 /**< J1939文档默认的优先级*/

// J1939 定义的地址
#define J1939_GLOBAL_ADDRESS 255 /**< 全局地址*/
#define J1939_NULL_ADDRESS   254 /**< 空地址*/

// J1939协议栈的PNG请求响应，相关的定义
#define J1939_PF_REQUEST2 201 /**< J1939协议栈的请求 PF */
#define J1939_PF_TRANSFER 202 /**< J1939协议栈的转移 PF */

#define J1939_PF_REQUEST        234 /**< 请求 或 用于握手机制*/
#define J1939_PF_ACKNOWLEDGMENT 232 /**< 确认请求 或 用于握手机制*/

#define J1939_ACK_CONTROL_BYTE            0 /**< 用于TP(长帧数据)，代表确认*/
#define J1939_NACK_CONTROL_BYTE           1 /**< 用于TP(长帧数据)，PNG不被支持。否定消息*/
#define J1939_ACCESS_DENIED_CONTROL_BYTE  2 /**< 拒绝访问，但是信息是被支持，暂时不能响应（需要再次发送请求）*/
#define J1939_CANNOT_RESPOND_CONTROL_BYTE 3 /**< 不能做出反应，有空但是接受的缓存不够，或则发送资源被占领，暂时不能响应（需要再次发送请求）*/

// TP协议的一些宏定义
#define J1939_PF_DT    235 /**< 协议传输---数据传输 PF*/
#define J1939_PF_TP_CM 236 /**< 协议传输---链接管理 PF*/

// TP的超时时间，单位（ms）
#define J1939_TP_Tr                  200  /**< 宏定义TP的超时时间*/
#define J1939_TP_Th                  500  /**< 宏定义TP的超时时间*/
#define J1939_TP_T1                  750  /**< 宏定义TP的超时时间*/
#define J1939_TP_T2                  1250 /**< 宏定义TP的超时时间*/
#define J1939_TP_T3                  1250 /**< 宏定义TP的超时时间*/
#define J1939_TP_T4                  1050 /**< 宏定义TP的超时时间*/
#define J1939_TP_TIMEOUT_NORMAL      0    /**< 未超时正常*/
#define J1939_TP_TIMEOUT_ABNORMAL    1    /**< 超时*/
#define J1939_RTS_CONTROL_BYTE       16   /**< TP.CM_RTS*/
#define J1939_CTS_CONTROL_BYTE       17   /**< TP.CM_CTS*/
#define J1939_EOMACK_CONTROL_BYTE    19   /**< 消息应答结束*/
#define J1939_BAM_CONTROL_BYTE       32   /**< 广播公告消息*/
#define J1939_CONNABORT_CONTROL_BYTE 255  /**< 连接中断控制字节（放弃连接）*/
#define J1939_RESERVED_BYTE          0xFF /**< 变量的保留位的值*/

// 与J1939网络层有关的定义
#define J1939_PGN2_REQ_ADDRESS_CLAIM 0x00
#define J1939_PGN1_REQ_ADDRESS_CLAIM 0xEA
#define J1939_PGN0_REQ_ADDRESS_CLAIM 0x00

#define J1939_PGN2_COMMANDED_ADDRESS 0x00
#define J1939_PGN1_COMMANDED_ADDRESS 0xFE /**< 命令地址消息*/
#define J1939_PGN0_COMMANDED_ADDRESS 0xD8 /**< 参考J1939-81 地址命令配置*/

#define J1939_PF_ADDRESS_CLAIMED      238
#define J1939_PF_CANNOT_CLAIM_ADDRESS 238
#define J1939_PF_PROPRIETARY_A        239 /**< 专用A*/
#define J1939_PF_PROPRIETARY_B        255 /**< 专用B*/

/**< 是否对TP协议的支持（是否支持长帧（大于8字节的数据）的发送与接受）*/
#define J1939_TP_RX_TX J1939_TRUE
/**< TP协议的支持的最大接受发送消息长度(最大可配置为1785)*/
#define J1939_TP_MAX_MESSAGE_LENGTH 240

/**CAN节点的选择枚举
 *
 * 默认支持最大4路CAN硬件\n
 */
typedef enum
{
    Select_CAN_NODE_Null, /**< 不选择任何CAN硬件*/
    Select_CAN_NODE_1,    /**< 选择CAN硬件 1*/
    Select_CAN_NODE_2,    /**< 选择CAN硬件 2*/
    Select_CAN_NODE_3,    /**< 选择CAN硬件 3*/
    Select_CAN_NODE_4,    /**< 选择CAN硬件 4*/
} CAN_NODE;

#if J1939_TP_RX_TX
/**TP的状态描述枚举
 *
 */
typedef enum
{
    J1939_TP_NULL,   /**< 长数据传输处于空闲，只有TP系统处于空闲，才能用处理下一个发送，和接受请求*/
    J1939_TP_RX,     /**< 长数据传输处于接收*/
    J1939_TP_TX,     /**< 长数据传输处于发送*/
    J1939_TP_OSBUSY, /**< 长数据传输处于繁忙，比如刚接受一整段长数据，但是CPU没来得处理，又一个长数据请求到来，为了数据不被覆盖，将状态设为本值*/
} J1939_TP_State;
/**TP的标志位结构体
 *
 * 本结构体记录了TP的状态，使用TP发送和接受的CAN硬件编号
 */
typedef struct
{
    J1939_TP_State state;          /**< TP的连接状态*/
    CAN_NODE       TP_RX_CAN_NODE; /**< TP接受请求产生的 CAN硬件编号*/
    CAN_NODE       TP_TX_CAN_NODE; /**< TP接受发送产生的 CAN硬件编号*/
} J1939_TP_Flags;
/**J1939消息对象的结构体
 *
 * 本结构体实现了 J1939的消息对象
 */
typedef struct
{
    j1939_uint32_t PGN;                               /**< J1939的消息对象的 PGN*/
    j1939_uint8_t  data[J1939_TP_MAX_MESSAGE_LENGTH]; /**< J1939的消息对象的 数据*/
    j1939_uint16_t byte_count;                        /**< J1939的消息对象的 数据大小*/
    j1939_uint8_t  SA;                                /**< J1939的消息对象的 目标地址（发送目的地  或  接受来源地）*/

} J1939_MESSAGE_T;
/**J1939消息对象的结构体
 *
 * 本结构体实现了 J1939的多帧消息对象
 */
typedef struct
{
    j1939_uint8_t *data;       /**< 缓存区指针*/
    j1939_uint16_t data_num;   /**< 缓存区大小*/
    j1939_uint8_t  SA;         /**< J1939的消息对象的 数据 源地址*/
    j1939_uint16_t byte_count; /**< J1939的消息对象的 数据大小*/
    j1939_uint32_t PGN;        /**< J1939的消息对象的 PGN*/
} TP_RX_MESSAGE;
/**J1939_TP_Tx_Step枚举
 *
 * 实现了记录长帧（多帧）传输的TX 的步骤
 */
typedef enum
{
    J1939_TP_TX_WAIT,
    J1939_TP_TX_CM_START,
    J1939_TP_TX_CM_WAIT,
    J1939_TP_TX_DT,
    J1939_TP_WAIT_ACK,
    J1939_TP_TX_ERROR,
    J1939_TX_DONE,
} J1939_TP_Tx_Step; // 协议的发送步骤
/**J1939_TRANSPORT_TX_INFO 结构体
 *
 * 实现了长帧传输中产生的临时数据，和一些传输交换数据
 */
typedef struct
{
    J1939_MESSAGE_T  tp_tx_msg;           /**< J1939的消息对象*/
    j1939_uint16_t   time;                /**< 时间*/
    j1939_uint8_t    packet_offset_p;     /**< 数据包偏移指针*/
    j1939_uint8_t    packets_total;       /**< 总共有多少个数据包*/
    j1939_uint8_t    packets_request_num; /**< 请求发送的数据包数（接受方准备接受的数据包数）*/
    J1939_TP_Tx_Step state;               /**< 协议的发送步骤*/
} J1939_TRANSPORT_TX_INFO;
/**J1939_TP_Rx_Step枚举
 *
 * 实现了记录长帧（多帧）传输的RX 的步骤
 */
typedef enum
{
    J1939_TP_RX_WAIT,
    J1939_TP_RX_READ_DATA,
    J1939_TP_RX_DATA_WAIT,
    J1939_TP_RX_ERROR,
    J1939_RX_DONE,
} J1939_TP_Rx_Step; // 协议的接收步骤

/**J1939_TRANSPORT_RX_INFO 结构体
 *
 * 实现了长帧传输中产生的临时数据，和一些传输交换数据
 */
typedef struct
{
    J1939_MESSAGE_T  tp_rx_msg;      /**< J1939的消息对象*/
    j1939_uint8_t    osbusy;         /**< 此位置1，代表系统繁忙，cpu需要处理其他的事物，直接拒绝一切的链接请求\n 如果正在接受中，此位置1，则会发出链接保持消息帧。*/
    j1939_uint16_t   time;           /**< 时间*/
    j1939_uint8_t    packets_total;  /**< 总共有多少个数据包*/
    j1939_uint8_t    packets_ok_num; /**< 已经接受的数据包数*/
    J1939_TP_Rx_Step state;          /**< 协议的接受步骤*/
} J1939_TRANSPORT_RX_INFO;

#endif // J1939_TP_RX_TX

/**
 * @note 实现Request_PGN 的响应
 */
struct Request_List
{
    j1939_uint8_t *data;
    j1939_uint16_t lenght;
    j1939_uint32_t PGN;
    CAN_NODE       Can_Node;
    void (*update)();          /**< 在函数里需要对data更新，如果不用更新data赋值为J1939_NULL*/
    struct Request_List *next; /**< 链表末尾，需要一直保持J1939_NULL*/
};

// J1939 Data Structures
// J1939_MESSAGE_STRUCT旨在J1939消息块映射到设备的地址映射。 只有字段PDU格式不映射到设备寄存器。
// 结构应该简单地使用PDUFormat和忽视PDUFormat_Top。调整将立即接收和传输之前。
// 注:编译器创建结构从低一点的位置高一些位置，所以可能出现不匹配的设备寄存器。
#define J1939_MSG_LENGTH  9 // 消息长度
#define J1939_DATA_LENGTH 8 // 数据长度

/** J1939_MESSAGE_UNION 结构体
 * 实现了J1939消息对象
 *
 *
 */
union J1939_MESSAGE_UNION
{
    /** j1939 的 ID 组成结构体
     *
     */
    struct j1939_PID
    {
        j1939_uint8_t  DataPage : 1;            /**< 数据页*/
        j1939_uint8_t  Res      : 1;            /**< Res位*/
        j1939_uint8_t  Priority : 3;            /**< 优先级*/
        j1939_uint8_t  Reserve  : 3;            /**< 空闲*/
        j1939_uint8_t  PDUFormat;               /**< PF*/
        j1939_uint8_t  PDUSpecific;             /**< PS*/
        j1939_uint8_t  SourceAddress;           /**< SA*/
        j1939_uint8_t  DataLength : 4;          /**< 数据长度*/
        j1939_uint8_t  RTR        : 4;          /**< RTR位*/
        j1939_uint8_t  Data[J1939_DATA_LENGTH]; /**< 数据*/
        j1939_uint32_t PGN        : 24;         /**< 参数群编号*/
        j1939_uint32_t ReservePGN : 8;          /**< 空闲*/
    };
    struct j1939_PID Mxe;                                         /**< j1939 的 ID 组成结构体*/
    j1939_uint8_t    Array[J1939_MSG_LENGTH + J1939_DATA_LENGTH]; /**< 联合体数组，方便快速处理结构体赋值*/
};

#define GroupExtension     PDUSpecific
#define DestinationAddress PDUSpecific
/** 一个宏定义，具体变量名称作用命名
 *
 */
typedef union J1939_MESSAGE_UNION J1939_MESSAGE;

union J1939_FLAGS_UNION
{
    struct
    {
        j1939_uint8_t TransmitMessagesdCover              : 1; // 发送数据时，J1939协议接受缓存有数据覆盖
        j1939_uint8_t ReceivedMessagesdCoverOrDroppedNode : 3;
        j1939_uint8_t ReceivedMessagesdCover              : 1; // 接受数据时，J1939协议接受缓存有数据覆盖
        j1939_uint8_t ReceivedMessagesDropped             : 1; // 接受数据时，J1939协议接受缓存有数据溢出
    };
    j1939_uint8_t FlagVal;
};

typedef union J1939_FLAGS_UNION J1939_FLAG;

/********************************************API**************************************************************/

// 初始化函数
extern void J1939_Initialization();
// CAN驱动收发中断入口
extern void J1939_ISR();
// 心跳函数,定时被调用
extern void J1939_Poll();
// 读取单帧消息
extern j1939_uint8_t J1939_Read_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
// 发送单帧消息
extern j1939_uint8_t J1939_Send_Message(J1939_MESSAGE *MsgPtr, CAN_NODE _Can_Node);
// 多帧（多组）消息发送函数  (RTS/CTS传输协议)
extern j1939_int8_t J1939_TP_TX_Message(j1939_uint32_t PGN, j1939_uint8_t DA, j1939_uint8_t *data, j1939_uint16_t data_num, CAN_NODE _Can_Node);
// 多帧（多组）消息接受函数  (RTS/CTS传输协议)
extern j1939_int8_t J1939_TP_RX_Message(TP_RX_MESSAGE *msg, CAN_NODE _Can_Node);
// 请求获去一个PGN
extern void J1939_Request_PGN(j1939_uint32_t pgn, j1939_uint8_t DA, CAN_NODE _Can_Node);
// 创建一个PGN响应
extern void J1939_Create_Response(j1939_uint8_t data[], j1939_uint16_t dataLenght, j1939_uint32_t PGN, void (*dataUPFun)(), CAN_NODE _Can_Node);

#endif //__J1939_H
