Toda a verdade sobre o RTOS. Artigo 16. Signals



Este artigo analisará os sinais, que são os mecanismos mais simples de interação entre tarefas no Nucleus SE. Eles fornecem uma maneira de baixo custo para transferir mensagens simples entre tarefas.


Artigos anteriores da série:
Artigo 15. Partições de memória: serviços e estruturas de dados
Artigo 14. Seções de memória: introdução e serviços básicos
Artigo 13. Estruturas de dados da tarefa e chamadas de API não suportadas
Artigo 12. Serviços para trabalhar com tarefas
Artigo 11. Tarefas: configuração e introdução à API
Artigo 10. Agendador: recursos avançados e preservação de contexto
Artigo 9. Agendador: implementação
Artigo 8. Núcleo SE: Projeto Interno e Implantação
Artigo # 7 Núcleo SE: Introdução
Artigo 6. Outros serviços RTOS
Artigo 5. Interação e sincronização de tarefas
Artigo 4. Tarefas, alternância de contexto e interrupções
Artigo # 3 Tarefas e planejamento
Artigo 2. RTOS: estrutura e modo em tempo real
Artigo 1. RTOS: introdução.

Usando sinais


Os sinais diferem de todos os outros tipos de objetos do kernel, pois não são autônomos: os sinais estão associados às tarefas e não podem existir sem eles. Se o aplicativo estiver configurado para usar sinais, cada tarefa terá um conjunto de oito sinalizadores de sinal.

Qualquer tarefa pode definir sinais para outra tarefa. Os sinais só podem ser lidos pelo proprietário do sinal. Durante a leitura, os sinais são redefinidos. As tarefas não podem ler ou redefinir sinais de outras tarefas.

O Nucleus RTOS possui uma ferramenta que permite que tarefas atribuam funções que são executadas quando outra tarefa define um ou mais sinalizadores de sinal. Isso lembra um pouco a rotina de processamento de interrupções. Esse recurso não é suportado no Nucleus SE; aqui, as tarefas devem solicitar sinalizadores de sinal explicitamente.

Configuração do sinal


Como na maioria dos objetos do Nucleus SE, o ajuste do sinal é determinado pelas diretivas #define em nuse_config.h . O parâmetro principal é NUSE_SIGNAL_SUPPORT , que ativa o suporte à funcionalidade (para todas as tarefas no aplicativo). A questão de indicar o número de sinais não vale a pena: 8 sinalizadores são alocados para cada tarefa.

A configuração desse parâmetro de habilitação serve como o principal ativador de sinal. Isso fornece uma estrutura de dados bem definida com um tamanho apropriado. Além disso, esta opção 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 sinais, eles incluem:

NUSE_SIGNALS_SEND NUSE_SIGNALS_RECEIVE 

Por padrão, eles são definidos como FALSE , desabilitando cada chamada de serviço e impedindo que o código que os implementa seja ativado. Para configurar os sinais no aplicativo, você precisa 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_SIGNAL_SUPPORT FALSE /* Enables support for signals */ #define NUSE_SIGNALS_SEND FALSE /* Service call enabler */ #define NUSE_SIGNALS_RECEIVE FALSE /* Service call enabler */ 

Uma função API ativada com o suporte de sinalização desativado resultará em um erro de compilação. 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. Obviamente, a inclusão de duas funções da API é um tanto desnecessária, pois não faz sentido ativar o suporte ao sinal na ausência dessas APIs. Ativadores foram adicionados para compatibilidade com outros recursos do Nucleus SE.

Call Signals


O núcleo RTOS suporta quatro chamadas aéreas relacionadas ao sinal que fornecem a seguinte funcionalidade:

  • Enviando sinais para uma determinada tarefa. O núcleo SE é implementado na função NUSE_Signals_Send () .
  • Recepção de sinais. O núcleo SE é implementado na função NUSE_Signals_Receive () .
  • Registro do manipulador de sinal. Não implementado no Nucleus SE.
  • Liga / desliga os sinais (controle). Não implementado no Nucleus SE.

A implementação de cada um desses desafios é discutida em detalhes abaixo.

Serviços de sinalização e recebimento


