
#ifndef J1939_H_
#define J1939_H_

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include "platmacro.h"


typedef uint8_t J1939Result;
typedef uint32_t uint32_T;
typedef uint16_t uint16_T;
typedef uint8_t  uint8_T;
typedef int32_t  int32_T;
typedef int16_t  int16_T;
typedef int8_t   int8_T;

#ifndef J1939_PAGED
#define J1939_PAGED
#endif

#ifndef FALSE
#define FALSE 0U
#endif

#ifndef TRUE
#define TRUE 1U
#endif

#define  J1939_CAN_FRAME_DATA_LEN   8

/******************************返回码定义***********************************/


#define J1939_OK                       0 //成功
#define J1939_ERR                      1 //错误
#define J1939_PTR_NULL                 2 //指针为空
#define J1939_QUEUE_FULL               3 //队列满
#define J1939_QUEUE_EMPTY              4 //队列空
#define J1939_TP_FRAME_NUM_ERROR       5 //TP帧序号错误
#define J1939_TP_RX_SESSION_FULL       6 //接收TP满
#define J1939_TP_RX_SESSION_NOT_OPEN   7 //接收TP没有打开
#define J1939_TP_RX_SESSION_NOT_EXIST  8 //不存在对应TP
#define J1939_TP_TX_SESSION_BUSY       9 //发送TP忙
#define J1939_TP_TX_SESSION_NOT_OPEN  10 //发送TP没有打开
#define J1939_MSG_FULL                11 //消息满
#define J1939_MSG_EMPTY               12 //消息空
#define J1939_MSG_LEN_TO_LONG         13 //消息长度过长
#define  J1939_WAIT_CTS_TIMEOUT       14 //等待CTS超时
#define  J1939_WAIT_ENDACK_TIMEOUT    15 //等待ENDACK超时
/******************************TP的PGN定义***********************************/
#define J1939_PGN_TP_CM         0x00EC00
#define J1939_PGN_TP_DATA       0x00EB00
/******************************TP优先级定义***********************************/
#define J1939_TP_CM_DEFAULT_PRI   0x07
#define J1939_TP_DATA_DEFAULT_PRI 0x07
#define J1939_MSG_DEFAULT_PRI     0x06
/******************************J1939CM定义***********************************/
#define J1939_TP_CM_RTS         16
#define J1939_TP_CM_CTS         17
#define J1939_TP_CM_END         19
#define J1939_TP_CM_BAM         32
#define J1939_TP_CM_ABORT       255        
/******************************超时时间定义***********************************/
#define J1939_TP_DATA_TX_TIME_INTERVAL  1       //TP发送数据时间间隔   2ms
#define J1939_BAM_TX_TIME_INTERVAL      50      //广播发送数据时间间隔 50ms
#define J1939_CTS_RESEND_TIMEOUT  20      //20ms
#define J1939_Tr_TIMEOUT          200     //200ms
#define J1939_Th_TIMEOUT          500     //500ms
#define J1939_T1_TIMEOUT          750     //750ms
#define J1939_T2_TIMEOUT          1250    //1250ms
#define J1939_T3_TIMEOUT          1250    //1250ms
#define J1939_T4_TIMEOUT          1050    //1050ms


/****************************************************************************/
#define GET_PGN_PS(PGN) ((uint8_T)(PGN))         //获取PGN的PS
#define GET_PGN_PF(PGN) ((uint8_T)((PGN) >> 8))  //获取PGN的PF
#define GET_PGN_DP(PGN) ((uint8_T)((PGN) >> 16))//获取PGN的DP(目标地址)
/****************************数据内存定义*************************************/
#define J1939_RX_MSG_QUEUE_MAX_NUM  1         //J1939接收到消息队列数目
#define J1939_TP_RX_SESSION_NUM     1         //支持TP数目(支持和其他通信CAN节点数)
#define J1939_CAN_FRAME_QUEUE_NUM   128        //CAN数据帧队列数目
/****************************************************************************/
#define  J1939_TP_DT_MAX_CNT     16//在正常的车辆运行期间，建议把每个CTS 中可发送的数据包最大数目设置为16


#define J1939_DTC_SEND_BUFF_MAX 32
#define J1939_DTC_MAX           20
#define J1939_OC_MAX            126

#define J1939_DTC_DM_BROADCAST_INTERVAL 1000

#define J1939_DM1_PRI           6
#define J1939_DM1_PGN           0xFECA


#define CAN_FRAME_DATA_MAX_LEN   8  

/************************************************
  * @enum   CanMode
  * @brief  CAN标识符
 ***********************************************/
typedef enum
{
    kCanStandardMode = 0,
    kCanExtendMode = 1,
} CanMode;

 typedef union
{
    uint32_T value; // 32-bit Data Type
    uint16_T words[2]; // 16-bit Data Type
    uint8_T bytes[4]; // Four 8-bit Data Type
} Can32Bit;

