12. ОСЛИК

Предварительные знания

OSAL (Operating System Abstraction Layer, уровень системной абстракции) в целом можно понимать как упрощенную версию операционной системы, которая обеспечивает базовые функции, такие как управление памятью, управление прерываниями и планирование задач для корректной работы Z-Stack.

  1. Идентификатор задачи: прикладной уровень — это задача, которой система присваивает уникальный числовой номер.

  2. Функция обработки событий задачи: задачи могут обрабатывать события, а коды для обработки событий находятся в одной функции.

  3. Переменная события задачи. Задача прикладного уровня также имеет 2-байтовую переменную.

  4. Связь между переменной события задачи прикладного уровня и событием , определенным на уровне приложения [ранее заданным с помощью макроса, две байтовые переменные, определенные для представления этого события]

    • Если переменная события, значение макроса и операция события равны 1, это означает, что задача прикладного уровня будет обрабатывать это событие.
  5. Когда система работает, она продолжает считывать переменную события задачи прикладного уровня. Когда она обнаруживает, что эта переменная равна 0, она думает, что задача прикладного уровня в настоящее время не имеет событий для обработки; если она обнаруживает, что эта переменная не равна 0 , он думает, что уровень приложения. Когда задача имеет событие для обработки, она вызывает функцию обработки событий задачи уровня приложения TestApp_ProcessEvent( byte task_id, UINT16 events )и передает значение переменной события задачи events.

  6. В функции обработки событий eventsон будет оперировать всеми значениями макросов событий, определенными прикладным уровнем. Если окажется, что оно равно 0, то будет выполнен соответствующий код для этой обработки событий.

  7. osal_set_event()Вызов функции события set Task TestApp_TaskIDвыполнит TestApp_SEND_MSG_EVTсоответствующий код обработки события.

    • Суть: Измените TestApp_TaskIDпеременную события задачи (задача прикладного уровня), соответствующую TestApp_SEND_MSG_EVTзначению макроса от 1 до 1. Таким образом, сначала переменная события задачи становится отличной от 0, и система обнаруживает, что переменная события задачи не равна 0. ., будет вызвана функция обработки события задачи TestApp_ProcessEvent. В этой функции переменная события задачи, TestApp_SEND_MSG_EVTзначение макроса и операция должны быть равны 1, поэтому код, связанный с этим событием, обязательно будет выполнен.
  8. Каждый уровень представляет собой задачу, поэтому каждый уровень имеет идентификатор задачи. Переменная события задачи обработчика событий задачи

    • FUN function array={обработка события задачи A, обработка события задачи B, обработка события задачи C...}
    • Массив переменных Arr = {переменная события задачи a, переменная события задачи b, переменная события задачи c...}
  9. Идентификатор задачи не назначается системой случайным образом. Вы можете использовать это значение, чтобы сразу найти собственную функцию обработки событий задачи и переменные событий .

    • Например: идентификатор задачи прикладного уровня — 8.
    • Тогда FUN[8] содержит имя функции соответствующей функции обработки задачи.
    • Arr[8] содержит переменную события задачи.

Определение профессионализма из других источников:

  • Задача : можно понимать как конкретную задачу, для обработки которой требуется процессор, например «включить свет через 1 секунду» или «выключить свет» и так далее.

  • Пул задач : это буфер, в котором можно хранить несколько задач. Например, пул задач может хранить «Включить свет через 1 секунду», «Выключить свет через 2 секунды», «Включить свет через 3 секунды». и «Выключить свет через 1 минуту». «Легкие» задания. Система выполнит каждую задачу в пуле задач в указанное время.

  • Приоритет : поскольку может быть несколько задач, которые необходимо выполнить одновременно, необходимо различать, какие задачи имеют приоритет, а какие задачи откладываются в данный момент.Приоритет используется для обозначения уровня приоритета каждой задачи. При тех же условиях система будет отдавать приоритет задачам с высоким приоритетом, а задачам с низким приоритетом придется ждать обработки. Кроме того, система может прерывать выполнение задач с более низким приоритетом и переключаться на задачи с более высоким приоритетом.

  • Опрос : система время от времени проверяет в пуле задач наличие задач, которые необходимо обработать сейчас.Этот процесс называется опросом.

  • Цикл планирования операционной системы . Цикл планирования относится к определенной продолжительности времени « время от времени » в концепции опроса. Период планирования системы также является минимальным периодом времени выполнения задачи.Например, период планирования системы составляет 1 секунду, но есть задача, которая «выключает свет через 0,1 секунды».Хотя эта задача требует выключения света после 0,1 секунды, 0,1 секунды меньше периода планирования системы. , поэтому эта задача будет выполнена через 1 секунду.

Практическое планирование системы

osal_init_system

В функции osal_init_systemесть функция osalInitTasks();, в которой система присваивает всем задачам идентификаторы.

void osalInitTasks( void ) // 定义函数 osalInitTasks,该函数不接受任何参数并且没有返回值  
{
    
      
  uint8 taskID = 0; // 定义一个 uint8 类型的变量 taskID 并初始化为 0,用于表示任务ID  
  
  // 为 tasksEvents 分配内存,tasksCnt 是任务的数量,这里分配的是 uint16 类型的大小乘以 tasksCnt 的大小  
  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);  
  // 将分配的内存区域用 0 填充  
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));  
  
  // 初始化 macTask,并使用 ++taskID 作为参数  
  macTaskInit( taskID++ );  
  // 初始化 nwk,并使用 ++taskID 作为参数  
  nwk_init( taskID++ );  
  // 初始化 Hal,并使用 ++taskID 作为参数  
  Hal_Init( taskID++ );  
    
