Jiacheng:

Given that your task is lower in priority than the LL task, you are going to 
run into issues if you dont either disable interrupts or prevent the LL task 
from running. Using interrupt disable as an example (since this is easy), you 
would do this. The code below is a function that returns the time till the next 
event.:

os_sr_t sr;
uint32_t time_now;
int32_t time_free;

time_free = 100000000;
OS_ENTER_CRITICAL(sr);
time_now = os_cputime_get32();
sch = TAILQ_FIRST(&g_ble_ll_sched_q);
if (sch) {
    time_free = (int32_t)(sch->start_time - time_now);
}
OS_EXIT_CRITICAL();

/* 
 * NOTE: if time_free < 0 it means that you have to wait since the LL task
 * should be waking up and servicing that event soon.
 */
return time_free;

Given that you are in control of what the LL is doing with your app, I guess 
you could do something like this in your task;

time_till_next = ll_eventq_free_time_from_now();
if (time_till_next > X) {
        /* Take control of transceiver and do what you want */
} else {
        /* Delay task until LL services event. This assumes time_till_next is 
not negative. */
        os_delay = os_cputime_ticks_to_usecs(time_till_next);
        os_time_delay((os_delay + 999) / 1000);
}

So the problem with the above code, and also with the code you have below is 
something I mentioned previously. If you check the sched queue and there is 
nothing on it, you might think you have time, but in reality you dont because 
the LL has pulled the item off the schedule queue and is executing it. The LL 
state will tell you if the LL task is doing anything. The API 
ble_ll_state_get() will return the current LL state. So you could modify the 
above to do this:

OS_ENTER_CRITICAL(sr);
time_now = os_cputime_get32();
sch = TAILQ_FIRST(&g_ble_ll_sched_q);
if (sch) {
    time_free = (int32_t)(sch->start_time - time_now);
} else {
    if (ble_ll_state_get() != BLE_LL_STATE_STANDBY) {
        /* LL is busy. You dont know how long it will be busy. You can
         * return some small time here and your task will just keep
           polling. */
    }
}
OS_EXIT_CRITICAL();
Not sure if this will work, and I think there are other things that you would 
want to do to insure that the LL task does not grab the transceiver while your 
task is using it.

Hope this helps.

