@@ -29,7 +29,8 @@ using namespace utest::v1;
29
29
30
30
#define MBED_ARRAY_SIZE (array ) (sizeof (array)/sizeof (array[0 ]))
31
31
32
- #define TIMESTAMP_MAX_DELTA MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA
32
+ #define TIMESTAMP_MAX_DELTA_BITS (bits ) ((uint64_t )(0x7 << ((bits) - 4 )))
33
+ #define TIMESTAMP_MAX_DELTA TIMESTAMP_MAX_DELTA_BITS (32 )
33
34
34
35
struct ticker_interface_stub_t {
35
36
ticker_interface_t interface;
@@ -43,9 +44,11 @@ struct ticker_interface_stub_t {
43
44
unsigned int clear_interrupt_call;
44
45
unsigned int set_interrupt_call;
45
46
unsigned int fire_interrupt_call;
47
+ unsigned int get_info_call;
46
48
};
47
49
48
50
static ticker_interface_stub_t interface_stub = { 0 };
51
+ static ticker_info_t interface_info_stub = { 0 };
49
52
50
53
static void ticker_interface_stub_init ()
51
54
{
@@ -81,6 +84,12 @@ static void ticker_interface_stub_fire_interrupt()
81
84
++interface_stub.fire_interrupt_call ;
82
85
}
83
86
87
+ static const ticker_info_t *ticker_interface_stub_get_info ()
88
+ {
89
+ ++interface_stub.get_info_call ;
90
+ return &interface_info_stub;
91
+ }
92
+
84
93
static void reset_ticker_interface_stub ()
85
94
{
86
95
interface_stub.interface .init = ticker_interface_stub_init;
@@ -91,6 +100,7 @@ static void reset_ticker_interface_stub()
91
100
ticker_interface_stub_clear_interrupt;
92
101
interface_stub.interface .set_interrupt =ticker_interface_stub_set_interrupt;
93
102
interface_stub.interface .fire_interrupt = ticker_interface_stub_fire_interrupt;
103
+ interface_stub.interface .get_info = ticker_interface_stub_get_info;
94
104
interface_stub.initialized = false ;
95
105
interface_stub.interrupt_flag = false ;
96
106
interface_stub.timestamp = 0 ;
@@ -101,6 +111,9 @@ static void reset_ticker_interface_stub()
101
111
interface_stub.clear_interrupt_call = 0 ;
102
112
interface_stub.set_interrupt_call = 0 ;
103
113
interface_stub.fire_interrupt_call = 0 ;
114
+
115
+ interface_info_stub.frequency = 1000000 ;
116
+ interface_info_stub.bits = 32 ;
104
117
}
105
118
106
119
// stub of the event queue
@@ -115,6 +128,12 @@ static void reset_queue_stub()
115
128
{
116
129
queue_stub.event_handler = NULL ;
117
130
queue_stub.head = NULL ,
131
+ queue_stub.tick_last_read = 0 ;
132
+ queue_stub.tick_remainder = 0 ;
133
+ queue_stub.frequency = 0 ;
134
+ queue_stub.bitmask = 0 ;
135
+ queue_stub.max_delta = 0 ;
136
+ queue_stub.max_delta_us = 0 ;
118
137
queue_stub.present_time = 0 ;
119
138
queue_stub.initialized = false ;
120
139
}
@@ -131,6 +150,34 @@ static void reset_ticker_stub()
131
150
reset_ticker_interface_stub ();
132
151
}
133
152
153
+ const uint32_t test_frequencies[] = {
154
+ 1 ,
155
+ 32768 , // 2^15
156
+ 1000000 ,
157
+ 0xFFFFFFFF // 2^32 - 1
158
+ };
159
+
160
+ const uint32_t test_bitwidths[] = {
161
+ 32 ,
162
+ 31 ,
163
+ 16 ,
164
+ 8
165
+ };
166
+
167
+ template < void (F)(uint32_t a, uint32_t b)>
168
+ static void test_over_frequency_and_width (void )
169
+ {
170
+ for (unsigned int i = 0 ; i < MBED_ARRAY_SIZE (test_frequencies); i++) {
171
+ for (unsigned int j = 0 ; j < MBED_ARRAY_SIZE (test_bitwidths); j++) {
172
+ reset_ticker_stub ();
173
+ interface_info_stub.frequency = test_frequencies[i];
174
+ interface_info_stub.bits = test_bitwidths[j];
175
+
176
+ F (test_frequencies[i], test_bitwidths[j]);
177
+ }
178
+ }
179
+ }
180
+
134
181
static utest::v1::status_t case_setup_handler (
135
182
const Case *const source, const size_t index_of_case
136
183
) {
@@ -175,8 +222,7 @@ static utest::v1::status_t greentea_failure_handler(
175
222
* Then:
176
223
* - The ticker interface should be initialized
177
224
* - The queue handler should be set to the handler provided in parameter
178
- * - The internal ticker timestamp should be synced with the counter in the
179
- * interface counter.
225
+ * - The internal ticker timestamp should be zero
180
226
* - interrupt should be scheduled in current timestamp +
181
227
* TIMESTAMP_MAX_DELTA
182
228
* - The queue should not contains any event
@@ -192,7 +238,7 @@ static void test_ticker_initialization()
192
238
193
239
TEST_ASSERT_TRUE (interface_stub.initialized );
194
240
TEST_ASSERT_EQUAL_PTR (dummy_handler, queue_stub.event_handler );
195
- TEST_ASSERT_EQUAL_UINT64 (interface_stub. timestamp , queue_stub.present_time );
241
+ TEST_ASSERT_EQUAL_UINT64 (0 , queue_stub.present_time );
196
242
TEST_ASSERT_EQUAL (1 , interface_stub.set_interrupt_call );
197
243
TEST_ASSERT_EQUAL_UINT32 (
198
244
interface_stub.timestamp + TIMESTAMP_MAX_DELTA,
@@ -347,7 +393,7 @@ static void test_legacy_insert_event_outside_overflow_range()
347
393
348
394
// test the beginning of the range
349
395
ticker_event_t first_event = { 0 };
350
- const timestamp_t timestamp_first_event = interface_stub.timestamp + 1 ;
396
+ const timestamp_t timestamp_first_event = interface_stub.timestamp + 1 ;
351
397
const uint32_t id_first_event = 0xAAAAAAAA ;
352
398
353
399
ticker_insert_event (
@@ -820,6 +866,7 @@ static void test_insert_event_us_outside_overflow_range()
820
866
ticker_set_handler (&ticker_stub, NULL );
821
867
interface_stub.set_interrupt_call = 0 ;
822
868
interface_stub.timestamp = 0xAAAAAAAA ;
869
+ queue_stub.tick_last_read = interface_stub.timestamp ;
823
870
queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp ;
824
871
825
872
// test the end of the range
@@ -881,6 +928,7 @@ static void test_insert_event_us_in_overflow_range()
881
928
ticker_set_handler (&ticker_stub, NULL );
882
929
interface_stub.set_interrupt_call = 0 ;
883
930
interface_stub.timestamp = 0xAAAAAAAA ;
931
+ queue_stub.tick_last_read = interface_stub.timestamp ;
884
932
queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp ;
885
933
886
934
// test the end of the range
@@ -944,6 +992,7 @@ static void test_insert_event_us_underflow()
944
992
interface_stub.set_interrupt_call = 0 ;
945
993
946
994
interface_stub.timestamp = 0xAAAAAAAA ;
995
+ queue_stub.tick_last_read = interface_stub.timestamp ;
947
996
queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp ;
948
997
949
998
// test the end of the range
@@ -979,6 +1028,7 @@ static void test_insert_event_us_head()
979
1028
ticker_set_handler (&ticker_stub, NULL );
980
1029
interface_stub.set_interrupt_call = 0 ;
981
1030
interface_stub.timestamp = 0xAAAAAAAA ;
1031
+ queue_stub.tick_last_read = interface_stub.timestamp ;
982
1032
queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp ;
983
1033
984
1034
const us_timestamp_t timestamps[] = {
@@ -2003,6 +2053,8 @@ static uint32_t ticker_interface_stub_read_interrupt_time()
2003
2053
*/
2004
2054
static void test_set_interrupt_past_time ()
2005
2055
{
2056
+ ticker_set_handler (&ticker_stub, NULL );
2057
+
2006
2058
interface_stub.set_interrupt_call = 0 ;
2007
2059
interface_stub.fire_interrupt_call = 0 ;
2008
2060
interface_stub.timestamp = 0xFF ;
@@ -2023,6 +2075,8 @@ static void test_set_interrupt_past_time()
2023
2075
*/
2024
2076
static void test_set_interrupt_past_time_with_delay ()
2025
2077
{
2078
+ ticker_set_handler (&ticker_stub, NULL );
2079
+
2026
2080
interface_stub.set_interrupt_call = 0 ;
2027
2081
interface_stub.fire_interrupt_call = 0 ;
2028
2082
interface_stub.timestamp = 0xFF ;
@@ -2038,6 +2092,168 @@ static void test_set_interrupt_past_time_with_delay()
2038
2092
TEST_ASSERT_EQUAL (1 , interface_stub.fire_interrupt_call );
2039
2093
}
2040
2094
2095
+ /* *
2096
+ * Convert ticks at a given frequency to time in microseconds
2097
+ *
2098
+ * Assert if there is a 64-bit overflow
2099
+ */
2100
+ static uint64_t convert_to_us (uint64_t ticks, uint32_t frequency)
2101
+ {
2102
+ uint64_t scaled_ticks = ticks * 1000000 ;
2103
+ // Assert that there was not an overflow
2104
+ TEST_ASSERT_EQUAL (ticks, scaled_ticks / 1000000 );
2105
+ return scaled_ticks / frequency;
2106
+ }
2107
+
2108
+ /* *
2109
+ * Given an uninitialized ticker instance and an interface of a
2110
+ * certain frequency and bit width.
2111
+ * Then the time returned the ticker should match the cumulative time.
2112
+ */
2113
+ void test_frequencies_and_masks (uint32_t frequency, uint32_t bits)
2114
+ {
2115
+ const uint32_t bitmask = ((uint64_t )1 << bits) - 1 ;
2116
+
2117
+ ticker_set_handler (&ticker_stub, NULL );
2118
+ uint64_t ticks = 0 ;
2119
+
2120
+ // Single tick
2121
+ ticks += 1 ;
2122
+ interface_stub.timestamp = ticks & bitmask;
2123
+ TEST_ASSERT_EQUAL_UINT32 (convert_to_us (ticks, frequency), ticker_read (&ticker_stub));
2124
+ TEST_ASSERT_EQUAL_UINT64 (convert_to_us (ticks, frequency), ticker_read_us (&ticker_stub));
2125
+
2126
+ // Run until the loop before 64-bit overflow (worst case with frequency=1hz, bits=32)
2127
+ for (unsigned int k = 0 ; k < 4294 ; k++) {
2128
+
2129
+ // Largest value possible tick
2130
+ ticks += ((uint64_t )1 << bits) - 1 ;
2131
+ interface_stub.timestamp = ticks & bitmask;
2132
+ TEST_ASSERT_EQUAL_UINT32 (convert_to_us (ticks, frequency), ticker_read (&ticker_stub));
2133
+ TEST_ASSERT_EQUAL_UINT64 (convert_to_us (ticks, frequency), ticker_read_us (&ticker_stub));
2134
+ }
2135
+ }
2136
+
2137
+ /* *
2138
+ * Given an uninitialized ticker_data instance.
2139
+ * When the ticker is initialized
2140
+ * Then:
2141
+ * - The internal ticker timestamp should be zero
2142
+ * - interrupt should be scheduled in current (timestamp +
2143
+ * TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval
2144
+ * - The queue should not contains any event
2145
+ */
2146
+ static void test_ticker_max_value ()
2147
+ {
2148
+ for (int bitwidth = 8 ; bitwidth <= 32 ; bitwidth++) {
2149
+ const uint64_t modval = 1ULL << bitwidth;
2150
+
2151
+ // setup of the stub
2152
+ reset_ticker_stub ();
2153
+ interface_info_stub.bits = bitwidth;
2154
+ interface_stub.timestamp = 0xBA ;
2155
+
2156
+ ticker_set_handler (&ticker_stub, NULL );
2157
+
2158
+ TEST_ASSERT_EQUAL_UINT64 (0 , queue_stub.present_time );
2159
+ TEST_ASSERT_EQUAL (1 , interface_stub.set_interrupt_call );
2160
+ TEST_ASSERT_EQUAL_UINT32 (
2161
+ (interface_stub.timestamp + TIMESTAMP_MAX_DELTA_BITS (bitwidth)) % modval,
2162
+ interface_stub.interrupt_timestamp
2163
+ );
2164
+ TEST_ASSERT_EQUAL_PTR (NULL , queue_stub.head );
2165
+ TEST_ASSERT_EQUAL (0 , interface_stub.disable_interrupt_call );
2166
+ }
2167
+ }
2168
+
2169
+ /* *
2170
+ * Check that _ticker_match_interval_passed correctly detects matches
2171
+ *
2172
+ * Brute force test that _ticker_match_interval_passed returns the correct match value
2173
+ * for all cominations of values within a small range.
2174
+ */
2175
+ static void test_match_interval_passed ()
2176
+ {
2177
+
2178
+ for (int modval = 1 ; modval <= 5 ; modval++) {
2179
+ for (int prev = 0 ; prev < modval; prev++) {
2180
+ for (int cur = 0 ; cur < modval; cur++) {
2181
+ for (int match = 0 ; match < modval; match++) {
2182
+ uint32_t delta = (cur - prev) % modval;
2183
+ uint32_t delta_to_match = (match - prev) % modval;
2184
+ bool match_expected = false ;
2185
+ if (delta_to_match) {
2186
+ match_expected = delta >= delta_to_match;
2187
+ }
2188
+
2189
+ // Sanity checks
2190
+ if (prev == cur) {
2191
+ // No time has passed
2192
+ TEST_ASSERT_EQUAL (false , match_expected);
2193
+ } else if (match == prev) {
2194
+ // Match can't occur without an overflow occurring
2195
+ TEST_ASSERT_EQUAL (false , match_expected);
2196
+ } else if (cur == match) {
2197
+ // All other cases where cur == match a match should be expected
2198
+ TEST_ASSERT_EQUAL (true , match_expected);
2199
+ }
2200
+
2201
+ // Actual test
2202
+ TEST_ASSERT_EQUAL (match_expected, _ticker_match_interval_passed (prev, cur, match));
2203
+ }
2204
+ }
2205
+ }
2206
+ }
2207
+ }
2208
+
2209
+ typedef struct {
2210
+ timestamp_t prev;
2211
+ timestamp_t cur;
2212
+ timestamp_t match;
2213
+ bool result;
2214
+ } match_interval_entry_t ;
2215
+
2216
+ /* *
2217
+ * Check that _ticker_match_interval_passed correctly detects matches
2218
+ *
2219
+ * Use a table of pre-computed values to check that _ticker_match_interval_passed
2220
+ * returns the correct match value.
2221
+ */
2222
+ static void test_match_interval_passed_table ()
2223
+ {
2224
+ static const match_interval_entry_t test_values[] = {
2225
+ /* prev, cur, match, result */
2226
+ {0x00000000 , 0x00000000 , 0x00000000 , false },
2227
+ {0x00000000 , 0x00000000 , 0xffffffff , false },
2228
+ {0x00000000 , 0x00000000 , 0x00000001 , false },
2229
+ {0x00000000 , 0xffffffff , 0x00000000 , false },
2230
+ {0x00000000 , 0x00000001 , 0x00000000 , false },
2231
+ {0xffffffff , 0x00000000 , 0x00000000 , true },
2232
+ {0x00000001 , 0x00000000 , 0x00000000 , true },
2233
+ {0x00005555 , 0x00005555 , 0x00005555 , false },
2234
+ {0x00005555 , 0x00005555 , 0x00005554 , false },
2235
+ {0x00005555 , 0x00005555 , 0x00005556 , false },
2236
+ {0x00005555 , 0x00005554 , 0x00005555 , false },
2237
+ {0x00005555 , 0x00005556 , 0x00005555 , false },
2238
+ {0x00005554 , 0x00005555 , 0x00005555 , true },
2239
+ {0x00005556 , 0x00005555 , 0x00005555 , true },
2240
+ {0xffffffff , 0xffffffff , 0xffffffff , false },
2241
+ {0xffffffff , 0xffffffff , 0xfffffffe , false },
2242
+ {0xffffffff , 0xffffffff , 0x00000000 , false },
2243
+ {0xffffffff , 0xfffffffe , 0xffffffff , false },
2244
+ {0xffffffff , 0x00000000 , 0xffffffff , false },
2245
+ {0xfffffffe , 0xffffffff , 0xffffffff , true },
2246
+ {0x00000000 , 0xffffffff , 0xffffffff , true },
2247
+ };
2248
+ for (int i = 0 ; i < MBED_ARRAY_SIZE (test_values); i++) {
2249
+ const uint32_t prev = test_values[i].prev ;
2250
+ const uint32_t cur = test_values[i].cur ;
2251
+ const uint32_t match = test_values[i].match ;
2252
+ const uint32_t result = test_values[i].result ;
2253
+ TEST_ASSERT_EQUAL (result, _ticker_match_interval_passed (prev, cur, match));
2254
+ }
2255
+ }
2256
+
2041
2257
static const case_t cases[] = {
2042
2258
MAKE_TEST_CASE (" ticker initialization" , test_ticker_initialization),
2043
2259
MAKE_TEST_CASE (
@@ -2130,12 +2346,28 @@ static const case_t cases[] = {
2130
2346
MAKE_TEST_CASE (
2131
2347
" test_set_interrupt_past_time_with_delay" ,
2132
2348
test_set_interrupt_past_time_with_delay
2349
+ ),
2350
+ MAKE_TEST_CASE (
2351
+ " test_frequencies_and_masks" ,
2352
+ test_over_frequency_and_width<test_frequencies_and_masks>
2353
+ ),
2354
+ MAKE_TEST_CASE (
2355
+ " test_ticker_max_value" ,
2356
+ test_ticker_max_value
2357
+ ),
2358
+ MAKE_TEST_CASE (
2359
+ " test_match_interval_passed" ,
2360
+ test_match_interval_passed
2361
+ ),
2362
+ MAKE_TEST_CASE (
2363
+ " test_match_interval_passed_table" ,
2364
+ test_match_interval_passed_table
2133
2365
)
2134
2366
};
2135
2367
2136
2368
static utest::v1::status_t greentea_test_setup (const size_t number_of_cases)
2137
2369
{
2138
- GREENTEA_SETUP (30 , " default_auto" );
2370
+ GREENTEA_SETUP (60 , " default_auto" );
2139
2371
return verbose_test_setup_handler (number_of_cases);
2140
2372
}
2141
2373
0 commit comments