
Grupos de sinalizadores de eventos já foram mencionados anteriormente em um dos artigos anteriores (nº 5). No Nucleus SE, eles são semelhantes aos sinais, mas são mais flexíveis. Eles fornecem uma maneira flexível e de baixo custo para transferir mensagens simples entre tarefas.
Artigos anteriores da série:
Artigo 16. SignalsArtigo 15. Partições de memória: serviços e estruturas de dadosArtigo 14. Seções de memória: introdução e serviços básicosArtigo 13. Estruturas de dados da tarefa e chamadas de API não suportadasArtigo 12. Serviços para trabalhar com tarefasArtigo 11. Tarefas: configuração e introdução à APIArtigo 10. Agendador: recursos avançados e preservação de contextoArtigo 9. Agendador: implementaçãoArtigo 8. Núcleo SE: Projeto Interno e ImplantaçãoArtigo # 7 Núcleo SE: IntroduçãoArtigo 6. Outros serviços RTOSArtigo 5. Interação e sincronização de tarefasArtigo 4. Tarefas, alternância de contexto e interrupçõesArtigo # 3 Tarefas e planejamentoArtigo 2. RTOS: estrutura e modo em tempo real
Artigo 1. RTOS: introdução.
Usando sinalizadores de eventos
No Nucleus SE, os sinalizadores de evento são definidos durante a fase de construção. O número máximo de grupos de sinalizadores de eventos no aplicativo é 16. Se os grupos de sinalizadores de eventos não estiverem definidos, o código relacionado às estruturas de dados e chamadas de serviço dos grupos de sinalizadores de eventos não serão incluídos no aplicativo.
Grupo de sinalizadores de eventos - um conjunto de sinalizadores de oito bits, cujo acesso é regulado para que várias tarefas possam usar com segurança um sinalizador. Uma tarefa pode definir ou limpar qualquer combinação de sinalizadores de eventos. Outra tarefa é ler um grupo de sinalizadores a qualquer momento e também pode esperar por uma determinada sequência de sinalizadores (por votação ou com uma pausa).
Configurando grupos de sinalizadores de eventos
Número de grupos de sinalizadores de eventos
Como na maioria dos objetos do Nucleus SE, a configuração dos grupos de sinalizadores de eventos é especificada pelas diretivas
#define em
nuse_config.h . O parâmetro principal é
NUSE_EVENT_GROUP_NUMBER , que determina quantos grupos de sinalizadores de eventos serão definidos no aplicativo. Por padrão, esse parâmetro é definido como 0 (ou seja, grupos de sinalizadores de eventos não são usados) e pode ter qualquer valor até 16. Um valor incorreto levará a um erro de compilação, que será gerado pela verificação de
nuse_config_check.h (ativado por
nuse_config.c , o que significa que ele compila com este módulo), como resultado, a diretiva
#error funcionará. A seleção de um valor diferente de zero serve como o principal ativador dos grupos de sinalizadores de eventos. Este parâmetro é usado ao definir estruturas de dados e seu tamanho depende de seu valor (mais sobre isso nos artigos a seguir). Além disso, um valor diferente de zero ativa as configurações da API.
Ativar chamadas de API
Cada função da API (chamada de utilitário) no Nucleus SE é ativada pela diretiva
#define em
nuse_config.h . Para grupos de sinalizadores de eventos, incluem:
NUSE_EVENT_GROUP_SET
NUSE_EVENT_GROUP_RETRIEVE
NUSE_EVENT_GROUP_INFORMATION
NUSE_EVENT_GROUP_COUNT
Por padrão, eles são definidos como
FALSE , desabilitando cada chamada de serviço e bloqueando a inclusão do código que os implementa. Para configurar grupos de sinalizadores de eventos, é necessário selecionar as chamadas de API necessárias e definir as diretivas correspondentes como
TRUE .
A seguir, um trecho do arquivo nuse_config.h padrão.
#define NUSE_EVENT_GROUP_NUMBER 0 #define NUSE_EVENT_GROUP_SET FALSE #define NUSE_EVENT_GROUP_RETRIEVE FALSE #define NUSE_EVENT_GROUP_INFORMATION FALSE #define NUSE_EVENT_GROUP_COUNT FALSE
Uma função de API ativada, se não houver grupos de sinalizadores de eventos no aplicativo, levará a um erro de compilação (exceto
NUSE_Event_Group_Count () , que sempre está ativado). Se o seu código usar uma chamada de API que não foi ativada, ocorrerá um erro de layout porque o código de implementação não foi incluído no aplicativo.
Chamadas do utilitário de chamada de evento
O Nucleus RTOS suporta sete chamadas de utilidade que fornecem a seguinte funcionalidade:
- Definir sinalizadores de evento. O núcleo SE é implementado na função NUSE_Event_Group_Set () .
- Lendo sinalizadores de eventos. No Nucleus SE, implementado em NUSE_Event_Group_Retrieve () .
- Fornecendo informações sobre um grupo específico de sinalizadores de eventos. No Nucleus SE, implementado em NUSE_Event_Group_Information () .
- Retorna o número de grupos de sinalizadores de eventos atualmente configurados no aplicativo. No Nucleus SE, implementado em NUSE_Event_Group_Count () .
- Adicionando um novo grupo de sinalizadores de eventos ao aplicativo. O núcleo SE não está implementado.
- Removendo um grupo de sinalizadores de eventos do aplicativo. O núcleo SE não está implementado.
- Retornando ponteiros para todos os grupos de sinalizadores de eventos no aplicativo. O núcleo SE não está implementado.
A implementação de cada uma dessas chamadas gerais é discutida em detalhes abaixo.
Vale ressaltar que não há função de redefinição no Nucleus RTOS ou no Nucleus SE. Isso é feito intencionalmente. A função de redefinição implica a prevalência do estado especial dos sinalizadores. Para grupos de sinalizadores de eventos, o único estado "especial" é redefinir todos os sinalizadores, o que pode ser feito usando
NUSE_Event_Group_Set () .
Chamadas de serviço para definir e ler grupos de sinalizadores de eventos
As operações fundamentais que podem ser executadas em um grupo de sinalizadores de eventos estão configurando o valor de um ou mais sinalizadores, bem como lendo os valores atuais do sinalizador. O Nucleus RTOS e o Nucleus SE fornecem quatro chamadas API básicas para essas operações.
Como os sinalizadores de eventos são bits, eles são melhor visualizados como números binários. Como o padrão C historicamente não suporta a representação de constantes binárias (apenas octal e hexadecimal), o Nucleus SE possui um arquivo de cabeçalho útil
nuse_binary.h , que contém
#define caracteres como
b01010101 para todos os 256 valores de 8 bits.
Definir sinalizadores de eventos
A chamada do utilitário Nucleus RTOS API para sinalização é muito flexível e permite definir e limpar valores de sinalizador usando operações
AND e
OR . O Nucleus SE fornece funcionalidade semelhante, mas a pausa da tarefa é opcional.
Chamada para definir sinalizadores no Nucleus RTOSProtótipo de chamada de serviço:
STATUS NU_Set_Events (NU_EVENT_GROUP * group, UNSIGNED event_flags, operação OPTION);Parâmetros:
group - um ponteiro para um bloco de controle fornecido pelo usuário para um grupo de sinalizadores de eventos;
event_flags - valor da máscara de bits do grupo de sinalizadores;
operação - a
operação a ser executada,
NU_OR (para definir sinalizadores) ou
NU_AND (para apagar sinalizadores).
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_GROUP - ponteiro inválido para um grupo de sinalizadores de eventos;
NU_INVALID_OPERATION - A operação especificada é diferente de
NU_OR e
NU_AND .
Chamada para definir sinalizadores no Núcleo SEEssa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada de serviço:
STATUS NUSE_Event_Group_Set (grupo NUSE_EVENT_GROUP, U8 event_flags, operação OPTION);Parâmetros:
group - o índice (ID) do grupo de eventos cujos sinalizadores são configurados / limpos;
event_flags - valor do bit maxi de um grupo de sinalizadores;
operação - a
operação a ser executada,
NUSE_OR (para definir sinalizadores) ou
NUSE_AND (para apagar sinalizadores).
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_INVALID_GROUP - índice inválido de um grupo de sinalizadores de eventos;
NUSE_INVALID_OPERATION - A operação especificada é diferente de
NUSE_OR e
NUSE_AND .
Implementando a instalação de sinalizadores de eventos no Nucleus SEO código inicial da função da API
NUSE_Event_Group_Set () é geral (após a verificação dos parâmetros), independentemente de a API suportar o bloqueio de chamadas (suspender tarefas) ou não. A lógica é bem simples:
NUSE_CS_Enter(); if (operation == NUSE_OR) { NUSE_Event_Group_Data[group] |= event_flags; } else /* NUSE_AND */ { NUSE_Event_Group_Data[group] &= event_flags; }
A
máscara de evento event_flags é sobreposta (usando a operação
AND ou
OR ) no valor do grupo selecionado de sinalizadores de evento.
O código restante é ativado apenas quando o bloqueio de tarefas está ativado:
#if NUSE_BLOCKING_ENABLE while (NUSE_Event_Group_Blocking_Count[group] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_EVENT_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == group)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Event_Group_Blocking_Count[group]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif #endif NUSE_CS_Exit(); return NUSE_SUCCESS;
Se alguma tarefa for pausada (para leitura) deste grupo de sinalizadores, elas serão retomadas. Quando eles têm a oportunidade de continuar a execução (depende do planejador), eles podem determinar se as condições para sua retomada são satisfeitas ou não (consulte a leitura de sinalizadores de eventos).
Lendo sinalizadores de eventos
As chamadas de utilitário da API Nucleus RTOS para leitura são muito flexíveis e permitem pausar tarefas indefinidamente ou com um tempo limite específico se a operação não puder ser executada imediatamente (por exemplo, se você tentar ler uma sequência específica de sinalizadores de eventos que não representa o estado atual). O Nucleus SE oferece os mesmos recursos, apenas a pausa da tarefa é opcional e o tempo limite não é implementado.
Desafio das bandeiras no núcleo RTOSProtótipo de chamada de serviço:
STATUS NU_Retrieve_Events (grupo NU_EVENT_GROUP *, UNSIGNED request_events, operação OPTION, UNSIGNED * retrieved_events, UNSIGNED suspende);Parâmetros:
group - um ponteiro para um bloco de controle fornecido pelo usuário para um grupo de sinalizadores de eventos;
request_events - uma máscara de bit que define os sinalizadores a serem lidos;
operação - quatro
operações estão disponíveis:
NU_AND ,
NU_AND_CONSUME ,
NU_OR e
NU_OR_CONSUME . As operações
NU_AND e
NU_AND_CONSUME indicam que todos os sinalizadores solicitados são necessários. As operações
NU_OR e
NU_OR_CONSUME indicam que um ou mais dos sinalizadores solicitados são suficientes. O parâmetro
CONSUME limpa automaticamente os sinalizadores existentes após uma solicitação bem-sucedida;
retrieved_events - ponteiro de armazenamento para os valores dos sinalizadores de eventos de leitura;
suspender - especificação para pausar tarefas; pode levar os valores
NU_NO_SUSPEND ou
NU_SUSPEND ou o valor do tempo limite em ticks do timer do sistema (de 1 a 4.294.967.293).
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_NOT_PRESENT - a operação especificada não retornou eventos (nem um único evento no caso de NU_OR e nem todos os eventos no caso de NU_AND);
NU_INVALID_GROUP - ponteiro inválido para um grupo de sinalizadores de eventos;
NU_INVALID_OPERATION - a operação especificada estava incorreta;
NU_INVALID_POINTER - ponteiro nulo para o armazenamento de sinalizadores de eventos (NULL);
NU_INVALID_SUSPEND - tenta pausar de um thread não relacionado à tarefa;
NU_TIMEOUT - a combinação necessária de sinalizadores de eventos não foi definida mesmo após o tempo limite especificado;
NU_GROUP_DELETED - o grupo de sinalizadores de eventos foi excluído enquanto a tarefa estava suspensa.
Flags Challenge no Núcleo SEEssa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada de serviço:
STATUS NUSE_Event_Group_Retrieve (grupo NUSE_EVENT_GROUP, eventos U8 solicitados, operação OPTION, operação U8 * eventos recuperados, suspensão U8);Parâmetros:
group - index (ID) do grupo de leitura de sinalizadores de eventos;
request_events - uma máscara de bit que define os sinalizadores a serem lidos;
operação - uma especificação indicando o número de sinalizadores necessários:
NUSE OR (alguns sinalizadores) ou
NUSE AND (todos os sinalizadores);
retrieved_events - um ponteiro para a loja para os valores reais dos sinalizadores de eventos de leitura (com a operação
NUSE_AND, será o mesmo que o transmitido no parâmetro
request_events );
suspender - especificação para pausar uma tarefa e pode assumir os valores
NUSE_NO_SUSPEND ou
NUSE_SUSPEND .
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_NOT_PRESENT - a operação especificada não retornou eventos (nem um único evento no caso de
NUSE_OR e nem todos os eventos no caso de
NUSE_AND );
NUSE_INVALID_GROUP - índice inválido de um grupo de sinalizadores de eventos;
NUSE_INVALID_OPERATION - a operação especificada é diferente de
NUSE_OR ou
NUSE_AND ;
NUSE_INVALID_POINTER - um ponteiro nulo para o armazenamento de sinalizadores de eventos de leitura (
NULL );
NUSE_INVALID_SUSPEND - uma tentativa de pausar de um fluxo que não seja de tarefa ou quando o suporte ao bloqueio de chamadas de API está desativado.
Implementando a leitura de sinalizadores de eventos no Nucleus SEA versão do código de função da API
NUSE_Event_Group_Retrieve () (após verificar os parâmetros) é selecionada durante a compilação condicional, dependendo se o suporte às chamadas da API para bloquear (suspender) tarefas está ativado ou não. Vamos considerar essas duas opções separadamente.
Se o bloqueio estiver desativado, o código completo para esta chamada de API será semelhante a:
temp_events = NUSE_Event_Group_Data[group] & requested_events; if (operation == NUSE_OR) { if (temp_events != 0) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } else /* operation == NUSE_AND */ { if (temp_events == requested_events) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } }
Os sinalizadores de eventos necessários são selecionados no grupo de sinalizadores de eventos especificado. O valor é comparado com os eventos necessários, dada a operação
AND / OR , assim como o resultado retornado e os valores imediatos dos sinalizadores solicitados.
Se o bloqueio de tarefas estiver ativado, o código se tornará mais complexo:
do { temp_events = NUSE_Event_Group_Data[group] & requested_events; if (operation == NUSE_OR) { if (temp_events != 0) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } else { if (temp_events == requested_events) { return_value = NUSE_SUCCESS; } else { return_value = NUSE_NOT_PRESENT; } } if (return_value == NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_SUSPEND) { NUSE_Event_Group_Blocking_Count[group]++; NUSE_Suspend_Task(NUSE_Task_Active, (group << 4) | NUSE_EVENT_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
O código é colocado em um
loop do ... while , que funciona enquanto o parâmetro de
suspensão é
NUSE_SUSPEND .
Os sinalizadores de eventos solicitados são lidos como se fossem chamados sem bloquear. Se a leitura não for bem-sucedida e o parâmetro de
suspensão for
NUSE_NO_SUSPEND , a chamada da API será definida como
NUSE_NOT_PRESENT . Se o parâmetro de
suspensão foi definido como
NUSE_SUSPEND , a tarefa é interrompida. Ao retornar (quando a tarefa é retomada), se o valor de retorno for
NUSE_SUCCESS , indicando que a tarefa foi retomada porque os sinalizadores de eventos nesse grupo foram definidos ou limpos, o ciclo começa do início, os sinalizadores são lidos e verificados. Como não há função da API para redefinir os grupos de sinalizadores de eventos, esse é o único motivo para a tarefa continuar, mas o processo de verificação
NUSE_Task_Blocking_Return [] foi deixado no sistema para compatibilidade do controle de bloqueio com outros tipos de objetos.
O artigo a seguir descreve chamadas de API adicionais associadas a grupos de sinalizadores de eventos, bem como suas estruturas de dados.
Sobre o autor: Colin Walls trabalha na indústria eletrônica há mais de trinta anos, dedicando a maior parte de seu tempo ao firmware. Ele agora é engenheiro de firmware na Mentor Embedded (uma divisão da Mentor Graphics). Colin Walls frequentemente fala em conferências e seminários, autor de vários artigos técnicos e dois livros sobre firmware. Vive no Reino Unido.
Blog profissional
de Colin , e-mail: colin_walls@mentor.com.