OSStatus bt_smartbridge_att_cache_disable( void )
{
    uint32_t a;
    linked_list_node_t* node = NULL;
    bt_smartbridge_att_cache_manager_t* manager = att_cache_manager;

    if ( att_cache_manager == NULL )
    {
        return MICO_BT_SUCCESS;
    }

    /* Set status at the beginning to prevent cached attributes being used even when deinitialisation failed */
    att_cache_manager = NULL;

    while ( linked_list_remove_node_from_front( &manager->free_list, &node ) == MICO_BT_SUCCESS )
    {
        bt_smartbridge_att_cache_t* cache = (bt_smartbridge_att_cache_t*)node->data;

        mico_bt_smart_attribute_delete_list( &cache->attribute_list );
    }

    linked_list_deinit( &manager->free_list );

    while ( linked_list_remove_node_from_front( &manager->used_list, &node ) == MICO_BT_SUCCESS )
    {
        bt_smartbridge_att_cache_t* cache = (bt_smartbridge_att_cache_t*)node->data;

        mico_bt_smart_attribute_delete_list( &cache->attribute_list );
    }

    linked_list_deinit( &manager->used_list );
    mico_rtos_deinit_mutex( &manager->mutex );

    /* Deinitialise mutexes for protecting access to cached attributes */
    for ( a = 0; a < manager->count; a++ )
    {
        mico_rtos_deinit_mutex( &manager->pool[a].mutex );
    }

    if( manager->att_cache_services_count != 0 )
    {
        free( manager->att_cache_services );
    }
    
    memset( manager, 0, CALCULATE_ATT_CACHE_MANAGER_SIZE( manager->count ) );
    free( manager );

    return MICO_BT_SUCCESS;
}
wiced_result_t bt_smartbridge_att_cache_enable( uint32_t cache_count )
{
    uint32_t a;
    wiced_result_t result;
    bt_smartbridge_att_cache_manager_t* manager;

    if ( att_cache_manager != NULL )
    {
        return WICED_BT_SUCCESS;
    }

    manager = (bt_smartbridge_att_cache_manager_t*)malloc_named( "att_cache", CALCULATE_ATT_CACHE_MANAGER_SIZE( cache_count ) );
    if ( manager == NULL )
    {
        return WICED_BT_OUT_OF_HEAP_SPACE;
    }

    memset( manager, 0, CALCULATE_ATT_CACHE_MANAGER_SIZE( cache_count ) );

    att_cache_manager = manager;
    manager->count    = cache_count;

    result = bt_linked_list_init( &manager->free_list );
    if ( result != WICED_BT_SUCCESS )
    {
        WPRINT_LIB_INFO( ( "Error creating linked list\n" ) );
        goto error;
    }

    result = bt_linked_list_init( &manager->used_list );
    if ( result != WICED_BT_SUCCESS )
    {
        WPRINT_LIB_INFO( ( "Error creating linked list\n" ) );
        goto error;
    }

    result = wiced_rtos_init_mutex( &manager->mutex );
    if ( result != WICED_SUCCESS )
    {
        WPRINT_LIB_INFO( ( "Error creating mutex\n" ) );
        goto error;
    }

    /* Initialise mutexes for protecting access to cached attributes */
    for ( a = 0; a < manager->count; a++ )
    {
        result = wiced_rtos_init_mutex( &manager->pool[a].mutex );
        if ( result != WICED_BT_SUCCESS )
        {
            goto error;
        }

        /* Point node data to cached attribute instance */
        manager->pool[a].node.data = (void*)&manager->pool[a];

        /* Insert cached attribute instance into free list */
        result = bt_linked_list_insert_at_rear( &manager->free_list, &manager->pool[a].node );
        if ( result != WICED_BT_SUCCESS )
        {
            goto error;
        }
    }

    return WICED_BT_SUCCESS;

    error:
    bt_smartbridge_att_cache_disable();
    return result;
}
OSStatus bt_smartbridge_att_cache_enable( uint32_t cache_count, mico_bt_uuid_t cache_services[], uint32_t service_count )
{
    uint32_t a;
    OSStatus result;
    bt_smartbridge_att_cache_manager_t* manager;
    mico_bt_uuid_t* services = NULL;

    if ( att_cache_manager != NULL )
    {
        return MICO_BT_SUCCESS;
    }

    manager = (bt_smartbridge_att_cache_manager_t*)malloc_named( "att_cache", CALCULATE_ATT_CACHE_MANAGER_SIZE( cache_count ) );
    if ( manager == NULL )
    {
        return MICO_BT_OUT_OF_HEAP_SPACE;
    }

    if( service_count != 0 )
    {
        services = (mico_bt_uuid_t *)malloc_named( "cache_services", service_count * sizeof(mico_bt_uuid_t) );
        if ( services == NULL )
        {
            return MICO_BT_OUT_OF_HEAP_SPACE;
        }
    }


    memset( manager, 0, CALCULATE_ATT_CACHE_MANAGER_SIZE( cache_count ) );

    att_cache_manager = manager;
    manager->count    = cache_count;
    manager->att_cache_services_count = service_count;
    if( service_count != 0 )
    {
        manager->att_cache_services = services;
        memcpy( manager->att_cache_services, cache_services, service_count * sizeof(mico_bt_uuid_t) );        
    }


    result = linked_list_init( &manager->free_list );
    if ( result != MICO_BT_SUCCESS )
    {
        bt_smartbridge_log( "Error creating linked list\n" );
        goto error;
    }

    result = linked_list_init( &manager->used_list );
    if ( result != MICO_BT_SUCCESS )
    {
        bt_smartbridge_log( "Error creating linked list\n" );
        goto error;
    }

    result = mico_rtos_init_mutex( &manager->mutex );
    if ( result != MICO_BT_SUCCESS )
    {
        bt_smartbridge_log( "Error creating mutex\n" );
        goto error;
    }

    /* Initialise mutexes for protecting access to cached attributes */
    for ( a = 0; a < manager->count; a++ )
    {
        result = mico_rtos_init_mutex( &manager->pool[a].mutex );
        if ( result != MICO_BT_SUCCESS )
        {
            goto error;
        }

        /* Point node data to cached attribute instance */
        manager->pool[a].node.data = (void*)&manager->pool[a];

        /* Insert cached attribute instance into free list */
        result = linked_list_insert_node_at_rear( &manager->free_list, &manager->pool[a].node );
        if ( result != MICO_BT_SUCCESS )
        {
            goto error;
        }
    }

    return MICO_BT_SUCCESS;

    error:
    bt_smartbridge_att_cache_disable();
    return result;
}