apache / mynewt-nimble

Apache mynewt
https://mynewt.apache.org/
Apache License 2.0
683 stars 392 forks source link

Events BLE_GAP_EVENT_DISC_COMPLETE and BLE_GAP_EVENT_ADV_COMPLETE are not received #823

Open deepthits opened 4 years ago

deepthits commented 4 years ago

We have integrated nimBLE stack over Linux npl porting. nimble_port_init() and nimble_port_run() are rightly called to initialize the nimBLE stack and to process the ble_npl_event events.

ble_gap_disc() and ble_gap_adv_start() are called with 'duration_ms' parameter set to non-zero values. So, it is expected that BLE_GAP_EVENT_DISC_COMPLETE and BLE_GAP_EVENT_ADV_COMPLETE events are received after the 'duration_ms' time elapses. But that doesn't happen and scanning/advertising goes on forever, as if 'duration_ms' was set to BLE_HS_FOREVER.

When I debugged further I understood that when ble_gap_slave_set_timer() or ble_gap_master_set_timer() is set it would just trigger a timer reset of 1 tick so immediately there would be a timer expiry and in the timer handler, the actual 'duration_ticks - 1' would be set in ble_hs_timer_sched(). But, the following condition check seem to have an issue,

if (!ble_npl_callout_is_active(&ble_hs_timer) || ((ble_npl_stime_t)(abs_time - ble_npl_callout_get_ticks(&ble_hs_timer))) < 0) { ble_hs_timer_reset(ticks_from_now);

ble_npl_callout_is_active() this is always true and (abs_time - ble_npl_callout_get_ticks(&ble_hs_timer))) is always greater than 0. Since, it has just triggered an expiry, the ble_npl_callout_get_ticks() returns the current value which will always be less than abs_time. So, timer is never reset to the correct duration_ticks.

I checked the same scenario in btshell where the mynewt npl layer is used. Here, the ble_npl_callout_is_active() is always false. So the condition turns to be true and timer is reset successfully.

So, this seems to be an issue in linux npl layer.

deepthits commented 4 years ago

bool ble_npl_callout_is_active(struct ble_npl_callout *c) { // TODO: seek native posix method to determine whether timer_t is active. // TODO: fix bug where one-shot timer is still active after fired. return c->c_active; }

I see the above comment, which means this is a known bug, so is there a solution already identified or is it being planned?

In addition to the above issues wrt to Discovery and Advertising, I see another one which seem to be very crucial. In a particular usecase I am trying to connect to a device by sending ble_gap_connect(), if the device doesnt respond after 30s (default connection duration) it is suppose to timeout, but it doesnt. It tries to connect forever. This is a crucial one for us. Can someone help in resolving this one?

nikitos1550 commented 1 year ago

Hi! How do you think is such solution valid?

bool ble_npl_callout_is_active(struct ble_npl_callout *c)
{
    struct itimerspec its;
    timer_gettime(c->c_timer, &its);

    if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0) {
        return 0;
    } else {
        // If timer seems active maybe struct property is not active?
        return c->c_active;
    }
}

I didn`t find any Linux method about active/nonactive timer property. But If I understand right, we can check time before expiration and if it already expired (remaining time is 0), then seems we can recognize it as not active. P.S. As I can see only one shot timers created (interval is always 0) P.P.S. From first look solution works, but I didn't go deep, so any useful comment are welcome.