As operações fundamentais que podem ser executadas em um conjunto de sinais de tarefas estão enviando dados (podem ser executados por qualquer tarefa) e lendo dados (portanto, a limpeza dos dados só pode ser executada pela tarefa do proprietário). O Nucleus RTOS e o Nucleus SE fornecem duas chamadas de API básicas para essas operações, que serão descritas abaixo.

Como os sinais 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. A seguir, um trecho do arquivo nuse_binary.h :

 #define b00000000 ((U8) 0x00) #define b00000001 ((U8) 0x01) #define b00000010 ((U8) 0x02) #define b00000011 ((U8) 0x03) #define b00000100 ((U8) 0x04) #define b00000101 ((U8) 0x05) 

Enviando sinais


Qualquer tarefa pode enviar sinais para qualquer outra tarefa no aplicativo. O envio de sinais envolve a configuração de um ou mais sinalizadores. Esta é uma operação OR que não afeta os sinalizadores definidos anteriormente.

Ligue para enviar sinais para o Nucleus RTOS
Protótipo de chamada de serviço:
STATUS NU_Send_Signals (tarefa NU_TASK *, sinais NÃO ASSINADOS);

Parâmetros:

task - ponteiro para a unidade de controle de tarefas à qual pertencem os sinalizadores definidos;
sinais - o valor dos sinalizadores definidos.

Valor de retorno:

NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_TASK - ponteiro inválido para a tarefa;

Ligue para enviar sinais para o Núcleo SE
Essa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.

Protótipo de chamada de serviço:

STATUS_NUSE_Signals_Send (tarefa NUSE_TASK, sinais U8);

Parâmetros:

task - index (ID) da tarefa à qual pertencem os sinalizadores definidos;
sinais - o valor dos sinalizadores definidos.

Valor de retorno:

NUSE_SUCCESS - a chamada de serviço foi concluída com sucesso;
NUSE_INVALID_TASK - índice de tarefa inválido.

