Well, things still might work even at 10-20msecs. All depends on the timing of 
the connection event in relation to the interrupts. You have to miss a number 
of connection events for a connection to drop. Will be interesting to see how 
it performs in those circumstances.

> On Jan 24, 2017, at 11:35 PM, WangJiacheng <[email protected]> wrote:
> 
> Thanks, Will,
> 
> Yes, my semaphore code has problem to run, I have removed the code of release 
> the semaphore, and  use “goto” to check the free time again after my task 
> wake up.
> 
> The interrupt frequency depends on the phone’s status. For standby phone, 
> there will be an interrupt every 30s, this is not a big issue since 30s is a 
> quite long time. However, for active phone such as making a call,  there will 
> be several interrupts, and the time separation will only be 10ms-20ms,  this 
> will cause BLE connections to fail. I will continue to work on this issue.
> 
> Best Regards,
> 
> Jiacheng
> 
> 
> 
>> 在 2017年1月25日,14:36,will sanfilippo <[email protected]> 写道:
>> 
>> Jiacheng
>> 
>> 1) Sorry about not converting msecs to os time ticks. Good catch!
>> 2) I understand using a semaphore to wake up a task but looking at the exact 
>> code you have shown, I dont understand why the task would release the 
>> semaphore in this case. Doesnt the interrupt release the semaphore?
>> 3) Blocking interrupts. If you block for 600-700 usecs you will cause 
>> failures in the underlying BLE stack. These wont be “catastrophic” (at 
>> least, I dont think so) but it can cause you to miss things like connection 
>> events, scan requests/responses, advertising events, etc. If your high 
>> priority interrupt fires off frequently you could possibly cause connections 
>> to fail. If you do it occasionally you should be ok.
>> 
>>> On Jan 24, 2017, at 5:08 PM, WangJiacheng <[email protected]> wrote:
>>> 
>>> Thanks, Will, you help me  a lot.
>>> 
>>> Since my task is triggered by a semaphore, and the semaphore is released by 
>>> another interrupt routine,  so if my task have no enough time to running 
>>> and go to sleep, after wake up, it will release the semaphore again. 
>>> Another minor change is time unit conversion (ms -> OS tick) by function 
>>> os_time_ms_to_ticks(). 
>>> 
>>> The main body of my task will like
>>> /********************************************************************************/
>>> while (1) 
>>> {
>>>  t = os_sched_get_current_task();
>>>  assert(t->t_func == phone_command_read_handler);
>>>             
>>>  /* Wait for semaphore from ISR */
>>>  err = os_sem_pend(&g_phone_command_read_sem, OS_TIMEOUT_NEVER);
>>>  assert(err == OS_OK);
>>> 
>>>> 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_time_ms_to_ticks((os_delay + 999) / 1000));
>>>                  
>>>          /* Release the semaphore after wake up  */
>>>         err = os_sem_release(&g_phone_command_read_sem);
>>>         assert(err == OS_OK);
>>> 
>>>> }
>>> }
>>> /********************************************************************************/
>>> 
>>> I will test if this can work. BTW, current test results show there will be 
>>> an event collision between 2 stacks about 3~4 hours running.
>>> 
>>> I have a question about using interrupt disable, How long can the LL task 
>>> be blocked by interrupt disable? The high priority interrupt of Nordic’s 
>>> SoftDevice can be blocked only within 10us. I have an interrupt with most 
>>> high priority, it will take 600us~700us, is it safe to block LL task and 
>>> other interrupt such as Nimble Radio and OS time tick during this time?
>>> 
>>> Best Regards,
>>> 
>>> Jiacheng 
>>>                                     
>>> 
>>> 
>>>> 在 2017年1月25日,00:37,will sanfilippo <[email protected]> 写道:
>>>> 
>>>> 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