Загрузка данных


static srtm_status_t SRTM_AutoService_Notify(srtm_service_t service, srtm_notification_t notif)
{
    SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_WARN, "%s: command %d unsupported!\r\n", __func__,
                       SRTM_CommMessage_GetCommand(notif));

    return SRTM_Status_ServiceNotFound;
}

static void SRTM_AutoService_Cleanup(srtm_auto_service_t handle, srtm_peercore_t core)
{
    srtm_auto_client_t client;
    srtm_list_t *list, *next;

    for (list = handle->clients.next; list != &handle->clients; list = next)
    {
        next   = list->next;
        client = SRTM_LIST_OBJ(srtm_auto_client_t, node, list);
        assert(client->channel);
        if (client->channel->core == core || !core)
        {
            SRTM_List_Remove(list);
            SRTM_Heap_Free(client);
        }
    }
}

srtm_service_t SRTM_AutoService_Create(srtm_auto_adapter_t vehicle)
{
    srtm_auto_service_t handle;

    SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);

    handle = (srtm_auto_service_t)SRTM_Heap_Malloc(sizeof(struct _srtm_auto_service));
    assert(handle);

    vehicle->service = &handle->service;
    handle->vehicle  = vehicle;

    SRTM_List_Init(&handle->clients);
    SRTM_List_Init(&handle->service.node);
    handle->service.dispatcher = NULL;
    handle->service.category   = SRTM_AUTO_CATEGORY;
    handle->service.destroy    = SRTM_AutoService_Destroy;
    handle->service.request    = SRTM_AutoService_Request;
    handle->service.notify     = SRTM_AutoService_Notify;

    return &handle->service;
}

void SRTM_AutoService_Destroy(srtm_service_t service)
{
    srtm_auto_service_t handle = (srtm_auto_service_t)service;

    assert(service);

    SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);

    /* Service must be unregistered from dispatcher before destroy */
    assert(SRTM_List_IsEmpty(&service->node));

    SRTM_AutoService_Cleanup(handle, NULL);

    SRTM_Heap_Free(handle);
}

void SRTM_AutoService_Reset(srtm_service_t service, srtm_peercore_t core)
{
    srtm_auto_service_t handle = (srtm_auto_service_t)service;

    assert(service);

    SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s\r\n", __func__);

    SRTM_AutoService_Cleanup(handle, core);
}

static void SRTM_AutoService_ResponseCallback(srtm_dispatcher_t disp,
                                              srtm_message_t req,
                                              srtm_message_t resp,
                                              void *param)
{
    srtm_auto_async_req_t asyncReq = (srtm_auto_async_req_t)param;
    struct _srtm_auto_payload *autoReq;
    struct _srtm_auto_payload *autoResp;
    uint32_t payloadLen = 0;
    bool freeAsyncReq   = false;

    autoReq  = (struct _srtm_auto_payload *)SRTM_CommMessage_GetPayload(req);
    autoResp = resp ? (struct _srtm_auto_payload *)SRTM_CommMessage_GetPayload(resp) : NULL;
    if (autoResp)
    {
        payloadLen = SRTM_CommMessage_GetPayloadLen(resp);
        if (payloadLen < sizeof(struct _srtm_auto_payload))
        {
            assert(false);
        }
    }

    SRTM_Mutex_Lock(asyncReq->mutex);
    if (asyncReq->reqState == SRTM_AUTO_ASYNC_REQ_STATE_WAITING)
    {
        asyncReq->retCode = autoResp ? autoResp->retCode : SRTM_Status_TransferFailed;
        if (asyncReq->syncResult)
        {
            if (asyncReq->result && autoResp)
            {
                assert(asyncReq->resultLen <= SRTM_USER_DATA_LENGTH);
                (void)memcpy(asyncReq->result, autoResp->data, asyncReq->resultLen);
            }
            SRTM_Sem_Post(asyncReq->sem);
        }
        else
        {
            asyncReq->resultCb(
                asyncReq->service, autoReq->clientId, (srtm_auto_cmd_t)SRTM_CommMessage_GetCommand(req), autoReq->data,
                asyncReq->cmdParamLen, autoResp ? autoResp->retCode : SRTM_Status_TransferFailed,
                autoResp ? autoResp->data : NULL, autoResp ? SRTM_USER_DATA_LENGTH : 0, asyncReq->resultCbParam);
            freeAsyncReq = true;
        }
        asyncReq->reqState = SRTM_AUTO_ASYNC_REQ_STATE_FINISHED;
    }
    else
    {
        freeAsyncReq = true;
    }
    SRTM_Mutex_Unlock(asyncReq->mutex);
    if (freeAsyncReq)
    {
        SRTM_AutoService_DestroyAsyncReq(asyncReq);
    }
}

/* Called in SRTM dispatcher context */
static void SRTM_AutoService_DeliverRequest(srtm_dispatcher_t dispatcher, void *param1, void *param2)
{
    srtm_auto_async_req_t asyncReq = (srtm_auto_async_req_t)param1;
    srtm_auto_service_t handle     = (srtm_auto_service_t)asyncReq->service;
    srtm_request_t req             = (srtm_request_t)param2;
    struct _srtm_auto_payload *autoReq;
    srtm_status_t status;
    srtm_auto_client_t client;
    srtm_list_t *list;

    autoReq = (struct _srtm_auto_payload *)SRTM_CommMessage_GetPayload(req);

    for (list = handle->clients.next; list != &handle->clients; list = list->next)
    {
        client = SRTM_LIST_OBJ(srtm_auto_client_t, node, list);
        if (client->clientId == autoReq->clientId)
        {
            req->channel = client->channel;
            status       = SRTM_Dispatcher_DeliverRequest(dispatcher, req, SRTM_AutoService_ResponseCallback, param1);
            if (status == SRTM_Status_Success)
            {
                asyncReq->reqState = SRTM_AUTO_ASYNC_REQ_STATE_WAITING;
            }
            break;
        }
    }
}

