Desenvolvimento de Aplicações Embarcadas Aplicações embarcadas, ou sistemas embarcados, executam em processadores instalados (embarcados) em dispositivos cuja função precípua não é o processamento da informação. Exemplos de tais dispositivos incluem equipamentos eletrodomésticos, robôs, veículos e máquinas operatrizes. Do ponto de vista do sistema operacional, o mesmo pode ser de livre escolha do desenvolvedor, ou se apresentar como um requisito da aplicação. Vamos examinar 4 arquiteturas básicas de aplicações embarcadas. Aplicações de Laço Único A aplicação de laço único (simple control loop) consiste de uma única tarefa que nunca será interrompida ou, no máximo, será interrompida apenas para o tratamento de interrupções. Estas aplicações comumente executam uma tarefa muito especfica, por exemplo, verificar as condições operacionais de um equipamento. Em muitos casos tais aplicações embarcadas executam em processadores mais simples como microcontroladores. Aplicações de Laço Único Arduino Due Atmel ATmega2560: Flash 256k bytes (8k usada pelo bootloader) - memória de programa (~ área de texto) SRAM 8k bytes - memória de variáveis (~ área de dados/pilha) EEPROM 4k byte - memória persistente O Arduino não possui SO, mas um bootloader que instala e executa programas transferidos via porta serial (USB). Aplicações de Laço Único Aplicações Controladas por Interrupções Nesta arquitetura a aplicação consiste de uma tarefa principal e de um conjunto de tratadores de interrupção. A tarefa principal pode se reduzir a um laço com uma única função tipo wait. Neste caso, toda a lógica da aplicação está dispersa nos tratadores de interrupção. Aplicações que seguem esta arquitetura usualmente executam em hardware especializado onde as interrupções estão associadas a valores de grandezas físicas, por exemplo, uma temperatura que ultrapassa um valor limite. O tratamento de interrupções pode ser preemptivo ou não preemptivo. No caso preemptivo associa-se prioridades às interrupções e um tratador de interrupção pode sofrer preempção para que outro associado a uma interrupção de prioridade mais alta possa ser invocado. No caso não preemptivo, uma interrupção é escalonada para tratamento caso outra interrupção esteja sendo tratada. Aplicações Multitarefa Cooperativas Nesta arquitetura a aplicação consiste de um conjunto de tarefas executadas de forma não preemptiva e escalonadas segundo a política FIFO. Tarefas são interrompidas apenas para o tratamento de interrupções, tratamento este também não preemptivo. O sistema operacional TinyOS foi concebido para esta arquitetura de aplicações. TinyOS possui uma linguagem de programação associada, nesC, com sintaxe muito semelhante à linguagem C. nesC é uma linguagem orientada a componentes. Um componente provê interfaces e declara as interfaces de outros componentes que utiliza. nesC define tarefas, equivalentes a processos. TinyOS não suporta proteção de memória e modos do processador (ou seja, o sistema operacional e as aplicações possuem os mesmos privilégios). A vantagem desta arquitetura de aplicações é a inexistência de condições de corrida e a desvantagem é o escalonamento de tarefas que recai sobre o desenvolvedor. Aplicações Multitarefa Preemptivas Nesta arquitetura a aplicação consiste de um conjunto de tarefas escalonadas de forma preemptiva. Para estas aplicações o sistema operacional deve ter núcleo preemptivo e oferecer mecanismos de sincronização. Tarefas podem tratar interrupções, executar ações periódicas, ou processar informação em função do estado da aplicação. Tarefas são implementadas como threads escalonadas por prioridades. Usualmente, o sistema operacional é baseado em um núcleo preemptivo como o Linux e executa em um processador com um ou mais cores. A vantagem desta arquitetura de aplicações é a flexibilidade no mapeamento das funcionalidades da aplicação em tarefas correspondentes, bem como a atribuição de prioridades a estas tarefas. A desvantagem é a dificuldade em se prever e evitar a ocorrência de deadlocks, estarvação de tarefas e inversões de prioridades. Aplicações Multitarefa Preemptivas Raspberrry PI: • Alimentação de 5V • 512 MB RAM • 2 USBs • Vídeo HDMI • Vídeo analógico • Fast Ethernet • Interface I2C • Interface MIPI (câmera) • Linux (Raspiam - Debian) Aplicações Embarcadas Bootloader Laço Único Vetor de Interrupções Legenda: Controladas por Interrupções Tarefa Controle Escalonador FIFO Escalonador Preemptivo Multitarefas Cooperativas Multitarefas Preemptivas Arquiteturas em Camadas Nem sempre uma aplicação embarcada emprega unicamente um dos modelos de aplicação descritos anteriormente. Na prática, uma combinação destes modelos é comum. Para compor estes modelos uma arquitetura em camadas pode ser empregada. Em uma arquitetura em camadas as funcionalidades da aplicação são organizadas em camadas de tal forma que uma camada oferece serviços por meio de interfaces bem definadas à camada superior. O próprio sistema operacional emprega esta arquitetura. Arquiteturas em camadas são empregadas em redes de computadores, aplicações Web e padrões de projeto de software (design patterns). Exemplo de Arquiteturas em Camadas Aplicações-fim Camada de Aplicação Cliente/Servidor Camada Executiva Troca de Mensagens Camada de Controle de Tempo Real Hardware Camada de Controle de Tempo Real A camada de controle de tempo real interage diretamente com o hardware, que pode ser considerado uma camada abaixo desta (mas não pertencente à arquitetura). A interação com o hardware se dá por meio de registradores, barramentos e portas, por exemplo, interface serial RS-232, barramento I2C (Inter-Integrated Circuit) e barramento SPI (Serial Peripheral Interface Bus). A camada de controle de tempo real tem suas funções comumente implementadas em microcontroladores como o Arduino e executa operações com período da ordem de milisegundos. Operações típicas incluem controladores (por exemplo, PID), filtragem, emissão de alarmes e geração de sinais (por exemplo, PWM) Esta camada provê uma interface para a camada executiva (via porta serial RS-232, rede Ethernet, etc.), bem como define um protocolo de interação tipicamente baseado em passagem de mensagens. Camada Executiva As funções da camada executiva são comumente realizadas em processadores de pequeno e médio porte tais como o Raspberry Pi, com sistema operacional instalado (Linux, na maioria dos casos). Esta camada executa operações com período da ordem de centenas de milisegundos. Tais operações são implementadas com processos e threads (comumente em C/C++) e utilizam as funções providas pela camada de controle de tempo real. Operações típicas da camada executiva incluem sensoriamento, estimação, atuação, proteção e fusão de dados. Para a implementação desta camada as seguintes funcionaliadades do sistema operacional são utilizadas: threads, escalonamento por prioridades, bibliotecas dinâmicas, sistema de arquivos em memória, programação de módulos. A camada executiva provê uma interface de mais alto nível para a camada de aplicação baseada, tipicamente, em protocolos de comunicação cliente/servidor tais como RPC (Remote Procedure Call) e HTTP. Camada de Aplicação A camada de aplicação oferece funções de alto nível que são utilizadas pelas aplicações-fim. Note que esta camada não implementa as aplicaçõesfim, mas sim facilidades para a implementação conveniente e eficaz destas aplicações. As funções presentes nesta camada são dependentes do domínio de aplicação. Por exemplo, no domínio da robótica móvel, estas funções incluem algoritmos de localização, de mapeamento, de planejamento de trajetória e de locomoção. Tais funções executam em processadores mais poderosos (ou mesmo em uma nuvem) e são codificadas em linguagens de alto nível como o Matlab, Python e Java. Desta forma, a interface que esta camada oferece para as aplicações-fim são baseadas em componentes, frameworks e classes de objetos, que são abstrações de software de mais alto nível comparado com protocolos cliente/servidor e passagem de mensagens. Exemplo de Aplicação Embarcada Controlar um robô móvel com movimentos musculares da face (piscadas). TCC da aluna Julia Amaya, publicado no XI Simpósio Brasileiro de Automação Inteligente (SBAI 2013). Módulo EMG Shimmer (executa TinyOS) Exemplo de Aplicação Embarcada Os sensores Shimmer utilizam um microcontrolador MSP 430 (TI) e interface de comunicação Bluetooth e IEEE 802.15.4 (rádio de curta distância utilizado em redes de sensores sem fio). Este sensores empregam o sistema operacional TinyOS e sua linguagem de programação nesC. nesC define tarefas (tasks), equivalentes a processos. Uma tarefa pode escalonar (postar) outras tarefas. TinyOS é um sistema operacional simples: • Não preemptivo (tarefas executam até completarem), exceto tarefas que tratam interrupções; • Tarefas são escalonadas com política FIFO; • Sem proteção de memória; • Sem modos do processador (SO e aplicações posuem os mesmos privilégios); • Sem chamadas de sistema (o interfaceamento com o SO é via nesC). Exemplo de Aplicação Embarcada Tipicamente, tarefas no TinyOS lêem dados dos sensores presentes no módulo com determinada frequência, executa algumas operações (por exemplo, cálculo de tendência), e envia as leituras para um nó sorvedouro. O envio pode ser hop-by-hop utilizando um protocolo de roteamento. O sorvedouro é um nó com capacidade maior de processamento (ex, PC) que realiza filtragem, fusão, correlação, etc., dos dados transmitidos pelos nós sensores. Na aplicação em questão, o nó sorvedouro é um smartphone com o sistema operacional Android. Exemplo de Aplicação Embarcada Android é um sistema operacional desenvolvido sobre o nucleo do Linux. Aplicações em Android são desenvolvidas em Java e executam um uma máquina virtual Java que por sua vez executa em um processo Linux. Android provê uma série de Frameworks (classes Java para telefonia, apresentação de mídias, etc.) que são utilizados no desenvolvimento de aplicações denominadas atividades (activities). Atividades podem utilizar múltiplas threads e não têm acesso às chamadas de sistema do Linux. Recebem um callback de pausa/reinício quando perdem/ganham "visibilidade". Exemplo de Aplicação Embarcada A detecção de piscada intencional é realizada via threshold. Taxa de acerto: 96%. Exemplo de Aplicação Embarcada A seguinte convenção foi adotada. Uma ação é iniciada e terminada com o mesmo comando (piscada). • piscada do olho direito: o robô gira para a direita a 7o/s; • piscada do olho esquerdo: o robô gira para a esquerda a 7o/s; • piscada de ambos os olhos: o robô se locomove a 150 mm/s. Exemplo de Aplicação Embarcada Camada de Aplicação Bluetooth Aplicação Robótica ARIA API HTTP WiFi Processador de Bordo protocolo de mensagens RS-232 ARCOS Camadas Executiva e de Controle Microcontrolador Exemplo de Aplicação Embarcada A aplicação ilustrada utiliza 3 sistemas operacionais: TinyOS, Android e Linux. A programação de aplicações nestes sistemas seguem modelos diferentes: tarefas, atividades e threads/processos. É imprescindível conhecer as características dos sistemas operacionais. Por exemplo: • tarefas TinyOS são sequenciais (escalonamento FIFO) e portanto não necessitam de sincronização; • atividades Android executam com permissões de usuários diferentes (por que?); • threads Linux devem ser sincronizadas porque o núcleo é preemptivo. A maioria das aplicações são embarcadas ou possuem componentes embarcados. Sistemas operacionais para estas aplicações são diferentes dos tradicionais e devemos conhecer suas restrições e capacidades para utilizá-los adequadamente.