Skip to content

Commit d2ecdb8

Browse files
committed
Cordio BLE: Rewrite reset test strategy
The existing test was expecting that the acknowledgement of the reset command would be the first and only event receive. This assumption is false. As a consequence, the new code parse all incoming packets and raise a flag in the following circumstances: * a reset packet has been successfully received. * RX stream is not synchronized * The status of the reset command is an error. Another test has been added that send a serie of reset commands.
1 parent 4f8a006 commit d2ecdb8

File tree

1 file changed

+155
-77
lines changed
  • features/FEATURE_BLE/targets/TARGET_CORDIO/TESTS/cordio_hci/transport

1 file changed

+155
-77
lines changed

features/FEATURE_BLE/targets/TARGET_CORDIO/TESTS/cordio_hci/transport/main.cpp

Lines changed: 155 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
*/
1616

1717
#include <stdio.h>
18+
#include <algorithm>
1819

1920
#include "driver/CordioHCITransportDriver.h"
2021
#include "driver/CordioHCIDriver.h"
2122
#include "hci_defs.h"
22-
#include "rtos/Semaphore.h"
23+
#include "rtos/EventFlags.h"
2324

2425
#include "greentea-client/test_env.h"
2526
#include "utest/utest.h"
@@ -56,126 +57,203 @@ struct CordioHCIHook {
5657

5758
using ble::vendor::cordio::CordioHCIHook;
5859

60+
//
61+
// Handle signal mechanism
62+
//
5963
#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+
6096
#define RESET_PARAMETER_LENGTH 4
6197
#define RESET_EXPECTED_STATUS 0
6298
#define HCI_OPCODE_RESET_LSB (HCI_OPCODE_RESET & 0xFF)
6399
#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
64102

65-
enum test_result_t {
66-
TEST_RESULT_TIMEOUT_FAILURE,
67-
TEST_RESULT_FAILURE,
68-
TEST_RESULT_SUCCESS
69-
};
103+
static bool is_reset_event(const uint8_t* data, uint16_t len) {
104+
if (len != RESET_PACKET_LENGTH) {
105+
return false;
106+
}
70107

71-
enum state_t {
72-
WAITING_EVENT_PACKET,
73-
WAITING_EVENT_CODE_COMPLETE,
74-
WAITING_PARAMETER_LENGTH,
75-
WAITING_STATUS,
76-
WAITING_NUM_HCI_EVT_PACKET,
77-
WAITING_OPCODE_LSB,
78-
WAITING_OPCODE_MSB,
79-
DONE
80-
};
108+
if (*data++ != HCI_EVT_TYPE) {
109+
return false;
110+
}
111+
112+
if (*data++ != HCI_CMD_CMPL_EVT) {
113+
return false;
114+
}
81115

82-
static state_t state = WAITING_EVENT_PACKET;
83-
static test_result_t test_result = TEST_RESULT_TIMEOUT_FAILURE;
116+
if (*data++ != RESET_PARAMETER_LENGTH) {
117+
return false;
118+
}
84119

85-
static rtos::Semaphore sem;
120+
// Note skip num of HCI packet as this is controller dependent
121+
data++;
86122

87-
static uint8_t reset_cmd[] = {
88-
HCI_OPCODE_RESET_LSB, HCI_OPCODE_RESET_MSB, // reset opcode
89-
0 // parameter length
90-
};
123+
if (*data++ != HCI_OPCODE_RESET_LSB) {
124+
return false;
125+
}
126+
127+
if (*data++ != HCI_OPCODE_RESET_MSB) {
128+
return false;
129+
}
91130

92-
static void hci_driver_rx_dummy_handler(uint8_t* data, uint8_t len) { }
131+
return true;
132+
}
93133

94134
static void hci_driver_rx_reset_handler(uint8_t* data, uint8_t len) {
95-
for (size_t i = 0; i < len; ++i) {
96-
switch (state) {
97-
case WAITING_EVENT_PACKET:
98-
if (data[i] == HCI_EVT_TYPE) {
99-
state = WAITING_EVENT_CODE_COMPLETE;
100-
} else {
101-
test_result = TEST_RESULT_FAILURE;
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;
102155
}
103-
break;
104156

105-
case WAITING_EVENT_CODE_COMPLETE:
106-
if (data[i] == HCI_CMD_CMPL_EVT) {
107-
state = WAITING_PARAMETER_LENGTH;
108-
} else {
109-
test_result = TEST_RESULT_FAILURE;
110-
}
157+
packet[position++] = *data++;
158+
--len;
159+
packet_length = 1 + HCI_EVT_HDR_LEN;
160+
reception_state = WAITING_FOR_HEADER_COMPLETE;
111161
break;
112162

113-
case WAITING_PARAMETER_LENGTH:
114-
if (data[i] == RESET_PARAMETER_LENGTH) {
115-
state = WAITING_NUM_HCI_EVT_PACKET;
116-
} else {
117-
test_result = TEST_RESULT_FAILURE;
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];
118176
}
119-
break;
177+
} break;
120178

121-
case WAITING_NUM_HCI_EVT_PACKET:
122-
// controler dependent; can be any value, pass on to the next token
123-
state = WAITING_OPCODE_LSB;
124-
break;
125179

126-
case WAITING_OPCODE_LSB:
127-
if (data[i] == HCI_OPCODE_RESET_LSB) {
128-
state = WAITING_OPCODE_MSB;
129-
} else {
130-
test_result = TEST_RESULT_FAILURE;
131-
}
132-
break;
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;
133184

134-
case WAITING_OPCODE_MSB:
135-
if (data[i] == HCI_OPCODE_RESET_MSB) {
136-
state = WAITING_STATUS;
137-
} else {
138-
test_result = TEST_RESULT_FAILURE;
139-
}
140-
break;
185+
case STATUS_ERROR:
186+
signal_flag(RESET_STATUS_ERROR_FLAG);
187+
return;
188+
}
141189

142-
case WAITING_STATUS:
143-
if (data[i] == RESET_EXPECTED_STATUS) {
144-
test_result = TEST_RESULT_SUCCESS;
145-
state = DONE;
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;
146199
} else {
147-
test_result = TEST_RESULT_FAILURE;
200+
signal_flag(RESET_RECEIVED_FLAG);
148201
}
149-
break;
150-
}
202+
}
151203

