Programming/Etc

PCAN ISO-TP Mapping 관련 정리 글

_SYPark 2024. 3. 22. 11:26
728x90

PEAK CAN ISO-TP API를 사용하면 PC에서도 USB 등을 이용하여 ISO-TP 통신을 사용할 수 있습니다.

 

PCAN-ISO-TP API: PEAK-System

Description ISO-TP (ISO 15765-2) is an international standard for the transfer of data packages via CAN. Above CAN (OSI layers 1 and 2), the protocol covers the OSI layers 3 (Network Layer) and 4 (Transport Layer). It can transmit data packages of up to 4

www.peak-system.com

 

이 API를 사용하면서 가장 헷갈리는 부분 중 하나가 Mapping 함수인데 간단히 설명하려고 합니다.

 

먼저 설명에 앞서 ISO-TP의 사양을 간단히 설명하면 CAN 혹은 CAN-FD의 메시지를 사용해서 통신을 하는 구조입니다. 메시지를 보낼 때 사이즈가 DLC(한번에 보내기로 결정한 데이터 사이즈)보다 크다면 여러 메시지를 주고 받으면서 통신을 진행합니다. 이때 First Frame, ConsecutiveFrame, FlowControl이라는 메시지를 사용하는데 FirstFrame과 Consecutive Frame은 송신 측에서 데이터를 보낼 때 사용하고 FlowControl은 수신측에서 수신 상태를 알려줄 때 사용합니다.

 

이 CAN Message를 보낼 때 ID를 사용하게 되는데 이 때 Mapping으로 ID를 미리 지정해두게 됩니다.

 

만약 내가 이 프로그램에서 ISOTP 메시지를 보낼 때 CAN ID를 0x01로 그리고 상대쪽에서 이 메시지에 대한 FlowControl ID가 0x02라면 아래와 같이 등록합니다. format, msgtype, target_type은 상황에 맞게 설정합니다. Target, Source Address는 Normal Format에서는 크게 중요치 않습니다.

m_SendCANID = 0x01;
m_SendFlowID = 0x02;

status = initSendMsgMappings(channel, m_SendCANID, m_SendFlowID);
if ( !CANTP_StatusIsOk_2016(status) ) {
    debug(QString::asprintf("Failed to Send initialize mapping"));
    return bResult;
} // ISO-TP 주소 매핑
// CAN ID = 내가 쓸 때의 ISOTP CAN ID
// FlowID = 상대방(GUI)에서 응답하는 FlowControl ID
// PCAN-ISO-TP API Usermanual p.265 / ISO-TP Document p.40 참고

cantp_status PCANISOTP::initSendMsgMappings(cantp_handle channel, uint32_t can_id, uint32_t can_id_flow_ctrl)
{
    cantp_mapping mapping_phys_tx;

    // clean variables (it is common to leave can_tx_dl uninitialized which can lead to invalid 0xCC values)
    memset(&mapping_phys_tx, 0, sizeof(mapping_phys_tx));

    // configure a mapping to transmit physical message
    mapping_phys_tx.can_id = can_id;
    mapping_phys_tx.can_id_flow_ctrl = can_id_flow_ctrl;
    mapping_phys_tx.can_msgtype = PCANTP_CAN_MSGTYPE_EXTENDED;
    mapping_phys_tx.netaddrinfo.format = PCANTP_ISOTP_FORMAT_NORMAL;
    mapping_phys_tx.netaddrinfo.msgtype = PCANTP_ISOTP_MSGTYPE_DIAGNOSTIC;
    mapping_phys_tx.netaddrinfo.target_type = PCANTP_ISOTP_ADDRESSING_PHYSICAL;
    mapping_phys_tx.netaddrinfo.source_addr = N_SA;
    mapping_phys_tx.netaddrinfo.target_addr = N_TA_PHYS;
    status = CANTP_AddMapping_2016(channel, &mapping_phys_tx);
    if (!CANTP_StatusIsOk_2016(status)) {
        return status;
    }

    return status;
}

 

Write 할 때 msgDataAlloc 후 MsgDataInit을 하는데 이 때 Mapping 할 때 등록했던 각종 정보를 그대로 전달합니다. 전달받은 netaddrinfo 정보를 토대로 Mapping 된 정보에서 CAN, Flow ID를 가져옵니다.

void PCANISOTP::Write(const char *pData, int nSize)
{
    cantp_msg message = {};
    cantp_can_msgtype msgtype = PCANTP_CAN_MSGTYPE_EXTENDED | PCANTP_CAN_MSGTYPE_FD | PCANTP_CAN_MSGTYPE_BRS;

    cantp_netaddrinfo isotp_nai = {};
    isotp_nai.source_addr = N_SA;
    isotp_nai.target_addr = N_TA_PHYS;
    isotp_nai.target_type = PCANTP_ISOTP_ADDRESSING_PHYSICAL;
    isotp_nai.msgtype = PCANTP_ISOTP_MSGTYPE_DIAGNOSTIC;
    isotp_nai.format = PCANTP_ISOTP_FORMAT_NORMAL;

    status = CANTP_MsgDataAlloc_2016(&message, PCANTP_MSGTYPE_ISOTP);
    if (CANTP_StatusIsOk_2016(status)) {
        // initialize ISOTP message
        status = CANTP_MsgDataInit_2016(&message, PCANTP_MAPPING_FLOW_CTRL_NONE, msgtype, nSize, pData, &isotp_nai);
        ...
}

 

이제 수신쪽 매핑입니다. 만약 상대쪽에서 ISOTP 메시지를 보낼 때 CAN ID를 0x03로 그리고 이 프로그램에서 메시지에 대한 FlowControl ID가 0x04라면 아래와 같이 등록합니다.

m_SendCANID = 0x03;
m_SendFlowID = 0x04;

status = initRecvMsgMappings(channel, m_RecvCANID, m_RecvFlowID);
if ( !CANTP_StatusIsOk_2016(status) ) {
    debug(QString::asprintf("Failed to Recv initialize mapping"));
    return bResult;
} // ISO-TP 주소 매핑
// CAN ID = 상대방의 ISOTP CAN ID
// FlowID = 내가 보내는 FlowControl ID

cantp_status PCANISOTP::initRecvMsgMappings(cantp_handle channel, uint32_t can_id, uint32_t can_id_flow_ctrl)
{
    cantp_mapping mapping_phys_rx;

    // clean variables (it is common to leave can_tx_dl uninitialized which can lead to invalid 0xCC values)
    memset(&mapping_phys_rx, 0, sizeof(mapping_phys_rx));

    // configure a mapping to transmit physical message
    mapping_phys_rx.can_id = can_id;
    mapping_phys_rx.can_id_flow_ctrl = can_id_flow_ctrl;
    mapping_phys_rx.can_msgtype = PCANTP_CAN_MSGTYPE_EXTENDED;
    mapping_phys_rx.netaddrinfo.format = PCANTP_ISOTP_FORMAT_NORMAL;
    mapping_phys_rx.netaddrinfo.msgtype = PCANTP_ISOTP_MSGTYPE_DIAGNOSTIC;
    mapping_phys_rx.netaddrinfo.target_type = PCANTP_ISOTP_ADDRESSING_PHYSICAL;
    mapping_phys_rx.netaddrinfo.source_addr = N_TA_PHYS;
    mapping_phys_rx.netaddrinfo.target_addr = N_SA;
    status = CANTP_AddMapping_2016(channel, &mapping_phys_rx);
    if (!CANTP_StatusIsOk_2016(status)) {
        return status;
    }

    return status;
}

 

자세한 내용은 PCAN ISOTP API 매뉴얼 참고 바랍니다.

728x90