UNIVERSIDADE DO MINHO

ESCOLA DE ENGENHARIA

DEPARTAMENTO DE ELECTRÓNICA INDUSTRIAL

Sistema de aquisição e monitorização baseado no sistema Linux/placa Fox Board SX18

Ramiro Gomes Correia 38051

Dissertação submetida à Universidade do Minho para obtenção do grau de Mestre em Electrónica Industrial e Computadores

Novembro 2007

Dissertação realizada sob a orientação científica do

Professor Adriano José da Conceição Tavares ,

Professor Auxiliar do Departamento de Electrónica

Industrial da Universidade do Minho.

Resumo

Este trabalho consiste no controlo remoto de uma máquina de teste de espuma de poliuretano, e posterior geração de relatório dos resultados adquiridos. O sistema é baseado num conjunto de sensores que estão estrategicamente posicionados que vão adquirindo valores ao longo do tempo, o sistema utiliza ligações para comunicação dos dados com o operador. Sendo para isso necessário de fazer o tratamento dos dados remotamente através de uma placa FOX com um sistema operativo Linux.

‐ A elaboração do projecto visa o controlo em tempo real, calibração dos sensores da máquina e elaboração do relatório em pdf sem intervenção humana num modelo pré definido. A vantagem de utilização de comunicação TCP/IP reside no facto a infra‐estrutura de comunicação se encontra muito desenvolvida em baixo custo. Podendo assim utilizar a ADSL ou cabo Ethernet para estabelecer ligação com o dispositivo remotamente, podendo mesmo utilizar a rede de Internet para controlar em qualquer parte do mundo.

Este procedimento tornou a utilização desta máquina numa forma simples e intuitiva, podendo recorrer a operadores com experiência de utilização de programas em Windows.

Deste trabalho resultou um sistema robusto, fiável e moderno, capaz de utilizar tecnologias de Ethernet e Internet e aproveitar as vantagens de dois sistemas operativos existentes no mercado.

V VI Abstract:

This project consists in the remote control of a polyurethane foam test machine with later generation of a report with the acquired results. The system is based on a set of strategically placed sensors that will acquire data over the time. The system uses a TCP/IP connection to present data to the operator. A FOXBoard with the Linux OS is used to gather the data, control it's acquisition's parameters and to manage the connection with the remote PC.

Our main goals are to develop the FOXBoard control software, establish the sensor calibration procedures and to develop the PC software with special interest to the report generation without human interaction and based in a pre‐defined model.

The advantage of using a TCP/IP communication is to take advantage of the low‐cost and worldwide spreaded TCP/IP infra‐structure. In this way, we can use the ADSL or Ethernet cable to establish the connection with the device remotely, and transfer the resulting data from anywhere in the world.

It's simple interface makes it usage simple and intuitive, making it available to be operated by Microsoft Windows users.

The result of this work is then a more flexible, robust, and modern system, capable of using Ethernet and Internet technologies to take advantage of two operating systems available in the market.

VII VIII Agradecimentos

Muitas pessoas me apoiaram no desenvolvimento deste projecto. Saliento o meu orientador, o Professor Doutor Adriano José da Conceição TAvares, cuja ajuda e orientação foram essenciais para a conclusão deste trabalho, os meus colegas de curso, e do laboratório onde trabalhei, pela amizade e momentos de alegria que me proporcionaram durante a realização do curso. Queria agradecer aos meus amigos de outros cursos, como a Carla e o Alberto

Por último mas não menos importante, queria agradecer aos meus pais e irmãos o apoio e força que me deram não só ao longo deste trabalho mas também ao longo de todos estes anos como estudante.

IX X Conteúdo

Resumo ...... V Abstract ...... VII

1. Introdução ...... 1 1.1. Poliuretano ...... 1 1.2. Motivação...... 4 1.3. -Preparação do trabalho...... 5 1.4. O sistema AFM ...... 7 1.5. Hardware ...... 10 1.6. O porquê das ferramentas utilizadas ...... 14

2- Introdução teórica para a realização do trabalho 17 2.1. Protocolo TCP/IP ...... 17 2.2. Multithreads e mutex...... 19 2.3. Introdução ao ambiente de desenvolvimento Linux ...... 22 3- O processo AFM1 25 3.1. Introdução...... 25 3.2. Descrição da Thread para conexão do Socket a correr no processo AFM1...... 26 3.3. Descrição global do processo AFM1 ...... 29 3.4. A função read_botton...... 31

4- O processo AFM2 33 4.1. Introdução...... 33 4.2. Descrição global do processo AFM2 ...... 33 5- O processo ReportSender 35 5.1. Introdução...... 35 5.2. Descrição global do processo ReportSender...... 35 5.3. Apresentação da programação do processo ReportSender ...... 38

XI 6- Controlo, monitorização e transmissão de dados no cliente. 45 6.1. Introdução...... 45 6.2. Descrição Controlo, monitorização e transmissão de dados no cliente ...... 45 6.3. Apresentação da programação do programa App ...... 47 7- Geração do relatório 55 7.1. Introdução...... 55 7.2. Introdução...... 60 7.3. O programa GnuPlot ...... 61 7.4. Introdução ao Latex...... 63 7.5. Descrição da programação de geração do relatório no programa App 64 8- Calibração 71 8.1. Introdução...... 71 8.2. Como utilizar o programa para calibração dos sensores ...... 74 8.3. Descrição da programação da parte de calibração do programa App..80

9- Testes 81

10- Conclusões 83

Bibliografia 85 Anexo I Apresentação do relatório gerado pelo programa

XII Lista de Figuras

1.1- Exemplo típico de reacção de formação da molécula de poliuretano.. .1 1.2- Exemplo típicos de e isolamento de casas em poliuretano. Figura à esquerda mostra a colocação do isolamento no telhado. A figura à direita mostra a colocação do isolamento no tecto. A pequena figura no centro mostra uma das formas de transportar o poliuretano, utilizado na maioria dos casos para fazer de enchimento, isolamento e de cola para colocação de peças de madeira ou em metal na construção civil...... 2 1.3:Funcionalidades principais do trabalho executado. 1- Relatório dos resultados. 2- Cliente Windows (máquina local). 3-Ligações TCP/IP entre o cliente e servidor. 4-Servidor Linux. 5- Ligação I2C entre servidor e módulos. 6-Modulo Ambiente (medição de temperatura e pressão). 7- Modulo poliuretano (medição de dieléctrico do material, temperatura, pressão e altura)...... 7 1.4 – Servidor com sistema operativo Linux. Apresenta na parte da frente um display com teclado alfanumérico. E na parte de trás uma Pen USB e oitos portas para conexão com os módulos de teste...... 8 1.5 – Programa cliente a correr em sistema operativo Windows. À esquerda temos o controlo de todo o sistema, transferência de ficheiros e geração de relatórios. À direita encontra-se a janela de calibração dos sensores...... 9 1.6. Foto de todo o sistema fazendo um teste de espuma de poliuretano.. .10 1.7 Na imagem do lado esquerdo temos um conjunto de módulos de poliuretano operacional para testes. Na imagem do lado direito temos a estrutura de alumínio para a montagem do módulo de testes...... 11 1.8. Módulo ambiente, com sensor de temperatura ambiente e humidade ambiente. Foto à direita apresenta caixa final do módulo ambiente. A foto á esquerda apresenta o hardware do módulo ambiente...... 11 1.9 Imagem que mostra o interior do servidor. A amarelo temos a placa Fox Board com o sistema operativo Linux integrado. A verde temos a placa dos Muxs para poder ligar oito módulos em simultâneo. A roxo temos os conectores para ligar os módulos. A vermelho temos o botão de ligar e a fonte comutada. Por ultimo a azul temos o display com teclado alfanumérico (Matrix Orbital LK204-24-USB) para interacção com o operador...... 12 2.1- Esquema da divisão do processo em threads e compartilhamento de recursos...... 19 .2.2 Esta tabela define os APIs definidos pelo padrão POSIX, mais conhecido por Pthreads...... 20

XIII .3.1.-O processo AFM1 é o responsável por o tratamento dos dados provenientes destes dois interfaces. A imagem da esquerda é o controlo da máquina no cliente, réplica em programação do teclado e ecrã físicos existentes no servidor. Imagem à direita mostra a interface do servidor...... 25 3.2-No esquema seguinte tem-se a função thread responsável por conectar com o cliente e fazer leitura do buffer do TCP/IP...... 27 3.3 Representação o esquema do código a correr em paralelo...... 29 3.4. Apresentação global das funções, variáveis e estruturas do processo AFM1...... 31 3.5. Função read_button()...... 31 4.1. Funções e variáveis globais existentes no processo AFM2...... 33 5.1.Constituição do processo ReportSender. Apresentação das estruturas (struct) a rosa, apresentação da classe CReportSender a azul, apresentação da variáveis e da função global...... 35 5.2.Esquema do processo ReportSender...... 37 6.1.Classes para controlo, monitorização e transmissão de dados...... 45 6.2. Representação das threads craiadas no programa App...... 47 6.3- Apresentação dos ficheiros de adição ao projecto, para criar um Socekt...... 51 7.1 Gráfico de evolução da temperatura presente no relatório...... 55 7.2.Características de evolução da temperatura...... 56 7.3.Gráfico de evolução da altura...... 56 7.4.Gráfico de evolução da pressão...... 57 7.5. Características de evolução da pressão...... 57 7.6.Gráfico de evolução da capacidade (dieléctrico)...... 58 7.7.Características de evolução da capacidade da espuma...... 58 7. 9. Geração do relatório AFMx16032007x081654xM2.pdf.Por cima da TreeView encontra-se a barra de progresso, responsável por saber o estado do relatório...... 60 7.10 Possíveis caminhos para geração de do ficheiro pdf, a partir do ficheiro tex...... 63 7.3 Diagrama da geração de relatórios...... 69 8.1-Entrar na janela de calibração. O vermelho apresenta o botão para poder calibrar os sensores...... 73 8.2- Envio da matriz unitária. Adição de pontos. O vermelho adiciona-se os pontos se estiver no group ‘Add Point’ ou envia-se o ficheiro de calibração unitário se estiver no group ‘Transfer Settings File’. O castanho apresenta os pontos adicionados. A azul apresenta os botões para eliminar um ponto ou eliminar todos os pontos...... 75 8.3- Escolha e geração da função de um sensor. O vermelho selecciona-se o sensor que se pretende gerar a função. A verde selecciona-se o botão para gerar função...... 76

XIV 8.4-Gravar a função no ficheiro de calibração. Vermelho selecção do módulo. Verde gravar a função no ficheiro de calibração...... 77 8.5- Adicionar pontos individuais e enviar matriz de calibração. O vermelho apresenta alteração de um ponto individual. O azul apresenta o botão para o envio do ficheiro...... 78 8.1. Classes para calibração dos sensores...... 79

XV

Capítulo 1

Introdução

1.1.Poliuretano Poliuretano é qualquer polímero que compreende uma cadeia de unidades orgânicas unidas por ligações uretânicas. É amplamente usado em espumas rígidas e flexíveis, em elastômeros duráveis e em adesivos de alto desempenho, em selantes, em fibras, vedações, carpetes e peças de plástico rígido. A principal reação de produção de poliuretanos tem como reagentes um diisocianato, disponível nas formas alifáticas ou aromáticas, e um poliol (como o etileno glicol, 1,4 butanodiol, dietileno glicol, glicerol ou trimetiol propano) ou um poliol poliéster, na presença de catalisador e de materiais para o controle da estrutura das células (surfactantes), no caso de espumas.

Figura 1.1- Exemplo típico de reacção de formação da molécula de poliuretano.

O poliuretano pode ter uma variedade de densidades e de durezas, que mudam de acordo com o tipo de monómero usado e de acordo com a adição ou não de substâncias modificadoras de propriedades. Os aditivos também podem melhorar a resistência à combustão, a estabilidade química, entre outras propriedades. Embora as propriedades do poliuretano possam ser determinadas principalmente pela escolha do poliol, o diisocianato também exerce

1 alguma influência. A taxa de cura é influenciada pela reatividade do grupo funcional, e a funcionalidade, pelo número de grupos isocianato. As propriedades mecânicas são influenciadas pela funcionalidade e pela forma da molécula. A escolha do diisocianato também afecta a estabilidade do poliuretano à exposição a luz. Os poliuretanos feitos com diisocianatos aromáticos amarelam-se quando exposto à luz, enquanto que aqueles feitos com diisocianatos alifáticos são estáveis. Surgem poliuretanos mais macios, elásticos e flexíveis quando segmentos de polietilenoglicol disfuncionais lineares, normalmente chamados de polióis poliéter, são usados nas ligações uretânicas. Esta estratégia é usada para se fazer fibras elastoméricas similares à Lycra (elastano) e peças de borracha macia, assim como espuma de borracha. Produtos mais rígidos surgem com o uso de polióis polifuncionais, já que estes criam uma estrutura tridimensional emaranhada. Pode-se obter uma espuma ainda mais rígida com o uso de catalisadores de trimerização, que criam estruturas cíclicas no interior da matriz da espuma. São designadas de espumas de poliisocianurato, e são desejáveis nos produtos de espuma rígida usados na construção civil. A espuma de poliuretano (inclusive a espuma de borracha) é geralmente feita com a adição de pequenas quantidades de materiais voláteis, chamados de agentes de sopro, à mistura reaccional. Tais materiais podem ser substâncias químicas voláteis e simples, como a acetona ou o cloreto de metileno, ou fluorocarbonetos mais sofisticados, que conferem características importantes de desempenho, primariamente a isolação térmica.

2

Figura 1.2- Exemplo típicos de isolamento de casas em poliuretano. Figura à esquerda mostra a colocação do isolamento no telhado. A figura à direita mostra a colocação do isolamento no tecto. A pequena figura no centro mostra uma das formas de transportar o poliuretano, utilizado na maioria dos casos para fazer de enchimento, isolamento e de cola para colocação de peças de madeira ou em metal na construção civil.

