/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#if !MBED_CONF_BLE_PRESENT
#error [NOT_SUPPORTED] BLE cordio test cases require the BLE library.
#else

#include <stdio.h>

#include "events/mbed_events.h"
#include "platform/Callback.h"

#include "ble/BLE.h"

#include "greentea-client/test_env.h"
#include "utest/utest.h"
#include "unity/unity.h"

#include "hci_api.h"
#include "hci_cmd.h"
#include "hci_core.h"
#include "dm_api.h"
#include "bstream.h"

using namespace utest::v1;
using mbed::callback;

#define INITIALIZATION_TIMEOUT (10 * 1000)

static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE);

enum initialization_state_t {
    WAITING_FOR_INITIALIZATION,
    INITIALIZATION_FAILURE,
    INITIALIZATION_SUCCESS
};

static initialization_state_t initialization_state = WAITING_FOR_INITIALIZATION;

static void process_ble_events(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    event_queue.call(callback(&ble, &BLE::processEvents));
}

static void on_initialization_complete(BLE::InitializationCompleteCallbackContext *params) {
    if (params->error == BLE_ERROR_NONE) {
        initialization_state = INITIALIZATION_SUCCESS;
    } else {
        initialization_state = INITIALIZATION_FAILURE;
    }

    event_queue.break_dispatch();
}

static void test_stack_initialization() {
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(process_ble_events);
    ble.init(on_initialization_complete);
    event_queue.dispatch(INITIALIZATION_TIMEOUT);

    // At this point ble is suppose to be initialized; inspect the various state
    // of the stack.
    TEST_ASSERT_EQUAL(INITIALIZATION_SUCCESS, initialization_state);

    // ensure that the size of ACL buffer of the controller has been filled in
    // during the initialisation
    TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.bufSize);

    // Ensure that the total number of buffer available in the controller has
    // been filled in during the initialisation
    TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.numBufs);

    // Ensure that at least one HCI buffer is available
    TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.availBufs);

    // Ensure that allowed LE state has been filled in during initialisation
    // Note: see BT command LE Read Supported States Command in BT specification
    uint8_t invalid_le_states[HCI_LE_STATES_LEN] = { 0 };
    TEST_ASSERT_NOT_EQUAL(0, memcmp(invalid_le_states, hciCoreCb.leStates, HCI_LE_STATES_LEN));

    // Ensure that the size of the whitelist of the controller has been filled
    // in during the initialisation
    TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.whiteListSize);

    // Note: cannot test supported features are the list may be null
    // Note: cannot test resolving list size as this may be null
}

Case cases[] = {
    Case("Test cordio stack reset sequence", test_stack_initialization),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
    GREENTEA_SETUP(15, "default_auto");
    return verbose_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main() {
    return !Harness::run(specification);
}

#endif // !MBED_CONF_BLE_PRESENT
