WXK
2025-01-21 8f1a91a8ec98e430cfe4357bda099d495917198e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
 * Copyright (c) 2017-2018 Oticon A/S
 * Copyright (c) 2021 Codecoup
 *
 * SPDX-License-Identifier: Apache-2.0
 */
 
#include "NRF_HW_model_top.h"
#include "NRF_HWLowL.h"
#include "bs_tracing.h"
#include "bs_types.h"
#include "bs_utils.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
 
/* Note: All timers are relative to hw_time and NOT to 'now' */
extern bs_time_t timer_nrf_main_timer;
 
/* The events priorities are as in this list from top to bottom
 * Priority being which timer executes first if several trigger at the same
 * instant
 */
static enum {
    NRF_HW_MAIN_TIMER = 0,
    NUMBER_OF_TIMERS,
    NONE
} next_timer_index = NONE;
 
static bs_time_t *Timer_list[NUMBER_OF_TIMERS] = {
    &timer_nrf_main_timer,
};
static bs_time_t next_timer_time = TIME_NEVER;
 
/*
 * Current absolute time of this device, as the device knows it.
 * It is never reset:
 */
bs_time_t now;
/* Current time the HW of this device things it is */
static bs_time_t hw_time;
/*
 * Offset between the current absolute time of the device and the HW time
 * That is, the absolute time when the HW_time got reset
 */
static bs_time_t hw_time_delta;
 
/* Last time we synchronized with the bsim PHY, in device abs time */
static bs_time_t last_bsim_phy_sync_time;
 
#define BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET 1000000
/* At least every second we will inform the simulator about our timing */
static bs_time_t max_resync_offset = BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET;
 
/**
 * Set the maximum amount of time the device will spend without talking
 * (synching) with the phy.
 * This does not change the functional behavior of the Zephyr code or of the
 * radio emulation, and it is only relevant if special test code running in the
 * device interacts behind the scenes with other devices test code.
 * Setting for example a value of 5ms will ensure that this device time
 * will never be more than 5ms away from the phy. Setting it in all devices
 * to 5ms would then ensure no device time is farther apart than 5ms from any
 * other.
 *
 * Note that setting low values has a performance penalty.
 */
void
tm_set_phy_max_resync_offset(bs_time_t offset_in_us)
{
    max_resync_offset = offset_in_us;
}
 
/**
 * Return the absolute current time (no HW model except the RADIO
 * should look into this)
 */
bs_time_t
tm_get_abs_time(void)
{
    return now;
}
 
/**
 * Return the current HW time
 */
bs_time_t
tm_get_hw_time(void)
{
    return hw_time;
}
 
bs_time_t
posix_get_hw_cycle(void)
{
    return tm_get_hw_time();
}
 
/**
 * Reset the HW time
 */
static void
tm_reset_hw_time(void)
{
    hw_time = 0;
    hw_time_delta = now;
    if (now != 0) {
        bs_trace_error_line("Reset not supposed to happen after "
                            "initialization\n");
    }
}
 
/**
 * Update the current hw_time value given the absolute time
 */
INLINE void
tm_update_HW_time(void)
{
    hw_time = now - hw_time_delta;
}
 
/*
 * Reset the HW time
 */
void
tm_reset_hw_times(void)
{
    tm_reset_hw_time();
}
 
/**
 * Advance the internal time values of this device until time
 */
void
tm_sleep_until_abs_time(bs_time_t time)
{
    if (time >= now) {
        /*
         * Ensure that at least we sync with the phy
         * every max_resync_offset
         */
        if (time > last_bsim_phy_sync_time + max_resync_offset) {
            hwll_sync_time_with_phy(time);
            last_bsim_phy_sync_time = time;
        }
 
        now = time;
    } else {
        /* LCOV_EXCL_START */
        bs_trace_warning_manual_time_line(now, "next_time_time "
                                               "corrupted (%"PRItime"<= %"PRItime", timer idx=%i)\n",
                                          time, now, next_timer_index);
        /* LCOV_EXCL_STOP */
    }
    tm_update_HW_time();
}
 
/**
 * Keep track of the last time we synchronized the time with the scheduler
 */
void
tm_update_last_phy_sync_time(bs_time_t abs_time)
{
    last_bsim_phy_sync_time = abs_time;
}
 
/**
 * Advance the internal time values of this device
 * until the HW time reaches hw_time
 */
void
tm_sleep_until_hw_time(bs_time_t hw_time)
{
    bs_time_t next_time = TIME_NEVER;
 
    if (hw_time != TIME_NEVER) {
        next_time = hw_time + hw_time_delta;
    }
 
    tm_sleep_until_abs_time(next_time);
}
 
/**
 * Look into all timers and update next_timer accordingly
 * To be called each time a "timed process" updates its timer
 */
void
tm_find_next_timer_to_trigger(void)
{
    next_timer_time = *Timer_list[0];
    next_timer_index = 0;
 
    for (uint i = 1; i < NUMBER_OF_TIMERS; i++) {
        if (next_timer_time > *Timer_list[i]) {
            next_timer_time = *Timer_list[i];
            next_timer_index = i;
        }
    }
}
 
bs_time_t
tm_get_next_timer_abstime(void)
{
    return next_timer_time + hw_time_delta;
}
 
bs_time_t
tm_hw_time_to_abs_time(bs_time_t hwtime)
{
    if (hwtime == TIME_NEVER) {
        return TIME_NEVER;
    }
    return hwtime + hw_time_delta;
}
 
bs_time_t
tm_abs_time_to_hw_time(bs_time_t abstime)
{
    if (abstime == TIME_NEVER) {
        return TIME_NEVER;
    }
    return abstime - hw_time_delta;
}
 
void
tm_tick_limited(bs_time_t max_time_diff)
{
    bs_time_t time_to_wait;
 
    if (max_time_diff != TIME_NEVER && now + max_time_diff < next_timer_time) {
        time_to_wait = now + max_time_diff;
    } else {
        time_to_wait = next_timer_time;
    }
 
    tm_sleep_until_hw_time(time_to_wait);
    switch (next_timer_index) {
        case NRF_HW_MAIN_TIMER:
            nrf_hw_some_timer_reached();
            break;
        default:
            bs_trace_error_time_line("next_timer_index "
                                     "corrupted\n");
            break;
    }
    tm_find_next_timer_to_trigger();
}
 
void
tm_tick(void)
{
    tm_tick_limited(TIME_NEVER);
}