152-
if (test_result != TEST_RESULT_TIMEOUT_FAILURE) {
153-
CordioHCIHook::set_data_received_handler(hci_driver_rx_dummy_handler);
154-
sem.release();
155-
return;
204+
reception_state = WAITING_FOR_PACKET_TYPE;
205+
position = 0;
206+
packet_length = 1;
156207
}
157208
}
158209
}
159210

211+
static uint8_t reset_cmd[] = {
212+
HCI_OPCODE_RESET_LSB, HCI_OPCODE_RESET_MSB, // reset opcode
213+
0 // parameter length
214+
};
215+
160216
void test_reset_command() {
161217
CordioHCIDriver& driver = CordioHCIHook::get_driver();
162218
CordioHCITransportDriver& transport_driver = CordioHCIHook::get_transport_driver();
163219

164220
driver.initialize();
165221

166222
CordioHCIHook::set_data_received_handler(hci_driver_rx_reset_handler);
223+
167224
transport_driver.write(HCI_CMD_TYPE, sizeof(reset_cmd), reset_cmd);
168-
sem.wait(RESET_COMMAND_TIMEOUT);
169-
CordioHCIHook::set_data_received_handler(hci_driver_rx_dummy_handler);
225+
uint32_t events = wait_for_event();
226+
227+
TEST_ASSERT_EQUAL(RESET_RECEIVED_FLAG, events);
170228

171229
driver.terminate();
230+
}
231+
232+
#define EXPECTED_CONSECUTIVE_RESET 10
172233

173-
TEST_ASSERT_EQUAL(TEST_RESULT_SUCCESS, test_result);
174-
TEST_ASSERT_EQUAL(DONE, state);
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();
175252
}
176253

177254
Case cases[] = {
178255
Case("Test reset command", test_reset_command),
256+
Case("Test multiple reset commands", test_multiple_reset_command)
179257
};
180258

181259
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {

0 commit comments

Comments
 (0)