MCUXpresso_MIMXRT1021xxxxx/boards/evkmimxrt1020/usb_examples/usb_device_phdc_weighscale_lite/bm/ieee11073_agent.c
2022-08-23 23:00:33 +08:00

952 lines
36 KiB
C

/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "usb_device_config.h"
#include "usb.h"
#include "ieee11073_timer.h"
#include "ieee11073_types.h"
#include "fsl_debug_console.h"
#include "ieee11073_timer.h"
#include "ieee11073_agent.h"
#include "usb_device.h"
#include "usb_device_descriptor.h"
#include "usb_shim_agent.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief Agent send data definition */
#define AGENT_SendData USB_ShimAgentSendData
/*! @brief the number of agent devices */
#define MAX_AGENT_NUM (1U)
/*******************************************************************************
* Prototypes
******************************************************************************/
/*! @brief local function prototypes */
#if IEEE_MAX_TIMER_OBJECTS
static void AGENT_SendAssociationRequestTimeout(void *arg);
static void AGENT_SendConfigTimeout(void *arg);
#endif
static agent_struct_t *AGENT_GetDeviceByHandle(void *handle);
static void AGENT_RecvAssociationResponse(void *handle, aare_apdu_t *associaionResponse);
static void AGENT_RecvPresentationProtocolDataUnit(void *handle, prst_apdu_t *pPrst);
#if AGENT_SUPPORT_FULL_FEATURE
static void AGENT_SendAssociationReleaseResponse(void *handle, release_request_reason_t releaseReason);
static void AGENT_SendRoer(void *handle, error_result_t *errorResult);
#endif
static void AGENT_RecvComplete(void *handle, uint8_t *dataBuffer, uint32_t size);
/*******************************************************************************
* Variables
******************************************************************************/
/*! @brief the agent device instance */
agent_struct_t g_agentDevice[MAX_AGENT_NUM];
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief send association request.
*
* This function gets the association request data from application and sends
* it to the host using PHDC transport channel, this request is to establish a
* connection between the device and the host.
*
* @param handle the agent handle.
* @param assoc_ptr the association request data.
* @param size the association request data size.
*/
void AGENT_SendAssociationRequest(void *handle, uint8_t *associationData, uint32_t size)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
if (AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState)
{
#if IEEE_MAX_TIMER_OBJECTS
/* preparing association timer object */
ieee11073_timer_struct_t *pAgentTimer = &pAgent->agentTimer[0U];
pAgentTimer->timerObject.timerCount = (int32_t)(RC_ASSOC * TO_ASSOC); /* 30S */
pAgentTimer->timerObject.timerCallback = AGENT_SendAssociationRequestTimeout;
pAgentTimer->timerObject.timerArgument = (void *)pAgent;
pAgentTimer->timerId = IEEE_AddTimerQueue(&pAgentTimer->timerObject);
#endif
/* the first time for sending the association request to host */
if (AGENT_SendData(handle, AGENT_SEND_DATA_QOS, (uint8_t *)associationData, size))
{
#if _USB_DEBUG
usb_echo("Send association request error\n\r");
#endif
}
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot get agent device \n\r");
#endif
}
}
#if IEEE_MAX_TIMER_OBJECTS
/*!
* @brief association request timeout.
*
* This is the callback function which is called every time association request
* timer expired.
*
* @param timerId the identify of timer associated with the agent device.
* @param arg the timer callback param.
*/
static void AGENT_SendAssociationRequestTimeout(void *arg)
{
agent_struct_t *pAgent = (agent_struct_t *)arg;
/* pAgent->agentState = AGENT_STATE_CON_UNASSOCIATED */
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
AGENT_SendAssociationAbortRequest(pAgent->agentHandle, (abort_reason_t)ABORT_REASON_RESPONSE_TIMEOUT);
#endif
}
#endif
/*!
* @brief send agent configuration.
*
* This function gets the agent configuration from application and sends it to
* the host using PHDC transport channel.
*
* @param handle the agent handle.
* @param config_ptr the agent configuration data.
* @param size the agent configuration data size.
*/
void AGENT_SendConfig(void *handle, uint8_t *config, uint32_t size)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
if (AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState)
{
#if IEEE_MAX_TIMER_OBJECTS
/* preparing association timer object */
ieee11073_timer_struct_t *pAgentTimer = &pAgent->agentTimer[1U];
pAgentTimer->timerObject.timerCount = TO_CONFIG; /* 10S */
pAgentTimer->timerObject.timerCallback = AGENT_SendConfigTimeout;
pAgentTimer->timerObject.timerArgument = (void *)pAgent;
pAgentTimer->timerId = IEEE_AddTimerQueue(&pAgentTimer->timerObject);
#endif
/* the first time for sending the association request to host */
if (AGENT_SendData(handle, AGENT_SEND_DATA_QOS, (uint8_t *)config, size))
{
#if _USB_DEBUG
usb_echo("Send configuration error\n\r");
#endif
}
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot get agent device \n\r");
#endif
}
}
#if IEEE_MAX_TIMER_OBJECTS
/*!
* @brief send configuration timeout.
*
* This is the callback function which is called every time sending configuration
* timer expired.
*
* @param timerId the identify of timer associated with the agent device.
* @param arg the timer callback param.
*/
static void AGENT_SendConfigTimeout(void *arg)
{
agent_struct_t *pAgent = (agent_struct_t *)arg;
/* pAgent->agentState = AGENT_STATE_CON_UNASSOCIATED */
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
AGENT_SendAssociationAbortRequest(pAgent->agentHandle, (abort_reason_t)ABORT_REASON_CONFIGURATION_TIMEOUT);
#endif
}
#endif
#if AGENT_SUPPORT_FULL_FEATURE
/*!
* @brief send association abort request.
*
* This function implements association abort request, it builds abort data
* and sends it out using PHDC transport channel.
*
* @param handle the agent handle.
* @param abort_reason the abort reason.
*/
void AGENT_SendAssociationAbortRequest(void *handle, abort_reason_t abortReason)
{
apdu_t *pApdu;
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
uint16_t size;
size = (uint16_t)(ABRT_DATA_LENGTH + APDU_HEADER_SIZE);
pApdu = (apdu_t *)&pAgent->agentTxBuffer[0U];
pApdu->choice = ABRT_CHOSEN;
pApdu->length = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(size - APDU_HEADER_SIZE);
pApdu->u.abrt.reason = USB_SHORT_FROM_BIG_ENDIAN(abortReason);
if (AGENT_SendData(pAgent->agentHandle, AGENT_SEND_DATA_QOS, (uint8_t *)pApdu, (uint32_t)size))
{
#if _USB_DEBUG
usb_echo("Send abort request error\n\r");
#endif
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find the agent device\n\r");
#endif
}
}
#endif
#if AGENT_SUPPORT_FULL_FEATURE
/*!
* @brief send association release request.
*
* This function implements association release request, it builds release data
* and sends it out using PHDC transport channel.
*
* @param handle the agent handle.
* @param release_reason the release reason.
*
* @retval AGENT_ERROR_SUCCESS sending request is successful.
* @retval AGENT_ERROR_INVALID_PARAM the agent device is not found.
*/
void AGENT_SendAssociationRleaseRequest(void *handle, release_request_reason_t releaseReason)
{
apdu_t *pApdu;
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
uint16_t size;
size = (uint16_t)(RLRQ_DATA_LENGTH + APDU_HEADER_SIZE);
pApdu = (apdu_t *)&pAgent->agentTxBuffer[0U];
pApdu->choice = RLRQ_CHOSEN;
pApdu->length = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(size - APDU_HEADER_SIZE);
pApdu->u.rlrq.reason = USB_SHORT_FROM_BIG_ENDIAN(releaseReason);
if (AGENT_SendData(pAgent->agentHandle, AGENT_SEND_DATA_QOS, (uint8_t *)pApdu, (uint32_t)size))
{
#if _USB_DEBUG
usb_echo("Send release request error\n\r");
#endif
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find agent device\n\r");
#endif
}
}
#endif
#if AGENT_SUPPORT_FULL_FEATURE
/*!
* @brief send association release response.
*
* This function implements association release response, it builds release
* response data and sends it out using PHDC transport channel.
*
* @param pAgent the agent device instance pointer.
* @param release_reason the release reason.
*
* @retval AGENT_ERROR_SUCCESS sending response is successful.
* @retval AGENT_ERROR_INVALID_PARAM sending response is fail.
*/
static void AGENT_SendAssociationReleaseResponse(void *handle, release_request_reason_t releaseReason)
{
apdu_t *pApdu;
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
uint16_t size;
size = (uint16_t)(RLRE_DATA_LENGTH + APDU_HEADER_SIZE);
pApdu = (apdu_t *)&pAgent->agentTxBuffer[0U];
pApdu->choice = RLRE_CHOSEN;
pApdu->length = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(size - APDU_HEADER_SIZE);
pApdu->u.rlre.reason = USB_SHORT_FROM_BIG_ENDIAN(releaseReason);
if (AGENT_SendData(handle, AGENT_SEND_DATA_QOS, (uint8_t *)pApdu, (uint32_t)size))
{
#if _USB_DEBUG
usb_echo("Send release response error\n\r");
#endif
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find the agent device\n\r");
#endif
}
}
#endif
/*!
* @brief get agent device by handle.
*
* This function searches the agent device instance corresponding with the
* specified agent handle.
*
* @param handle the agent handle.
*
* @retval pAgent the agent device instance.
* @retval NULL the agent device is not found.
*/
static agent_struct_t *AGENT_GetDeviceByHandle(void *handle)
{
agent_struct_t *pAgent = NULL;
for (uint8_t i = 0U; i < MAX_AGENT_NUM; i++)
{
if (handle == g_agentDevice[i].agentHandle)
{
pAgent = (agent_struct_t *)(&g_agentDevice[i]);
break;
}
}
return pAgent;
}
/*!
* @brief set agent device state.
*
* This function sets the state of device corresponding with specified agent.
*
* @param handle the agent handle.
* @param state the state to set.
*
* @retval AGENT_ERROR_SUCCESS the agent device is found.
* @retval AGENT_ERROR_INVALID_PARAM the agent device is not found.
*/
void AGENT_SetAgentState(void *handle, uint8_t state)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
switch (state)
{
case AGENT_STATE_DISCONNECTED:
#if IEEE_MAX_TIMER_OBJECTS
/* de-queue timer */
for (uint8_t i = 0U; i < IEEE_MAX_TIMER_OBJECTS; i++)
{
ieee11073_timer_struct_t *pAgentTimer = &pAgent->agentTimer[i];
IEEE_RemoveTimerQueue(pAgentTimer->timerId);
}
#endif
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER DISCONNECTED state");
#endif
break;
case AGENT_STATE_CON_UNASSOCIATED:
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER UNASSOCIATED state");
#endif
break;
case AGENT_STATE_CON_ASSOCIATING:
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER ASSOCIATING state");
#endif
break;
case AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG:
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER CONFIGURING SENDING CONFIG state");
#endif
break;
case AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL:
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER CONFIGURING WAITING APPROVAL state");
#endif
break;
case AGENT_STATE_CON_ASSOC_OPERATING:
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER OPERATING state");
#endif
break;
case AGENT_STATE_CON_DISASSOCIATING:
pAgent->agentState = state;
#if _USB_DEBUG
usb_echo("\n\r11073Agent: ENTER DISASSOCIATING state");
#endif
break;
default:
#if _USB_DEBUG
usb_echo("\n\r11073Agent: Error invalid state");
#endif
break;
}
}
else
{
#if _USB_DEBUG
usb_echo("\n\r11073Agent: Error invalid param");
#endif
}
}
/*!
* @brief initialize the agent device.
*
* This function initializes the agent device and starts transporting.
*
* @param handle the agent handle.
*/
void AGENT_Init(void *handle)
{
uint8_t isNonActiveAgent = 0U;
uint8_t agentIndex = 0U;
agent_struct_t *pAgent = NULL;
for (; agentIndex < MAX_AGENT_NUM; agentIndex++)
{
if (0U == g_agentDevice[agentIndex].agentHandle)
{
isNonActiveAgent = 1U;
break;
}
}
if (0U == isNonActiveAgent)
{
#if _USB_DEBUG
usb_echo("ERROR: Users need to increase the max number of agent devices!\n\r");
#endif
}
else
{
/* Initialize Global Variable Structure */
pAgent = (agent_struct_t *)(&g_agentDevice[agentIndex]);
memset(pAgent, 0U, sizeof(agent_struct_t));
#if IEEE_MAX_TIMER_OBJECTS
IEEE_TimerInit();
#endif
/* set the default state of agent device is disconnected */
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_DISCONNECTED);
pAgent->agentHandle = handle;
}
}
/*!
* @brief agent callback.
*
* This function is the callback function called by transport layer and then it
* will call to proper agent functions.
*
* @param handle the agent handle.
* @param request the callback request.
* @param data the callback data.
* @param size the callback data size.
*/
void AGENT_Callback(void *handle, uint8_t request, uint8_t *data, uint32_t size)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
switch (request)
{
case SHIM_AGENT_EVENT_RECV_MESSAGE_PREAMBLE:
case SHIM_AGENT_EVENT_RECV_OPAQUE_DATA:
break;
case SHIM_AGENT_EVENT_RECV_COMPLETE:
{
AGENT_RecvComplete(handle, data, size);
}
break;
case SHIM_AGENT_EVENT_SENT_COMPLETE:
{
if (AGENT_STATE_DISCONNECTED == pAgent->agentState)
{
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_CON_UNASSOCIATED);
pAgent->isSendingRorsCmipGet = 0U;
AGENT_MedicalCallback(handle, AGENT_EVENT_CONNECTED, NULL);
}
else if (AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState)
{
#if IEEE_MAX_TIMER_OBJECTS
ieee11073_timer_struct_t *pAgentTimer = &pAgent->agentTimer[0U];
IEEE_RemoveTimerQueue(pAgentTimer->timerId);
#endif
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_CON_ASSOCIATING);
}
else if (AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState)
{
#if IEEE_MAX_TIMER_OBJECTS
ieee11073_timer_struct_t *pAgentTimer;
pAgentTimer = &pAgent->agentTimer[1U];
IEEE_RemoveTimerQueue(pAgentTimer->timerId);
#endif
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL);
}
else if (AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState)
{
if (1U == pAgent->isSendingRorsCmipGet)
{
pAgent->isSendingRorsCmipGet = 0U;
AGENT_MedicalCallback(handle, AGENT_EVENT_RORS_CMIP_GET_SENT, NULL);
}
}
else
{
}
}
break;
default:
break;
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot the Agent device\n\r");
#endif
}
}
/*!
* @brief the agent receive complete.
*
* This function analyses the received APDU data and calls to corresponding
* agent function.
*
* @param handle the agent handle.
* @param dataBuffer pointer to data
* @param size data size
*/
static void AGENT_RecvComplete(void *handle, uint8_t *dataBuffer, uint32_t size)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
if (AGENT_STATE_DISCONNECTED != pAgent->agentState)
{
uint16_t apduChoice;
apdu_t *pApdu = NULL;
pApdu = (apdu_t *)dataBuffer;
apduChoice = USB_SHORT_FROM_BIG_ENDIAN(pApdu->choice);
switch (apduChoice)
{
case AARQ_CHOSEN:
if ((AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOCIATING == pAgent->agentState))
{
/* agent-agent association - send aare request to reject association reqeuest*/
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
/* cannot establish a connection between two USB devices, this case will never occurs */
#endif
}
else if ((AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState) ||
(AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState))
{
/* Should not happen - send abort request*/
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
AGENT_SendAssociationAbortRequest(handle, (abort_reason_t)ABORT_REASON_UNDEFINED);
#endif
}
else
{
}
break;
case AARE_CHOSEN:
if ((AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState) ||
(AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState))
{
/* Should not happen - send abort request */
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
/* send abort request */
AGENT_SendAssociationAbortRequest(handle, (abort_reason_t)ABORT_REASON_UNDEFINED);
#endif
}
else if ((AGENT_STATE_CON_ASSOCIATING == pAgent->agentState))
{
AGENT_RecvAssociationResponse(handle, &(pApdu->u.aare));
}
else
{
}
break;
case RLRQ_CHOSEN:
if ((AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOCIATING == pAgent->agentState))
{
/* Should not happen - send abort request to host */
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
/* send abort request */
AGENT_SendAssociationAbortRequest(handle, (abort_reason_t)ABORT_REASON_UNDEFINED);
#endif
}
else if ((AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState) ||
(AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState))
{
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
/* send rlre(normal) */
AGENT_SendAssociationReleaseResponse(handle,
(release_request_reason_t)RELEASE_REQUEST_REASON_NORMAL);
#endif
}
else
{
}
break;
case RLRE_CHOSEN:
if ((AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOCIATING == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState))
{
/* Should not happen - send abort request to host */
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
#if AGENT_SUPPORT_FULL_FEATURE
/* send abort request */
AGENT_SendAssociationAbortRequest(handle, (abort_reason_t)ABORT_REASON_UNDEFINED);
#endif
}
else if (AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState)
{
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
}
else
{
}
break;
case ABRT_CHOSEN:
if ((AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOCIATING == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState) ||
(AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState))
{
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
}
break;
case PRST_CHOSEN:
AGENT_RecvPresentationProtocolDataUnit(handle, &(pApdu->u.prst));
break;
default:
break;
}
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find the Agent device\n\r");
#endif
}
}
/*!
* @brief receive association response handle.
*
* This function handles the association request response sent by the host.
*
* @param handle the agent handle.
* @associaionResponse association response data
*/
static void AGENT_RecvAssociationResponse(void *handle, aare_apdu_t *associaionResponse)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
if (ACCEPTED == USB_SHORT_FROM_BIG_ENDIAN(associaionResponse->result))
{
/* The Agent is accepted by manager, change the state to operating,
and wait roivCmipGet event from manager to change the procedure to
operating */
AGENT_SetAgentState(handle, AGENT_STATE_CON_ASSOC_OPERATING);
AGENT_MedicalCallback(handle, AGENT_EVENT_ACCEPTED_AARQ, NULL);
}
else if (ACCEPTED_UNKNOWN_CONFIG == USB_SHORT_FROM_BIG_ENDIAN(associaionResponse->result))
{
/* The Agent is accepted by manager with unknown configuration, change agent state
to configuring sending config, callback to application to send the device's configuration
to the manager then change the procedure to configuring */
AGENT_SetAgentState(handle, AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG);
AGENT_MedicalCallback(handle, AGENT_EVENT_ACCEPTED_UNKNOWN_CONFIG_AARQ, NULL);
}
else
{
/* The Agent is rejected by manager, change to state to unassociated, change the procedure
to unassociated, callback to application with Reject event */
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
AGENT_MedicalCallback(handle, AGENT_EVENT_REJECTED_AARQ, NULL);
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find the Agent device\n\r");
#endif
}
}
/*!
* @brief receive PRST handle.
*
* This function handles the request/data sent by the host when the device is in
* operating state.
*
* @param handle the agent handle.
* @param pPrst presentation data unit pointer.
*/
static void AGENT_RecvPresentationProtocolDataUnit(void *handle, prst_apdu_t *pPrst)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
data_apdu_t *dataApdu = (data_apdu_t *)&(pPrst->value[0U]);
/* Store the invoke ID */
pAgent->invokeId = dataApdu->invokeId;
if ((AGENT_STATE_CON_UNASSOCIATED == pAgent->agentState) || (AGENT_STATE_CON_ASSOCIATING == pAgent->agentState))
{
#if AGENT_SUPPORT_FULL_FEATURE
/* should not happen, send abort request to the manager */
AGENT_SendAssociationAbortRequest(handle, ABORT_REASON_UNDEFINED);
#endif
}
switch (USB_SHORT_FROM_BIG_ENDIAN(dataApdu->choice.choice))
{
case ROIV_CMIP_GET_CHOSEN:
if ((AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState))
{
/* The remote operation response | Get is sending */
pAgent->isSendingRorsCmipGet = 1U;
/* callback to application to send rors-cmip-ge (MDS attribute) */
AGENT_MedicalCallback(handle, AGENT_EVENT_RECV_ROIV_CMIP_GET, (uint8_t *)&pAgent->invokeId);
}
else if (AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState)
{
/* do nothing */
}
else
{
}
break;
case ROIV_CMIP_EVENT_REPORT_CHOSEN:
case ROIV_CMIP_CONFIRMED_EVENT_REPORT_CHOSEN:
case ROIV_CMIP_SET_CHOSEN:
case ROIV_CMIP_CONFIRMED_SET_CHOSEN:
case ROIV_CMIP_ACTION_CHOSEN:
case ROIV_CMIP_CONFIRMED_ACTION_CHOSEN:
if ((AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState))
{
#if AGENT_SUPPORT_FULL_FEATURE
/* not allowed, send roer with no-such-object-instance */
uint8_t tempBuffer[4U];
error_result_t *errorResult = (error_result_t *)&tempBuffer[0];
errorResult->errorValue = USB_SHORT_FROM_BIG_ENDIAN(NO_SUCH_OBJECT_INSTANCE);
errorResult->parameter.length = 0U; /* There is no parameter for error result */
/* Send rors or rore or rorj, no state transition */
AGENT_SendRoer(handle, errorResult);
#endif
}
else if (AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState)
{
/* normal processing of message */
}
else if (AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState)
{
/* do nothing */
}
else
{
}
break;
case RORS_CMIP_CONFIRMED_EVENT_REPORT_CHOSEN:
if ((AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState))
{
#if AGENT_SUPPORT_FULL_FEATURE
/* should not happen, send abort request to the manager */
AGENT_SendAssociationAbortRequest(handle, ABORT_REASON_UNDEFINED);
#endif
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
}
else if (AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState)
{
/* configuration accepted */
config_report_rsp_t *configReport =
(config_report_rsp_t *)(&dataApdu->choice.u.rorsCmipConfirmedEventReport.eventReplyInfo
.value[0]);
configReport->configReportId = USB_SHORT_FROM_BIG_ENDIAN(configReport->configReportId);
if ((EXTENDED_CONFIG_START == configReport->configReportId) &&
(ACCEPTED_CONFIG == configReport->configResult))
{
/* The device's configuration is accepted by manager, change the state to operating, callback to
application to start sending data */
AGENT_SetAgentState(handle, AGENT_STATE_CON_ASSOC_OPERATING);
AGENT_MedicalCallback(handle, AGENT_EVENT_ACCEPTED_CONFIG, NULL);
}
else
{
/* The device's configuration is not accepted by manager, change the state to sending
configuration,
callback to application to resent the config */
AGENT_SetAgentState(pAgent->agentHandle, AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG);
AGENT_MedicalCallback(handle, AGENT_EVENT_UNSUPPORTED_CONFIG, NULL);
}
}
else if (AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState)
{
/* the measurement data is sent complete, callback to application to send measurement data */
AGENT_MedicalCallback(handle, AGENT_EVENT_MEASUREMENT_SENT, NULL);
}
else if (AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState)
{
#if AGENT_SUPPORT_FULL_FEATURE
/* send abort */
AGENT_SendAssociationAbortRequest(handle, ABORT_REASON_UNDEFINED);
#endif
}
else
{
}
break;
case RORS_CMIP_GET_CHOSEN:
case RORS_CMIP_CONFIRMED_SET_CHOSEN:
case RORS_CMIP_CONFIRMED_ACTION_CHOSEN:
case ROER_CHOSEN:
case RORJ_CHOSEN:
if ((AGENT_STATE_CON_ASSOC_CFG_SENDING_CONFIG == pAgent->agentState) ||
(AGENT_STATE_CON_ASSOC_CFG_WAITING_APPROVAL == pAgent->agentState))
{
#if AGENT_SUPPORT_FULL_FEATURE
/* should not happen, send abort request to the manager */
AGENT_SendAssociationAbortRequest(handle, ABORT_REASON_UNDEFINED);
#endif
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
}
else if (AGENT_STATE_CON_ASSOC_OPERATING == pAgent->agentState)
{
/* normal processing of message, do nothing */
}
else if (AGENT_STATE_CON_DISASSOCIATING == pAgent->agentState)
{
#if AGENT_SUPPORT_FULL_FEATURE
/* send abort */
AGENT_SendAssociationAbortRequest(handle, ABORT_REASON_UNDEFINED);
#endif
AGENT_SetAgentState(handle, AGENT_STATE_CON_UNASSOCIATED);
}
else
{
}
break;
default:
break;
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find the Agent device\n\r");
#endif
}
}
#if AGENT_SUPPORT_FULL_FEATURE
/*!
* @brief send error.
* This function is called to send error command to the device.
*
* @param param the phdc manager instance pointer.
* @param errorResult error result.
*/
static void AGENT_SendRoer(uint32_t handle, error_result_t *errorResult)
{
agent_struct_t *pAgent = NULL;
pAgent = AGENT_GetDeviceByHandle(handle);
if (NULL != pAgent)
{
uint16_t size;
apdu_t *pApdu;
data_apdu_t *pPrst;
/* Calculate the size of Roer data */
size = (uint16_t)(APDU_HEADER_SIZE + PRST_HEADER_LENGTH + sizeof(errorResult->errorValue) +
sizeof(errorResult->parameter.length) +
USB_SHORT_FROM_BIG_ENDIAN(errorResult->parameter.length));
pApdu = (apdu_t *)&pAgent->agentTxBuffer[0];
pApdu->choice = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(PRST_CHOSEN);
pApdu->length = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(size - APDU_HEADER_SIZE);
pApdu->u.prst.length = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(size - APDU_HEADER_SIZE - sizeof(uint16_t));
pPrst = (data_apdu_t *)&pApdu->u.prst.value[0U];
pPrst->invokeId = pAgent->invokeId;
pPrst->choice.choice = USB_SHORT_FROM_BIG_ENDIAN(ROER_CHOSEN);
pPrst->choice.length = (uint16_t)USB_SHORT_FROM_BIG_ENDIAN(size - APDU_HEADER_SIZE - PRST_HEADER_LENGTH);
pPrst->choice.u.roer.errorValue = errorResult->errorValue;
pPrst->choice.u.roer.parameter.length = errorResult->parameter.length;
if (USB_SHORT_FROM_BIG_ENDIAN(errorResult->parameter.length) > 0U)
{
memcpy(&pPrst->choice.u.roer.parameter.value[0U], &errorResult->parameter.value[0U],
USB_SHORT_FROM_BIG_ENDIAN(errorResult->parameter.length));
}
if (AGENT_SendData(handle, AGENT_SEND_DATA_QOS, (uint8_t *)pApdu, (uint32_t)size))
{
#if _USB_DEBUG
usb_echo("Send release response error\n\r");
#endif
}
}
else
{
#if _USB_DEBUG
usb_echo("Cannot find the agent device\n\r");
#endif
}
}
#endif
/* EOF */