/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include "uds_dtc.h"

/*******************************************************************************
 * the defines
 ******************************************************************************/

#define DTCG_EMISSION_START   (0x00000000ul) /* 24Bit DTC define ISO-15031-6 DTC + ISO-15031-6 Failure Type, ISO14229-1 format */
#define DTCG_EMISSION_END     (0x000FFFFFul)
#define DTCG_POWERTRAIN_START (0x00100000ul)
#define DTCG_POWERTRAIN_END   (0x003FFFFFul)
#define DTCG_CHASSIS_START    (0x00400000ul)
#define DTCG_CHASSIS_END      (0x007FFFFFul)
#define DTCG_BODY_START       (0x00800000ul)
#define DTCG_BODY_END         (0x00BFFFFFul)
#define DTCG_NETWORK_START    (0x00C00000ul)
#define DTCG_NETWORK_END      (0x00FFFFFFul)

#define FAULTDT_MAX           (127)  /* refers to ISO14229-1 D.6 */
#define FAULTDT_MIN           (-128) /* refers to ISO14229-1 D.6 */
#define AGING_MAX             (40)   /* refers to ISO14229-1 D.7 */

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

/*******************************************************************************
 * the globals
 ******************************************************************************/

/* the meaning of UDS DTC value refers to ISO 15031-6 */
static Uds_DtcType udsDtcTable[DTC_MAX_COUNT] = {
    {0x04621A, 0x50, 0x00, 0x00}, /* P0462  fuel level sensor "A" circuit resistance low */
    {0x04631B, 0x50, 0x00, 0x00}, /* P0463  fuel level sensor "A" circuit resistance high */
    {0xF00316, 0x50, 0x00, 0x00}, /* U3003  battery voltage low */
    {0xF00317, 0x50, 0x00, 0x00}, /* U3003  battery voltage high */
    {0xC07388, 0x50, 0x00, 0x00}, /* U0073  control module communication bus off */
    {0xC10001, 0x50, 0x00, 0x00}, /* U0100  lost communication with ECM/PCM "A" */
    {0xC10101, 0x50, 0x00, 0x00}, /* U0101  lost communication with TCM */
    {0xC12101, 0x50, 0x00, 0x00}, /* U0121  lost communication with ABS control module */
    {0xC12701, 0x50, 0x00, 0x00}, /* U0127  lost communication with tire pressure monitor module */
    {0xC12801, 0x50, 0x00, 0x00}, /* U0128  lost communication with park brake control module */
    {0xC12901, 0x50, 0x00, 0x00}, /* U0129  lost communication with brake system control module */
    {0xC13101, 0x50, 0x00, 0x00}, /* U0131  lost communication with power sterring control module */
    {0xC14100, 0x50, 0x00, 0x00}, /* U0141  lost communication with body control module "A" */
    {0xC15101, 0x50, 0x00, 0x00}, /* U0151  lost communication with restraints control module */
    {0xC16300, 0x50, 0x00, 0x00}, /* U0163  lost communication with navigation control module */
    {0xC16900, 0x50, 0x00, 0x00}, /* U0169  lost communication with sunroof control module */
    {0xC18101, 0x50, 0x00, 0x00}, /* U0181  lost communication with headlamp leveling control module */
    {0xC23601, 0x50, 0x00, 0x00}, /* U0236  lost communication with column lock module */
    {0xC16400, 0x50, 0x00, 0x00}, /* U0164  lost communication with HVAC control module */
    {0xC16700, 0x50, 0x00, 0x00}, /* U0167  lost communication with vehicle immobilizer control module */
};

static bool dtcOffCtrl = false;

/*******************************************************************************
 * the constants
 ******************************************************************************/

/*******************************************************************************
 * the functions
 ******************************************************************************/

void Uds_SetDtcOffCtrl(bool val)
{
    dtcOffCtrl = val;
}

bool Uds_GetDtcOffCtrlState(void)
{
    return dtcOffCtrl;
}

void Uds_ClearDtcByDtcIndex(uint16_t dtcIndex)
{
    if(dtcIndex >= DTC_MAX_COUNT)
    {
        return;
    }

    udsDtcTable[dtcIndex].dtcStatus.all             = 0;
    udsDtcTable[dtcIndex].dtcStatus.bit.testNcmpSlc = 1;
    udsDtcTable[dtcIndex].dtcStatus.bit.testNcmpToc = 1;

    udsDtcTable[dtcIndex].faultDtCnt = 0;
    udsDtcTable[dtcIndex].AgingCnt   = 0;
}

