// uds_zlgcan_wrap.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "uds_zlgcan_wrap.h"
#include <thread>
#include <map>
#include <memory>

static uint32 STDCALL OnZlgcanTransmit(void* ctx, const ZUDS_FRAME* frame, uint32 count);

std::map<CHANNEL_HANDLE, bool> gChannelUseCanfd;
std::map<ZUDS_HANDLE, CHANNEL_HANDLE> gUdsChannel;

ZUDS_HANDLE STDCALL ZUDS_WRAP_Init(CHANNEL_HANDLE hCanChannel)
{
    ZUDS_HANDLE hUDS = ZUDS_Init(DoCAN);
    if (hUDS == ZUDS_INVALID_HANDLE) {
        return hUDS;
    }

    ZUDS_SetTransmitHandler(hUDS, hCanChannel, OnZlgcanTransmit);
    gUdsChannel[hUDS] = hCanChannel;

    return hUDS;
}

void STDCALL ZUDS_WRAP_Release(ZUDS_HANDLE handle)
{
    ZUDS_Release(handle);
}

void STDCALL ZUDS_WRAP_SetParam(ZUDS_HANDLE handle, PARAM_TYPE type, void* param)
{
    ZUDS_SESSION_PARAM* session = NULL;
    ZUDS_ISO15765_PARAM* iso = NULL;
    if (type == PARAM_TYPE_SESSION) {
        session = (ZUDS_SESSION_PARAM*)param;
    }
    if (type == PARAM_TYPE_ISO15765) {
        iso = (ZUDS_ISO15765_PARAM*)param;
    }

    ZUDS_SetParam(handle, type, param);
}

uint32 STDCALL ZUDS_WRAP_Request(ZUDS_HANDLE handle, const ZUDS_WRAP_REQUEST_PAR* requestPar, const uint8 *data, uint32 dataLen,
    ZUDS_WRAP_RESPONSE_PAR *respPar, uint8* respBuf, uint32 respBufSize, int isCanfd)
{
    if (!data || dataLen == 0) {
        respPar->status = ZUDS_ERROR_OTHTER;
        return 0;
    }

    gChannelUseCanfd[gUdsChannel[handle]] = !!isCanfd;

    ZUDS_REQUEST req;
    req.src_addr = requestPar->src_addr;
    req.dst_addr = requestPar->dst_addr;
    req.suppress_response = requestPar->suppress_response;
    req.sid = data[0];
    req.reserved0 = 0;
    req.param = (uint8*)&data[1];
    req.param_len = dataLen - 1;
    req.reserved = 0;

    ZUDS_RESPONSE resp;
    memset(&resp, 0, sizeof(resp));
    ZUDS_Request(handle, &req, &resp);

    respPar->status = resp.status;
    respPar->type = resp.type;

    uint32 respDataLen = 0;
    if (resp.status == ZUDS_ERROR_OK) {
        if (resp.type == RT_POSITIVE)
        {
            respDataLen = resp.positive.param_len + 1;
            if (respBufSize >= respDataLen) {
                respBuf[0] = resp.positive.sid;
                memcpy(&respBuf[1], resp.positive.param, resp.positive.param_len);
                return respDataLen;
            }
            else {
                return 0;
            }
        }
        else if (resp.type == RT_NEGATIVE) {
            respDataLen = 3;
            if (respBufSize >= respDataLen) {
                respBuf[0] = resp.negative.neg_code;
                respBuf[1] = resp.negative.sid;
                respBuf[2] = resp.negative.error_code;
                return respDataLen;
            }
            else {
                return 0;
            }
        }
    }

    return 0;
}

static void UDSFrame2ZCAN(ZCAN_Transmit_Data* can, const ZUDS_FRAME* uds, uint32 count)
{
    for (uint32 i = 0; i < count; ++i)
    {
        auto &can_frm = can[i];
        auto &uds_frm = uds[i];
        memset(&can_frm, 0, sizeof(ZCAN_Transmit_Data));
        can_frm.frame.can_id = MAKE_CAN_ID(uds_frm.id, uds_frm.extend, uds_frm.remote, 0);
        can_frm.frame.can_dlc = uds_frm.data_len;
        memcpy(can_frm.frame.data, uds_frm.data, uds_frm.data_len);
    }
}