> On Jan 24, 2017, at 3:00 AM, WangJiacheng <[email protected]> wrote:
> 
> Hi, Will,
> 
> My use scenario is when I have an event (with knowing running time) ready to 
> run,  I’ll try to get a free time slot (with a required duration) in the 
> Nimble events queue. 
> 
> 1). Only consider Nimble connection events, do not consider scanning events, 
> so only look at the scheduled events queue in “g_ble_ll_sched_q”;
> 2). Only consider the event start_time in the queue, since  I only care if 
> there is enough free time slot from now to nearest future event start_time to 
> run my event, if there is no enough time, just wait.
> 3). My code is in a lower priority task function than nimble stack task (in 
> blue_ll.c, task “ble_ll” is initialized with task priority 0),so when I check 
> the free time slot, there should be no Nimble events running.
> 4). When I’m waiting the free time slot, since Nimble stack has higher 
> priority, the Nimble events in the queue will keep on running.
> 5). If an event start_time in the queue already expired, I will get a 
> negative number of  free time slot from now, since I always require a 
> positive number of free time slot, so I’ll wait the event to be done.
> 6) For the periodic events, the event already in the queue is always 
> “earlier” than the following periodic events, so I do not care the following 
> events. The worst case is that the periodic time is less than  my event 
> running time, I can not get any opportunity to run my event.
> 
> Function for check free time slot from now is as 
> /********************************************************************************/
> int32_t ll_eventq_free_time_from_now(void)
> {
>  struct ble_ll_sched_item *sch;
>  uint32_t cpu_time_now;
>  int32_t time_free;
>  int32_t time_diff;
>       
>  time_free = 100000000;
>  cpu_time_now = os_cputime_get32();
> 
>  /* Look through the schedule queue */
>  TAILQ_FOREACH(sch, &g_ble_ll_sched_q, link)
>  {
>    time_diff = sch->start_time - cpu_time_now;
>    if (time_diff < time_free)
>    {
>      time_free = time_diff;
>    }          
>  }    
>       
>  return (time_free);
> }
> /********************************************************************************/
> 
> When I have a event (require 10000 CPU time ticks) ready to run, the code 
> will be:
> /********************************************************************************/
> /* wait for time slot to run event */
> while (ll_eventq_free_time_from_now( ) < 10000)
> {
>  /* just loop to wait the free time slot > 10000 CPU time ticks */
>  /* Nimble events have higher task priority, will keep on running */
>  if (time_out)
>   {
>     return(1);
>   }
> }
> 
> /********** my event require 10000 CPU time ticks run here **************/    
>                 
> /********************************************************************************/
> 
> Does this make sense?
> 
> Thanks,
> 
> Jiacheng
> 
> 
> 
> 
>> 在 2017年1月24日,14:25,WangJiacheng <[email protected]> 写道:
>> 
>> Thanks, Will,
>> 
>> It seems I can not get the things  work by the simple way. I just want to 
>> find out a free time slot at high level to access PHY resource such as CPU 
>> and radio RF exclusively. With your explain, I should interleave my events 
>> into BLE events at low level in the same schedule queue.
>> 
>> Best Regards,
>> 
>> Jiacheng
>> 
>> 
>>> 在 2017年1月24日,13:48,will sanfilippo <[email protected]> 写道:
>>> 
>>> Jiacheng:
>>> 
>>> First thing with the code excerpt below: TAILQ_FIRST always gives you the 
>>> head of the queue. To iterate through all the queue elements you would use 
>>> TAILQ_FOREACH() or you would modify the code to get the next element using 
>>> TAILQ_NEXT. I would just use TAILQ_FOREACH. There is an example of this in 
>>> ble_ll_sched.c.
>>> 
>>> Some other things to note about scheduler queue:
>>> 1) It is possible for items to be on the queue that have already expired. 
>>> That means that the current cputime might have passed sch->start_time. 
>>> Depending on how you want to deal with things, you are might be  better off 
>>> doing a signed 32-bit subtract when calculating time_tmp.
>>> 2) You are not taking into account the end time of the scheduled event. The 
>>> event starts at sch->start_time and ends at sch->end_time. Well, if all you 
>>> care about is the time till the next event you wont have to worry about the 
>>> end time of the event, but if you want to iterate through the schedule, the 
>>> time between events is the start time of event N minus the end time of 
>>> event N - 1.
>>> 3) When an event is executed it is removed from the scheduler queue. Thus, 
>>> if you asynchronously look at the first item in the scheduler queue and 
>>> compare it to the time now you have to be aware that an event might be 
>>> running and that the nimble stack is using the PHY. This could also cause 
>>> you to think that nothing is going to be done in the future, but when the 
>>> scheduled event is over that item gets rescheduled and might get put back 
>>> in the scheduler queue (see #4, below).
>>> 4) Events in the scheduler queue appear only once. This is not an issue if 
>>> you are only looking at the first item on the queue, but if you iterate 
>>> through the queue this could affect you. For example, say there are two 
>>> items on the queue (item 1 is at head, item 2 is next and is last). You see 
>>> that the gap between the two events is 400 milliseconds (I just made that 
>>> number up). When item 1 is executed and done, that event will get 
>>> rescheduled. So lets say item 1 is a periodic event that occurs every 100 
>>> msecs. Item 1 will get rescheduled causing you to really only have 100 
>>> msecs between events.
>>> 5) The “end_time” of the scheduled item may not be the true end time of the 
>>> underlying event. When scheduling connections we schedule them for some 
>>> fixed amount of time. This is done to guarantee that all connections get a 
>>> place in the scheduler queue. When the schedule item executes at 
>>> “start_time” and the item is a connection event, the connection code will 
>>> keep the current connection going past the “end_time” of the scheduled 
>>> event if there is more data to be sent and the next scheduled item wont be 
>>> missed. So you may think you have a gap between scheduled events when in 
>>> reality the underlying code is still running.
>>> 6) For better or worse, scanning events are not on the scheduler queue; 
>>> they are dealt with in an entirely different manner. This means that the 
>>> underlying PHY could be used when there is nothing on the schedule queue.
>>> 
>>> I have an idea of what you are trying to do and it might end up being a bit 
>>> tricky given the current code implementation. You may be better served 
>>> adding an item to the schedule queue but it all depends on how you want to 
>>> prioritize BLE activity with what you want to do.
>>> 
>>> Will
>>> 
>>>> On Jan 23, 2017, at 8:56 PM, WangJiacheng <[email protected]> wrote:
>>>> 
>>>> Hi, 
>>>> 
>>>> I’m trying to find out a free time slot between Nimble scheduled events.
>>>> 
>>>> I try to go through  all items on the schedule queue  global variable 
>>>> “g_ble_ll_sched_q” to find out all the scheduled LL events near future, 
>>>> function as
>>>> /********************************************************************************/
>>>> uint32_t ll_eventq_free_time_from_now(void)
>>>> {
>>>> struct ble_ll_sched_item *sch;
>>>> uint32_t cpu_time_now;
>>>> uint32_t time_free;
>>>> uint32_t time_tmp;
>>>>    
>>>> time_free = 1000000000;
>>>> cpu_time_now = os_cputime_get32();
>>>> 
>>>> /* Look through schedule queue */
>>>> while ((sch = TAILQ_FIRST(&g_ble_ll_sched_q)) != NULL)
>>>> {
>>>> time_tmp = sch->start_time - cpu_time_now;
>>>> if  (time_tmp < time_free)
>>>> {
>>>>    time_free = time_tmp;
>>>> }
>>>> }  
>>>>    
>>>> return (time_free);
>>>> }
>>>> /********************************************************************************/
>>>> 
>>>> Does above function make sense to find out the free time at any given time 
>>>> point? or any suggestion to find out the free time slot between LL events?
>>>> 
>>>> 
>>>> Thanks,
>>>> 
>>>> Jiacheng
>>>> 
>>> 
>> 
> 

Reply via email to