void Uds_LoadDtc(void)
{
    /* code implemented by the user */
}

void Uds_SaveDtc(void)
{
    /* code implemented by the user */
}

uint16_t Uds_GetDtcNumberByStatusMask(uint8_t mask)
{
    uint16_t dtcCnt   = 0;
    uint8_t  dtcState = 0;
    uint16_t dtcNum   = 0;

    for(dtcCnt = 0; dtcCnt < DTC_MAX_COUNT; dtcCnt++)
    {
        dtcState = (udsDtcTable[dtcCnt].dtcStatus.all & DTC_AVAILABILITY_STATUS_MASK);
        if(0 != (dtcState & mask))
        {
            dtcNum++;
        }
    }

    return dtcNum;
}

uint16_t Uds_GetDtcByStatusMask(uint8_t *pDtcBuf, uint16_t bufLen, uint8_t mask)
{
    uint16_t dtcCnt   = 0;
    uint8_t  dtcState = 0;
    uint16_t dtcDlc   = 0;

    for(dtcCnt = 0; dtcCnt < DTC_MAX_COUNT; dtcCnt++)
    {
        dtcState = udsDtcTable[dtcCnt].dtcStatus.all;
        if(0 != (dtcState & mask))
        {
            if((dtcDlc + 4) <= bufLen)
            {
                pDtcBuf[dtcDlc++] = (uint8_t)(udsDtcTable[dtcCnt].dtcCode >> 16);
                pDtcBuf[dtcDlc++] = (uint8_t)(udsDtcTable[dtcCnt].dtcCode >> 8);
                pDtcBuf[dtcDlc++] = (uint8_t)(udsDtcTable[dtcCnt].dtcCode >> 0);
                pDtcBuf[dtcDlc++] = (dtcState & DTC_AVAILABILITY_STATUS_MASK);
            }
            else
            {
                break;
            }
        }
    }

    return dtcDlc;
}

uint16_t Uds_GetSupportedDtc(uint8_t *pDtcBuf, uint16_t bufLen)
{
    uint16_t dtcCnt   = 0;
    uint8_t  dtcState = 0;
    uint16_t dtcDlc   = 0;

    for(dtcCnt = 0; dtcCnt < DTC_MAX_COUNT; dtcCnt++)
    {
        dtcState = udsDtcTable[dtcCnt].dtcStatus.all;
        if((dtcDlc + 4) <= bufLen)
        {
            pDtcBuf[dtcDlc++] = (uint8_t)(udsDtcTable[dtcCnt].dtcCode >> 16);
            pDtcBuf[dtcDlc++] = (uint8_t)(udsDtcTable[dtcCnt].dtcCode >> 8);
            pDtcBuf[dtcDlc++] = (uint8_t)(udsDtcTable[dtcCnt].dtcCode >> 0);
            pDtcBuf[dtcDlc++] = (dtcState & DTC_AVAILABILITY_STATUS_MASK);
        }
        else
        {
            break;
        }
    }

    return dtcDlc;
}

void Uds_ClearDtcByGroup(uint32_t group)
{
    uint16_t dtcCnt = 0;

    switch(group)
    {
    case EMISSION_SYSTEM_GROUP:
        for(dtcCnt = 0; dtcCnt < DTC_MAX_COUNT; dtcCnt++)
        {
            if(udsDtcTable[dtcCnt].dtcCode <= DTCG_EMISSION_END)
            {
                Uds_ClearDtcByDtcIndex(dtcCnt);
            }
        }
        break;
    case SAFETY_SYSTEM_GROUP:
        for(dtcCnt = 0; dtcCnt < DTC_MAX_COUNT; dtcCnt++)
        {
            if((udsDtcTable[dtcCnt].dtcCode >= DTCG_CHASSIS_START) && (udsDtcTable[dtcCnt].dtcCode <= DTCG_CHASSIS_END))
            {
                Uds_ClearDtcByDtcIndex(dtcCnt);
            }
        }
        break;
    case ALL_FUNC_SYSTEM_GROUP:
        for(dtcCnt = 0; dtcCnt < DTC_MAX_COUNT; dtcCnt++)
        {
            Uds_ClearDtcByDtcIndex(dtcCnt);
        }
        break;
    }
}