typedef struct
{
    Can32Bit   id;  // CAN报文id
    uint8_T    len;  // CAN 报文长度
    uint8_T    data[CAN_FRAME_DATA_MAX_LEN]; //CAN报文数据域数组8
    uint8_T    piro;  //报文优先级
    CanMode  can_id_mode;
} J1939CanMessage;
//TP状态定义
typedef enum
{
	kTp_IDLE,//空闲
	kTp_RTS,//发送请求
	kTp_CTS,//等待CTS
	kTp_DT, //发送或接收数据
	kTp_END,//数据发送或接收完成
	kTp_ABORT,
//错误
} TpStatus;
//j1939CAN  ID定义
typedef union
{
	uint32_T value;
	struct
	{
          uint32_T SA :8; //源地址
          uint32_T PS :8; //目标地址
          uint32_T PF :8; //PF
          uint32_T DP :1; //页
          uint32_T R :1; //远程帧还是...
          uint32_T P :3; //优先级
	  uint32_T NA :3; //空	
	} Bits;
} J1939CanId;
typedef struct
{
	J1939CanId id; //id号
	uint8_T data_len; //数据长度
	uint8_T data[J1939_CAN_FRAME_DATA_LEN];
	uint8_T  piro;  //报文优先级
	uint8_T mode; //模式
} J1939CanFrame;

//CAN设备参数定义
typedef struct
{
	uint8_T handleid; //设备号HANDLE
	uint32_T bps; //波特率
	uint8_T addr; //设备地址
} J1939CanDeviceParam;
//存放单帧CAN数据帧的环形数组栈
typedef struct
{
	J1939CanMessage frame[J1939_CAN_FRAME_QUEUE_NUM];
	uint8_T pop_index;
	uint8_T push_index;
	uint8_T cnt;
	pthread_mutex_t mutex; //互斥锁
} J1939CanFrameQueue;
//j1939消息结构体定义
typedef struct
{
	J1939CanId id;//ID号
	uint32_T pgn; //PGN
	uint8_T dest_addr; //目标地址
	uint8_T source_addr;//原地址
	uint16_T msg_len; //消息长度
	uint16_T msg_max_len;
	uint8_T * J1939_PAGED data;//消息
} J1939Msg;
//j1939TP通讯过程结构体定义
typedef struct
{
	J1939Msg msg; //J1939消息
	uint8_T is_open; //是否开启
	uint8_T is_bam;//是否是广播信息
	uint8_T frame_cnt; //帧总数
	uint8_T max_tx_frame_num;//最大发送帧数
	uint8_T frame_index; //帧编号
	uint8_T frame_err_flag;//接收帧编号错误标志(漏帧)
	uint8_T start_frame;//起始帧号
	uint8_T end_frame; //结束帧号
	TpStatus status; //TP状态
	uint32_T last_tick;//上次时间
	uint16_T time_out;//超时时间
	uint8_T  frame_recved_flag[J1939_CAN_FRAME_QUEUE_NUM];//多帧已接收标志
	uint32_T resendTick;//重发请求时间
} J1939TpSession;
//j1939最终接收到消息存放的环形数组队列中
typedef struct
{
	J1939Msg msg[J1939_RX_MSG_QUEUE_MAX_NUM];
	uint8_T pop_index;
	uint8_T push_index;
	uint8_T cnt;
	pthread_mutex_t mutex; //互斥锁
} J1939RxMsgQueue;


typedef enum
{
    kDTCNone = 0,
    kDTCOn,
    kDTCOff
}DtcStatus;

typedef struct
{
    uint32_T spn;
    uint8_T fmi;
    uint8_T cm;
    uint8_T oc;
}J1939DtcInfo;

typedef struct _LIST_ITEM
{
  struct _LIST_ITEM* next;
}LIST_ITEM;

typedef struct
{
    LIST_ITEM* J1939_PAGED next;
    DtcStatus status;
    uint8_T send_flag;
    uint8_T oc_last_second;
    uint32_T last_tick;
    J1939DtcInfo info;
}J1939DtcItem;

typedef struct
{
    J1939DtcItem* J1939_PAGED dtc_item_start;
    uint8_T is_start;
    uint32_T last_tick; //用于1秒周期计时
    uint8_T occure_cnt_one_second;
    uint8_T release_cnt_one_second;
    uint8_T send_failure_flag;
    uint8_T dtc_item_cnt;
    uint8_T dtc_item_max;
    J1939DtcItem  dtc_item_buff[J1939_DTC_MAX];
}J1939DtcContext;




//j1939结构体定义
typedef struct
{
	J1939CanDeviceParam device_param; //CAN设备参数
	J1939TpSession tp_rx_session[J1939_TP_RX_SESSION_NUM]; //J1939接收信息过程
	J1939TpSession tp_tx_session; //J1939发送信息过程
	J1939CanFrameQueue tx_frame_tmp_queue; //发送CAN数据帧中间缓存队列
	J1939CanFrameQueue rx_frame_tmp_queue; //接收CAN数据帧中间缓存队列
	J1939CanFrameQueue rx_frame_queue; //最终接收到的信息队列(单帧,根据pgn具体分析)
	J1939RxMsgQueue rx_msg_queue; //最终接收到的信息队列
	uint16_T rx_msg_max_len;
	J1939DtcContext dtc_context;
} J1939Context;

J1939Result J1939_Init(J1939Context* J1939_PAGED context, J1939CanDeviceParam* J1939_PAGED can_dev);

J1939Result J1939_TxMsg(J1939Context* J1939_PAGED context, J1939Msg* J1939_PAGED msg);

J1939Result J1939_RxMsg(J1939Context* J1939_PAGED context, J1939Msg* J1939_PAGED msg);

J1939Result J1939_TxCanFrame(J1939Context* J1939_PAGED context);

void J1939_TpSession(J1939Context* J1939_PAGED context);






#endif
