Programming/Etc

PCAN ISOTP 송신 시 루프백 이용해서 처리

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

PCAN ISOTP API Write 호출 시 비동기 처리가 되기 때문에 loop back을 이용해서 제대로 모든 데이터가 처리가 되었는지 확인할 수 있습니다.

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);
        if (CANTP_StatusIsOk_2016(status)) {
            // write message
            do {
                status = CANTP_Write_2016(channel, &message);
                if (CANTP_StatusIsOk_2016(status)) {
                    debug(QString::asprintf("Successfully queued ISOTP message: Length %i (sts=0x%04X).", nSize, (int)status));
                }
                else {
                    debug(QString::asprintf("Failed to write ISOTP message: Length %i (sts=0x%04X).", nSize, (int)status));
                    return;
                }

            } while ( !checkWriteState(message) );
            emit emit_sendISOTPPacketData(enTx, message);
        }
        else {
            debug(QString::asprintf("Failed to initialize ISOTP message: Length %i (sts=0x%04X).", nSize, (int)status));
            return;
        }
        // release message

        if (!CANTP_StatusIsOk_2016(status)) {
            debug(QString::asprintf("Failed to deallocate message (sts=0x%04X).", status));
            return;
        }
    }
    else {
        debug(QString::asprintf("Failed to allocate message (sts=0x%04X).", status));
        return;
    }
}

bool PCANISOTP::checkWriteState(cantp_msg& rx_msg)
{
    cantp_msg loopback_msg;

    bool bRes = false;
    cantp_msgprogress progress;
    cantp_status result;
    memset(&loopback_msg, 0, sizeof(loopback_msg));
    memset(&progress, 0, sizeof(progress));

    HANDLE receive_event = NULL;

    status = CANTP_GetValue_2016(channel, PCANTP_PARAMETER_RECEIVE_EVENT, &receive_event, sizeof(receive_event));
    if (!CANTP_StatusIsOk_2016(status) || receive_event == NULL) {
        debug(QString("Failed to make loop back receive event"));
        return false;
    }

    do {
        int nResult = WaitForSingleObject(receive_event, 10);
        if (nResult == WAIT_OBJECT_0) {
            status = CANTP_MsgDataAlloc_2016(&loopback_msg, PCANTP_MSGTYPE_NONE);
            // Read transmission confirmation.

            result = CANTP_Read_2016(channel, &loopback_msg, 0, PCANTP_MSGTYPE_ANY);
            if (CANTP_StatusIsOk_2016(result, PCANTP_STATUS_OK, false)) {
                if (((PCANTP_MSGTYPE_ISOTP & loopback_msg.type) == PCANTP_MSGTYPE_ISOTP) && (loopback_msg.msgdata.isotp->flags == PCANTP_MSGFLAG_LOOPBACK)
                    && ((loopback_msg.msgdata.isotp->netaddrinfo.msgtype & PCANTP_ISOTP_MSGTYPE_FLAG_INDICATION_TX) == PCANTP_ISOTP_MSGTYPE_FLAG_INDICATION_TX)) {
                    // The message is being received, wait and show progress
                    do {
                        result = CANTP_GetMsgProgress_2016(channel, &loopback_msg, PCANTP_MSGDIRECTION_RX, &progress);
                    } while (progress.state == PCANTP_MSGPROGRESS_STATE_PROCESSING);

                    if ( CANTP_MsgEqual_2016(&rx_msg, &loopback_msg, true) ) {
                        qDebug() << "Equal";
                        bRes = true;
                    }
                }
            }
        }
    } while ( !bRes );
    CANTP_MsgDataFree_2016(&loopback_msg);

    return bRes;
}

checkWriteState 함수를 통해 loop back read를 진행 후 전송한 cantp_msg를 CANTP_MsgEqual_2016 호출로 비교해서 같다면 전송이 성공했다는 방식으로 처리를 할 수 있습니다.

728x90