Outra rota comum de se produzir espumas é pela adição de água a um dos líquidos precursores do poliuretano antes que sejam misturados. A água então reage com uma porção do isocianato, dando dióxido de carbono, formando bolhas relativamente uniformes que, com o endurecimento do polímero, formam uma espuma sólida. A presença de água significa que uma pequena parcela das reações resultam em ligações uréia do tipo -NC(=O)N-, em lugar das ligações uretânicas, de forma que o material resultante deveria ser tecnicamente chamado de poli(uretano-co-uréia). O controle cuidadoso de propriedades visco elásticas - pela modificação do catalisador ou dos polióis utilizados, por exemplo - podem levar à formação da chamada memory foam, uma espuma que é muito mais macia à temperatura da pele humana do que à temperatura ambiente. Quanto às espumas, há duas variantes principais: uma na qual a maior parte das "bolhas" da espuma (células) permanece fechada e o gás, preso nestas bolhas; e uma outra que são sistemas que têm, em sua maioria, células abertas, que resultam depois de um estágio crítico no processo de formação da espuma (se as células não se formam ou se tornam abertas muito cedo, simplesmente não há formação de espuma). Este é um processo vital e importante: se as espumas flexíveis

3 tiverem células fechadas, sua maciez fica severamente comprometida; tem-se a sensação de ser um material pneumático em vez de uma espuma macia; por isso, em palavras mais simples, as espumas flexíveis devem ter células abertas. Já o oposto é o caso da maioria das espumas rígidas. Aqui, a retenção do gás nas células é desejável, já que o tal gás (especialmente os fluorocarbonetos mencionados anteriormente) dá à espuma sua característica principal: a alta isolação térmica. Existe ainda uma terceira variante de espuma, chamada de espuma microcelular, que são os materiais elastoméricos rígidos tipicamente encontrados nos revestimentos de volantes de automóveis e em outros componentes automotivos. [HWP 07]

4 1.2. Motivação No fim do século anterior e neste século, a substituição do homem pela máquina, e o fazer mais e mais rápido, o querer chegar ao além da capacidade biológica humana, simplificações de processos, apareceu como um sonho tornando-se realizado. A busca do conhecimento de querer ser o criador (uma espécie de Deus), que transforma a matéria com arte e simplicidade para formar os mais incríveis e indispensáveis equipamentos do sonho humano! Com este trabalho caminha-se ao encontro de uma parte de sonho humano, com o tornar de um processo complicado e moroso num simples e rápido, não necessitando de grande intervenção humana, estando acessíveis as capacidades de maior parte dos seres humanos. Outra motivação deste trabalho foi o querer desenvolver um produto que utiliza-se os dois sistemas operativos mais utilizados e utilizar- se as maiores vantagens de cada um deles. Perante este cenário foi construído este trabalho de controlo de sistema de teste de espuma de poliuretano, e posterior geração de relatório.

5 1.3- Preparação do trabalho O sistema utilizado anteriormente era feito recorrendo a linhas de comando e scripts em sistema operativo Linux, era um sistema moroso e que por vezes apresentava erros. Com a realização deste trabalho, vem-se a optimizar o processo e acrescentar novas funcionalidades. Durante o estudo de preparação do trabalho, não se encontrou na pesquisa outras máquinas de teste de espuma de Poliuretano. Como este projecto é uma máquina de características singulares, e como a máquina em questão é para várias empresas de poliuretano fazerem o teste, não é certamente do conhecimento da comunidade, a existência de outro dispositivo, a não ser a versão anterior, que agora foi melhorada. Sendo muitos projectos de carácter confidencial, as empresas guardam em segredo o trabalho efectuado para ter vantagem tecnológica sobre a concorrência. Encontrar outro produto do mesmo género torna-se uma tarefa difícil, quase impossível. A realização de teste é uma área onde se aposta a nível mundial, pois é através dela que temos melhores produtos e mais eficientes. Sendo o objectivo do homem atingir a perfeição, isso leva a que a nível mundial existe cada vez maior aposta no desenvolvimento de sensores mais rápidos, mais baratos, onde a influencia sobre medida efectuada seja menor, ou seja, erro de medição seja cada vez mais próximo de zero, e melhoramentos de outros factores não referidos, que nem por isso, são menos importantes. O controlo de sensores de teste é utilizado independente e de modo integrado em diversas aplicação no campo da automação. Quando fala-se em actuação temos associado uma referência, sendo essa referência um teste efectuado, podendo esse teste ser realizado de diferentes formas. Em grande parte dos casos as máquinas realizam os testes tentando imitar o ser humano ou animais que o ser humano tem contacto. Este facto deve-se a que o Homem lida todos os dias com os seus sentidos tendo um grande conhecimento

6 adquirido, tentando aplicar os sentidos da audição, tacto, visão, olfacto entre outros sentidos aos sensores (sentidos humanos artificiais). A filosofia criada na implementação deste trabalho não passa por só escolher bom material, mas sim a opção mais económico. «A qualidade da medida de qualquer aparelho, não só depende da qualidade do sensor, mas também da técnica e algoritmo de implementação!».

7 1.4. O sistema AFM Muitas das opções tomadas foram feitas com base num sistema que já estava começado. Se o sistema fosse começado de raiz, este teria tomado outro rumo, como a criação de um só processo no servidor lançando várias threads e recorrendo a mutex para gerir a concorrência de dados. Tendo assim aumentando a velocidade de reposta, e evitado problemas como comunicação entre processos.

Figura 1.3:Funcionalidades principais do trabalho executado. 1- Relatório dos resultados. 2- Cliente Windows (máquina local). 3-Ligações TCP/IP entre o cliente e servidor. 4-Servidor Linux. 5- Ligação I2C entre servidor e módulos. 6-Modulo Ambiente (medição de temperatura e pressão). 7- Modulo poliuretano (medição de dieléctrico do material, temperatura, pressão e altura).

O sistema AFM é constituído, por um posto remoto com o sistema operativo Linux responsável por adquirir as características da espuma de poliuretano autonomamente ao longo de um tempo determinado pelo operador, este é controlado por um posto local onde faz o controlo e calibração em tempo real (a arquitectura servidor cliente encontra-se presente entre o controlo remoto e o controlo local via o protocolo TCP/IP). O sistema gera o relatório dos dados lidos para formato PDF e apresenta se for a vontade do operador do sistema. Todo o sistema é desenvolvido recorrendo a utilização de multitarefas, de lançamento de processos e utilização de Sockets. Para

8 a realização de multitarefas recorre-se a Multithreads, e a utilização de Mutex para gerir as concorrências entre threads.

Figura 1.4 – Servidor com sistema operativo Linux. Apresenta na parte da frente um display com teclado alfanumérico. E na parte de trás uma Pen USB e oitos portas para conexão com os módulos de teste.

O servidor é uma máquina remota que se encontra perto dos módulos de teste, podendo controlar os módulos directamente através de um display e teclado integrado de marca (Matrix Orbital LK204-24- USB), em concorrência com o cliente Windows. Sendo o servidor a placa FOX que faz comunicação via I2C com os sensores dos módulos, e via protocolo TCP/IP com o cliente. Esta placa é um pequeno computador com o sistema operativo Linux fabricado por Acmesystem. Apresenta um micro controlador (Axis ETRAX 100LX), com 16 Mb de ram e 4 Mb de flash, existindo para comunicação com o exterior duas portas USB, uma porta Ethernet e 48 pinos de entrada e saída. Como a placa não apresenta capacidade suficiente para armazenamento de software é necessário o anexo de um Pen USB para armazenamento de dados e de programas, ficando uma porta USB disponível para futuras utilizações. O script de arranque foi colocado no boot do sistema Linux para rápida utilização, evitando perda de tempo e intervenção de utilização nas janelas de linhas de comando. Existe três processos a correr no servidor, são estes: o AFM1, o AFM2 e o processo ReportSender. O processo AFM1 e AFM2 já existiam na versão anterior, sofrendo uma profunda reestruturação para

9 funcionar como máquina remota. A explicação deste processos é abordado no capítulo 3, 4e 5.

Figura 1.5 – Programa cliente a correr em sistema operativo Windows. À esquerda temos o controlo de todo o sistema, transferência de ficheiros e geração de relatórios. À direita encontra-se a janela de calibração dos sensores.

O cliente é um programa local o qual o operador tem acesso e controla todo o sistema. O cliente tem por nome App, e foi desenvolvido em MFC4 do Visual C++ para utilização em plataformas Windows. Sendo esta parte do software responsável por calibração, controlo em tempo real, transferência de dados e geração dos relatórios. Descrita cada uma das partes do único processo, pelos capítulos 6,7 e 8. O controlo é feito utilizando um réplica do LCD (Matrix Orbital LK204-24-USB) em interface gráfico utilizando skins, como se pode comparar entre as imagens esquerdas das figuras 1.4 e 1.5. Para geração do relatório é necessário instalar um programa de designação Miktec 2.6 que contem a ferramentas do GnuPlot e do Latex indispensável para a geração do relatório. A escolha deste programa baseia-se no facto de este ter uma licença sem custos, não apresentando custos adicionais para réplica da máquina. O Relatório apresenta os gráficos da interpolação dos dados provenientes dos sensores que medem os valores do estado ambiental e das características da espuma de poliuretano.

10 1.5. Hardware

Figura 1.6. Foto de todo o sistema fazendo um teste de espuma de poliuretano.

O hardware divide-se em quatro grandes partes que são: modulo de ambiente, modulo de teste, servidor (máquina que faz controlo directo através de I2C dos vários módulos) e cliente (um computador que tenha sistema operativo Windows, e que apresente ligação Ethernet (tenha uma placa de rede)).

11

Figura 1.7 Na imagem do lado esquerdo temos um conjunto de módulos para teste de poliuretano, pronto para entrar em operação. Na imagem do lado direito temos a estrutura de alumínio para a montagem do módulo de testes.

A máquina tem como finalidade o teste de evolução das propriedades da espuma de poliuretano, durante períodos de 8 horas. As características medidas são de temperatura, capacidade (alteração das propriedades da sua constituição), pressão e altura. Estas características são medidas por um módulo de testes onde integra quatro sensores, e a placa de conversão para I2C, para comunicação dos dados com o servidor. O módulo de testes vem sempre aos pares, apresentando assim sua característica de construção.

Figura 1.8. Módulo ambiente, com sensor de temperatura ambiente e humidade ambiente. Foto à direita apresenta caixa final do módulo ambiente. A foto á esquerda apresenta o hardware do módulo ambiente.

12 Existe outro módulo denominado de módulo de temperatura ambiente, que apresenta dois sensores responsável por medir a temperatura ambiente e a humidade ambiente. A importância do módulo de medição de características ambientais, prende-se no facto que existe a necessidade de saber as condições ambientais pois estas influenciam a medição dos parâmetros que se pretende testar. Além dos sensores existe ainda uma placa de conversão dos dados lidos para o formato digital na forma I2C, para ligação a um canal do servidor. O hardware do cliente é um computador com o sistema operativo Windows e com placa Ethernet para ligação com o servidor.

Figura 1.9 Imagem do interior do servidor. A amarelo temos a placa Fox Board com o sistema operativo Linux integrado. A verde temos a placa dos para poder ligar oito módulos em simultâneo. A roxo temos os conectores para ligar os módulos. A vermelho temos o botão de ligar e a fonte comutada. Por ultimo a azul temos o display com teclado alfanumérico (Matrix Orbital LK204-24-USB) para interacção com o operador.

O servidor é constituído essencialmente por três placas, que são:

13 - Placa Fox ou placa de processamento de dados onde está instalado o sistema operativo Linux. Este é responsável pelo controlo dos módulos ligados, e como esta placa não apresenta capacidade de armazenamento suficiente, está ligado uma Pen para fornecer capacidade de armazenamento adicional. A ligação dos módulos á placa de processamento de dados pode ser feita em qualquer uma das oito portas disponíveis, porque cada dispositivo apresenta uma identificação tratando-se de uma característica do I2C. -A placa do multiplexer é responsável pela ligação de múltiplos módulos, precisamente no máximo oito, através do protocolo I2C. Esta placa tem como objectivo ultrapassar o reduzido número de portas existentes na placa Fox. O servidor apresenta no seu interior uma fonte doze volt para alimentação das duas placas referidas anteriormente.

14 1.6. Ambiente de desenvolvimento.

As ferramentas e dispositivos utilizado neste projecto apresentam razões para a sua utilização, como qualquer bom projecto de engenharia. Em seguida descreve-se essas ferramentas: MFC (Microsoft Foundation Classes) é uma ferramenta para o desenvolvimento de interface gráfico usando VC++, que dão aos desenvolvedores de programas um conjunto de componentes reutilizáveis escritos em C++, que encapsulam (wrappers) as funcionalidades necessárias para desenvolver de aplicações para sistema operacional Windows. O MFC apresenta bibliotecas, que encapsulam a API nativa do Windows e estruturas de uso comum como listas, pilhas, strings, etc. Usando os componentes prontos do MFC os programadores podem criar rapidamente aplicações baseadas em Windows. O uso da biblioteca MFC economiza um tempo de desenvolvimento considerável dos programadores. [MWM 07] A utilização do MFC do visual C++, é fruto do conhecimento já adquirido ao longo de anos, evitando perder tempo de aprendizagem para uma nova ferramenta. O Windows é a escolha utilizada para o sistema operativo do cliente. Pois trata-se de um sistema popular e acessível a pessoas que tem pouco conhecimento em informática, ou seja, é um “sistema operativo” encaminhado para a utilização. Usou-se o Linux para o servidor, pois trata-se de um sistema operativo livre, de código aberto, onde consegue-se manipular o kernel e colocar num sistema com poucos recursos (sistema embebido), comparado com o computador de secretaria (desktop). Para desenvolvimento do código para a placa Fox, utilizou-se o Ubunto como plantaforma de desenvolvimento. O código é compilado na plantaforma de desenvolvimento utilizando o GCC. O GCC (GNU Compile Collection) é um conjunto de compiladores produzidos por diferentes

