
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 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 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 #define NUSE_SIGNALS_SEND FALSE #define NUSE_SIGNALS_RECEIVE FALSE
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 RTOSProtó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 SEEssa 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 SEAbaixo 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 RTOSProtó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 SEEssa 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 SEA 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.