找回密码
 立即注册
首页 业界区 业界 BLE 4.2 Controller:高精度调度器与冲突仲裁 ...

BLE 4.2 Controller:高精度调度器与冲突仲裁

各卧唯 4 天前
由于芯片通常只有一个 Radio(单射频),我们不能同时进行广播、扫描和保持连接。如果我在 37 信道广播时,连接的锚点(Anchor Point)也到了,该怎么办?如果我正在扫描,突然需要回复一个连接请求,怎么保证时间差精确在 150µs?
这就是我们需要一个高精度调度器(High-Precision Scheduler) 的原因。通用的 RTOS(如 FreeRTOS)基于 SysTick 的 1ms 调度精度在这里完全不够看,我们需要的是微秒级的控制。
1 设计哲学:时间轴上的俄罗斯方块

BLE Controller 的调度本质上是时分复用(TDM)。我们可以把时间看作一条无限延伸的单行铁轨,而每一个任务(广播一次、连接交互一次)就是一列列火车。
我们的调度器只有两个核心目标:

  • 不撞车: 保证任意两个任务在时间轴上不重叠。
  • 准点率: 任务必须在预定的微秒时刻触发(误差 < 2µs)。
    1.png

为了实现这一点,我们需要抛弃“线程优先级”的概念,转而使用基于绝对时间的有序链表
2 冲突仲裁

显然,这样插入非常容易出现时间上的重叠。但幸好,蓝牙中并不是所有事件都对时间要求非常严格,为了解决冲突,可以根据事件的优先级一定的策略调整不同事件开始的时间。
2.png

下面以 Cordio 源码为例,分析不同情况的处理方法。
2.1.1 新事件优先级更高

如果新事件优先级更高,新事件获胜,则移除旧的事件,插入新的事件,然后通过回调函数 abortCback 通知旧事件被取消了。回调函数针对不同的事件单独实现。
  1. static bool_t SchResolveConflict(BbOpDesc_t *pItem, BbOpDesc_t *pTgt)
  2. {
  3.   schRemoveForConflict(pTgt);
  4.   schInsertToEmptyList(pItem);
  5.   if (pDeleted->abortCback) {
  6.     pDeleted->abortCback(pDeleted);  
  7.   }
  8.   
  9.   return TRUE;
  10. }
复制代码
2.1.2 优先级相同

如果新事件优先级相同,就使用冲突回调函数 conflictCback 来决定怎么处理。回调函数针对不同的事件单独实现。
  1. static bool_t SchIsBodResolvable(
  2.   BbOpDesc_t *pItem,           // 新BOD
  3.   BbOpDesc_t *pTgt,            // 现有BOD
  4.   BbConflictAct_t conflictCback
  5. )
  6. {
  7.   // 策略1: 比较重调度策略(优先级)
  8.   if (pItem->reschPolicy < pTgt->reschPolicy) {
  9.     return TRUE;  // 新BOD优先级更高,可以抢占
  10.   }
  11.   
  12.   // 策略2: 优先级相同,使用冲突回调
  13.   else if ((pItem->reschPolicy == pTgt->reschPolicy) &&
  14.            conflictCback) {
  15.     if (conflictCback(pItem, pTgt) == pItem) {
  16.       return TRUE;  // 回调选择了新BOD
  17.     }
  18.   }
  19.   
  20.   // 策略3: 新BOD优先级更低或相同但无回调
  21.   else {
  22.     LL_TRACE_WARN2("!!! Scheduling conflict: existing=%u vs incoming=%u",
  23.                    pTgt->reschPolicy, pItem->reschPolicy);
  24.     return FALSE;  // 保留现有BOD
  25.   }
  26.   
  27.   return FALSE;
  28. }
复制代码
2.1.3 新事件优先级更低

如果新事件优先级更低,则保留旧事件,调整新事件的事件重新尝试插入。
例如一个普通的广播事件在调度时碰到了更高优先级的连接事件,广播事件重新计算下一次的广播事件,然后重新尝试调度。对于广播,错过一次几乎不影响用户体验。
3.png
  1. static bool_t SchResolveConflict(
  2.   BbOpDesc_t *pItem,  // 要插入的BOD
  3.   BbOpDesc_t *pTgt    // 冲突的BOD
  4. )
  5. {
  6.   BbOpDesc_t *pCur = pTgt;
  7.   int numDeletedBod = 0;
  8.   BbOpDesc_t *pDeleted[SCH_MAX_DELETE_BOD];  // 最多删除8个
  9.   
  10.   // 1. 遍历并移除所有冲突的BOD
  11.   while (TRUE) {
  12.    
  13.     // 防止删除过多
  14.     if (numDeletedBod == SCH_MAX_DELETE_BOD) {
  15.       result = FALSE;
  16.       break;
  17.     }
  18.    
  19.     pDeleted[numDeletedBod++] = pCur;
  20.    
  21.     // 如果只与pCur冲突
  22.     if ((pCur->pNext == NULL) ||
  23.         SCH_IS_DONE_BEFORE(pItem, pCur->pNext)) {
  24.       result = schRemoveForConflict(pCur);
  25.       break;
  26.     }
  27.    
  28.     // 继续移除下一个冲突的BOD
  29.     if (!schRemoveForConflict(pCur)) {
  30.       result = FALSE;
  31.       break;
  32.     }
  33.    
  34.     pCur = pCur->pNext;
  35.   }
  36.   
  37.   // 2. 如果成功移除,插入新BOD
  38.   if (result == TRUE) {
  39.     if (pCur->pNext) {
  40.       schInsertBefore(pItem, pCur->pNext);
  41.     }
  42.     else if (pTgt->pPrev) {
  43.       schInsertAfter(pItem, pTgt->pPrev);
  44.     }
  45.     else {
  46.       schInsertToEmptyList(pItem);
  47.     }
  48.    
  49.     // 3. 调用所有被移除BOD的中止回调
  50.     for (int i = 0; i < numDeletedBod; i++) {
  51.       if (pDeleted[i]->abortCback) {
  52.         pDeleted[i]->abortCback(pDeleted[i]);
  53.       }
  54.     }
  55.   }
  56.   
  57.   return result;
  58. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册