'Implements the DescribeStackResources API action.
Return details of resources specified by the parameters.
`StackName`: returns all resources belonging to the stack.
`PhysicalResourceId`: returns all resources belonging to the stack this
resource is associated with.
Only one of the parameters may be specified.
Optional parameter:
`LogicalResourceId`: filter the resources list by the logical resource
id.'

def describe_stack_resources(self, req):

    self._enforce(req, 'DescribeStackResources')
    def format_stack_resource(r):
        'Reformat    engine    output    into    AWS    "StackResource"    format.'
        keymap = {rpc_api.RES_DESCRIPTION: 'Description', rpc_api.RES_NAME: 'LogicalResourceId', rpc_api.RES_PHYSICAL_ID: 'PhysicalResourceId', rpc_api.RES_STATUS_DATA: 'ResourceStatusReason', rpc_api.RES_TYPE: 'ResourceType', rpc_api.RES_STACK_ID: 'StackId', rpc_api.RES_STACK_NAME: 'StackName', rpc_api.RES_UPDATED_TIME: 'Timestamp'}
        result = api_utils.reformat_dict_keys(keymap, r)
        result['ResourceStatus'] = self._resource_status(r)
        return self._id_format(result)
    con = req.context
    stack_name = req.params.get('StackName')
    physical_resource_id = req.params.get('PhysicalResourceId')
    if (stack_name and physical_resource_id):
        msg = 'Use    `StackName`    or    `PhysicalResourceId`    but    not    both'
        return exception.HeatInvalidParameterCombinationError(detail=msg)
    try:
        if (stack_name is not None):
            identity = self._get_identity(con, stack_name)
        else:
            identity = self.rpc_client.find_physical_resource(con, physical_resource_id=physical_resource_id)
        resources = self.rpc_client.describe_stack_resources(con, stack_identity=identity, resource_name=req.params.get('LogicalResourceId'))
    except Exception as ex:
        return exception.map_remote_error(ex)
    result = [format_stack_resource(r) for r in resources]
    return api_utils.format_response('DescribeStackResources', {'StackResources': result})