static srtm_status_t SRTM_AutoService_DoRequest(
    srtm_auto_async_req_t asyncReq, uint32_t clientId, srtm_auto_cmd_t cmd, uint8_t *cmdParam, uint32_t paramLen)
{
    srtm_request_t req;
    struct _srtm_auto_payload *autoReq;
    srtm_status_t status;
    srtm_procedure_t proc;

    assert(paramLen <= SRTM_USER_DATA_LENGTH);

    req = SRTM_Request_Create(NULL, SRTM_AUTO_CATEGORY, SRTM_AUTO_VERSION, cmd, sizeof(struct _srtm_auto_payload));
    if (!req)
    {
        return SRTM_Status_OutOfMemory;
    }

    autoReq           = (struct _srtm_auto_payload *)SRTM_CommMessage_GetPayload(req);
    autoReq->clientId = clientId;
    if (cmdParam)
    {
        (void)memcpy(autoReq->data, cmdParam, paramLen);
    }

    proc = SRTM_Procedure_Create(SRTM_AutoService_DeliverRequest, asyncReq, req);
    if (!proc)
    {
        SRTM_Request_Destroy(req);
        return SRTM_Status_OutOfMemory;
    }

    status = SRTM_Dispatcher_CallProc(asyncReq->service->dispatcher, proc, SRTM_WAIT_FOR_EVER);
    if (status != SRTM_Status_Success || asyncReq->reqState == SRTM_AUTO_ASYNC_REQ_STATE_INIT)
    {
        SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_ERROR, "%s: clientId %d, cmd %d request error\r\n", __func__, clientId,
                           cmd);
        SRTM_Request_Destroy(req);
        status = SRTM_Status_Error;
    }

    SRTM_Procedure_Destroy(proc);

    return status;
}

srtm_status_t SRTM_AutoService_SendCommand(srtm_service_t service,
                                           uint32_t clientId,
                                           srtm_auto_cmd_t cmd,
                                           uint8_t *cmdParam,
                                           uint32_t paramLen,
                                           uint8_t *result,
                                           uint32_t resultLen,
                                           uint32_t timeout)
{
    srtm_status_t status;
    srtm_auto_async_req_t asyncReq;
    bool freeAsyncReq = true;

    assert(service);
    assert(timeout > 0);

    SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: clientId %d, cmd %d\r\n", __func__, clientId, cmd);

    asyncReq = SRTM_AutoService_CreateAsyncReq(service);
    if (!asyncReq)
    {
        return SRTM_Status_OutOfMemory;
    }

    asyncReq->syncResult  = true;
    asyncReq->result      = result;
    asyncReq->resultLen   = resultLen;
    asyncReq->cmdParamLen = paramLen;
    status                = SRTM_AutoService_DoRequest(asyncReq, clientId, cmd, cmdParam, paramLen);
    if (status == SRTM_Status_Success)
    {
        /* Wait result */
        SRTM_Sem_Wait(asyncReq->sem, timeout);
        SRTM_Mutex_Lock(asyncReq->mutex);
        if (asyncReq->reqState != SRTM_AUTO_ASYNC_REQ_STATE_FINISHED)
        {
            /* Timeout, we cancel the request. asyncReq will be destroyed by response callback. */
            asyncReq->reqState = SRTM_AUTO_ASYNC_REQ_STATE_CANCELLED;
            status             = SRTM_Status_TransferTimeout;
            freeAsyncReq       = false; /* asyncReq will be freed later in response callback. */
        }
        else
        {
            status = asyncReq->retCode == SRTM_AUTO_RETURN_CODE_SUCEESS ? SRTM_Status_Success : SRTM_Status_Error;
        }
        SRTM_Mutex_Unlock(asyncReq->mutex);
    }

    if (freeAsyncReq)
    {
        SRTM_AutoService_DestroyAsyncReq(asyncReq);
    }

    return status;
}

srtm_status_t SRTM_AutoService_DeliverCommand(srtm_service_t service,
                                              uint32_t clientId,
                                              srtm_auto_cmd_t cmd,
                                              uint8_t *cmdParam,
                                              uint32_t paramLen,
                                              srtm_auto_cmd_cb_t callback,
                                              void *userParam)
{
    srtm_status_t status;
    srtm_auto_async_req_t asyncReq;

    assert(service);

    SRTM_DEBUG_MESSAGE(SRTM_DEBUG_VERBOSE_INFO, "%s: clientId %d, cmd %d\r\n", __func__, clientId, cmd);

    asyncReq = SRTM_AutoService_CreateAsyncReq(service);
    if (!asyncReq)
    {
        return SRTM_Status_OutOfMemory;
    }

    asyncReq->syncResult    = false;
    asyncReq->resultCb      = callback;
    asyncReq->resultCbParam = userParam;
    asyncReq->cmdParamLen   = paramLen;
    status                  = SRTM_AutoService_DoRequest(asyncReq, clientId, cmd, cmdParam, paramLen);

    return status;
}