15 linguagens de programação, onde esta incluído a linguagem C e linguagem C++. Este compilador desenvolvido para grande variedade de arquitecturas. As várias arquitecturas suportadas por o gcc são: Alpha, ARM, Atmel AVR, Blackfin, HC12, H8/300, IA - 32 (), X86 - 64, IA - 64, MorphoSys, Motorola 68000, MIPS, PA - RISC, PDP - 11, PowerPC, R8C / M16C / M32C, System/390 / zSeries, SuperH, SPARC, VAX, A29K, ARC, C4x, ETRAX CRIS, D30V, DSP16xx, FR - 30, FR - V, Intel i960, IP2000, M32R, 68 HC11, MCORE, MMIX, MN10200, MN10300, Motorola 88000, NS32K, ROMP, Stormy16, , Xtensa, AVR32, D10V, MeP, MicroBlaze, Nios II e Nios, PDP - 10, MSP430, Z8000,etc. O GCC é geralmente um compilador de padrão Unix, onde os utilizadores invocam o comando chamado gcc, que interpreta os argumentos do comando, decidindo qual é a linguagem usada para cada ficheiro de entrada. Tendo os ficheiros identificados, serão produzidos os ficheiros objectos, e logo em seguida faz o link para produzir o ficheiro binário completo [WGC 07]. A grande vantagem deste compilador é grátis e aberto a uma comunidade global que fazem constantemente melhoramentos. Para a geração do relatório recorreu-se ao Miktec 2.6, pois este ferramenta apresenta um conjunto de programas de livre utilização, como o Latex o GnuPlot. A Fox Board já estava presente nas versões anteriores do projecto, sendo este dispositivo uma boa escolha de engenharia para a altura que a versão anterior foi criada pois apresenta um micro controlador (Axis ETRAX 100LX), com 16 Mb de ram e 4 Mb de flash, existindo para comunicação com o exterior duas portas USB, uma porta Ethernet e 48 pinos de entrada e saída. Com estas características temos uma máquina que apresenta o indispensável para o projecto com baixo custo. O problema deste dispositivo é o facto de não apresentar ambiente de desenvolvimento estável, e suporte de depuração sobre Hardware, tornando muito difícil garantir uma qualidade de programação. No momento actual existe no mercado melhores

16 soluções de engenharia, ou seja, existe produtos com o custo mais baixo, apresentando as mesmas características da placa Fox Board, com a vantagem de um melhor ambiente de desenvolvimento, tornando possível fazer depuração directamente sobre a placa usando um emulador. Não sendo do conhecimento do público uma máquina que faça as mesmas características, existem contudo dispositivos que fornecem algumas funcionalidades como é o caso do exemplo mostrado de seguida: Medidor Bosch DLE 150 Professional este dispositivo trata de um medidor laser de grande precisão que apresenta as seguintes características: Medição fácil de comprimentos, superfícies e volumes, tendo o raio de acção até 150 m, a sua operação é simples e intuitiva com mostrador panorâmico, apresenta uma multiplicidade de funções práticas, como por exemplo, medição indirecta de comprimentos, medição contínua, função mínimo e máximo, função de adição e subtracção ou memória. Com a peça terminal universal podem ser efectuadas medições a partir de superfícies, arestas e cantos, apresentando nível com tripé para medir vários pontos [WFB 11].

17 Capítulo 2

Introdução teórica para a realização do trabalho

2.1 Protocolo TCP/IP Um protocolo é uma convenção ou conjunto de regras que máquinas, pessoas ou dispositivo, usam para se poderem entenderem ou comunicar. Em telecomunicações é um conjunto de características físicas ou abstractas pré definidas como o tempo, frequência, largura de banda, tamanho da trama, sequência de bytes, etc. Quando fala-se em protocolo TCP/IP, não se fala de um mas sim de dois protocolos. Como isto pode ser? A interligação entre dispositivos, está organizado por camadas, sendo estas responsáveis por uma determinada tarefa na comunicação, podendo assim detectar mais facilmente problemas ou efectuar melhorias. Como por exemplo, a passagem do protocolo IPV4 para o protocolo IPV6 devido á falta de IP para todos os computadores a nível global, teria sido mais difícil a mudança se não estivesse organizado por camadas. Sendo o modulo OSI (Open Systems Interconnection) o mais utilizado, onde se descreve por sete camadas. A camada Aplicação que representa o software a que a aplicações recorrem para aceder aos recursos da rede. Em seguida temos a camada da Apresentação é responsável por tradução dos dados como por exemplo a encriptação e a desencriptação dos dados. A camada Sessão funciona como elo de ligação entre aplicações permitindo identificar aplicação através da rede, a camada Transporte que tem como tarefa controlar o fluxo da informação é nesta camada que se encontra o protocolo TCP, UDP e outros. A camada Rede é responsável por encaminhar os pacotes de dados através da rede utilizando o IP, sem esta camada os pacotes não chegavam ao seu destino. Funciona em interacção com a placa de rede, que se encontra no nível mais baixo. A camada de ligação tem a

18 responsabilidade para estabelecer a comunicação com a outra máquina, controlar o fluxo de frames , detectar a ocupação ou não do meio de transporte por outras placas, bem como determinar se os frames que passam na rede lhe são destinados, sendo nesse caso aceites e transmitidos ás camadas superiores. Esta camada é dividida em duas partes: LLC e MAC onde os drivers da placa de rede actuam. A última camada é a física que é responsável pelos componentes físicos da rede como tensões, impedâncias, conexões e outros aspectos físicos da rede. O TCP/IP é composto por dois protocolos situados na camada Transporte, o TCP, e pela camada Rede pelo IP. Embora muito usado em LANs, o TCP/IP é um protocolo adequado a WANs, onde este é composto por milhões de máquinas associadas em redes de diversos tamanhos, separados por routers, sendo possível chegar a informação ao destino por múltiplos caminhos. A garantia de integridade, ou seja, a detecção de erros, pedidos de novas transmissão e controlar a sequencia de pacotes a ser recebidos é tarefa do protocolo TCP. O IP é o responsável por identificar as máquinas envolvidas, tendo cada máquina um IP único. As características fundamentares do endereço IP é a existência de identificador de rede e a identificação do hospedeiro. O identificador de Rede é dado pelo o AND entre a mascara e o endereço IP, e o identificador de hospedeiro é dado pelo o AND entre o IP e a mascara negada. Cada rede apresenta um IP de rede, um IP de broadcast, e pelo menos um IP do router se este estiver ligado a outra redes. O IP de rede é identificado por ter o número do hospedeiro igual a zero, é utilizado para a máquina adquirir o seu endereço IP. O IP de broadcast é caracterizado por apresentar todos os bits correspondentes à identificação do hospedeiro a 1 e é responsável por mandar mensagem a todas as máquinas da rede.

19 2.2 Multithreads e mutex O sistemas operativos recentes oferecem suporte multi processos e multi threads para desenvolvidamente de aplicações concorrentes. Com threads, um processo pode ter diferentes partes do seu código executado concorrente ou simultaneamente, com menos overhead comparativo com sistemas multiprocessos . Como as threads de um mesmo processo compartilham o mesmo espaço de endereçamento, a comunicação entre threads torna-se mais rápidos do que processos, contribuindo assim para economizar recursos do sistema e tempo. As threads podem ser criadas através do kernel ou através do user (neste caso o kernel não processa como um conjunto de threads mas sim como um processo único), mas também existe threads híbridas. Todos estes modos têm vantagem de desvantagem a nível de rapidez e complexidade de implementação.

20 Figura 2.1- Esquema da divisão do processo em threads e compartilhamento de recursos [LPM 07].

Como apresenta o esquema anterior, tem-se um processo com várias threads, apresentando em comum variáveis globais, heap, identificadores, sinais, arquivos, temporizadores, etc. Estes recursos comuns necessitam de suporte para garantir a integridade da programação. Em 1995 surgiu o padrão POSIX (Portable Operating System Interface), também designado por Pthreads, tornando mais fácil desenvolvimento. O Pthreads é muito utilizado em Linux (Unix), geralmente em aplicações escritas em Linguagem C. O Pthread utiliza a abordagem de orientação a objectos para representar as suas propriedades, como o tamanho da pilha, politica de escalonamento e prioridade para as threads. Com o Pthread as threads podem ser criadas e eliminadas dinamicamente conforme a necessidade, oferecendo mecanismos de sincronização, como semáforos, mutexes e variáveis condicionais.

Figura 2.2 Esta tabela define os APIs definidos pelo padrão POSIX, mais conhecido por Pthreads [LPM 07].

21 Uma variável condicional permite associar uma variável a um evento, que pode ser, por exemplo, um contador alcançar um determinado valor ou uma flag ser ligado ou desligado. Os semáforos são semelhantes aos mutexes, com a diferença que, enquanto o mutex variar seu valor entre zero e um, os semáforos podem assumir outros valores, permitindo a utilização como contadores. [LPM 07]. Em Windows as threads têm suporte idêntico ao usado em Linux, mas varia um pouco da estratégia comunicação entre threads. A comunicação entre threads no Windows pode-se fazer por mensagens, através de eventos gerados pelo próprio Windows, enquanto no sistema operativo Linux tem-se de recorrer a variáveis globais. Estas diferenças entre Windows e o Linux com as comunicações com o Kernel devem-se ou facto dos dois sistemas Operativos terem arquitecturas de construção diferentes, e a implementação das threads no Linux ficou mais robusta só com o kernel 2.6 . Existem ter dois tipos de implementação de Threads em MFC, as work thread e as Gui Threads. Uma work thread trata-se de uma thread “independente” responsável por fazer um determinada tarefa onde só apresenta praticamente uma mensagem para desligar. As threads GUI utilizam o sistema de mensagem do Windows para coordenar as suas tarefas e haver troca de informação.

22 2.3 Introdução ao ambiente de desenvolvimento Linux.

Comandos Linux Mais Utilizados na linha de comandos

$ pw – ver o utilizador que esta a “trabalhar”. $/home/ramiro – ir para a pasta ramiro $ cp – copiar ficheiro $ man cp – (man) comando help (q) para sair $ ls –al – ver todos os ficheiros encontrados na pasta local $ ls *.rpm – ver todos os ficheiros com terminação rpm $ su – entrar com privilegio de super administrador $ su- – sair de super administrador $ ./ – executar um executável ou um script $alias l= ls – renomear os comandos $ cat dir_ficheiros\egp $gedit debug.h – (gedit) editor $rm –f AFMApp*.o core $ vi (nome do ficheiro) – abrir o editor Vi (:syntax on) para aparecer cores de $chmod 777 (nome do ficheiro)—mudar permissão para autorizar toda a hierarquia. “Ctrl+C” – matar o processo $ssh –l root 192.168.1.90 – aceder á máquina com endereço 192.168.1.90 por ssh $cd /home/afm/devboard-R2_01 – pasta onde se tem que chamar o comando . init_env – Utilizado mudificar as váriaveis, para poder compilar para outra máquina (comando utilizado para poder programar a Fox Board) $cd /home/afm/devboard-R2_01/apps – pasta onde contem os programas para compilar, deve-se chamar o comando make cris-axis-linux-gnu (comando para poder programar a Fox Board) #!/bin/sh – para modar o intrepertrador da shell. $make cris-axis-linux-gnu – este comando é necessário para o “compilador saber” que este código vai ser para outra pantaforma (que está a trabalhar como hospedeiro. $._init-env – serve para inicializar as variáveis para compilar o programa para correr na fox board $ make– para chmar o Makefile $make clean – vai ao Makefile e executa o comando clean

Ficheiro Makefile para compilar o programa AFMReportSenderProcess construído na linguagem c++

AXIS_USABLE_LIBS = GLIBC #AXIS_USABLE_LIBS = UCLIBC GLIBC include $(AXIS_TOP_DIR)/tools/build/Rules.axis

PROGS = AFMReportSenderProcess INSTMODE = 0755 INSTOWNER = root

23 INSTGROUP = root OBJS = ReportSender.o OPTIONS = -D_DBG

LDFLAGS += -lpthread -D_REENTRANT

all: $(PROGS)

$(PROGS): $(OBJS) #$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(CXX) -fno-default-inline $(OPTIONS) $(LDFLAGS) $^ $(LDLIBS) - o $@ cris-strip $(PROGS)

clean: rm -f $(PROGS) *.o core

Script para inicalizar os processos no servidor

#!/bin/sh killall AFMReportSenderProcess killall afm1 killall afm2 echo acabou o Killall

chmod 777 afm1 chmod 777 afm2 chmod 777 AFMReportSenderProcess chmod 600 log.txt ecmv /mnt/1/prog/log.txt /mnt/1/log/oldlog.txt

#colocar a libraria na path export LD_LIBRARY_PATH=/mnt/1/prog/lib

/mnt/1/prog/afm1 & /mnt/1/prog/AFMReportSenderProcess & /mnt/1/prog/afm2& exit 0

24

Tendo este ficheiro na directoria /mnt/1/prog do servidor a correr com o sistema operativo Linux. Só é necessário dentro desta directoria colocar e executar o script, se o ficheiro chamar-se startnow, coloca-se em execução do seguinte modo: ./startnow. Este script é responsável por matar os processos, se estes estiverem em execução, executando-os de seguida.

25 Capítulo 3 O processo AFM1

