
Sobre o que vamos falar?

Princípios da arquitetura Inter
A arquitetura Inter foca em separar as responsabilidades funcionais do seu produto em diferentes módulos. O seu produto irá fazer uma série de atividades fantásticas mas não é legal que todo o código delas fique todo junto, num único emaranhado de um ou poucos arquivos.
Pra que fazer isso, Andre?
- GPIO: Este sempre trará rotinas relacionadas à ler e escrever informações de pinos.
- Timer: Este driver sempre trará rotinas relacionadas à contagem de tempo.
- Um módulo de sistema de arquivos sempre nos proverá rotinas relacionadas à leitura e escrita de arquivos, independente se é implementado o sistema X, Y, Z…
Cabeçalhos públicos
- Definições necessárias para o seu uso.
- As funções e rotinas disponíveis.
- Helper dos testes unitários.
Tipo de rotinas
“Rotina fulana! Faça isto já!”
“Rotina ciclana! Comece a fazer isto e me avise por aqui [aponta um callback] quando você terminar!”
Este tipo de operação é ideal para sistemas determinísticos, pois seus clientes ficam livres para realizar outras atividades enquanto o módulo está trabalhando. Porém, a lógica envolvida para operar estas rotinas é um pouco mais complicada, o que faz muitos desenvolvedores preferirem implementar rotinas bloqueantes. Muitas vezes, entretanto, estas decisões se tornam grandes erros.
Que tipo de rotina usar, Andre?
Vamos por a mão na massa!
- Definiremos que módulos teremos em nosso primeiro projeto.
- O que cada um precisa fornecer.
- O que cada um precisa dos outros (dependências).
- Vamos criar os cabeçalhos públicos.
Definição dos módulos
- O produto deve coordenar um LED, fazendo ele piscar de acordo com uma entrada digital. Nesta entrada está ligado um push-button, o qual vai ser pressionado pela crianç… pelo usuário!
- Quando o botão não estiver pressionado, o LED deve piscar com um período total de [TBD1] ms, duty 50%.
- Quando o botão estiver pressionado, o LED deve piscar com um período total de [TBD2] ms, duty 50%.
- O botão é controlado pelo nosso produto, então ele precisa ter seu nível mantido por pulls e uma outra saída digital ser responsável por dar o nível quando o botão for pressionado.
- A entrada digital deve ser lida periodicamente e seu nível reavaliado a cada [TBD3] ms.
- hal, drivers, myGpio.
- hal, drivers, myTimer.
- hal, myBoard.
- libs, cmsis_os.
- products, blinky, app, appButton.
- products, blinky, app, appLed.
Os cabeçalhos básicos
- Inclusão dos tipos básicos da biblioteca C, os quais sempre usaremos quando possível. Recomendo que sempre trabalhe com os tipos ‘uintx_t’, mas isso é assunto para outro post.
- Criação do seu tipo de retorno padrão. ‘myRet_t’ será o seu tipo mais importante, ele indicará se alguma operação foi (ou não) bem sucedida. Repare que o valor de ‘sucesso’ é zero, isso é particularmente útil na hora de trabalhar com os testes unitários, pois com isso os valores default dos mocks serão de sucesso e nossos testes ficarão mais clean.
- Criação do seu primeiro tipo de callback. Este é o mais simples, que simplesmente chama algo, sem argumento nenhum. Vamos usar ele já na nossa rotina não bloqueante do timer.
Como ficou nosso diretório?
Agora que definimos os nossos cabeçalhos públicos e os cabeçalhos básicos, vamos atualizar o nosso repositório:

