iso14229 icon indicating copy to clipboard operation
iso14229 copied to clipboard

question on error behavior

Open slowCoder72 opened this issue 2 years ago • 5 comments

the following might not be a real issue, but i would like to discuss the observation. We have a situation in which we act as a tester and the other nodes go into reboot/health check after an update. We then poll repeatedly to be aware when the nodes have rebooted. We needed to request idle in this situation, otherwise the lib stayed in UDS_ERR_BUSY even after the nodes had been back - no issue this is according to the examples. However when we repeatedly send SendRDBI requests to get the status of the nodes while they are still not present, we get an oscillating pattern of errors: UDS_ERR_TIMEOUT, UDS_ERR_TPORT, UDS_ERR_TIMEOUT, UDS_ERR_TPORT etc. we tried to understand how this happens and enabled the debug outputs: client state: AwaitSendComplete (2) -> AwaitResponse (3) read failed: -1 with errno: 70 timeout: 1 client state: AwaitResponse (3) -> Idle (0) client state: Idle (0) -> Sending (1) Condition met: client->send_size (3, 3), == ret (3) Sending (1) -> AwaitSendComplete (2) client state: AwaitSendComplete (2) -> AwaitResponse (3) timeout: 1 client state: AwaitResponse (3) -> Idle (0) awaiting idle failed with err = 1 and msg = 'UDS_ERR_TIMEOUT' client state: Idle (0) -> Sending (1) tport err: -1, nsend=3 bytes Condition met: client->send_size (3, 3), == ret (3) client state: Sending (1) -> AwaitSendComplete (2) awaiting idle failed with err = 6 and msg = 'UDS_ERR_TPORT' in the code imho this happens in: case kRequestStateSending: { UDSTpAddr_t ta_type = client->_options_copy & UDS_FUNCTIONAL ? UDS_A_TA_TYPE_FUNCTIONAL : UDS_A_TA_TYPE_PHYSICAL; UDSSDU_t info = { .A_Mtype = UDS_A_MTYPE_DIAG, .A_TA_Type = ta_type, }; ssize_t ret = UDSTpSend(client->tp, client->send_buf, client->send_size, &info); if (ret < 0) { client->err = UDS_ERR_TPORT; UDS_DBG_PRINT("tport err: %zd\n", ret); } else if (0 == ret) { UDS_DBG_PRINT("send in progress...\n"); ; // 等待发送成功 } else if (client->send_size == ret) { changeState(client, kRequestStateAwaitSendComplete); } else { client->err = UDS_ERR_BUFSIZ; } break; and we are puzzled how ret < 0 can be true and shortly after client->send_size == ret?? Any idea from your experience?

slowCoder72 avatar Feb 29 '24 15:02 slowCoder72

Hi @slowCoder72 . Please share an example client code noting expected and actual behavior.

driftregion avatar Mar 02 '24 06:03 driftregion

Hello James,

This is a bit complex: we wrapped your lib so that we can use it in a lua script and then try reading data by identifier. So we try to update targets and trigger an image activation where we do not know how long the target needs to reboot. After the reboot we poll and for some time have no targets being up. Then the reported alternating errors occur.

The wrapper for drbi looks like: static int lua_UDSSendRDBI(lua_State *L) { UDSClient_t *client; client = (UDSClient_t *)luaL_checkudata(L, 1, LUA_UDS_CLIENT_METATABLE_NAME); uint16_t *didList; uint16_t numDataIdentifiers = 0; UDSErr_t ret = 0;

/* 2nd argument must be a table with the Data Identifiers (DIDs) */
luaL_checktype(L, 2, LUA_TTABLE);

numDataIdentifiers = (uint16_t)luaL_len(L, 2);
if (numDataIdentifiers > 0)
{
    didList = (uint16_t *)malloc(sizeof(uint16_t) * numDataIdentifiers);
    if (didList == NULL)
        return pushErrAndMsg(L, 1, "Failed allocating memory for data didList ...\n");
}
else
{
    return pushErrAndMsg(L, 1, "Table length is zero. No identifiers to read from. Not sending RDBI request ...\n");
}

/* parsing the Lua table on the stack to uint16_t array */
if (luaTableToUint16Array(L, 2, didList, numDataIdentifiers))
{
    free(didList);
    return pushErrAndMsg(L, 1, "Could not parse Lua table to an uint16_t array...\n");
}

uint8_t functionalReq = (uint8_t)lua_toboolean(L, 3);
if (functionalReq)
    client->options |= UDS_FUNCTIONAL;

if ((ret = UDSSendRDBI(client, (const uint16_t *)didList, numDataIdentifiers)))
{
    client->options &= ~UDS_FUNCTIONAL;
    free(didList);
    return pushErrAndMsg(L, ret, UDSErrortoString(ret));
}

client->options &= ~UDS_FUNCTIONAL;
free(didList);
return pushErrAndMsg(L, UDS_OK, NULL);

}

The lua script uses the snippet:

-- fetch all responses from image activation
for _, scannedTarget in pairs(transferResults) do -- loop through scanned targets to check for status 0x08
    if scannedTarget.matched and scannedTarget.transferredImage then
        local msg = string.format(
            "checking if board type = 0X%X and board address = 0X%X is in HEALTH_CHECK, IMAGE_ACTIVATED or UPDATE_FAIL",
            scannedTarget.boardType, scannedTarget.boardAddress)
        swupdate.notify(swupdate.RECOVERY_STATUS.IDLE, 0, msg)
        scannedTarget.imageActivated = false
        local UDSClient, msg = initUDSClient("can0", scannedTarget.boardType, scannedTarget.boardAddress)
        if not UDSClient then
            swupdate.notify(swupdate.RECOVERY_STATUS.RUN, 0, msg)
        else
            local maxAttempts = 60
            local attemptCounter = 0
            local switch = 1

            repeat
                local response, err, msg = requestRdbi(UDSClient, enums.DataIDs.BOARD_STATE, 2)
                if not response then
                    msg = string.format(
                        "error requesting state from board type = 0X%02X with address = 0X%02X, err = %d, msg = %s",
                        scannedTarget.boardType, scannedTarget.boardAddress, err, msg)
                    swupdate.notify(swupdate.RECOVERY_STATUS.RUN, 0, msg)
                else
                    msg = string.format("requested state = 0X%02X from board type = 0X%02X, address = 0X%02X, ",
                        response[1], scannedTarget.boardType, scannedTarget.boardAddress)
                    swupdate.notify(swupdate.RECOVERY_STATUS.RUN, 0, msg)
                    -- check states
                    if response[1] == enums.SMStates.IMAGE_ACTIVATED then -- CHECK STATE RESPONSE AND ACTIVATE IMAGE
                        scannedTarget.imageActivated = true
                        switch = 0
                    elseif response[1] == enums.SMStates.UPDATE_FAIL then
                        switch = 0
                        msg = string.format("update failed for board type = 0X%X with address = 0X%X, state = 0X%X",
                            scannedTarget.boardType, scannedTarget.boardAddress, response[1])
                        swupdate.notify(swupdate.RECOVERY_STATUS.FAILURE, 0, msg)

                        -- send cancel command if update failed
                        local err, msg = requestWdbi(UDSClient, enums.WriteIDs.Update_Cancel_ID, {0x00})
                        if err ~= 0 then
                            msg = string.format("error sending cancel command: error %d, msg = '%s'", err, msg)
                            swupdate.notify(swupdate.RECOVERY_STATUS.FAILURE, 0, msg)
                        else
                            msg = string.format("sent cancel command to board type = 0X%02X and address = 0X%02X",
                                scannedTarget.boardType, scannedTarget.boardAddress)
                            swupdate.notify(swupdate.RECOVERY_STATUS.RUN, 0, msg)
                            break
                        end

                    elseif response[1] == enums.SMStates.DEVICE_HEALTH_CHECK then
                        -- continue asking since the target is not done with the health check
                   else
                        switch = 0
                        msg = string.format(
                            "board type = 0X%X with address = 0X%X is not meant to be in state = 0X%X after activate image command",
                            scannedTarget.boardType, scannedTarget.boardAddress, response[1])
                        swupdate.notify(swupdate.RECOVERY_STATUS.RUN, 0, msg)
                    end
                end
                attemptCounter = attemptCounter + 1 -- counting attempts
                swupdate.notify(swupdate.RECOVERY_STATUS.RUN, 0, "attemptCounter " .. attemptCounter)
                sleep(3)
            until switch == 0 or attemptCounter >= maxAttempts

            UDSClient:deinit()
            UDSClient = nil

            if attemptCounter >= maxAttempts then
                msg = string.format(
                    "tried too many times to request state IMAGE_ACTIVATED, board type = 0X%X, address = 0X%X not responding ...",
                    scannedTarget.boardType, scannedTarget.boardAddress)
                swupdate.notify(swupdate.RECOVERY_STATUS.FAILURE, 0, msg)
            end
        end
    end
end

and the lua script uses:

function requestRdbi(UDSClient, did, didSize) assert(type(UDSClient) == "userdata", "UDSClient has to be of type userdata") assert(getmetatable(UDSClient).__name == "LuaUDSClient", "UDSClient has to have the metatable LuaUDSClient") assert(type(did) == "number", "did has to be of type number") assert(type(didSize) == "number", "didSize has to be of type number") assert(didSize > 0, "didSize has to be greater than zero")

local response
UDSClient:awaitIdle()
local err, msg = UDSClient:sendRdbi({did})
if err ~= 0 then
    msg = string.format("error sending RDBI to request ID 0X%02X: %s", tableprint.dump(did), msg)
    UDSClient:setError(enums.UDSError.UDS_OK)
else
    err, msg = awaitAndCheckPositiveResponse(UDSClient)
    if err ~= 0 then
        msg =
            string.format("error receiving response from RDBI to request ID 0X%02X: %s", tableprint.dump(did), msg)
        UDSClient:setError(enums.UDSError.UDS_OK)
    else
        local buf = UDSClient:getRecvBuffer()
        response = {table.unpack(buf, 1 + didSize + 1, #buf)}
        if next(response) == nil then
            response, err, msg = nil, 1, "No data received or didSize is wrong (greater than actual size of DID)"
            UDSClient:setError(enums.UDSError.UDS_OK)
        end
    end
end

hope this can somehow be understood!

Hi @slowCoder72https://github.com/slowCoder72 . Please share an example client code noting expected and actual behavior.

— Reply to this email directly, view it on GitHubhttps://github.com/driftregion/iso14229/issues/27#issuecomment-1974479986, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AMOSMJ5QOMT6IMEWR4QXSNDYWFZJHAVCNFSM6AAAAABEAENUFGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNZUGQ3TSOJYGY. You are receiving this because you were mentioned.Message ID: @.***>

slowCoder72 avatar Mar 06 '24 12:03 slowCoder72

I do not see UDSClientInit() called in your snippet. See example client code here: https://github.com/driftregion/iso14229/blob/main/examples/linux_server_0x27/client.c

driftregion avatar Mar 07 '24 00:03 driftregion

In the lua script we do "initUDSClient" and this via our wrapper executes UDSClientInit() in the lib. The communication to the targets also works and we took the above client.c as an inspiration. It is just the error behavior when there is no communication partner that i wanted to mention and probably discuss.

slowCoder72 avatar Mar 07 '24 06:03 slowCoder72

Hi @slowCoder72 , are you still having this issue?

Using the information you've provided I cannot tell whether the issues is in iso14229 or in the transport layer. Please post a c-only implementation of a client that produces the error behavior.

driftregion avatar Aug 18 '24 02:08 driftregion