3.1 Introdução O programa AFM1 é o responsável por realizar os tratamentos dos dados da interface com o utilizador através do servidor ou do cliente, fazendo trocas de dados com um teclado alfanumérico e um ecrã. Como existe uma réplica em ambiente gráfico da interface físico existente no servidor, todo o controlo realizado remotamente pelo servidor pode ser efectuado pelo cliente localmente. Devido a este facto, no programa AFM1 existe concorrência de dados provenientes de dois locais diferentes. Para comunicar os dados com o cliente o código AFM1 recorre a um canal TCP/IP, garantindo assim a fiabilidade dos dados. Este processo é desenvolvido em C e apresenta uma estrutura simplificada. O processo lança uma thread logo ao iniciar o programa, para estabelecer ligação com o cliente, logo que a ligação esteja estabelecida, esta é responsável por fazer a leitura do buffer TCP/IP dos dados provenientes do cliente. Esta thread é lançada no início do programa (processo), e só termina quando o programa(processo) termina. Este processo corre na placa Fox que apresenta um servidor com sistema operativo Linux.

Figura 3.1.-O processo AFM1 é o responsável por o tratamento dos dados provenientes destes dois interfaces. A imagem da esquerda é o controlo da máquina no cliente, réplica em programação do teclado e ecrã físicos existentes no servidor. Imagem à direita mostra a interface do servidor.

26 27 3.2 Descrição da Thread para conexão do Socket a correr no processo AFM1

A thread existente no processo AFM1 é chamada no início do processo, esta é responsável por primeiro conectar e em seguida se a conexão for estabelecida, ler os dados do buffer TCP/IP. Neste processo porque é o primeiro a ser descrito, irá falar detalhadamente da thread lançada pelo processo AFM1. Para iniciar e ter uma conexão TCP/IP, tem-se que adicionar as bibliotecas #include e #include para ter acesso as funções descritas posteriormente. Ao entrar na thread começa-se por iniciar todas as variáveis, em seguida chama-se a função int socket(int domain, int type, int protocol). Esta função tem como primeiro parâmetro o domínio da comunicação o qual o socket vai ser criado, ou seja , utilizando a constante designada por AF_INET neste caso, significa que vai usar o protocolo IP4. O segundo parâmetro é responsável por definir o protocolo TCP ou UDP entre outros, com a utilização da constante SOCK_STREAM define-se que se trata de uma ligação TCP. O terceiro parâmetro define um particular protocolo, que pode ser utilizado com o socket, este parâmetro nos casos normais é sempre zero. A função socket devolvendo um valor menor do que zero, significa que não consegui criar um ponto de ligação , saindo assim da função (como pode constatar no diagrama que se encontra a seguir), se caso se verificar um valor positivo este salta para a função bind.

Em seguida utiliza-se a função bind(int sockfd, struct sockaddr *addr, int addrlen), responsável por atribuir o canal a um endereço físico, para isso utiliza a estrutura struct sockaddr_in que define o tipo de protocolo IP usado (m_ServerAddress.sin_family = AF_INET(que significa que é um IPV4)), identifica o endereço do servidor (m_ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY)), e por último

28 define o número da porta que vai estabelecer a comunicação (m_ServerAddress.sin_port = htons(26000)).

29 Figura 3.2-No esquema seguinte tem-se a função thread responsável por conectar com o cliente e fazer leitura do buffer do TCP/IP.

Connect_thread

Iniciar variaveis Criar socket

Se criado

Sim(>0)

Não(<0)

Atribuir o endereço físico do servidor às variáveis. Fazer o Bind do Socket

Se bind criado Não(<0)

Sim(>0)

Não Listen Accept

Sim

Terminar Thread

Se accept

N<0

N=>0 N= recev (recever os dados)

N>0

30

Se o valor de retorno da função bind , for menor do que zero este sai da thread pois não consegui ligar a conexão a um endereço físico (neste ponto é muito difícil ocorrer um erro) . Se o valor de retorno for igual a zero, a máquina fica em modo listen(m_hListenSocket). Se o listen tiver valor zero, o código fica à espera na função accept(m_hListenSocket,(struct sockaddr *)&m_ClientAddress,&fromlen), esperando por uma conexão de um cliente. Se o cliente estabelecer a comunicação este preenche a estrutura struct sockaddr com os seus dados físicos, e devolve um valor maior do que zero que identifica a comunicação. Estabelecendo uma ligação com o cliente, o servidor (este código) fica á espera da leitura com a utilização da função ssize_t recv(int socket, void *buffer, size_t length, int flags. Sendo o primeiro parâmetro do recv um inteiro, proveniente do retorno do accept que identifica que a ligação que está estabelecida. O segundo parâmetro do recv é o apontador para uma variável, vector ou estrutura onde vai se poder ler os dados transmitidos, o terceiro parâmetro o número de bytes que se pretende ler. O quarto parâmetro normalmente é sempre zero e identifica o tipo de mensagem na recepção. O valor de retorno da função recv identifica o número de caracteres lidos. Se este for inferior a zero, então houve um problema na transmissão, neste caso tenta terminar a comunicação com a função shutdown(m_hConnectSocket, SHUT_RDWR) e a função close (m_hConnectSocket), e logo em seguida faz um break de modo sai fora do ciclo while(1) e tenta fazer uma nova ligação, indo de novo para a função accept.

31 3.3 Descrição global do processo AFM1

Figura 3.3 Representação o esquema do código a correr em paralelo. Ao iniciar o processo o programa AFM1, começa-se por inicializar todas as variáveis, para a utilização no processo. Logo que estejam as variáveis todas inicializadas, este inicia a thread descrita anteriormente, abrindo assim uma conexão com o cliente. Estando a thread lançada, correndo em paralelo com a função main, que em seguida estabelece a ligação com o processo AFM2, criando uma zona de memória partilhada. Para criar uma espaço de memória partilhada, é necessário, em primeiro lugar criar uma chave única que identifique o espaço de memória, isto consegue-se através da função ftok(). Em seguida a função shmget(), cria o espaço de memória, definindo o tamanho e as suas características de acesso. Por último utiliza-se a função shmat() para adquirir-se o endereço da primeira posição, para posteriormente ter acesso recorrendo a um apontador. Como os dois processos são lançados ao mesmo tempo é necessário identificar se a memoria já foi criada, e se já foi criada, esta abre como cliente.

32

Este código encontra-se-se nos programas AFM1 e AFM2,e é responsável por criar a memória partilhada para comunicação entre processo AFM1 e AFM2. //key identify the memory /* Create unique key via call to ftok() */ key = ftok(".", 'S'); /* Open the shared memory segment - create if necessary */ if((shmid = shmget(key, SEGSIZE, IPC_CREAT|IPC_EXCL|0666)) == -1) { printf("KEY Shared memory segment exists - opening as client\n"); if( (int)(shmid = shmget(key, SEGSIZE, 0)) == -1) { perror("shmget"); exit(1); } } else { printf("KEY Creating new shared memory segment\n"); }

/* Attach (map) the shared memory segment into the current process */ if( (int)(status_data = shmat(shmid, 0, 0)) == -1) { perror("shmat"); exit(1); }

Estando tudo inicializado, o programa AFM1 é responsável por ler os valares do teclado alfanumérico, ou ler os valores provenientes da ligação com o servidor, fazendo o tratamento dos dados e posteriormente coloca-los na memória partilhada para o programa AFM2. O programa AFM1 também é responsabel por ler os dados relativos ao display, proveniente da memória partilhada, apresentando- os no display e envia-os para o cliente, se estiver conectado.

33

Figura 3.4. Apresentação global das funções, variáveis e estruturas do processo AFM1.

Na figura anterior pode-se ver todas as funções que fazem parte do processo AFM1, pode-se verificar que quase todas as funções auxiliares faz correspondência ao LCD, ou ao ler do botão, as restantes funções servem como auxilio, para o processo conseguir fazer o desejado.

3.4. A função read_botton

Figura 3.5. Função read_button()

A função read_button começa por verificar se existe uma entrada, dos dados provenientes dos botões existentes no servidor. Se

34 existir, a função read_botton chama a função command_push(), para introduzir o valor na fila, este valor também é introduzido através da thread a correr neste processo , que recebe os comandos proveniente do cliente. Ao sair da função read_button(), chama a função command_pop() para dar entrada de um comando dos botões que existe na fila. A construção de uma fila neste caso é a melhor opção, pois em caso contrario receber informação de dois lugares concorrentes, podia-se perder informação, ou podia-se perder o controlo da ordem correcta.

Esta função é responsável por colocar os dados vindos clientes ou servidor numa fila. Estes dados são das entradas dos botões. void command_push(char f_ent) {

pthread_mutex_lock (&job_queue_mutex); *queue_p=f_ent; queue_p++; pthread_mutex_unlock (&job_queue_mutex); return; }

Esta função serve para poder ir buscar o primeiro elemento da fila colocado pela função commaand_push. char command_pop (void) { int i=0; char q; char * f_p = filaCommand; pthread_mutex_lock (&job_queue_mutex);

if (queue_p != filaCommand)//esta vazia {

q=*f_p;

while(f_p != queue_p) { filaCommand[i]=filaCommand[i+1]; f_p++; i++; }

queue_p--; pthread_mutex_unlock (&job_queue_mutex);

35 return q; } pthread_mutex_unlock (&job_queue_mutex); return 0; } Capítulo 4

36 O processo AFM2

4.1 Introdução Este processo é responsável por tratamento dos dados proveniente do processo AFM1, com estes dados o processo AFM2 actua na leitura dos sensores. E se for a vontade do utilizador este começa a criar um ficheiro com extensão dat, com os valores de todos os sensores, de um intervalo de tempo entre eles definido, e durante um determinado período de tempo. Os ficheiros de extensão dat servem para posterior geração de relatório. Este processo foi desenvolvido em linguagem c. Neste processo não é lançada nenhuma thread, faz ligação só com o processo AFM2 através da memória partilhada. Este processo corre na placa Fox, que apresenta um servidor com sistema operativo Linux.

4.2. Descrição global do processo AFM2

Figura 4.1. Funções e variáveis globais existentes no processo AFM2.

37 Como se pode verificar pelas funções existentes no processo AFM2, este processo é responsável pelo controlo dos módulos acoplados ao servidor. Os módulos fazem comunicação via I2C com o servidor, pode-se verificar, observando a figura 4.1 com as funções começadas por i2c_. Neste processo para seleccionar o modulo pretendido, recorre à função mux_select() que controla a placa de multiplexer existente no servidor. È na função main onde se cria os ficheiros de extensão dat.

38 Capítulo 5 O processo ReportSender

5.1 Introdução

Este processo é responsável por fazer a transferência dos ficheiros de extensão dat, para o cliente para posterior geração do relatório, e por recepção do ficheiro de calibração dos sensores, proveniente do cliente. Este processo corre no servidor, e foi desenvolvido em c++. Este processo lança uma thread como o processo AFM1, para estabelecer uma ligação, para conexão TCP/IP com o Cliente (programa a correr em Windows). A ligação feita para transferência de ficheiros não é a mesma que o processo AFM1, garantindo assim robustez no programa.

5.2. Descrição global do processo ReportSender

Figura 5.1.Constituição do processo ReportSender. Apresentação das estruturas (struct) a rosa, apresentação da classe CReportSender a azul, apresentação da variáveis e da função global.

Este processo começa por definir o buffer, com o tamanho 3*(MTU-m_IP_HEADER_SIZE) para poder transferir o ficheiro via TCP/IP sem perda de dados.

39 MTU (MAximum Trasmit UNit, Unidade Máxima de transmissão) é o maior datagrama de o protocolo TCP/IP, sem que este se divida a transmitir na rede. Depois de ter criado o buffer, o processo cria uma ligação TCP/IP, para fazer comunicação com o cliente, para transferir os ficheiros de extensão dat. E faz recepção do ficheiro de calibração e dos pedidos de transmissão através da função main . Se o socket(ligação TCP/IP) foi criado com sucesso, o processo cria uma thread para enviar os ficheiros. O esquema do processo pode ser visto na figura a baixo.

40

41 5.3. Apresentação da programação do processo ReportSender.

Como se inicia uma tread: Ficheiro h private: static void * ThreadFunction(void *arg); //esta função tem que ser global static pthread_t m_ThreadID; pthread_attr_t * m_pThreadAttribute;

Ficheiro cpp No inicio do cpp (para fazer a declaração): pthread_t CReportSender::m_ThreadID;

//A função tem que conter esta estrutura: void *CReportSender::ThreadFunction(void *arg) { CReportSender * pThis = (CReportSender*)arg; return NULL; }

Para inicializar a função, faz da seguinte maneira: if( pthread_create(&m_ThreadID,m_pThreadAttribute,ThreadFunction,(void*)this) ) { cout << "CReportSender thread creation failed" << endl; return false; }

Iniciar os parâmetros para criar Tread: Inicialização no constructor: : m_pThreadAttribute(NULL)

No Destrutor: if(m_pThreadAttribute) pthread_attr_destroy(m_pThreadAttribute); EndSock();

// A função EndSock: void CReportSender::EndSock(void) {

::shutdown(m_hConnectSocket,SHUT_RD); ::shutdown(m_hConnectSocket,SHUT_WR); ::shutdown(m_hConnectSocket,SHUT_RDWR); ::close(m_hConnectSocket); m_hConnectSocket = -1; }

As threads são fundamentais para o programa fazer tarefas em paralelo. Com o exemplo do código anterior pode-se criar threads em Linux.

42 MUTEX

public: pthread_mutex_t m_ReportAccessLock;

Iniciar no constructor o mutex: //{ pthread_mutex_init(&m_ReportAccessLock,NULL); //}

Destroir no destructor o mutex pthread_mutex_destroy(&m_ReportAccessLock); Iniciar o lock de um mutex dentro de Tread pthread_mutex_lock(&(pThis->m_ReportAccessLock)); O this tem que ser iniciado dentro da tread, pois as treads são globais (a tread é static). Para fazer o unlock do mutex pthread_mutex_unlock(&(pThis->m_ReportAccessLock));

Quando utiliza-se threads è necessário utilizar Mutex, estes são indispensáveis para os dados não ficarem corrompidos. Quando se constrói um programa, è boa programação utilizar os mutex no estado luck no menor tempo possível, pois estes são responsáveis pelo mau desempenho do programa. Se uma thread esta lock e depende de outras treads e não passar a unlock, o programa encontra-se encravado (bloqueado). Quando aparece a função pthread_mutex_lock(&(pThis>m_ReportAccessLock)); e noutro lugar tenha um lock já efectuado o programa fica neste ponto á espera que se faça o unlock. A pergunta que qualquer programador se deve fazer ao colocar o mutex “se a integridade esta garantida”.