#if defined( MT_TASK ) // 如果定义了 MT_TASK  
  // 初始化 MT_Task,并使用 ++taskID 作为参数  
  MT_TaskInit( taskID++ );  
    
#endif  
  // 初始化 APS,并使用 ++taskID 作为参数  
  APS_Init( taskID++ );  
    
#if defined ( ZIGBEE_FRAGMENTATION ) // 如果定义了 ZIGBEE_FRAGMENTATION  
  // 初始化 APSF,并使用 ++taskID 作为参数  
  APSF_Init( taskID++ );  
    
#endif  
  // 初始化 ZDApp,并使用 ++taskID 作为参数  
  ZDApp_Init( taskID++ );  
    
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
  // 如果定义了 ZIGBEE_FREQ_AGILITY 或者 ZIGBEE_PANID_CONFLICT  
  // 初始化 ZDNwkMgr,并使用 ++taskID 作为参数  
  ZDNwkMgr_Init( taskID++ ); 
    
#endif  
  // 初始化 TestAPP,没有提供任务ID,可能是最后初始化的任务,或者是之前的任务ID都在其他任务中使用了  
  TestAPP_Init( taskID );  
}

osal_start_system

Роль цикла do- while:

Опросите весь пул задач, то есть посмотрите, есть ли какие-нибудь задачи, требующие обработки. В цикле есть только одно условное суждение, если условие истинно, то цикл завершается.

Среди них TaskEvents — это массив типа uint16, каждый элемент которого представляет тип задачи.То есть, TaskSEvents — это пул задач, а TasksCnt — размер этого пула задач.

Логика работы этого цикла следующая:

  • Во-первых, начальное значение idx равно 0;
  • Когда значение TasksEvents[idx] равно 0, это означает, что в задаче нечего обрабатывать. В этот момент условное суждение не устанавливается и вводится следующий цикл;
  • Перед каждым выполнением цикла idx увеличивается на 1, а затем определяется, меньше ли он задачCnt;
  • Когда значение TasksEvents[idx] не равно 0, это означает, что в задаче есть что-то, что нужно обработать.В этот момент устанавливается условное суждение, поэтому цикл завершается прерыванием;
  • Когда цикл завершится, если во всем пуле задач нет задач для обработки, то idx обязательно будет >= TasksCnt. Следовательно, если idx < TasksCnt, это означает, что в пуле задач есть задачи, которые необходимо обработать, азадачиEvents[idx] — это задача, которую необходимо обработать в данный момент. Поэтому после завершения цикла Z-Stack сначала использует оператор if (idx < TasksCnt), чтобы определить, есть ли задачи, которые необходимо обработать.
/*
 * 这是一个不返回的函数,是任务系统的主循环函数。它将遍历所有任务事件并为有事件的任务调用task_event_processor()函数。  
 * 如果所有任务都没有事件,此函数会让处理器进入睡眠模式。  
 */  
void osal_start_system( void )
{
    
      
#if !defined ( ZBIT ) && !defined ( UBIT ) // 如果未定义ZBIT和UBIT宏  
  for(;;) // 进入无限循环,除非外部中断或者其他条件停止  
#endif  
  {
    
      
    uint8 idx = 0; // 定义一个uint8类型的变量idx并初始化为0,用于表示任务索引  
  
    osalTimeUpdate(); // 更新系统时间  
    Hal_ProcessPoll(); // 执行Hal的轮询处理,这替换了MT_SerialPoll()和osal_check_timer()函数  
     
    // 开始do-while循环,直到idx达到tasksCnt(任务数量)为止 
    do {
    
       
      if (tasksEvents[idx]) // 如果当前任务有事件(事件为非零值)  
      {
    
      
        break; // 则跳出循环,执行后续代码  
      }  
    } while (++idx < tasksCnt); // idx自增1并判断是否小于tasksCnt,若小于则继续循环  
  
    // 如果idx小于tasksCnt(还有任务未处理) 
    if (idx < tasksCnt) 
    {
    
      
      uint16 events; // 定义一个uint16类型的变量events,用于存储事件  
      halIntState_t intState; // 定义一个halIntState_t类型的变量intState,用于存储中断状态(用于锁住临界区)  
  
      HAL_ENTER_CRITICAL_SECTION(intState); // 进入临界区,锁定中断以保护临界区代码的执行,将intState设置为当前的中断状态  
      events = tasksEvents[idx]; // 从tasksEvents数组中获取当前任务的事件  
      tasksEvents[idx] = 0; // 清零当前任务的未处理事件(清除事件)  
      HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区,解锁中断恢复原始的中断状态  
  
      // 调用tasksArr数组中对应任务的回调函数,参数为当前任务的索引idx和已处理的事件events,并将返回的事件添加到当前任务的事件中  
      events = (tasksArr[idx])( idx, events );   
  
      HAL_ENTER_CRITICAL_SECTION(intState); // 再次进入临界区,锁定中断以保护临界区代码的执行,将intState设置为当前的中断状态  
      tasksEvents[idx] |= events; // 将未处理的事件添加回当前任务的事件中(添加未处理事件)  
      HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区,解锁中断恢复原始的中断状态  
    }  
#if defined( POWER_SAVING ) // 如果定义了POWER_SAVING宏(开启节能模式)  
    else // 如果整个任务事件循环没有任何活动(没有任务有事件)  
    {
    
      
      osal_pwrmgr_powerconserve(); // 则调用osal_pwrmgr_powerconserve()函数将处理器/系统置于睡眠模式以节省电力(节能模式)  
    }  
#endif // 结束if宏定义判断(如果有定义POWER_SAVING宏)  
  } // 结束for循环(整个任务事件处理流程)  
} // 结束函数定义(osal_start_system函数)

Guess you like

Origin blog.csdn.net/qq_61228493/article/details/134192253