Criando os cabeçalhos públicos
Com os módulos definidos e nossos cabeçalhos básicos declarados, podemos partir para as declarações de nossos cabeçalhos públicos.
- Faça uma breve descrição do que o módulo deve fazer.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
- Que dependências este módulo terá?
- Que tipos específicos este módulo precisará declarar para poder ser usado?
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
- Que rotinas o módulo terá?
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
Bolacha ou biscoito? (Não, esse não, Andre!) 🤣
- Faça uma breve descrição do que o módulo deve fazer.
Este módulo deve realizar a leitura periódica de uma entrada digital. Dependendo do nível desta entrada, ele deve atuar no módulo de LED para mudar o período que ele pisca. Este módulo deve configurar o necessário para o uso de um push button: uma saída digital e a entrada com um pull.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
Ele é totalmente independente, tendo apenas uma rotina para a sua inicialização.
- Que dependências este módulo terá?
appLed.
cmsis_os.
myGpio.
myTimer.
- Que tipos específicos este módulo precisará declarar para poder ser usado?
Nenhum.
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
Será desenvolvido totalmente por nós.
- Que rotinas o módulo terá?
Rotina de inicialização do módulo.
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
A inicialização é bloqueante e apenas responde se foi bem sucedida (ou não).
- Faça uma breve descrição do que o módulo deve fazer.
Este módulo deve coordenar uma saída digital, ligada à um LED. Ele deve manter este LED piscando de acordo com um intervalo de tempo, intervalo este passado pelos clientes.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
Além da inicialização, ele fornecerá uma função para alterar o período de piscar do LED.
- Que dependências este módulo terá?
cmsis_os.
myGpio.
myTimer.
- Que tipos específicos este módulo precisará declarar para poder ser usado?
Nenhum.
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
Será desenvolvido totalmente por nós.
- Que rotinas o módulo terá?
Rotina de inicialização do módulo.
Rotina para definir o período de piscar do LED.
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
As rotinas são bloqueantes e apenas respondem se foram bem sucedidas (ou não).
- Faça uma breve descrição do que o módulo deve fazer.
Este módulo deve fornecer os serviços do sistema operacional. Em particular, deve prover a capacidade de iniciarmos threads e de enviarmos mensagens para elas.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
Este módulo fornecerá funções para outros módulos.
- Que dependências este módulo terá?
Da implementação do sistema operacional.
- Que tipos específicos este módulo precisará declarar para poder ser usado?
Os seus tipos para os artefatos do sistema operacional.
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
Será a abstração de módulos de terceiros. Inclusive na maioria das vezes estes mesmos terceiros que irão nos fornecer o cabeçalho deste módulo.
- Que rotinas o módulo terá?
As rotinas de uso abstraído do sistema operacional.
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
São inúmeras rotinas, estas informações já estão definidas e o cabeçalho já está implementado. Não precisamos nos preocupar.
- Faça uma breve descrição do que o módulo deve fazer.
Este módulo deve realizar a inicialização da placa do nosso produto, iniciando o core do microcontrolador e quaisquer pinos que forem necessários.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
Ele é independente, apenas fornecendo uma rotina para a sua inicialização.
- Que dependências este módulo terá?
Apenas do SDK do fabricante do microcontrolador.
- Que tipos específicos este módulo precisará declarar para poder ser usado?
Nenhum.
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
Será desenvolvido por nós.
- Que rotinas o módulo terá?
Rotina de inicialização do módulo.
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
As rotinas são bloqueantes e apenas respondem se foram bem sucedidas (ou não).
myGpio.h
- Faça uma breve descrição do que o módulo deve fazer.
Este módulo deve atuar sobre os pinos do microcontrolador, fornecendo funções de entrada e saída digitais simples. Os pinos podem ser configurados como saídas e colocados em níveis lógicos altos ou baixos. Também, eles podem ser configurados como entradas digitais, com o módulo indicando se eles estão em nível lógico alto ou baixo. As entradas podem ter pull-ups ou pull-downs habilitados.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
Ele fornecerá funções para que outros módulos possam configurar e usar os pinos do microcontrolador.
- Que dependências este módulo terá?
Apenas do SDK do fabricante do microcontrolador.
- Que tipos específicos este módulo precisará declarar para poder ser usado?
Ele precisará declarar tipos específicos e uma estrutura de configuração que um cliente indique como deseja que um pino seja operado.
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
Será desenvolvido por nós.
- Que rotinas o módulo terá?
Rotinas para configuração e uso dos pinos.
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
As rotinas são bloqueantes, as de inicialização e saída digital apenas respondem se foram bem sucedidas (ou não) e as de entrada digital informam o nível lógico atual dos pinos.
- Faça uma breve descrição do que o módulo deve fazer.
Este módulo deve usar de periféricos do microcontrolador para prover contagem de tempo, na escala de milissegundos. Como exemplo, os clientes querem ser notificados depois que um certo tempo passou. Algumas partes vão querer ser periodicamente notificados, enquanto que outras apenas uma única vez (single shot). Por enquanto não temos clientes que vão usar deste último caso.
- Este módulo é independente ou ele fornecerá funções para outros módulos?
Ele fornecerá interfaces para que os clientes possam configurar e requisitar pedidos de contagem de tempo.
- Que dependências este módulo terá?
Apenas do SDK do fabricante do microcontrolador.
- Que tipos específicos este módulo precisará declarar para poder ser usado?
Ele precisará declarar tipos específicos e uma estrutura de configuração para indicar como um cliente deseja que um timer seja operado.
- Este módulo será todo desenvolvido por nós ou será a abstração de módulos de terceiros?
Será desenvolvido por nós.
- Que rotinas o módulo terá?
Rotinas para configuração e uso dos timers.
- Que respostas cada rotina precisa ter? Quais são bloqueantes e quais são não bloqueantes?
A rotina de inicialização é bloqueante, a de contagem de tempo são é bloqueante.
Finalizando...

André, conteúdo de OURO, estou aprendendo como nunca. Na parte dos callbacks eu tive que fritar os neurônios pra entender mas depois que eu aprendí, um novo horizonte se abriu. Agora não entendo muito bem ainda a parte dos “assertions” e sua relação com os testes unitários, mas vou ficar ligado aqui pra continuar aprendendo contigo. Muito obrigado pela sua disposição em compartilhar esse conhecimento fantástico. Abraços !
Olá novamente, Wagner!
Obrigado pelos comentários e por estar acompanhando, fico feliz destas informações estarem lhe sendo úteis! Quanto aos assertions e testes unitários, bem… eles não tem relação nenhuma! Tenho certeza que nos próximos posts isto ficará mais claro… outro abraço!
Não é possível comentar.