Implementando a sinalização no núcleo SE
Abaixo está o código completo da função NUSE_Signals_Send ():

 STATUS NUSE_Signals_Send(NUSE_TASK task, U8 signals) { #if NUSE_API_PARAMETER_CHECKING if (task >= NUSE_TASK_NUMBER) { return NUSE_INVALID_TASK; } #endif NUSE_CS_Enter(); NUSE_Task_Signal_Flags[task] |= signals; NUSE_CS_Exit(); return NUSE_SUCCESS; } 

O código é muito simples. Após qualquer verificação dos parâmetros, os valores do sinal passam pela operação OR nos sinalizadores da tarefa especificada. O bloqueio de tarefas não afeta os sinais.

Recebendo sinais


Uma tarefa pode apenas ler seu próprio conjunto de sinalizadores de sinal. Durante a leitura, os valores do sinalizador são redefinidos.

Ligue para receber sinais no Nucleus RTOS
Protótipo de chamada de serviço:
NU_Receive_Signals NÃO ASSINADOS (VOID);

Parâmetros: nenhum.

Valor de retorno:
Valores do sinalizador de sinal.

Ligue para receber sinais no Nucleus SE
Essa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.

Protótipo de chamada de serviço:
U8 NUSE_Signals_Receive (nulo);

Parâmetros: nenhum.

Valor de retorno:
Valores do sinalizador de sinal.

Implementação da recepção de sinais do Núcleo SE
A seguir, está o código completo da função NUSE_Signals_Receive () :

 U8 NUSE_Signals_Receive(void) { U8 signals; NUSE_CS_Enter(); Signals = NUSE_Task_Signal_Flags[NUSE_Task_Active]; NUSE_Task_Signal_Flags[NUSE_Task_Active] = 0; NUSE_CS_Exit(); return signals; } 

O código é muito simples. O valor dos sinalizadores é copiado, o valor inicial é redefinido e a cópia é retornada pela função API. O bloqueio de tarefas não afeta os sinais.

Estruturas de dados


Como os sinais não são objetos independentes, o uso da memória depende das tarefas às quais eles pertencem. Abaixo estão algumas informações para um entendimento completo. Os sinais usam uma estrutura de dados (na RAM), que, como outros objetos do Nucleus SE, é uma tabela cujas dimensões correspondem ao número de tarefas no aplicativo. Essa estrutura de dados é usada apenas se o suporte ao sinal estiver ativado.

Eu recomendo que o código do aplicativo não acesse essa estrutura de dados diretamente, mas use as funções de API disponíveis. Isso evita incompatibilidade com versões futuras do Nucleus SE, efeitos colaterais indesejados e também simplifica a portabilidade do aplicativo para o Nucleus RTOS. A estrutura de dados é discutida em detalhes abaixo para simplificar o entendimento dos princípios de chamada e depuração de serviço.

A estrutura dos dados colocados na RAM


Estrutura de dados:
NUSE_Task_Signal_Flags [] - uma matriz do tipo U8 com uma entrada para cada tarefa configurada; os sinalizadores de sinal são armazenados nessa matriz.

Essa estrutura de dados é inicializada em zeros pela função NUSE_Init_Task () ao carregar o Nucleus SE.

Estrutura dos dados colocados na ROM


Os sinais não possuem estruturas de dados na ROM.

Quantidades de memória para armazenar dados de sinal


Como em todos os objetos principais do Nucleus SE, a quantidade de memória necessária para os sinais é previsível.

A quantidade de dados na ROM para todos os sinais no aplicativo é 0.

A quantidade de memória para armazenar dados na RAM (em bytes) para todos os sinais no aplicativo é igual ao número de tarefas configuradas ( NUSE_TASK_NUMBER ). Mas, de fato, esses dados pertencem às tarefas e são descritos no artigo anterior sobre tarefas.

Chamadas de API não realizadas


Duas chamadas de sinalização da API Nucleus RTOS não são implementadas no Nucleus SE:

Registro do manipulador de sinal


Essa chamada de API configura o procedimento de processamento de sinal (função) para a tarefa atual. O Nucleus SE não precisa disso porque os manipuladores de sinal não são suportados.

Protótipo de chamada de serviço:
STATUS NU_Register_Signal_Handler (VOID (* signal_handler) (UNSIGNED));

Parâmetros:
signal_handler - uma função que deve ser chamada ao receber sinais

Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_POINTER - ponteiro nulo para o manipulador de sinal ( NULL )

Controle (ativação / desativação) de sinais


Este serviço ativa e / ou desativa sinais para a tarefa atual. Para cada tarefa, 32 sinais estão disponíveis. Cada sinal é representado por um bit em signal_enable_mask . Adicionar um pouco a signal_enable_mask ativa o sinal correspondente e excluir um pouco o desativa.

Protótipo de chamada de serviço:
UNSIGNED NU_Control_Signals (UNSIGNED enable_signal_mask);

Parâmetros:
enable_signal_mask - padrão de bits que representa os sinais corretos.

Valor de retorno:
Máscara para ativar / desativar o sinal anterior.

Compatível com núcleo RTOS


Ao desenvolver o Nucleus SE, meu objetivo era manter o nível de código compatível com o Nucleus RTOS. Os sinais não são excepção e, do ponto de vista do desenvolvedor, são implementados da mesma maneira que no Nucleus RTOS. Existem algumas incompatibilidades que considerei válidas, uma vez que o código final é muito mais fácil de entender e pode usar a memória com mais eficiência. Caso contrário, as chamadas da API do Nucleus RTOS podem ser quase diretamente transferidas para as chamadas do Nucleus SE.

Manipuladores de sinal


No Nucleus SE, os manipuladores de sinal não são implementados para simplificar a estrutura geral.

Disponibilidade e quantidade de sinal


No Nucleus RTOS, as tarefas podem ter 32 sinalizadores de sinal. No Nucleus SE, decidi reduzir o número para oito, pois isso será suficiente para aplicativos mais simples e economizará recursos de RAM. Se necessário, os sinais podem ser completamente desligados.

Chamadas de API não realizadas


O núcleo RTOS suporta quatro chamadas de serviço de sinalização. Desses, dois não foram implementados no Nucleus SE. Sua descrição pode ser encontrada acima na seção "Chamadas de API não realizadas".

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.

Source: https://habr.com/ru/post/pt427439/


All Articles