
Neste artigo, continuaremos a considerar os canais de transmissão de dados.
Serviços de suporte ao canal
O Nucleus RTOS possui quatro chamadas de API que fornecem funções auxiliares relacionadas aos canais: redefinir um canal, recuperar informações do canal, recuperar o número de canais em um aplicativo e recuperar ponteiros para todos os canais em um aplicativo. As três primeiras funções são implementadas no Nucleus SE.
Artigos anteriores da série:
Artigo 25. Canais de Dados: Introdução e Serviços BásicosArtigo 24. Filas: serviços auxiliares e estruturas de dadosArtigo 23. Filas: introdução e serviços básicosArtigo 22. Caixas de correio: serviços auxiliares e estruturas de dadosArtigo 21. Caixas de correio: Introdução e serviços básicosArtigo 20. Semáforos: Serviços Auxiliares e Estruturas de DadosArtigo 19. Semáforos: introdução e serviços básicosArtigo # 18 Grupos de Sinalizadores de Eventos: Serviços Auxiliares e Estruturas de DadosArtigo 17. Grupos de Sinalizadores de Eventos: Introdução e Serviços BásicosArtigo 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.Redefinição de canal
Essa chamada de API redefine o canal para seu estado original e não utilizado. Quaisquer mensagens armazenadas nele serão perdidas. Todas as tarefas suspensas no canal são retomadas com o código de retorno
NUSE_PIPE_WAS_RESET .
Chamada de redefinição de canal no Nucleus RTOSProtótipo de chamada de serviço:
STATUS NU_Reset_Pipe (NU_PIPE * pipe);Parâmetros:
pipe - um ponteiro para um bloco de controle de canal definido pelo usuário.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_PIPE - ponteiro de canal inválido.
Desafio de redefinição de canal no Nucleus SEEsta chamada de serviço da API suporta a funcionalidade principal da API Nucleus RTOS.
Protótipo de chamada de serviço:
STATUS NUSE_Pipe_Reset (canal NUSE_PIPE);Parâmetros:
pipe é o índice (ID) do
pipe que está sendo descartado.
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_INVALID_PIPE - índice de canal inválido.
Implementação de redefinição de canal no Nucleus SEO código para a função
NUSE_Pipe_Reset () (depois de verificar os parâmetros) é bastante simples. Os índices de início e término do canal, bem como o contador de mensagens no canal, são definidos como 0.
Se o bloqueio de tarefas estiver ativado, um código adicional será responsável por restaurar as tarefas suspensas:
while (NUSE_Pipe_Blocking_Count[pipe] != 0) { U8 index; /* check whether any tasks are blocked */ /* on this pipe */ for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_PIPE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == pipe)) { NUSE_Task_Blocking_Return[index] = NUSE_PIPE_RESET; NUSE_Task_Status[index] = NUSE_READY; break; } } NUSE_Pipe_Blocking_Count[pipe]--; } #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER NUSE_Reschedule(NUSE_NO_TASK); #endif
Cada tarefa suspensa no canal recebe o status "pronto" com o código de retorno
NUSE_PIPE_WAS_RESET . Após a conclusão desse processo, se o agendador de prioridade for usado, a função
NUSE_Reschedule () será
chamada , pois uma ou mais tarefas com alta prioridade podem estar prontas para execução.
Informações do canal
Esta chamada de serviço retorna informações do canal. A implementação dessa chamada no Nucleus SE difere do Nucleus RTOS, pois retorna menos informações. Isso ocorre porque a nomeação de objetos, as mensagens de tamanho variável e a ordem de pausa da tarefa não são suportadas no Nucleus SE e a pausa da tarefa pode ser desativada.
Chamada para informações de canal no Nucleus RTOSProtótipo de chamada de serviço:
STATUS NU_Pipe_Information (NU_PIPE * pipe, nome CHAR *, VOID ** start_address, UNSIGNED * pipe_size, UNSIGNED * disponível, mensagens UNSIGNED *, OPTION * message_type, UNSIGNED * message_size, OPTION * suspend_type, UNSIGNED * tasks_waask **;Parâmetros:
pipe - ponteiro para o bloco de controle de canal fornecido pelo usuário;
nome - ponteiro para a área de 8 caracteres para o nome da mensagem do canal;
start_address - um ponteiro para um ponteiro no qual o endereço do início da área de dados do canal será gravado;
pipe_size - um ponteiro para uma variável para armazenar o número total de bytes no canal;
available - ponteiro para uma variável para armazenar o número de bytes disponíveis no canal;
messages - um ponteiro para uma variável para armazenar o número de mensagens no canal;
message_type - um ponteiro para uma variável para armazenar o tipo de mensagem suportado pelo canal. Pode levar os valores
NU_FIXED_SIZE e
NU_VARIABLE_SIZE ;
message_size - ponteiro para uma variável para armazenar o número de bytes em cada mensagem do canal. Se o canal suportar mensagens de tamanho variável, esse número será o tamanho máximo da mensagem;
suspend_type - um ponteiro para uma variável para armazenar o tipo de tarefa de suspensão. Pode levar os valores
NU_FIFO e
NU_PRIORITY ;
tasks_waiting - um ponteiro para uma variável para armazenar o número de tarefas suspensas neste canal;
first_task - um ponteiro para um ponteiro para a primeira tarefa pausada.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_PIPE - ponteiro de canal inválido.
Ligue para obter informações sobre o canal no Nucleus SEEssa chamada de API suporta a funcionalidade principal da API do Nucleus RTOS.
Protótipo de chamada de serviço:
STATUS NUSE_Pipe_Information (canal NUSE_PIPE, endereço ADDR * start_address, U8 * tamanho_do_ pipe, U8 * disponível, U8 * disponível, mensagens U8 *, U8 * tamanho_da mensagem, U8 * tarefas_a espera, NUSE_TASK * first_task);Parâmetros:
pipe - índice do canal, informações sobre as quais é solicitada;
start_address - ponteiro para uma variável do tipo
ADDR para armazenar o endereço do início da área de dados do canal;
pipe_size - um ponteiro para uma variável do tipo
U8 para armazenar o número total de mensagens que o canal pode receber;
disponível - um ponteiro para uma variável do tipo
U8 para armazenar o número de mensagens para as quais resta espaço livre no canal;
messages - um ponteiro para uma variável do tipo
U8 para armazenar o número atual de mensagens no canal;
message_size - ponteiro para uma variável do tipo
U8 para armazenar o tamanho das mensagens processadas por este canal;
tasks_waiting - um ponteiro para uma variável para armazenar o número de tarefas suspensas neste canal (nada será retornado se a suspensão da tarefa estiver desativada);
first_task - um ponteiro para uma variável do tipo
NUSE_TASK , que aceita o índice da primeira tarefa suspensa (nada será retornado se a suspensão da tarefa estiver desativada).
Valor de retorno:
NUSE_SUCCESS - a chamada foi concluída com sucesso;
NUSE_INVALID_PIPE - índice de canal inválido;
NUSE_INVALID_POINTER - um ou mais parâmetros do ponteiro estão incorretos.
Implementando informações do canal no Nucleus SEA implementação desta chamada de API é bastante simples:
*start_address = NUSE_Pipe_Data[pipe]; *pipe_size = NUSE_Pipe_Size[pipe]; *available = NUSE_Pipe_Size[pipe] - NUSE_Pipe_Items[pipe]; *messages = NUSE_Pipe_Items[pipe]; *message_size = NUSE_Pipe_Message_Size[pipe]; #if NUSE_BLOCKING_ENABLE *tasks_waiting = NUSE_Pipe_Blocking_Count[pipe]; if (NUSE_Pipe_Blocking_Count[pipe] != 0) { U8 index; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_PIPE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == pipe)) { *first_task = index; break; } } } else { *first_task = 0; } #else *tasks_waiting = 0; *first_task = 0; #endif
A função retorna o status do canal. Em seguida, se os bloqueios de tarefas estiverem ativados, o número de tarefas pendentes e o índice do primeiro deles serão retornados (caso contrário, esses dois parâmetros serão definidos como 0).
Obtendo o número de canais
Esta chamada de serviço retorna o número de canais configurados no aplicativo. No Nucleus RTOS, esse valor pode mudar com o tempo e o valor de retorno indicará o número atual de canais. No Nucleus SE, o valor de retorno é definido durante a fase de construção e não pode ser alterado.
Ligue para um contador de canais no Nucleus RTOSProtótipo de chamada de serviço:
UNSIGNED NU_Established_Pipes (VOID);Parâmetros:
Estão ausentes.
Valor de retorno:
O número de canais criados no sistema.
Ligue para um contador de canais no Nucleus SEEsta chamada de utilitário suporta a funcionalidade principal da API Nucleus RTOS
Protótipo de chamada de serviço:
U8 NUSE_Pipe_Count (nulo);Parâmetros:
Estão ausentes.
Valor de retorno:
O número de canais configurados no aplicativo.
Implementando um contador de canais no Nucleus SEA implementação desta chamada de API é bastante simples: o valor do símbolo
#define NUSE_PIPE_NUMBER é
retornado .
Estruturas de dados
Os canais usam seis ou sete estruturas de dados (que estão na RAM ou na ROM), que são (como outros objetos do Nucleus SE) um conjunto de tabelas, cujo tamanho e número correspondem ao número de canais configurados e seus parâmetros.
Eu recomendo fortemente que o código do aplicativo não use acesso direto a essas estruturas de dados, mas faça referência a elas através das funções de API fornecidas. Isso evitará a incompatibilidade com versões futuras do Nucleus SE e efeitos colaterais indesejados, além de simplificar a portabilidade de aplicativos para o Nucleus RTOS. A seguir, é apresentada uma visão geral detalhada das estruturas de dados para simplificar o entendimento da chamada de serviço e do código de depuração.
Dados do kernel na RAM
Esses dados têm a seguinte estrutura:
NUSE_Pipe_Head [] é uma matriz de ponteiros do tipo
U8 , com uma entrada para cada canal configurado e indicando o início do canal de mensagens. Usado como um índice de endereço em
NUSE_Pipe_Data [] (veja abaixo).
NUSE_Pipe_Tail [] é uma matriz
U8 que possui uma entrada para cada canal configurado e aponta para o final do canal de mensagens. Usado como um índice de endereço em
NUSE_Pipe_Data [] (veja abaixo).
NUSE_Pipe_Items [] é uma matriz do tipo
U8 , que possui uma entrada para cada canal configurado e é um contador do número atual de mensagens no canal. Esses dados são redundantes, pois esse valor pode ser obtido através dos índices de início e fim do canal, mas a presença de um contador simplifica o código.
NUSE_Pipe_Blocking_Count [] - essa matriz do tipo
U8 contém contadores do número de tarefas bloqueadas em cada canal. Essa matriz é criada apenas se o suporte ao bloqueio de tarefas estiver ativado.
Todas essas estruturas de dados são inicializadas com zeros pela função
NUSE_Init_Pipe () quando o Nucleus SE é iniciado. Isso é lógico, pois todos os canais são criados vazios (não utilizados). Um dos artigos a seguir fornecerá uma descrição completa dos procedimentos de inicialização do Nucleus SE.
A seguir, estão as definições dessas estruturas de dados no arquivo
nuse_init.c :
RAM U8 NUSE_Pipe_Head[NUSE_PIPE_NUMBER]; RAM U8 NUSE_Pipe_Tail[NUSE_PIPE_NUMBER]; RAM U8 NUSE_Pipe_Items[NUSE_PIPE_NUMBER]; #if NUSE_BLOCKING_ENABLE RAM U8 NUSE_Pipe_Blocking_Count[NUSE_PIPE_NUMBER]; #endif
Dados do usuário da RAM
É de responsabilidade do usuário fornecer uma área de dados na RAM para armazenar os dados de cada canal configurado. O tamanho dessa área deve conter uma matriz do tipo
U8 , na qual todas as mensagens do canal serão ajustadas.
Dados ROM
A estrutura desses dados é a seguinte:
NUSE_Pipe_Data [] é uma matriz do tipo
ADDR que possui um registro para cada canal configurado e indica a área de dados de cada canal (consulte a seção "Dados do usuário na RAM" acima).
NUSE_Pipe_Size [] é uma matriz do tipo
U8 , com uma entrada para cada canal configurado e mostrando o número de mensagens que podem caber em cada canal.
NUSE_Pipe_Message_Size [] é uma matriz do tipo
U8 que possui um registro para cada canal configurado e mostra o tamanho das mensagens (em bytes) que podem ser colocadas em cada canal.
Essas estruturas de dados são declaradas e inicializadas (estaticamente) no arquivo
nuse_config.c , assim:
ROM ADDR *NUSE_Pipe_Data[NUSE_PIPE_NUMBER] = { /* addresses of pipe data areas ------ */ }; ROM U8 NUSE_Pipe_Size[NUSE_PIPE_NUMBER] = { /* pipe sizes ------ */ }; ROM U8 NUSE_Pipe_Message_Size[NUSE_PIPE_NUMBER] = { /* pipe message sizes ------ */ };
Memória do canal
Como todos os outros objetos principais do Nucleus SE, a quantidade de memória necessária para os canais é previsível.
A quantidade de dados na ROM (em bytes) para todos os canais no aplicativo pode ser calculada da seguinte maneira:
NUSE_PIPE_NUMBER * (sizeof (ADDR) + 2)A quantidade de dados do kernel na RAM (em bytes) para todos os canais de aplicativos quando as tarefas são ativadas pode ser calculada da seguinte maneira:
NUSE_PIPE_NUMBER * 4Caso contrário:
NUSE_PIPE_NUMBER * 3A quantidade de dados do usuário em RAM (em bytes) para o canal com o índice de canal:
NUSE_Pipe_Size [pipe] * NUSE_Pipe_Message_Size [pipe]Chamadas de API não realizadas
Quatro chamadas de serviço da API Nucleus RTOS não são implementadas no Nucleus SE.
Criação de canal
Essa chamada de API cria um canal. O Nucleus SE não precisa disso porque os canais são criados estaticamente.
Protótipo de chamada de serviço:
STATUS NU_Create_Pipe (NU_PIPE * pipe, nome CHAR *, VOID * start_address, UNSIGNED pipe_size, OPTION message_type, UNSIGNED message_size, OPTION suspend_type);Parâmetros:
pipe - um ponteiro para o bloco de controle de canal fornecido pelo usuário; ele será usado como o ativador do canal principal em outras chamadas de API;
name - ponteiro para um nome de canal de 7 caracteres com um zero final;
endereço_início - endereço inicial do canal;
pipe_size - o número total de bytes no canal;
message_type - tipo de mensagem suportado pelo canal. Pode levar os valores
NU_FIXED_SIZE ou
NU_VARIABLE_SIZE ;
message_size - se o canal suportar mensagens de tamanho fixo, este parâmetro indica o tamanho exato de cada mensagem. Caso contrário, se o canal suportar mensagens de tamanho variável, esse valor será o tamanho máximo da mensagem;
suspend_type - indica o tipo de suspensão da tarefa no canal. Pode levar os valores
NU_FIFO e
NU_PRIORITY (planejador FIFO e planejador PRIORITY, respectivamente).
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_PIPE - ponteiro nulo para a unidade de controle de canal (
NULL ), ou a unidade de controle já está em uso;
NU_INVALID_MEMORY - uma área de dados incorreta foi especificada em
start_address ;
NU_INVALID_MESSAGE - parâmetro
message_type inválido;
NU_INVALID_SIZE - o tamanho da mensagem é maior que o tamanho do canal ou o tamanho do canal ou da mensagem é zero;
NU_INVALID_SUSPEND - parâmetro
suspend_type inválido.
Excluir canal
Essa chamada de API exclui um canal criado anteriormente. O Nucleus SE não precisa, porque os canais são criados estaticamente e não podem ser excluídos.
Protótipo de chamada de serviço:
STATUS NU_Delete_Pipe (NU_PIPE * pipe);Parâmetros:
pipe - um ponteiro para um bloco de controle de canal.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_PIPE - ponteiro de canal inválido.
Ponteiros de canal
Essa chamada de API cria uma lista seqüencial de ponteiros para todos os canais no sistema. No Nucleus SE, não é necessário, pois os canais são identificados por um índice simples, não por um ponteiro; portanto, essa função seria redundante.
Protótipo de chamada de serviço:
UNSIGNED NU_Pipe_Pointers (NU_PIPE ** pointer_list, UNSIGNED maximum_pointers);Parâmetros:
pointer_list - um ponteiro para uma matriz de ponteiros
NU_PIPE . Essa matriz será preenchida com ponteiros para os canais criados anteriormente no sistema;
ponteiros máximos - o número máximo de ponteiros na matriz.
Valor de retorno:
O número de ponteiros
NU_PIPE na matriz
Transmitir para um canal
Essa chamada de API passa a mensagem para todas as tarefas que aguardam mensagens de um canal específico. No Nucleus SE, esse recurso não foi implementado, pois adiciona complexidade redundante.
Protótipo de chamada de serviço:
STATUS NU_Broadcast_To_Pipe (canal NU_PIPE *, mensagem VOID *, tamanho NÃO ASSINADO, suspensão NÃO ASSINADA);Parâmetros:
pipe - um ponteiro para um bloco de controle de canal;
message - ponteiro para a mensagem transmitida;
tamanho - o número de elementos de dados
NÃO ASSINADOS na mensagem. Se o canal suportar mensagens de tamanho variável, esse parâmetro deverá ser igual ou menor que o tamanho da mensagem suportada pelo canal. Se o canal suportar mensagens de tamanho fixo, esse parâmetro deverá ser exatamente igual ao tamanho das mensagens suportadas pelo canal;
suspender - indica se a tarefa de chamada deve ser suspensa se o canal já estiver cheio. Pode ser
NU_NO_SUSPEND ,
NU_SUSPEND ou um valor de tempo limite.
Valor de retorno:
NU_SUCCESS - a chamada foi concluída com sucesso;
NU_INVALID_PIPE - ponteiro inválido para o canal;
NU_INVALID_POINTER - ponteiro nulo para uma mensagem (
NULL );
NU_INVALID_SIZE - o tamanho da mensagem especificado é incompatível com o tamanho da mensagem especificado ao criar o canal;
NU_INVALID_SUSPEND - tente suspender de um thread não relacionado à tarefa;
NU_PIPE_FULL - não há espaço suficiente no canal para a mensagem;
NU_TIMEOUT - o canal ainda está cheio, mesmo após o término do tempo limite especificado;
NU_PIPE_DELETED - o canal foi excluído enquanto a tarefa estava suspensa;
NU_PIPE_RESET - O canal foi redefinido enquanto a tarefa estava suspensa.
Compatível com núcleo RTOS
Como com todos os outros objetos do Nucleus SE, meu objetivo era maximizar a compatibilidade do código do aplicativo com o Nucleus RTOS. Os canais não são exceção e, do ponto de vista do usuário, são implementados da mesma maneira que no Nucleus RTOS. Há também uma certa incompatibilidade, que eu considerei aceitável, já que, como resultado, o código se tornará mais compreensível e mais eficiente em termos da quantidade de memória necessária. Caso contrário, as chamadas da API do Nucleus RTOS poderão ser portadas quase diretamente para o Nucleus SE.
Identificadores de objeto
No Nucleus RTOS, todos os objetos são descritos por uma estrutura de dados (bloco de controle) que possui um tipo de dados específico. Um ponteiro para esta unidade de controle serve como um identificador de canal. Decidi que no Nucleus SE é necessária uma abordagem diferente para o uso eficiente da memória: todos os objetos do kernel são descritos por um conjunto de tabelas na RAM e / ou ROM. O tamanho dessas tabelas é determinado pelo número de objetos configurados de cada tipo. O identificador de um objeto específico é o índice nesta tabela. Então, eu defini
NUSE_PIPE como o equivalente a
U8 , uma variável (não um ponteiro) desse tipo serve como identificador de canal. Essa pequena incompatibilidade é fácil de lidar se o código for portado do Nucleus SE para o Nucleus RTOS e vice-versa. Normalmente, nenhuma operação é executada nos identificadores de objeto além de mover e armazenar.
O núcleo RTOS também suporta a nomeação de canais. Esses nomes são usados apenas para depuração. Excluí-os do Nucleus SE para economizar memória.
Tamanho e tipo da mensagem
No Nucleus RTOS, um canal pode ser configurado para processar mensagens que consistem em um número arbitrário de bytes, assim como o Nucleus SE. O núcleo RTOS também suporta canais de mensagens de comprimento variável para os quais apenas o tamanho máximo da mensagem é especificado no momento da criação. Mensagens de tamanho variável não são suportadas no Nucleus SE.
Tamanho do canal
No Nucleus SE, o número máximo de mensagens por canal é 256, pois todas as variáveis e constantes são do tipo
U8 . O Nucleuts RTOS não tem essas limitações.
Chamadas de API não realizadas
O núcleo RTOS suporta dez sobrecargas de canal. Quatro deles não estão implementados no Nucleus SE. Uma descrição detalhada dessas chamadas, bem como os motivos dessa decisão, pode ser encontrada na seção "Chamadas de API não realizadas", anteriormente neste artigo.
No artigo a seguir, consideraremos a hora do sistema.
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.