43 Como utilizar uma lista: No ficheiro h Como se define vários tipos de listas public: typedef std::list CommandRequestList_t; typedef std::list ReportRequestList_t;

Definir uma variavel para a lista public: CommandRequestList_t m_ReceivedCommandBuffer;

Função para adquirir um elemento da lista CommandPkt * GetCommandTop(void) { CommandPkt * cmd;

if ( !m_ReceivedCommandBuffer.empty() ) //verifica se a lista esta vazia cmd= NULL; else { //pthread_mutex_lock(&m_CommandAccessLock); cmd = m_ReceivedCommandBuffer.front(); //vai buscar o elemento do topo //pthread_mutex_unlock(&m_CommandAccessLock); m_ReceivedCommandBuffer.pop_front(); //retira o elemento do topo da pilha } return cmd; //devolve o elemento }

Função para colocar valor na lista. void SaveCommand(CommandPkt_t *pkt) { pthread_mutex_lock(&m_CommandAccessLock); m_ReceivedCommandBuffer.push_back(pkt); //inserir valor na lista pthread_mutex_unlock(&m_CommandAccessLock); } As listas são necessárias para desenvolvimento mais rápido do código e para melhor estruturação. È utilizado no código para armazenamento dos dados a transmitir.

Socket: (servidor para linux)

No ficheiro h // variaveis para o socket public: int m_hConnectSocket; //struct sockaddr_in * m_pClientAddress; No ficheiro cpp Iniciar variável no construtor

44 : m_hConnectSocket(-1), //m_pClientAddress(NULL),

Iniciar o socket int m_hListenSocket; struct sockaddr_in m_ServerAddress; struct sockaddr_in m_ClientAddress; m_hListenSocket = socket(AF_INET, SOCK_STREAM, 0); if (m_hListenSocket < 0) { cout << "cannot create listen socket: 1702\n"; return false; } //Bind listen socket to listen port m_ServerAddress.sin_family = AF_INET; m_ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY); m_ServerAddress.sin_port = htons(1702);

if (bind(m_hListenSocket,(struct sockaddr *) &m_ServerAddress,sizeof(m_ServerAddress)) < 0) { cout << "cannot bind socket: 1702" << endl; return false; }

// Wait for connections from clients. listen(m_hListenSocket, 5); //check if SOMAXCONN=5 will be acceptable

for( ;m_hConnectSocket < 0; ) { //Accept a connection with a client that is requesting one. socklen_t fromlen = sizeof(m_ClientAddress); m_hConnectSocket = accept(m_hListenSocket,(struct sockaddr *)&m_ClientAddress, &fromlen); //Fica no ac //Neste momento encontra-se ligado pela porta 1702

cout << "Aceitei conexao 1702: m_hConnectSocket: " << m_hConnectSocket << endl;

if (m_hConnectSocket < 0) { cout << "cannot accept connection 1702 " << endl; return false; } //Show the IP address of the client and the client's port number cout << " connected to " << inet_ntoa(m_ClientAddress.sin_addr); cout << ":" << ntohs(m_ClientAddress.sin_port) << endl; }

Enviar pacotes if( (nBytes = send(m_hConnectSocket,pPkt,len,0) )<0 ) cout << "cannot send the packet" << endl; else cout << "Escreveu: " << nBytes << endl;

45

Recepção dos dados n += recv(report.m_hConnectSocket, rcv_msg+nReceived, nNeededTo, 0); //incrementa os dados que recebe

Para a comunicação entre várias máquinas utiliza-se os sockets para ligações TCP e UDP. Esta implementação é utilizada para estabelecer ligação com o programa App (o cliente a correr no sistema operativo Windows).

Singleton:

No ficheiro h public:

static CBoxController * GetInstance(void) { //return &m_BoxController; if (!m_BoxController) m_BoxController= new CBoxController(); return m_BoxController; }

private: static CBoxController *m_BoxController;

CBoxController();

No ficheiro Cpp CBoxController::CBoxController() { } Uma classe Singleton serve para só criar uma variável de uma determinada classe, isto é feito recorrendo a uma função chamada GetInstance () que utiliza uma variável statica para poder aceder ao construtor só uma vez, onde está declarado como privado.

Os ficheiros:

A forma de aceder a ficheiro em Linux é feita de acordo com o padrão utilizado em c e c++. Utilizando a classe FILE para fazer leitura e escrita.

46 Verificar se existe uma pasta, ir buscar os ficheiros dentro dessa pasta, e verificar o tipo de ficheiro existente // identificar path da directoria. const char CReportSender::m_ReportDirectory[20] = "/mnt/1/results";

int CReportSender::SearchDir4MatchingFiles(ReportPkt_t *request) { int nFiles = 0;

DIR* dir = opendir(m_ReportDirectory); if(dir == NULL) {// se a directoria não existir cout << "Can not open directory '" << m_ReportDirectory << "'\n"; return -1; } cout << "directory '" << m_ReportDirectory << "' opened ok\n"; struct dirent *d; while( (d = readdir(dir)) != 0) // guarda todos os ficheiros queue. { string str(d->d_name); if( d->d_type == DT_REG && DoesDataMatch(request,str) ) // verifica se o ficheiro é do tipo DT_REG (tipo txt) e a função DoesDataMatch verifica se o cabeçalho è valido, verificando se a data esta dentro dos limites. { nFiles++; m_FNameRequestPool.push(str); } } closedir(dir); return nFiles; } O código anterior é utilizado para abrir um directório utilizando a função opendir(), e em seguida ler os ficheiros existentes dentro do directório utilizando a função readdir().

47 48 Capítulo 6 Controlo, monitorização e transmissão de dados no cliente.

6.1 Introdução Esta parte do código é responsável por enviar comandos para o servidor, receber as tramas vindo do servidor para o ecrã virtual, receber e eliminar os ficheiros existentes no servidor para a geração de relatório. Os comandos são enviados ao pressionar os botões existentes na Dialog utilizando Skins para a sua criação. O ecrã apresenta a recepção da trama, proveniente do servidor por o protocolo TCP/IP, apresentando um espaço para oitenta caracteres, ou seja, quatro linhas de vinte caracteres. O pedido de transmissão dos ficheiros é feito através do botão OK existente na primeira caixa de diálogo (DialogBox). A interacção gráfica das funções descritas atrás é ilustrada na figura 1.5 do lado esquerdo.

6.2. Descrição Controlo, monitorização e transmissão de dados no cliente.

Figura 6.1.Classes para controlo, monitorização e transmissão de dados.

49 O programa começa por iniciar o construtor CAppDlg e em seguida invocar a função OnInitDialog(). A função OnInitDialog é a recomendável para iniciar todos os passos à configuração da caixa de diálogo. Logo ao iniciar o programa, tem-se a thread (SocketClientConnectThread() a iniciar dentro da função OnInitDialog(), sendo responsável por fazer a conexão do cliente com os processos AFM1 e ReportSender. Quando uma conexão é criada, a thread utiliza a função PostMessage() para enviar uma mensagem, onde a sua recepção é feita através da função OnThreadEvent(). Esta thread só termina a execução quando se estabelece as duas conexões e se por algum motivo houver uma desconexão, desencadear-se-á um evento que faz com que esta thread entre outra vez em execução, repondo a ligação ou ligações. Existindo um evento, de ocorrência de conexão com o programa ReportSender, o programa App cria uma nova thread, cuja a função associada è SocketCommandsReadThread, sendo está responsável pela recepção e gravação em ficheiro, dos pacotes proveniente do processo ReportSender a correr no servidor. A quando da ocorrência de um evento, o programa cria uma nova thread cuja função de suporte é SocketCommandsReadThread(), responsável pela recepção das tramas para o LCD virtual existente no interface gráfico do programa App (figura 1.5 lado esquerdo). Estas tramas apenas são transmitidas para o cliente quando diferem da trama anterior, fazendo com que não se gaste mais recursos do que os necessários, para a transmissão de dados via TCP/IP. Todos os eventos gerados ao pressionar os botões no programa App, para transmissão via TCP/IP para o servidor, é feito na própria função associada ao botão, isto porque são transmissão de pedidos, onde o tamanho de dados é muito pequena e de rápido tratamento, sendo mais moroso e complexo criar outros mecanismos para chegar ao mesmo fim.

50 O esquema de execução das threads descritas neste teste através da figura 6.2.

Figura 6.2. Representação das threads criadas no programa App.

6.3. Apresentação da programação do programa App.

Adicionar bibliotecas e ficheiros LIB aos projectos

Adicionar livrarias: ToolsÆoptions (depois)Ædirectories *adiciona-se em «include Files» os ficheiros *.h *adiciona-se em «library» Files os ficheiros *.lib

O compilador necessita de conhecer o caminho para os ficheiros a incluir no projecto. A organização de ficheiros num projecto que apresenta várias dependências pode-se tornar moroso e complicado. try // se quando tenta estabelecer a ligação ocorrer um erro salta de imediato para a função //catch se estabelecer a ligação sai do programa através do comando break. while (true) { try { // escreve aqui o código como o seguinte CSock *temp = new CSock( ip,CReportReceiver::REPORTS_PORT);

51 break; } catch(...) // se não conseguir estabelecer a ligação espera 500 mil segundos { Sleep(500); } } Este comando é utilizado em c++ e serve para fazer tratamentos de excepções, ou seja, quando ocorrer uma excepção o programa dá um caminho alternativo, não necessitando assim de abortar o programa. Este comando é utilizado quando estabelece a ligação com o servidor, se a ligação não for feita ocorre uma excepção.

CString

CString csName; while ( csName.IsEmpty() ) //verifica se a string esta vazia. csName = _T('?'); // esta a introduzir um carácter na csName csName = _T(“Introduzir texto” ); “encontra-se a introduzir texto. csName.Format("O valor é = %d",valor);

A classe CString é idêntica á classe string utilizada em c++, esta é implementada em Visual c++ e apresenta mais funcionalidades.

Copia de memória.

memcpy(ToTreeView,rcv_msg,21); // 1 parâmetro destino 2 parâmetro origem 3 numero de bytes a ser transmitidos.

Esta função serve para fazer cópia de variáveis completas de forma simples, rápida e eficaz. Esta função è muito utilizada no programa para fazer copia das tramas da rede para as respectivas variáveis.

Caixa de dialogo com resposta

answer = AfxMessageBox("File already exists.\nDelete the existing file?",MB_YESNO); if(answer == IDYES)

Esta função serve para enviar mensagens, através de janela de uma forma simples e rápida, podendo apresentar uma resposta simples como ‘Yes’, ‘No’, Cancel’,etc.

52 Para atualização dos valores de entrada da DialogBox UpdateData(true); //Manipular aqui o código para actualizar as variáveis UpdateData(false); Quando necessita-se de ler os valores que o utilizador colocou no interface gráfico, tem-se de actualizar as variáveis, e isto faz-se através das funções anteriores.

Para inicializar alguma função ou variável, acrescenta-se na função OnInitDialog(): BOOL CSimpleClienteDlg::OnInitDialog() { …. ….

// TODO: Add extra initialization here //Adicioanr aqui as variáveis ou funções

return TRUE; // return TRUE unless you set the focus to a control } As variáveis podem-se inicializar nesta função ou no construtor, as funções também podem ser inicializadas no construtor mas para isso já tem que ser um programador experiente (neste caso tem-se implicação que os gráficos não se encontram inicializados), sendo assim aconselhável inicializar na função OnInitDialog().

Para encontrar (Search) ficheiros, numa determinada pasta (qualquer tipo de ficheiro) (procura via código) A classe CFileFind tem muitas propriedades interessantes e úteis para ficheiros. Declaração das variáveis CFileFind fSearch; char directoria[30] = "c:\\alta\\reports\\"; char name[20] = "5114afm2a.pdf";

Encontrar ficheiro nome_total.Format("%s%s",directoria,name); if(fSearch.FindFile(nome_total))//Existe o pdf...abri-lo { MessageBox(“Existe ficheiro”); } Para procurar a existência de um ficheiro numa determinada pasta, utiliza-se esta função. Utiliza-se esta parte do código, para procurar se já foi gerado o ficheiro pdf de um determinado ficheiro.

Trabalhar com ficheiros CFile File;

53 if(!File.Open( file_dir_and_name, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone | CFile::typeBinary)) { AfxMessageBox("Impossivel criar ficheiro...abortar"); p->PostMessage( p->UWM_THREADEVENT, CCommandSender::FSE_STATUSDISCONNECTED, 0L ); return 1; } Em VisualC++ existe uma classe própria para trabalhar com ficheiros. Essa classe chama-se CFile. Depois da recepção dos pacotes, o programa guardas os dados em ficheiros utilizando esta classe.

Treads

Ficheiro h

public: static UINT SocketCommandsReadThread(LPVOID pParam); // iniciado no (.h)

//Defenição da função para recepção de mensagem private: afx_msg LRESULT OnThreadEvent(WPARAM, LPARAM);

// para criar uma variavel do tipo CCommandReceive class CCommandReceive; class CAppDlg : public CDialog { // inicialização public: CCommandReceive m_CommandReceiveObj; }

// Ficheiro cpp

//para iníciar a tread. afx_msg LRESULT CAppDlg::OnThreadEvent(WPARAM wParam, LPARAM lParam) { …. AfxBeginThread(m_CommandReceiveObj.SocketCommandsReadThread,this, THREAD_PRIORITY_NORMAL); …. }

Esta thread é inicializada dentro de um função de eventos do Windows, sendo só criada depois de acontecer um determinado evento.

54 UINT CCommandReceive::SocketCommandsReadThread(LPVOID pParam) { CAppDlg *p = (CAppDlg*)pParam; // para poder aceder aos parâmetros da classe

…. return 1; }

Função que vai correr em paralelo com o resto do programa.

Prioridades das treads • THREAD_PRIORITY_TIME_CRITICAL • THREAD_PRIORITY_HIGHEST • THREAD_PRIORITY_ABOVE_NORMAL • THREAD_PRIORITY_NORMAL • THREAD_PRIORITY_BELOW_NORMAL • THREAD_PRIORITY_LOWEST • THREAD_PRIORITY_IDLE

Para comunicar entre treads através de mensagens do Windows.

Definição da mensagem a enviar static const int FSE_STATUSDISCONNECTED; const int CCommandSender::FSE_STATUSDISCONNECTED = 2;

Utilização da função PostMessage para envio de mensagem. //ter acesso a classe dentro da tread p->PostMessage( p->UWM_THREADEVENT, p->m_CommandReceiveObj.FSE_STATUSDISCONNECTED, 0L );

declarar como uma mensagem do Windows BEGIN_MESSAGE_MAP(CAppDlg, CDialog) //{{AFX_MSG_MAP(CAppDlg) … //}}AFX_MSG_MAP ON_REGISTERED_MESSAGE( UWM_THREADEVENT, OnThreadEvent ) END_MESSAGE_MAP()

O código anterior mostra todos os passos que se tem de efectuar para criar uma thread e a comunicação entre threads através de mensagens. Qualquer boa programação com interface gráfica recorre a threads!

55

Ficheiros necessários para o socket do cliente

Ficheiros para incluir no socket.

Figura 6.3- Apresentação dos ficheiros de adição ao projecto, para criar um Socekt.

Ficheiro h public: CSock *pConnSock; Ficheiro cpp

Abrir uma nova ligação m_CommandReceiveObj.pConnSock = new CSock( "192.168.1.90", 1700);

Ler valores n += m_CommandReceiveObj.pConnSock->Read(rcv_msg+nReceived,nNeededTo);

Enviar valores int CCommandReceive::SendCommandPacket(CommandPkt_t *pack) { return pConnSock->Write(pack,3); // envia valor }

Desconectar delete m_CommandReceiveObj.pConnSock; Para fazer comunicações entre máquinas distintas através de TCP ou UDP é necessário recorrer à classe CSockt.

Como criar uma DialogBox nova, adicionando a uma classe:

(i)ResourceÆ(d) (MRB)DialobÆ (MRB)ÆInsert dialog (op) proprieties para alterar o nome. CTRL+WÆ Messages(DoModal)ÆAdd class (NEW) Æ Name “nome da classe”; Base class (CDialog); Dialog ID “escolher as opções disponíveis”.

Chamar a nova DialogBox …. CNovaDialog Novadialog; // define a variável para a nova classe Novadialog.DoModal(); //chama a nova classe. ….

56 Grande parte dos projectos são criados com mais de que uma DialogBox, para maior simplificação e facilidade de aprendizagem. Neste projecto faz-se a criação de uma nova DialogBox para a calibração dos sensores.

Trabalhar com TreeView:

Verifica se existe elemento na lista (se não tiver devolve NULL) HTREEITEM hItem = pTreeCtrl->GetRootItem(); //(Lista de elementos inseridos) se não houver elemento na lista devolve NULL.

Verifica e adquire o próximo elemento da lista hItem = pTreeCtrl->GetNextVisibleItem(hItem);

Insere elementos numa treeview char str_to_tree_view[25]; pTreeCtrl->InsertItem(str_to_tree_view,TVI_ROOT,TVI_LAST);

Quando pretende-se apresentar grande quantidade de dados de forma organizada, recorre-se á Tree View para interacção com o utilizador. No programa App utiliza três TreeView para apresentação dos dados.

Ir buscar um caminho (path) de uma pasta via rato, aparecendo uma dialogBox

void CSettingsWnd::OnPathButton() { BROWSEINFO bi = { 0 }; bi.lpszTitle = _T("Please select location for recording"); LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if(pidl != 0) { // get the name of the folder TCHAR path[MAX_PATH]; if(SHGetPathFromIDList(pidl, path)) { if(IsWindowVisible()) { m_PathEdit.SetWindowText(path); } }

// free memory used IMalloc * imalloc = 0; if(SUCCEEDED(SHGetMalloc(&imalloc))) {

57 imalloc->Free(pidl); imalloc->Release(); } } } Para aceder a ficheiros que são responsabilidade do utilizador, utiliza-se as funções descritas atrás, esta função abre uma janela onde o utilizador escolhe o ficheiro, devolvendo o seu caminho.

58

59 Capítulo 7 Geração do relatório.

7.1 Introdução

Este capítulo descreve a geração do relatório contido no programa App. O relatório è essencial para melhor visualização e interpretação dos dados, por parte do operador do sistema. O relatório é gerado no formato pdf, apresentando os gráficos e as estatísticas das características físicas da espuma. Os gráficos apresentam as curvas de evolução das características lidas pelos vários sensores, ao longo de oito horas, sessenta minutos, e vinte minutos. Existindo seis sensores distintos em todo o sistema. Dois medem a temperatura e humidade ambiente respectivamente, e quatro sensores medem as características da espuma de poliuretano, onde é calculado a estatísticas de parâmetros diferentes de acordo com cada sensor. Sensor de temperatura:

Figura 7.1.Gráfico de evolução da temperatura presente no relatório.

60

61 Para o sensor de temperatura, são apresentadas as seguintes estatísticas: Temperatura inicial e respectivo tempo, temperatura máxima, mínima, de retorno e os respectivos tempos associados, variação máxima e variação de retorno da temperatura.

Figura 7.2.Características de evolução da temperatura.

Sensor de altura:

Figura7.3.Gráfico de evolução da altura.

Para o sensor de altura, são apresentadas as seguintes estatísticas: Altura inicial e respectivo tempo, altura aos dez minutos, aos trinta minutos, aos sessenta minutos, percentagem de variação de altura aos dez, trinta e sessenta minutos e percentagem de variação total em relação ao valor inicial.

62

Figura 7.4.Características de evolução da altura.

Sensor de pressão:

Figura 7.5.Gráfico de evolução da pressão.

As estatísticas para o sensor de pressão são: Pressão inicial e respectivo tempo, pressão máxima e tempo associado, pressão a dez,e a cinquenta por cento do máximo e respectivos tempos antes (50’ e 10’) e depois(50 e 10) do ponto máximo .

Figura 7.6. Características de evolução da pressão.

63 Sensor da medição da constituição da espuma:

Figura 7.7.Gráfico de evolução da constituição da espuma.

Para o sensor de medição da constituição da espuma são apresentadas as seguintes características: capacidade mínima, máxima e de retorno e respectivas temperaturas, e por último é apresentado o maior grau de inclinação da recta tangente ao gráfico.

Figura 7.8.Características de evolução da constituição da espuma.

64 A vantagem de o Latex e o GnuPlot è que estes apresentam uma licença free, podendo-se replicar a máquina sem custos adicionais em relação ao software. Outra vantagem do Latex e GnuPlot é que são linguagem “compiláveis” utilizando comandos e scripts para geração de resultado final e fundamentalmente o controlo do seus programas pode ser feito através de um terminal, podendo ser integrado num programa (tornando todo o sistema automático).

65 7.2. Como o utilizador inicia a geração do relatório. A geração do relatório é iniciada com o seleccionar do ficheiro que se pretende gerar, presente na TreeView existente no programa App, onde posteriormente aparece uma caixa de diálogo para pedir confirmação. Ao longo da geração do relatório, é apresenta uma barra de progresso, que identifica a fase da geração do relatório. Se o relatório já estiver gerado, ao precionar no ficheiro na TreeView, é apresentado de imediato o relatório em formato pdf

Figura 7.9. Geração do relatório AFMx16032007x081654xM2.pdf.Por cima da TreeView encontra-se a barra de progresso, responsável por saber o estado do relatório.

66 7.3 O programa GnuPlot.

Durante a geração do relatório, utilizou-se os comandos GnuPlot como poderosos comandos para a geração de gráficos. Estes comandos apresentam inúmeras alternativas, onde neste texto se falará dos comandos utilizados neste projecto. O plot pode receber dados de um arquivo e fazer a geração do respectivo gráfico. Exemplo de um arquivo de nome teste.dat. #O ficheiro teste.dat 1 10.3 2 12.5 3 15.6 4 20.2 Como se pode verificar este ficheiro apresenta um comentário, que é identificado pelo carácter ‘#’ no início da linha. De seguida o ficheiro apresenta duas colunas, onde a primeira corresponde ao eixo dos ‘X’ no gráfico e a segunda corresponde ao eixo dos ‘Y’. Como se pode reparar no arquivo exemplo, os pontos estão separados por TABS e as casas decimais estão separadas por pontos. Se não fosse feito desta forma o programa GnuPlot não conseguiria identificar as respectivas colunas. Se o ficheiro teste.dat se encontrar no mesmo directório do executável GnuPlot, utiliza-se o comando plot “teste.dat” para geração do gráfico. Se no ficheiro tivesse uma terceira coluna correspondente ao erro, este poderia aparecer no gráfico da seguinte maneira: plot “teste.dat” with yerrorbar. Arquivos de automação no GnuPlot , são arquivos que contém uma sequência de comandos que serão executados pelo próprio. O formato deste arquivo segue a lógica de entrada de comandos no próprio GnuPlot , ou seja, os comandos de definição da aparência do gráfico, limites do gráfico, definições de funções, ajustes de funções, definições de tipos de saída de arquivo, nome de arquivos, dentre outros, estes devem ser especificados antes do comando para

67 desenhar o gráfico. Um exemplo de um arquivo deste tipo pode ser visto a seguir:

68 # script

set term postscript color set output "teste.ps" set encoding iso_8859_1 set title "Geração do relatório" set ylabel "Sensor em y" set xlabel "Tempo em x" set key outside f(x) = a*x**2 + b*sin(x) FIT_LIMIT = 1e-15 fit f(x) "variaveis.dat" via a, b plot "teste.dat" with points ps 10 , f(x) with lines 1

Neste script começa-se por definir, que o gráfico vai ter uma apresentação a cores num ficheiro com nome teste.ps, ou seja, muda o terminal para este tipo. Se operador não especificar a saída dos dados este aparecem no terminal da linha de comandos, sendo importante apresentar os dados em ficheiros (para este projecto). O comando “set encoding” identifica a letra para escrita do título e nomes do eixo do X e do Y, que são introduzidos pelos 3 comandos em seguida, o ficheiro iso_8859_1 permite colocar nomes com acentos. O comando “set key outside” posiciona as legendas no gráfico. A função f(x) = a*x**2 + b*sin (ax2 + bsen(x) )apresenta as constantes a,b que são declaradas no ficheiro variaveis .dat, a sua atribuição é feita com o comando fit f(x) "variaveis.dat" via a, b. O limite de ajuste da função é dado pelo comando FIT_LIMIT = 1e-15. O plot descrito no script faz a apresentação de dois gráficos, um proveniente dos pontos presentes no ficheiro teste.dat e outro da função definida anteriormente. No projecto desenvolvido não apresenta um gráfico de uma função predefinida, mas de geração de um gráfico a partir de um ficheiro. Neste trabalho cria-se vários e diferentes scripts, o primeiro serve para fazer divisão dos dados, em seguida filtragem e interpolação dos dados, só por último é que tem-se o script para geração dos gráficos.

69 7.4 Introdução ao Latex. No processador de texto da Microsoft, o Word, tudo o que o operador escreve e vê é o que aparece como resultado final. No Latex funcionam de maneira diferente, este utiliza comandos (símbolos especiais começados pelo carácter ‘\’ que identifica o tipo de letra, a formatação, a posição do texto, a colocação de caracteres especiais, etc) para geração de um ficheiro que posterior vai ser interpretado (“compilado”) pelo programa que se dá o nome de latex, para gerar o resultado “igual” ao Word. Este programa é muito utilizado para escrita de fórmulas matemáticas, devido à apresentação e à diversidade de criação da formulação. Para criar um ficheiro pdf através de um ficheiro Latex passa por várias fazes: Primeiro tem-se de criar um ficheiro de extensão tex, como por exemplo o ficheiro teste.tex. Este ficheiro apresenta uma certa estrutura organizacional, como qualquer ficheiro que é compilado, ou interpretado. Tendo o ficheiro de extensão tex e o latex instalado, recorre-se à linha de comando DOS, na pasta onde se encontra o programa instalado digitando “latex teste.tex”, e será gerado um ficheiro de extensão dvi. De seguida com o ficheiro dvi pode ser gerado o ficheiro postscript e posteriormente para pdf. Outra forma de gerar os ficheiros pdf é a partir do ficheiro de extensão tex. A baixo pode ver um esquema tirado do tutorial “Breve Introducâo ao LATEX2”[LNB 00]

Figura 7.10 Possíveis caminhos para geração de do ficheiro pdf, a partir do ficheiro tex.

70 71 7.5 Descrição da programação de geração do relatório no programa App.

O código correspondente à geração do relatório, começa por carregar as características do relatório “settings”, através da chamada da função initEnvironment() da classe GlobalSettings, dentro da função OnInitDialog() do programa App. Para a geração do relatório, o utilizador selecciona o ficheiro na TreeView, o que desencadeia a execução da função OnDblclkLogTree(). A função OnDblclkLogTree() é responsável por adquirir o nome que fora seleccionado, e fazer a conversão do nome, para que esta seja procurado na pasta. Antes da geração do relatório é verificado se existe o ficheiro em formato pdf, em caso afirmativo apresenta-se de imediato o ficheiro pdf. Caso contrário é apresentado uma caixa de diálogo a perguntar se pretende gerar o relatório. Se for a vontade do utilizador a função OnDblclkLogTree() lança a thread GenerateReportThread para a geração do relatório (ver figura 6.2). No interior da thread GenerateReportThread() é inicializado a barra de progresso. Esta è responsável por apresentar o estado da geração do relatório ao utilizador, e em seguida é chamada a função generateReport() da classe ReportGenerator para começar a geração de relatório.

72

Função responsável por seleccionar, controlar e gerar relatórios através ficheiros. void CAppDlg::OnDblclkLogTree(NMHDR* pNMHDR, LRESULT* pResult) {

if( ( nRet = m_LogTree.HitTest( pt ) ) != NULL ) { // nRet is the index of the item we hit. char nome_ficheiro[27]; char nome_ficheiro_pdf[27];

item_selected = m_LogTree.GetItemText( nRet); GetnamefromTreeView(item_selected,nome_ficheiro);

//Vou verificar se já existe um pdf gerado...se existir, apresenta-o...se não gerar relatório CFileFind fSearch; char directoria[30] = "c:\\afm\\report\\"; //Buscar a classe para geração de relatório

CString parametros_total; //Apenas para testar a abertura de um pdf...este valor dependerá do nome do pdf...virá da informação do double-click

datconverttopdf(nome_ficheiro,nome_ficheiro_pdf); nome_total_pdf.Format("%s%s",directoria,nome_ficheiro_pdf);

if(fSearch.FindFile(nome_total_pdf))//Existe o pdf...abri-lo ShellExecute(this->m_hWnd,"open",nome_total_pdf,"","",SW_SHOW ); else { CString str_aux; str_aux.Format("Do you want to generate the report %s?",nome_ficheiro_pdf);

if (IDYES ==AfxMessageBox(str_aux,MB_YESNO)) {

struct in_par { CAppDlg *p; CString s; }; struct in_par *entrada = new (struct in_par);

entrada->p = this; entrada->s = nome_ficheiro;

m_pThread_ReportGenerator=AfxBeginThread(GenerateReportThread,entrada,THREAD_PRIORITY_BE LOW_NORMAL);

} //No final da geração, apresento o report do mesmo modo

} } *pResult = 0; }

73

No método generateReport() da classe ReportGenerator executam-se cinco tarefas: (1) Preparar os ficheiros, (2) gerar os gráfico para o relatório e (3) fazer o calculo das estatísticas, (4) geração do ficheiro Latex, e (5)compilação do ficheiro latex. Para preparar os ficheiros recorre-se ás funções prepareDataFile(). Primeiro esta função é responsável por: fazer a limpeza de ficheiros que podem ser prejudiciais para a geração do relatório, segundo fazer uma cópia do ficheiro que pretende gerar, separa os dados do ficheiro em ficheiros para cada sensor, retira os pontos de alta-frequência, e verifica a versão do ficheiro a gerar.

O método prepareDataFile pertencente à classe ReportGenerate, responsável por preparar os ficheiro para posterior geração relatório. int ReportGenerator::prepareDataFile(const std::string& dataFile,void *p_Janela) { CAppDlg *p_jan = (CAppDlg*)p_Janela; …. cleanTmpFiles(); if (status= copyDataFile(dataFile)) { std::cerr << "Error: durante a cópia do ficheiro de dados (" << status << ")" << std::endl; return status; }

if (status= splitAndClipDataFiles()) { std::cerr << "Error: durante o split dos dados (" << status << ")" << std::endl; return status; }

if (status= smoothDataFiles()) { std::cerr << "Error: durante o smooth dos dados (" << status << ")" << std::endl; return status; } p_jan->PostMessage( p_jan->UWM_THREADEVENT, p_jan- >m_CommandReceiveObj.FSE_PROGRESS_BAR, 10 );

determineSystemVersion(); if (mp_Settings->isDataFileNewVersion()) { if (status= splitAndSmoothNewDataEntries()) { std::cerr << "Error: durante o split dos dados (" << status << ")" << std::endl; return status; } }

Rproce= synch(mp_Settings->getTmpDir(),(void*)p_Janela,(int)mp_Settings->isDataFileNewVersion()); if (Rproce==2) { return 2; }

74 if (status= processDataFiles()) { std::cerr << "Error: durante o cálculo do start time (" << status << ")" << std::endl; return status; } return status; }

Através dos scripts pré preparados o programa lança os vários processos do pgnuplot. Utiliza a função synch() para verificar se todos os ficheiros foram gerados, e verificar se os processos wgnuplot.exe no gestor de tarefas que está a correr. Se todos os ficheiros já foram gerados este sai do ciclo infinito da função synch(), com um retorno válido para poder continuar. E verificar se os processos não estão em execução termina o programa e apresenta uma caixa de diálogo para o utilizador com o sucedido (erro na geração do relatório). Depois de todos os gráficos estarem gerados, o programa App calcula as estatísticas para o relatório, acrescenta todos os dados ao script gerando depois o ficheiro .DVI. Tendo o ficheiro DVI gera-se o ficheiro PS e através deste o de extensão pdf, chegando assim ao resultado pretendido. Este processo está apresentado no diagrama da figura 7.11. Estratos de scripts, utilizados para geração do relatório. # ------# ---- D A T A E X T R A C T I O N O P E R A T I O N S # ------#FILE split.gp # General settings TIME_COL= "$1" TEMP_COL= "$3" HEIGHT_COL= "$4" PRESSURE_COL= "$5" CURING_COL= "$6"

TEMP_CONDITION= "((@TEMP_COL > MIM_TEMP) && (@TEMP_COL < MAX_TEMP))"; HEIGHT_CONDITION= "((@HEIGHT_COL > MIM_HEIGHT) && (@HEIGHT_COL < MAX_HEIGHT))" PRESSURE_CONDITION= "((@PRESSURE_COL > MIM_PRESSURE) && (@PRESSURE_COL < MAX_PRESSURE))" CURING_CONDITION= "((@CURING_COL > MIM_CURING) && (@CURING_COL < MAX_CURING))"

# ------# Extract time and temperature information from data file: columns '1' #and '3' set format

75 # N_SAMPLES é o número de pontos utilizados para fazer o gráfico. set samples N_SAMPLES set terminal dumb set output plot filename using (@TIME_COL):(@TEMP_CONDITION ? @TEMP_COL:0) set term table set output temp_table_file replot set output

# ------# Extract time and height information from data file: columns '1' and '4' set terminal dumb plot filename using (@TIME_COL):(@HEIGHT_CONDITION ? @HEIGHT_COL:0) set term table set output height_table_file replot set output

# ------# ---- D A T A S M O O T H I N G O P E R A T I O N S # ------#File smooth.gp # General settings set format set samples N_SAMPLES set autoscale

INTERP_COEF_GEN= "($2 > 0 ? 1 : 0.0000001)" INTERP_COEF_HEIGHT= "($2 > 2.5 ? 1 : 0.0000001)"

INTERP_SMOOTH_STYLE= "smooth acsplines with lines lt 1" INTERP_SMOOTH_BZ_STYLE= "smooth bezier with lines lt 1"

# Interpolate TEMPERATURE curve with natural smoothing spline. # The weighting of the interpolation polynomial coefficients is given #by the third column. set term dumb plot temp_table_file using 1:2:(@INTERP_COEF_GEN) @INTERP_SMOOTH_STYLE set term table set output temp_file replot set output

O primeiro script (split.gp) é responsável por eliminar os pontos que se encontram fora dos limites, e a partir da tabela retirar a coluna do tempo e a coluna de uma característica da espuma.

76 O segundo script (smooth.gp) faz a interpolação dos dados. O modo “smooth acsplines” faz splines naturais de forma suavizada. O modo “smooth bezier” aproxima os dados com uma curva de Bezier.de grau igual ao número de pontos.

Gerador de Relatório

-Iniciar Variáveis -Eliminação de ficheiros temporários - Cópia do ficheiro para gerar

-Divisão do ficheiro, em ficheiro de duas colunas para cada sensor, utilizando o GnuPlot. - Lançar procesos de filtragem e interpolação dos dados de cada sensor utilizando o GnuPlot.

-Executar a função de sincronismo, para verificar se todos os ficheiros foram gerados

Não

Não Se todos os ficheiros foram gerados Verificar ocorrência de erro Sim

- Gera os vários gráficos - Gera o ficheiro latex - Cria o ficheiro pdf -Apresenta o relatório em Pdf Sim

Relatório terminado

Figura 7.11 Diagrama da geração de relatórios.

77 78 Capítulo 8

79 Calibração.

8.1 Descrição do método de calibração A calibração dos sensores é um processo delicado, que requer alguma experiência, podendo o operador pensar que este encontra-se bem calibrado, mas no entanto apresenta um grande erro associado à medida efectuada. A curva que descreve a variação dos sensores è polinomial, por exemplo o sensor de pressão apresenta uma curva polinomial de terceiro grau e os outros sensores uma curva polinomial de primeiro grau. A maneira mais fácil e intuitiva de calibração é a aquisição de um certo número de pontos igual ao grau do polinómio mais um, gerando um número de equações iguais ao número de pontos adquiridos. Através das equações resolve-se o sistema e obtém-se a equação do sensor. Pode-se ver por o exemplo seguinte:

Exemplo para sensor humidade ambiente 1. Coloca-se a Fox Board a correr com os valores EHoff=0 e o valor EHmul=1. 2. Adquire-se dois pontos, nos quais se sabe o resultado. Substitui- se os dois pontos nas equações seguintes, onde o valor esperado é colocado na variável “EH” e o valor lido na variável “x”. Resolvendo o sistema obtém-se o valor de EHmul e EHoff.

⎧ EH1 = x1 × EHmul − EHoff ⎧ ⎨ ⎨ ... ⎩ EH 2 = x 2 × EHmul − EHoff ⎩

⎧ x 2 x2 ⎪ EHoff = ( EH 2 − × EH1 )/(1− ) ⎨ x1 x1 ⎪ ⎩ EHmul = ( EH 2 − EHoff)/ x2

80 Todos os sensores que tem um polinómio de primeiro grau como equação que o descreve, resolve-se da mesma forma. No sensor de pressão a correr na Fox Board, tem-se de colocar Pc=1 e Pa, Pb e Pc igual a zero. Depois adquirir quatro pontos distintos e de seguida calcular os valores de Pa, Pb, Pc, Pd. Este método descrito (exemplo anterior) se apresentar um erro de medição, ou um erro do operador num dos pontos, a sua equação desvia-se muito da realidade. Estando em risco toda a utilização que se dá aos sensores. A nova implementação efectuada é a utilização do algoritmo de mínimos quadrados. Com este algoritmo pode-se gerar, por exemplo uma equação de primeiro grau a partir de mais de dois pontos. Se num ponto ocorrer um erro, este erro será minimizado pelos outros pontos. Com o algoritmo dos mínimos quadrados quanto maior o número de pontos introduzidos, menor é a percentagem teórica de erro em relação á curva real. Esta técnica é utilizada quando temos medições, e também um erro associado à medição e sabe-se o comportamento do dispositivo a calibrar. Os Mínimos Quadrados são utilizados para através de um modelo, gerar uma função que minimize o erro obtido, ou seja, o algoritmo gera uma função em que a soma dos quadrados da distância entre a função e os pontos de geração da função seja o mínimo possível. A seguir pode-se ver o algoritmo que se implementou para a utilização dos mínimos quadrados:

81 Algoritmo de Mínimos Quadrados

1. ler n,m,valor e para j = 1,...,m ler x j e f j

2. fazer aux0 = m , P0m+1 = 1, l = 0 , para j = 1,...,m fazer P0 j = 1 e calcular m num = ∑ x j j=1 3. para i = 0,...,n fazer 3.1. se i = 0 então num 3.1.1. calcular B0 = aux0

3.1.2. para j = 1,…,m calcular P1 j = x j − B0 m b 3.1.3. Calcular b = ∑ f j e c0 = j=1 aux0 3.2. senão m m 2 b 3.2.1. Calcular aux1 = ∑ Pij , b = ∑ f j Pij e ci = j=1 j=1 aux1 3.2.2. se i = n então ir para o passo 4 m 2 num aux1 3.2.3. calcular num = ∑ x j Pij , Bi = e Ci = j=1 aux1 aux0

3.2.4. para j = 1,…,m calcular Pi+1 j = (x j − Bi )Pij − Ci Pi−1 j

3.2.5. fazer aux0 = aux1

4. para i = 0,...,n imprimir ci

5. fazer polin = c0 6. para i = 0,...,n −1fazer

6.1 se i = 0 então calcular P1m+1 = valor − B0

6.2 senão calcular Pi+1m+1 (valor − Bi )Pim+1 − Ci Pi−1m+1

6.3.calcular polin = polin + ci+1Pi+1m+1

7. se «quer interpolar para outro valor de x» então 7.1. fazer l = l +1

7.2. colocar polin em pn1 (valor ) e ler novo valor 7.3.ir para o passo 5

8. terminar com pn1+1 (valor) ← polin

82 8.2 Como utilizar o programa para calibração dos sensores. 1. Seleccionar na primeira caixa de diálogo o botão “Settings”.

Figura 8.1-Entrar na janela de calibração. O vermelho apresenta o botão para poder calibrar os sensores.

83 2. Enviar a matriz unitária, para que a máquina esteja pronta para calibrar. Para isso selecciona-se a check box, do grupo Transfer Settings File, e em seguida envia-se a matriz por TCP/IP pressionando o botão Send do mesmo grupo. Pode ver na figura por um dos seleccionados vermelhos. 3. Adiciona-se os pontos para a posterior geração de função. Na edit box ‘X’ adiciona-se o valor que apresenta na máquina, na edit box ‘F(x) coloca-se o valor pretendido. Estando as duas edit box preenchidas com os valores desejados adiciona-se o ponto pressionando no botão ‘Add Point’, fazendo o mesmo procedimento para os próximos pontos. O descrito aqui pode ser visto no grupo ‘Add Point’ seleccionado por uma elipse vermelha, na elipse castanha apresenta os pontos já inseridos. Se o utilizador necessitar de eliminar todos os pontos pressiona o botão ‘Delete All Points’, se pretender eliminar um ponto, selecciona o ponto na TreeView e depois pressiona o botão ‘Delete Point’. Eliminar pontos pode-se ver na figura abaixo dentro do grupo ‘Add Point’, com uma elipse azul a seleccionar os botões.

84

Figura 8.2- Envio da matriz unitária. Adição de pontos. O vermelho adiciona-se os pontos se estiver no group ‘Add Point’ ou envia-se o ficheiro de calibração unitário se estiver no group ‘Transfer Settings File’. O castanho apresenta os pontos adicionados. A azul apresenta os botões para eliminar um ponto ou eliminar todos os pontos.

4. Seleccionar o sensor. Dentro da combo box, que mostra no grupo ‘Sensors Function Generation’ seleccionado por uma elipse vermelha, selecciona-se o sensor que se pretende gerar a função. Depois de seleccionar o sensor aparece a expressão da sua função, onde aparecia a palavra ‘Equation’. 5. Carregar no botão ‘Generate function’ para gerar função. Este botão pode ser visto abaixo, com uma elipse verde.

85

Figura 8.3- Escolha e geração da função de um sensor. O vermelho selecciona-se o sensor que se pretende gerar a função. A verde selecciona-se o botão para gerar função.

6. Gravação da função no ficheiro de calibração. Em primeiro selecciona-se o número do módulo no grupo ‘File Content’, na figura 8.4 apresenta o módulo 3 seleccionado. Depois selecciona-se o botão ‘Store Setting’do grupo ‘Sensors Functions Generation’, para transferir a função para o ficheiro de calibração.

86

Figura 8.4-Gravar a função no ficheiro de calibração. Vermelho selecção do módulo. Verde gravar a função no ficheiro de calibração.

7. Alteração de um ponto individual. Para alteração de um ponto individual é necessário introduzir os parâmetros no grupo ‘Change Point’, que está seleccionado abaixo com um elipse vermelha. A primeira Combo box selecciona-se o módulo que se pretende alterar, na segunda Combo box introduz-se o parâmetro que se pretende alterar, e o valor é introduzido na Edit box com o nome ‘New Value’. Para executar a mudança de valor pressiona-se o botão de nome ‘Change Now’.

8. Geração de funções para outros sensores. Repete-se o passo 3,4,5,6,7. Estando todos os sensores calibrados, passa-se para passo 9.

9. Envio da matriz de calibração para a máquina. No grupo de nome ‘transfer Settings File’, retira-se de selecção da check box de nome ‘Unitary Matrix’ e pressiona-se o botão de nome ‘Send’, envio do ficheiro de calibração.

87

10. Sair do programa. Se seleccionar o botão “Ok” o programa sai, mas primeiro é gravado o ficheiro de calibração com as alterações efectuadas. Se for seleccionado o botão “Cancel” o programa sai sem gravar.

Figura 8.5- Adicionar pontos individuais e enviar matriz de calibração. O vermelho apresenta alteração de um ponto individual. O azul apresenta o botão para o envio do ficheiro.

88 8.3 Descrição da programação da parte de calibração do programa App.

Figura 8.1. Classes para calibração dos sensores.

Para calibrar os sensores pressiona-se o botão com a designação de “Settings” na primeira DialogBox que aparece no programa App. Ao criar uma nova DialogBox através do modo DoModal(), transfere-se através do construtor da Classe CTeste o apontador da ligação TCP/IP com o processo ReportSend, a correr em Linux. Ao iniciar o programa é carregado para as variáveis o ficheiro de calibração que se encontra no Cliente. Quando o utilizador sai da janela, e carrega em OK este altera o ficheiro existente, caso carregue no botão Cancel sai sem gravar. A programação deste pedaço de código é directa e intuitiva utilizando as funções existentes na classe Cteste e CMinimosQuadrados.

89 Capítulo 9 Testes

O teste è a validação do trabalho efectuado, durante o desenvolvimento foram efectuados muitos e variados testes parciais. Cada bocado de código que era feito era testado, muito do código fora desenvolvido em pequenas aplicações de teste, e depois transferido para o projecto. Como foram vários os pequenos testes efectuados com a criação de vários programas, fez com que o programa torna-se robusto, fazendo com que o teste final (global) fosse um sucesso, tendo poucos problemas. Os testes feitos a calibração com os mínimos quadrados foram bem sucedidos, conseguindo-se obter valores idênticos aos obtidos através do sistema com o mesmo número de pontos. O sensor de pressão fora calibrado utilizando 6 pesos diferentes, onde os pontos foram obtidos através de cálculos teóricos e os valores obtidos na máquina, colocando anteriormente uma equação neutra nos sensores, para retirar os primeiros pontos. O problema obtido com os sensores de pressão é que estes nunca paravam de variar, e se colocar um peso específico em cima do sensor e ler o valor lido, dava valor diferente de retirar o peso e coloca-lo outra vez. A conclusão que se tirou, foi que estes sensores não têm grande precisão. Nos testes efectuados ás ligações, quando iniciava o programa pela primeira vez, este não apresenta problemas de conexão, se desligar-se a ligação e volta-se a ligar este nem sempre conseguia estabelecer nova ligação, este problema foi muito explorado, tentando chegar à sua resolução. Tentou-se quando perdia a ligação fechar a ligação com shutdown() e com a função close() e depois esperar por nova ligação, mas dava na mesma problemas. Os problemas de não conseguir estabelecer nova ligação, devia ser a existência de dados no

90 buffer do socket TCP/IP, uma solução talvez passa-se por o esvaziamento do buffer antes de este desligar a ligação.

91 92 Capítulo 10

93 Conclusões

A criação dos processos em Linux, para a posterior utilização na Fox Board foi um processo demorado devido á falta de ambiente de depuração, como referido anteriormente. Isto cria alguns problemas como a perda de tempo e cansaço por parte de quem programa. Se for um programador experiente, que já tenha criado milhares de linhas de código, este processo é mais ou menos facilitado proveniente do conhecimento adquirido ao longo de anos. Se for um programador pouco experiente, esta tarefa torna-se muito complicada, podendo por em causa a integridade e robustez do código feito, onde as únicas garantias são o bom senso, “e se funcionou nos testes efectuados então é porque está a funcionar!”. Para resolver este problema tem-se algumas soluções. Uma passa por fazer o desenvolvimento numa plantaforma que tenha hardware idêntico, e apresente sistema de depuração, podendo no fim adaptar ao outro hardware se for mais barato. Se as pessoas aprendem com os erros, este foi um desses trabalhos que ao longo da sua criação fez-se e desfez-se, ou seja, implementava-se um bloco código, aprendia-se outra ferramenta para fazer outro bloco de código, tinha-se de já adaptar os blocos já feitos. Sendo a primeira versão de software, ficou muito estável, se fosse a fazer o software de novo seria mais rápido ficaria melhor estruturado, isto porque, já se adquiriu conhecimento, já se sabe o objectivo, etc. O trabalho realizado foi um sucesso, porque chegou-se ao objectivo projectado, com um bom grau de confiança. Como trabalho futuro deste projecto, passa por mudar de hardware para substituir a Fox Board, um hardware que tenha software de depuração. As alterações feitas no software, poderia passar por transmitir logo caso tenha conectado para visualização do gráfico em tempo real.

94

-

95 96 Bibliografia

[TBT 98] Tesesa Bisaillon, Brad Werner: TCP/IP with Windows NT Illustrated; McGraw-Hill, 1998;ISBN 0-07-913648-6 [MEI 94] Matthew Flint Arnett, Emmett Dulaney,..: Inside TCP/IP; New Riders Publisshing, 1994;ISBN-10: 1-56205-354-x, ISBN-13: 978-156205354 [DBV 97] David Bennett: Visual C++ 5, First Edition; Sams Publishing, 1997; ISBN: 0-672-31031-7 [PLT 03] Paulo Loureiro: TCP/IP em Redes Microsoft para profissionais, sexta edição; FCA, Maio de 2003; ISBN: 972-722-349-4 [FPL 00] Fernando Pereira: Linux curso completo, terceira edição; FCA, Maio de 2000; ISBN: 972-722-263-3 [DBR 99] David Pitts, Bill Ball: Red Hat Linux 6; Sams,1999; ISBN: 0-672-31689-7 [HWP 07] wikipedia http://pt.wikipedia.org/wiki/Poliuretano, 30 Agosto de 2007 [DJT 98] Davis Chapman,Jeff Heaton: Teach Yourself Visual C++ 6, reference edition; SAMS, December 1998; ISBN: 0-672-31404-5 [LPM 07] Departamento de Ciência da Computação, Luís Paulo Maia http://www.geocities.com/fatecsp/multithread.pdf, 5 Setembro de 2007 [HWL 07] wikipedia http://pt.wikipedia.org/wiki/Linux, 8 Novembro de 2007 [HWW 07] wikipedia http://pt.wikipedia.org/wiki/Microsoft_Windows, 7 Novembro de 2007 [WLW 11] Linux VS Windows http://www.dei.unicap.br/~almir/seminarios/99.1/Linux_vs_NT/ncaract.htm [MWM 07] wikipedia http://pt.wikipedia.org/wiki/Microsoft_Foundation_Classes; 12 Outubro de 2007 [WGC 07] wikipedia http://en.wikipedia.org/wiki/GNU_Compiler_Collection; 9 November de 2007 [WFB 11] Ferramentas Eléctricas Bosch - Artes e Ofícios/Indústria - Medidor laser de distâncias DLE http://ptptocs.bosch-pt.com/boptocs-pt/ Product.jsp;jsessionid=7A5CD9E30CDAE77C36F3891C939EE33B ?division=gw&ccat_id=81941&prod_id=6848 [PAC 02] Luiz Carlos Guidolin http://proaluno.if.usp.br/minicursos/mini04/mini04/node7.html; 6 Janeiro de 2002 [LNB 00] Lenimar Nunes de Andrade; Breve Introducâo ao LATEX2, edição 2.1;24 de Abril de 2000

97

Anexo I

Apresentação do relatório gerado pelo programa.

Alta Foam Monitor

Measurement data AFMx12072006x191153xM1.dat:

Detail of first hour 80 T [oC] 75 H [cm] P [kPa] 70 C [au]o 65 T [ C] H [%RH] 60 55 50 45 40 35 30 25 20 15 10 5 0 0 10 20 30 40 50 60 time (min)

Detail of first hour 80 T [oC] 75 H [cm] P [kPa] 70 C [au]o 65 T [ C] H [%RH] 60 55 50 45 40 35 30 25 20 15 10 5 0 0 2 4 6 8 time (min)

page 1 of 7 Alta Foam Monitor Report

Temperature — Detail of first hour 35 T [oC]

30

25

20

15

10

5

0 0 10 20 30 40 50 60 time (min)

Temperature Statistics

o 0.00 s o 109.36 s Tstart 24.81 C tTstart Tmin 21.16 C tTmin 0.00 min 1.82 min

o 5816.37 s o o Tmax 25.85 C tTmax ALTdrop 0.03 C/min ALTreturn 0.01 C/min 96.94 min 621.96 s 20381.20 s o o Treturn 24.81 C tTreturn 10.37 min Treturn 24.81 C tTreturn 339.69 min 0.17 h 5.66 h

Data file: ’AFMx12072006x191153xM1.dat’ page 2 of 7 Alta Foam Monitor Report

Height — Detail of first 20 minutes 15 H [cm]

10

5

0 −1 0 2 4 6 8 10 12 14 16 18 20 time (min)

Height Statistics

6.83 s 601.46 s H 5.52 cm tH0 H 6.34 cm tH10 0 0.11 min 10 10.02 min 1804.38 s 3601.91 s H 6.58 cm tH30 H 6.59 cm tH60 30 30.07 min 60 60.03 min 81073.64 s 14.73 % 19.10 % HMed 6.58 cm tHMed PE min PE min 1351.23 min 10 77.01 % of tot30 99.81 % of tot 19.20 % PE min PEtot 19.13 % 60 100.38 % of tot

Data file: ’AFMx12072006x191153xM1.dat’ page 3 of 7 Alta Foam Monitor Report

Pressure — Detail of first 8 hours 15 P [kPa]

10

5

0 0 2 4 6 8 time (h)

Pressure Statistics

0.00 s 3759.11 s − − Pstart 0.00 kPa tPstart 0.00 min P10 0.55 kPa tP10 62.65 min −0.00 h 1.04 h 6438.33 s 13895.00 s

P50 2.77 kPa tP50 107.31 min Pmax 5.55 kPa tPmax 231.58 min 1.79 h 3.86 h 37884.89 s 60029.49 s 0 0 P50 2.77 kPa tP500 631.41 min P10 0.55 kPa tP100 1000.49 min 10.52 h 16.67 h

Data file: ’AFMx12072006x191153xM1.dat’ page 4 of 7 Alta Foam Monitor Report

Curing — Detail of first 8 hours 80 C [au] 75 70 65 60 55 50 45 40 35 30 25 20 15 10 5 0 0 2 4 6 8 time (h)

Curing Statistics

0.00 s 5508.80 s tstart 0.00 min Creturn 68.04 au treturn 91.81 min 0.00 h 1.53 h 1578.83 s 12459.70 s

Cmin 67.61 au tCmin 26.31 min Cmax 68.48 au tCmax 207.66 min 0.44 h 3.46 h Alpha 33.16 o

Data file: ’AFMx12072006x191153xM1.dat’ page 5 of 7 Alta Foam Monitor Report

Environment Temperature — Detail of first 8 hours

35 o Tenv [ C]

30

25

20

15

10

5

0 0 2 4 6 8 time (h)

Data file: ’AFMx12072006x191153xM1.dat’ page 6 of 7 Alta Foam Monitor Report

Humidity — Detail of first 8 hours 55 H [%RH] 50

45

40

35

30

25

20

15

10

5

0 0 2 4 6 8 time (h)

Data file: ’AFMx12072006x191153xM1.dat’ page 7 of 7