static void UDSFrame2ZCANFD(ZCAN_TransmitFD_Data* canfd, const ZUDS_FRAME* uds, uint32 count)
{
    for (uint32 i = 0; i < count; ++i)
    {
        auto &canfd_frm = canfd[i];
        auto &uds_frm = uds[i];
        memset(&canfd_frm, 0, sizeof(ZCAN_TransmitFD_Data));
        canfd_frm.frame.can_id = MAKE_CAN_ID(uds_frm.id, uds_frm.extend, uds_frm.remote, 0);
        canfd_frm.frame.len = uds_frm.data_len;
        memcpy(canfd_frm.frame.data, uds_frm.data, uds_frm.data_len);
    }
}

static void ZCAN2UDSFrame(ZUDS_FRAME* uds, const ZCAN_Receive_Data* can)
{
    memset(uds, 0, sizeof(ZUDS_FRAME));
    uds->id = GET_ID(can->frame.can_id);
    uds->extend = IS_EFF(can->frame.can_id);
    uds->remote = IS_RTR(can->frame.can_id);
    uds->data_len = can->frame.can_dlc;
    memcpy(uds->data, can->frame.data, uds->data_len);
}

static void ZCANFD2UDSFrame(ZUDS_FRAME* uds, const ZCAN_ReceiveFD_Data* canfd)
{
    memset(uds, 0, sizeof(ZUDS_FRAME));
    uds->id = GET_ID(canfd->frame.can_id);
    uds->extend = IS_EFF(canfd->frame.can_id);
    uds->remote = IS_RTR(canfd->frame.can_id);
    uds->data_len = canfd->frame.len;
    memcpy(uds->data, canfd->frame.data, uds->data_len);
}

void STDCALL ZUDS_WRAP_OnReceiveCAN(ZUDS_HANDLE handle, ZCAN_Receive_Data* pReceive, UINT len)
{
    ZUDS_FRAME frame;
    for (UINT i = 0; i < len; i++) {
        ZCAN2UDSFrame(&frame, &pReceive[i]);
        ZUDS_OnReceive(handle, &frame);
    }
}

void STDCALL ZUDS_WRAP_OnReceiveCANFD(ZUDS_HANDLE handle, ZCAN_ReceiveFD_Data* pReceive, UINT len)
{
    ZUDS_FRAME frame;
    for (UINT i = 0; i < len; i++) {
        ZCANFD2UDSFrame(&frame, &pReceive[i]);
        ZUDS_OnReceive(handle, &frame);
    }
}

void STDCALL ZUDS_WRAP_Stop(ZUDS_HANDLE handle)
{
    ZUDS_Stop(handle);
}

void STDCALL ZUDS_WRAP_SetTesterPresent(ZUDS_HANDLE handle, uint8 enable, const ZUDS_TESTER_PRESENT_PARAM* param)
{
    ZUDS_SetTesterPresent(handle, enable, param);
}

static uint32 STDCALL OnZlgcanTransmit(void* ctx, const ZUDS_FRAME* frame, uint32 count)
{
    CHANNEL_HANDLE hChannle = (CHANNEL_HANDLE)ctx;

    if (!gChannelUseCanfd[hChannle])
    {
        auto can = new ZCAN_Transmit_Data[count];
        std::unique_ptr<ZCAN_Transmit_Data[]> ptr_release{ can };
        UDSFrame2ZCAN(can, frame, count);
        return count == ZCAN_Transmit(hChannle, can, count) ? TRANSPORT_OK : TRANSPORT_ERROR;
    }

    // CANFD
    auto canfd = new ZCAN_TransmitFD_Data[count];
    std::unique_ptr<ZCAN_TransmitFD_Data[]> ptr_release{ canfd };
    UDSFrame2ZCANFD(canfd, frame, count);
    return count == ZCAN_TransmitFD(hChannle, canfd, count) ? TRANSPORT_OK : TRANSPORT_ERROR;
}



