Skip to content

Commit 34513f2

Browse files
author
Cruz Monrreal
authored
Merge pull request #7221 from pan-/cordio-port-test
Cordio: Add tests that validates a cordio port.
2 parents e8ec361 + d2ecdb8 commit 34513f2

File tree

2 files changed

+379
-0
lines changed
  • features/FEATURE_BLE/targets/TARGET_CORDIO/TESTS/cordio_hci

2 files changed

+379
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <stdio.h>
18+
19+
#include "events/mbed_events.h"
20+
#include "platform/Callback.h"
21+
22+
#include "ble/BLE.h"
23+
24+
#include "greentea-client/test_env.h"
25+
#include "utest/utest.h"
26+
#include "unity/unity.h"
27+
28+
#include "hci_api.h"
29+
#include "hci_cmd.h"
30+
#include "hci_core.h"
31+
#include "dm_api.h"
32+
#include "bstream.h"
33+
34+
using namespace utest::v1;
35+
using mbed::callback;
36+
37+
#define INITIALIZATION_TIMEOUT (10 * 1000)
38+
39+
static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE);
40+
41+
enum initialization_state_t {
42+
WAITING_FOR_INITIALIZATION,
43+
INITIALIZATION_FAILURE,
44+
INITIALIZATION_SUCCESS
45+
};
46+
47+
static initialization_state_t initialization_state = WAITING_FOR_INITIALIZATION;
48+
49+
static void process_ble_events(BLE::OnEventsToProcessCallbackContext* context) {
50+
BLE &ble = BLE::Instance();
51+
event_queue.call(callback(&ble, &BLE::processEvents));
52+
}
53+
54+
static void on_initialization_complete(BLE::InitializationCompleteCallbackContext *params) {
55+
if (params->error == BLE_ERROR_NONE) {
56+
initialization_state = INITIALIZATION_SUCCESS;
57+
} else {
58+
initialization_state = INITIALIZATION_FAILURE;
59+
}
60+
61+
event_queue.break_dispatch();
62+
}
63+
64+
static void test_stack_initialization() {
65+
BLE &ble = BLE::Instance();
66+
ble.onEventsToProcess(process_ble_events);
67+
ble.init(on_initialization_complete);
68+
event_queue.dispatch(INITIALIZATION_TIMEOUT);
69+
70+
// At this point ble is suppose to be initialized; inspect the various state
71+
// of the stack.
72+
TEST_ASSERT_EQUAL(INITIALIZATION_SUCCESS, initialization_state);
73+
74+
// ensure that the size of ACL buffer of the controller has been filled in
75+
// during the initialisation
76+
TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.bufSize);
77+
78+
// Ensure that the total number of buffer available in the controller has
79+
// been filled in during the initialisation
80+
TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.numBufs);
81+
82+
// Ensure that at least one HCI buffer is available
83+
TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.availBufs);
84+
85+
// Ensure that allowed LE state has been filled in during initialisation
86+
// Note: see BT command LE Read Supported States Command in BT specification
87+
uint8_t invalid_le_states[HCI_LE_STATES_LEN] = { 0 };
88+
TEST_ASSERT_NOT_EQUAL(0, memcmp(invalid_le_states, hciCoreCb.leStates, HCI_LE_STATES_LEN));
89+
90+
// Ensure that the size of the whitelist of the controller has been filled
91+
// in during the initialisation
92+
TEST_ASSERT_NOT_EQUAL(0, hciCoreCb.whiteListSize);
93+
94+
// Note: cannot test supported features are the list may be null
95+
// Note: cannot test resolving list size as this may be null
96+
}
97+
98+
Case cases[] = {
99+
Case("Test cordio stack reset sequence", test_stack_initialization),
100+
};
101+
102+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
103+
GREENTEA_SETUP(15, "default_auto");
104+
return verbose_test_setup_handler(number_of_cases);
105+
}
106+
107+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
108+
109+
int main() {
110+
return !Harness::run(specification);
111+
}
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <stdio.h>
18+
#include <algorithm>
19+
20+
#include "driver/CordioHCITransportDriver.h"
21+
#include "driver/CordioHCIDriver.h"
22+
#include "hci_defs.h"
23+
#include "rtos/EventFlags.h"
24+
25+
#include "greentea-client/test_env.h"
26+
#include "utest/utest.h"
27+
#include "unity/unity.h"
28+
29+
using namespace utest::v1;
30+
31+
using ble::vendor::cordio::CordioHCIDriver;
32+
using ble::vendor::cordio::CordioHCITransportDriver;
33+
34+
extern ble::vendor::cordio::CordioHCIDriver& ble_cordio_get_hci_driver();
35+
36+
namespace ble {
37+
namespace vendor {
38+
namespace cordio {
39+
40+
struct CordioHCIHook {
41+
static CordioHCIDriver& get_driver() {
42+
return ble_cordio_get_hci_driver();
43+
}
44+
45+
static CordioHCITransportDriver& get_transport_driver() {
46+
return get_driver()._transport_driver;
47+
}
48+
49+
static void set_data_received_handler(void (*handler)(uint8_t*, uint8_t)) {
50+
get_transport_driver().set_data_received_handler(handler);
51+
}
52+
};
53+
54+
} // namespace cordio
55+
} // namespace vendor
56+
} // namespace ble
57+
58+
using ble::vendor::cordio::CordioHCIHook;
59+
60+
//
61+
// Handle signal mechanism
62+
//
63+
#define RESET_COMMAND_TIMEOUT (10 * 1000)
64+
65+
static const uint32_t RESET_RECEIVED_FLAG = 1 << 0;
66+
static const uint32_t RECEPTION_ERROR_FLAG = 1 << 1;
67+
static const uint32_t RESET_STATUS_ERROR_FLAG = 1 << 2;
68+
69+
static const uint32_t WAITING_FLAGS =
70+
RESET_RECEIVED_FLAG | RECEPTION_ERROR_FLAG | RESET_STATUS_ERROR_FLAG;
71+
72+
static rtos::EventFlags event_channel;
73+
74+
static void signal_flag(uint32_t flag) {
75+
if (!(event_channel.get() & flag)) {
76+
event_channel.set(flag);
77+
}
78+
}
79+
80+
uint32_t wait_for_event() {
81+
// clear reception flags
82+
uint32_t flags = event_channel.get();
83+
event_channel.clear(flags & ~RESET_RECEIVED_FLAG);
84+
85+
return event_channel.wait_any(
86+
WAITING_FLAGS,
87+
/* timeout */ RESET_COMMAND_TIMEOUT,
88+
/* clear */ false
89+
);
90+
}
91+
92+
//
93+
// Handle reset command reception
94+
//
95+
96+
#define RESET_PARAMETER_LENGTH 4
97+
#define RESET_EXPECTED_STATUS 0
98+
#define HCI_OPCODE_RESET_LSB (HCI_OPCODE_RESET & 0xFF)
99+
#define HCI_OPCODE_RESET_MSB (HCI_OPCODE_RESET >> 8)
100+
#define RESET_PACKET_LENGTH (1 + HCI_EVT_HDR_LEN + RESET_PARAMETER_LENGTH)
101+
#define RESET_STATUS_INDEX 6
102+
103+
static bool is_reset_event(const uint8_t* data, uint16_t len) {
104+
if (len != RESET_PACKET_LENGTH) {
105+
return false;
106+
}
107+
108+
if (*data++ != HCI_EVT_TYPE) {
109+
return false;
110+
}
111+
112+
if (*data++ != HCI_CMD_CMPL_EVT) {
113+
return false;
114+
}
115+
116+
if (*data++ != RESET_PARAMETER_LENGTH) {
117+
return false;
118+
}
119+
120+
// Note skip num of HCI packet as this is controller dependent
121+
data++;
122+
123+
if (*data++ != HCI_OPCODE_RESET_LSB) {
124+
return false;
125+
}
126+
127+
if (*data++ != HCI_OPCODE_RESET_MSB) {
128+
return false;
129+
}
130+
131+
return true;
132+
}
133+
134+
static void hci_driver_rx_reset_handler(uint8_t* data, uint8_t len) {
135+
enum packet_state_t {
136+
WAITING_FOR_PACKET_TYPE,
137+
WAITING_FOR_HEADER_COMPLETE,
138+
WAITING_FOR_DATA_COMPLETE,
139+
SYNCHRONIZATION_ERROR,
140+
STATUS_ERROR
141+
};
142+
143+
static uint8_t packet[256] = { 0 };
144+
static uint16_t position = 0;
145+
static uint16_t packet_length;
146+
static packet_state_t reception_state = WAITING_FOR_PACKET_TYPE;
147+
148+
while (len) {
149+
switch (reception_state) {
150+
case WAITING_FOR_PACKET_TYPE:
151+
if (*data != HCI_EVT_TYPE) {
152+
reception_state = SYNCHRONIZATION_ERROR;
153+
signal_flag(RECEPTION_ERROR_FLAG);
154+
return;
155+
}
156+
157+
packet[position++] = *data++;
158+
--len;
159+
packet_length = 1 + HCI_EVT_HDR_LEN;
160+
reception_state = WAITING_FOR_HEADER_COMPLETE;
161+
break;
162+
163+
case WAITING_FOR_HEADER_COMPLETE:
164+
case WAITING_FOR_DATA_COMPLETE: {
165+
uint16_t step = std::min((uint16_t) len, (uint16_t) (packet_length - position));
166+
memcpy(packet + position, data, step);
167+
position+= step;
168+
data += step;
169+
len -= step;
170+
171+
if (reception_state == WAITING_FOR_HEADER_COMPLETE &&
172+
position == packet_length
173+
) {
174+
reception_state = WAITING_FOR_DATA_COMPLETE;
175+
packet_length += packet[HCI_EVT_HDR_LEN];
176+
}
177+
} break;
178+
179+
180+
// dead end; we never exit from the error state; just asignal it again.
181+
case SYNCHRONIZATION_ERROR:
182+
signal_flag(RECEPTION_ERROR_FLAG);
183+
return;
184+
185+
case STATUS_ERROR:
186+
signal_flag(RESET_STATUS_ERROR_FLAG);
187+
return;
188+
}
189+
190+
bool packet_complete = (reception_state == WAITING_FOR_DATA_COMPLETE) &&
191+
(position == packet_length);
192+
193+
if (packet_complete) {
194+
if (is_reset_event(packet, packet_length)) {
195+
if (packet[RESET_STATUS_INDEX] != RESET_EXPECTED_STATUS) {
196+
reception_state = STATUS_ERROR;
197+
signal_flag(RESET_STATUS_ERROR_FLAG);
198+
return;
199+
} else {
200+
signal_flag(RESET_RECEIVED_FLAG);
201+
}
202+
}
203+
204+
reception_state = WAITING_FOR_PACKET_TYPE;
205+
position = 0;
206+
packet_length = 1;
207+
}
208+
}
209+
}
210+
211+
static uint8_t reset_cmd[] = {
212+
HCI_OPCODE_RESET_LSB, HCI_OPCODE_RESET_MSB, // reset opcode
213+
0 // parameter length
214+
};
215+
216+
void test_reset_command() {
217+
CordioHCIDriver& driver = CordioHCIHook::get_driver();
218+
CordioHCITransportDriver& transport_driver = CordioHCIHook::get_transport_driver();
219+
220+
driver.initialize();
221+
222+
CordioHCIHook::set_data_received_handler(hci_driver_rx_reset_handler);
223+
224+
transport_driver.write(HCI_CMD_TYPE, sizeof(reset_cmd), reset_cmd);
225+
uint32_t events = wait_for_event();
226+
227+
TEST_ASSERT_EQUAL(RESET_RECEIVED_FLAG, events);
228+
229+
driver.terminate();
230+
}
231+
232+
#define EXPECTED_CONSECUTIVE_RESET 10
233+
234+
void test_multiple_reset_command() {
235+
CordioHCIDriver& driver = CordioHCIHook::get_driver();
236+
CordioHCITransportDriver& transport_driver = CordioHCIHook::get_transport_driver();
237+
238+
driver.initialize();
239+
240+
CordioHCIHook::set_data_received_handler(hci_driver_rx_reset_handler);
241+
242+
for (size_t i = 0; i < EXPECTED_CONSECUTIVE_RESET; ++i) {
243+
transport_driver.write(HCI_CMD_TYPE, sizeof(reset_cmd), reset_cmd);
244+
uint32_t events = wait_for_event();
245+
TEST_ASSERT_EQUAL(RESET_RECEIVED_FLAG, events);
246+
if (events != RESET_RECEIVED_FLAG) {
247+
break;
248+
}
249+
}
250+
251+
driver.terminate();
252+
}
253+
254+
Case cases[] = {
255+
Case("Test reset command", test_reset_command),
256+
Case("Test multiple reset commands", test_multiple_reset_command)
257+
};
258+
259+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
260+
GREENTEA_SETUP(15, "default_auto");
261+
return verbose_test_setup_handler(number_of_cases);
262+
}
263+
264+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
265+
266+
int main() {
267+
return !Harness::run(specification);
268+
}

0 commit comments

Comments
 (0)