Sie sind auf Seite 1von 32

Sistemas Operacionais Embarcados

Relatório do Trabalho 1: Intel Galileo e Yocto

Alysson J. M. de Freitas, Lucas H. S. L. Silva, Marcos Yamasaki, Matheus A. S. L.


Silva, Ronny S. R. Milleo
Universidade Federal do Paraná,
Engenharia Elétrica com Ênfase em Sistemas Eletrônicos Embarcados
E-mail: alyssonmalko@gmail.com, lucashsls@ufpr.br,
yamasaki.marcos@gmail.com, matheus.augusto.sls@ufpr.br,
ronnymilleo@ufpr.br

Abstract: Este trabalho apresenta projeto prático que aborda a tecnologia de Internet
das Coisas (Internet of Things - Iot) através da plataforma Intel Galileo Gen 1 e tem como
objetivo o monitoramento remoto de telemetria a partir da implementação de um servidor
web que mostre dados relativos a sensores de temperatura de luminosidade em uma página
HTML com uma determinada frequência, além de mostrar hora e contagem numérica da
leitura.

Keywords: Galileo, IoT, Servidor, TCP.


Sumário

1 Introdução 1

2 A Plataforma Intel Galileo Gen 1 2

3 O Yocto Project 3

4 Sensores 4
4.1 Sensor de Luminosidade LDR 4
4.2 Sensor de temperatura 5

5 Fase 1 5
5.1 O Servidor Web 5
5.1.1 O Socket 6
5.1.2 Outras Funções Primitivas 6
5.1.3 O Código do Servidor Web 7

6 Fase 2 7
6.1 Comunicação TCP/IP 7
6.2 Funções Extras Utilizadas 8
6.3 O Código para Comunicação TCP/IP 8

7 Fase 3 8

A Apêndice 9

1 Introdução

Os recentes avanços na tecnologia de semicondutores possibilitaram soluções para integrar


processos embarcados e telemetria, por meio de redes de computadores, trazendo consigo
surgimento de um novo conceito de tecnologia que pode-se chamar Internet das Coisas
(Internet of Things – IoT ).
A IoT pode ser definida como as interconexões entre itens utilizados no dia-a-dia à
rede mundial de computadores [1]. Esse tipo de tecnologia possibilita o monitoramento e
manipulação de parâmetros remota de sensore e é atualmente considerada como uma das
tecnologias mais proeminentes para o mercado consumidor de eletrônicos e no uso para
desenvolvimento das chamadas "casas inteligentes", sendo um segmento de mercado com
grande potencial.
Nesse contexto, muitas empresas têm investido em plataformas que possibilitem o de-
senvolvimento e a implementação desse tipo de tecnologia, de modo que sejam amigáveis

–1–
tanto para estudantes, quanto para profissionais, para que sejam criadas novas possibilida-
des e soluções para movimentação desse mercado, como por exemplo, a Intel R que com o
desenvolvimento da Plataforma Intel Galileo Gen 1 vem sendo visionária nesta tecnologia.
Neste trabalho busca-se desenvolver de maneira prática esse tipo de tecnologia a partir
de um projeto que será dividido em três fases, utilizando a Plataforma supracitada.
Na Fase 1, se busca fazer com que O Galileo monitore a temperatura e a luminosidade
do ambiente, além de se criar um servidor Web no Galileo, que fique aguardando conexões
na porta 80, que possa ser acessada por um Cliente Web de qualquer lugar na Internet,
onde as leituras dos valores são continuamente atualizadas em uma página que indique o
horário da leitura e o número da leitura em relação às leituras anteriores.
Na Fase 2, busca-se que os valores lidos de temperatura e luminosidade sejam enviados
para um servidor, que irá armazena-los em um arquivo texto. Para isso, busca-se desenvolver
um programa cliente TCP que irá enviar o arquivo ao servidor, esse que com um programa
servidor desenvolvido utilizando a biblioteca Sockets, recebe e armazena os dados em um
arquivo texto, esse que possui uma linha para cada leitura, sendo a primeira coluna para
hora, a segunda para a temperatura e a terceira para luminosidade. Tudo isso desenvolvido
com um protocolo para transmissão dos dados.
A metodologia empregada para elaboração desse projeto seguiram os seguintes passos:
- Pesquisar e definir sensores que mais se adequam as necessidades do projeto, bem
como verificar a necessidade de circuitos adicionais;
- comprar e testar o funcinamento dos sensores;
- pesquisar através de datasheets e manuais do usuário sobre Intel Galileo Gen 1 e
estudar exemplos para melhor copreensão de seu funcionamento;
- instalar o Yocto no cartão SD;
- pesquisar e desenvolver código de servidor web em C;
- pesquisar e desenvolver código para leitura dos pinos analógicos, bem como bibliotecas
ou fórmulas a serem empregadas para a conversão do sinal dos sensores, além de integrar
com o código servidor;
- desenvolver código HTML;
- pesquisar principais funções e desenvolver Socket Cliente/Servidor em C que atenda
as especificações do projeto.

2 A Plataforma Intel Galileo Gen 1

A placa de desenvolvimento Intel Galileo trata-se de um microcontrolador baseado no pro-


cessador Intel
R Quark SoC X1000 de 32-bits e Sistema Intel Pentium-class.
É a primeira placa baseada na arquitetura Intel R projetada para ser compatível em
hardware e software com shields projetados para Arduino Uno R3. Seus pinos digitais vão
de 0 a 13. As entradas analógicas vão de 0 a 5, o conector de alimetação, o conector ICSP,
e os pinos da porta UART (0 e 1), estão todos nos mesmos locais que no Arduino Uno R3.
O Galileo também foi projetado para ser compatível com shields que operam tanto em
3.3V como em 5V. A tensão de funcionamento do núcleo de Galileo é 3.3 V. No entanto, um
jumper na placa permite a mudança de tensão para 5V nos pinos de E/S. Isso possibilita

–2–
o suporte para integração com shields para Arduino Uno que tem por padrão 5V. Além
disso, observa-se também que essa plataforma possui compatibilidade em software com o
ambiente de desenvolvimento Arduino.
Além de compatibilidade em hardware e software com Arduino, a plataforma Galileo
tem compatibilidade com vários padrões de E/S da indústria de PCs e recursos para ex-
pandir o uso e capacidades para ir muito além do "ecossistema"Arduino, possuindo, slots
para mini-PCI Express, para Ethernet e para micro-SD, além de porta serial RS-232, USB
Host, USBClient e uma memória NOR flash de 8MBytes, sendo uma plataforma versátil e
atrativa tanto para estudantes como para profissionais.
O hardware está funcionando com uma versão atualizada do sistema operacional Yocto
criado para a plataforma Intel Galileo instalado em um cartão microSD. Para fazer a comu-
nicação com a placa, optou-se por usar SSH para acessar o usuário root@galileo e controlar
o sistema operacional remotamente. Além disso, os arquivos de código são escritos e envi-
ados para a placa por FTP usando o aplicativo gratuito Filezilla, com isso os códigos são
compilados no próprio sistema operacional embarcado.

3 O Yocto Project

O Yocto Project é um projeto de colaboração open source que provê ferramentas, modelos
e métodos para ajudar a criar sistemas personalizados baseados em Linux embarcado, de
forma idependente da arquitetura de hardware, o que possibilita o uso de processadores de
variadas plataformas, como ARM, MIPS, PowerPC and x86 e x86-64 [2].
Os componentes do projeto Yocto podem ser usados para projetar, desenvolver, cons-
truir, debugar, simular e testar completamente uma pilha de software embarcado composta
pelo Kernel do Linux, o sistema Linux, X Window System, GNOME Mobile-based appli-
cation frameworks, e o Qt frameworks.
Teve sua fundação em 2010 em colaboração com vários fabricantes de hardware, for-
necedores de sistemas operacionais open source e empresas de eletrônicos na tentativa de
organizar o desenvolvimento do Linux embarcado.
No processo de desenvolvimento o Yocto é formado por diversas partes. Essas partes
são nomeadas como projetos dentro do Yocto e incluem ferramentas de criação, metadados
de instruções de criação chamados de receitas, bibliotecas, utilitários e interfaces gráficas
com o usuário [3].
Ele prove um Kernel Linux atual, com um conjunto de comandos de sistemas e bibliote-
cas adaptados para o uso em ambientes embarcados. Disponibiliza componentes de sistema
como X11, GTK+, Qt, Clutter, e SDL de modo a se permitir a construção de interface
gráfica configurável para os hardwares de display. Além de criar um núcleo compatível com
o projeto OpenEmbedded que pode ser extensível e distribuído.O projeto também fornece
um plug-in Eclipse IDE.

–3–
4 Sensores

Para realização desse projeto à priori foram especificados dois sensores, esses que serão
descritos a seguir. (Código 4)

4.1 Sensor de Luminosidade LDR

Os LDRs ou Light Dependent Resistors, conhecidos também como fotoresistores e células


de sulfeto de cádmio, são sensores do tipo fotocondutivo, onde a resistência à passagem de
uma corrente elétrica varia com quantidade de luz que incide numa superfície sensível à
base de Sulfeto de Cádmio ou CdS [4].

Estruturalmente a montagem típica desse sensor é feita de modo a maximizar a super-


fície sensível, os eletrôdos formam uma estrutura em ziguezague. Quanto maior o sensor,
maior será a sua capacidade de controlar correntes mais intensas.

No escuro, a resistência de um LDR pode chegar a mais de 1 mega ohm. No claro,


sob iluminação solar , essa resistência pode cair até algumas dezenas . Na figura 1 temos a
curva característica de um sensor desse tipo.

Os cálculos foram feitos levando em consideração as resistências medidas no sensor para


o valor mínimo e máximo em Lux através de uma referência conhecida. Cada resistência há
uma tensão que é lida pelo conversor analógico-digital de 10 bits da placa, ou seja, os valores
de entrada estão entre 0 e 1023. Como a figura 1 mostra, os valores seguem um padrão
não linear, portando foi necessário linearizar cada parte da curva. Os valores calculados de
cada reta são os seguintes:

LUX ANALOG
0 350
33 590
70 690
140 750
280 820
520 882

Tabela 1. Tabela de valores da figura 1

–4–
Figura 1. Gráfico comparando Lux com os sinais analógicos recebidos pela placa

O LDR é um sensor bidirecional, ou seja, ele pode operar diretamente inclusive em


circuitos de corrente alternada. Apesar de ter uma resposta espectral extensa, o LDR é um
dispositivo lento, sendo usado muito mais em aplicações de automação em função da luz
do que controle ou sensoriamento de variações rápidas de luz [4].
O LDR não apresenta uma característica linear de sensibilidade, conforme se pode ver
pela curva característica, não sendo portanto muito indicado para instrumentos de medida.
Ao se usar um LDR, pode-se usar da propriedade do divisor de tensão para medir a
variação da queda de tensão em cima do mesmo. Sabe-se que a tensão total e a resistência
total são fixas. Assim, o divisor de tensão vai variar com a resistência entre a entrada
analógica e o GND.
Considerando que quanto menos luz incidir sobre o LDR maior será sua resistência,
tem-se a tensão sobre o LDR e por conseguinte o valor na entrda analógica maior com um
índice de luminosidade incidente menor, ou seja, em um lugar mais escuro.

4.2 Sensor de temperatura


Primeiramente tentou-se utilizar o sensor DHT11, mas devido a problemas com a biblioteca
optou-se pela utilizar o sensor de temperatura do próprio GALILEO.

5 Fase 1

Nessa fase objetiva-se que o Galileo monitore a temperatura e a luminosidade do ambiente,


além de se criar um servidor Web no Galileo, que fique aguardando conexões na porta 80,
que possa ser acessada por um Cliente Web de qualquer lugar na Internet, onde as leituras
dos valores são continuamente atualizadas em uma página que indique o horário da leitura
e o número da leitura em relação às leituras anteriores.

5.1 O Servidor Web


O Servidor web pode ser um programa de computador responsável por aceitar pedidos
HTTP de clientes, geralmente os navegadores, e servi-los com respostas HTTP [5].Essas que

–5–
usualmente são páginas web, tais como documentos HTML com objetos embutidos, como
imagens ou podem um computador que executa um programa que provê a funcionalidade
supracitada.
Os servidores web são responsáveis por armazenar e trocar informações com outras
máquinas [6]. Logo, pelo menos dois entes são envolvidos em cada troca de informações,
sendo um o cliente, que solicita informações, e outro, o servidor, que atende a esses pedidos.
Os pedidos http que se referem habitualmente a páginas HTML são normalmente feitos
por meio de browsers. O processo inicializa com a conexão entre o computador onde está
instalado o servidor web e o computador do cliente.
Então, é processado o pedido do cliente, e conforme as restrições de segurança e a
existência da informação solicitada, o servidor devolve os dados, ou po-se dizer tudo o que
se enquadre no conceito de ficheiro pode ser enviado como resultado de um pedido http.
Sendo esse o tipo de servidor utilizado nessa fase, esse que para o desenvolvimento
de seu código necessita-se do conhecimento de algumas das funções primitivas que serão
descritas na sequência.

5.1.1 O Socket
O acesso aos serviços da camada de transporte pode ser feito por primitivas de transporte,
essas primitivas são denominadas SOCKET [7]. Por meio dessas primitivas é possível
acessar vários protocolos da camada de transporte, dentre eles TCP e UDP.
Os Sockets garantem a intercomunicação bidirecional entre processos,esses sendo exe-
cutados localmente ou em máquinas conectadas através de uma LAN/WAN.
Todos os Sockets criados utilizam endereços para fazerem referências entre si. O espaço
de possíveis endereços é chamado domínio.
No caso de sockets, alguns exemplos de domínios podem ser conferidos a seguir:
AF_UNIX - endereço é composto por um caminho dentro do sistema de arquivos.
Utilizado quando os processos rodam em uma mesma máquina;
AF_INET - O endereço é composto pelo endereço de rede da máquina (IP) e o número
de identificação da porta que está sendo utilizada pelo processo.
Os tipos mais comuns são:
SOCK_STREAM - indica que os dados irão trafegar pelo socket na forma de um stream
de caracteres.
SOCK_DGRAM - indica que os dados irão trafegar pelo socket na forma de datagra-
mas.

5.1.2 Outras Funções Primitivas


Algumas das funções primitivas estão listadas a seguir, essas que em sua maioria integrarão
os códigos desenvolvidos:
Bind - Anexa um endereço local a um socket. Parâmetros: o descritor do socket, uma
estrutura de dados com o endereço e o tamanho dessa estrutura de dados. Um processo
servidor deve executar essa primitiva para disponibilizar um endereço aos clientes. Na
arquitetura cliente/servidor após sua execução os clientes podem se conectar ao servidor.

–6–
Listen - Torna o processo servidor apto a aceitar conexões dos clientes, aloca uma
fila de espera para conexões pendentes. Se a fila já foi alocada mostra o seu tamanho.
Parâmetros: o descritor do socket e o tamanho máximo da fila de conexões pendentes.
Caso seja solicitada conexão e a fila de espera estiver cheia é enviada uma mensagem de
erro ao solicitante.
Accept - Faz com que um processo servidor permaneça bloqueado até que uma soli-
citação de conexão seja feita. Parâmetros: o descritor do socket, um ponteiro para uma
estrutura que endereça o solicitante da conexão e um inteiro que informa o tamanho dessa
estrutura.
Connect - Solicita uma conexão ao servidor, bloqueia o processo até que a conexão seja
estabelecida. Parâmetros: o descritor do socket, ponteiro para estrutura com o endereço
destino e o tamanho da estrutura. Essa primitiva deve ser executada por um processo
cliente para estabelecer comunicação com o servidor.
Send ou Write -Envia dados pela conexão para a entidade destino. Parâmetros: o
descritor do socket, ponteiro para o buffer com os dados a serem enviados, o tamanho do
buffer, códigos de condição especiais (normalmente 0).
Receive ou Read - Recebe dados da conexão. Parâmetros: o descritor do socket, pon-
teiro para uma estrutura onde os dados recebidos podem ser colocados, o tamanho da
estrutura, códigos de condição especiais (normalmente 0).
Close - Termina a conexão. Como o encerramento da conexão é simétrico apenas
quando ambos os processos tiverem executado essa primitiva a conexão será terminada.
Parâmetros: o descritor do socket e códigos de término (normalmente 0).

5.1.3 O Código do Servidor Web


O código desenvolvido pela equipe pode ser observado no Apêndice A.

6 Fase 2

Essa segunda fase tem por objetivo que os valores aferidos de temperatura e luminosidade
sejam enviados para um servidor, esse que irá armazená-los em um arquivo texto. Para
isso, um programa cliente TCP irá enviar o arquivo ao servidor, esse que com um programa
servidor desenvolvido utilizando a biblioteca Sockets, recebe e armazena os dados em um
arquivo texto, esse que possui uma linha para cada leitura, sendo a primeira coluna para
hora, a segunda para a temperatura e a terceira para luminosidade. Tudo isso desenvolvido
com um protocolo para transmissão dos dados.

6.1 Comunicação TCP/IP


Para desenvolver o cliente é necessário levar em conta que a comunicação TCP/IP é iniciada
sempre pelo cliente, portanto este deve conhecer o endereço IP do servidor e a porta para
a conexão. O servidor TCP estará aguardando conexão para fazer o three-way handshake
e concluir a conexão, a partir desse ponto sempre que o cliente envia uma requisição, o
servidor responde.

–7–
Neste projeto, o cliente vai enviar um conjunto de dados contendo horário e valores de
temperatura e luminosidade e o servidor os salvará em um arquivo de texto.
Para o desenvolvimento do código dessa etapa foi necessário a utilização de novas
funções, essas que serão descritas a seguir.

6.2 Funções Extras Utilizadas


Apresenta-se na sequência algumas definições de funções utilizadas na fase 2 do projeto.
inet_ntoa() - essa função converte o endereço de rede em uma string ASCII.
bzero() - função que copia n bytes, cada um com o valor zero, em uma string.

6.3 O Código para Comunicação TCP/IP


Ambos os códigos estão em apêndice.
O código do cliente 2.
O código do servidor 3.

7 Fase 3

A última especificação de projeto consiste em definir prioridades para os processos que


estão sendo executados no Intel Galileo. Define-se que a comunicação do cliente TCP com
um servidor em outro endereço IP deve ser mais prioritária do que a comunicação entre o
servidor web e seus clientes.
Para fazer com que os processos criados pelos códigos do servidor web e do cliente TCP
tenham diferentes prioridades de base, usa-se o comando nice em sistemas unix. No caso
do sistema operacional Yocto, que é baseado em unix, a prioridade mais alta é -20 enquanto
a mais baixa é 20.
Exemplo:
nice − n (Prioridade 0 a 20 ) ./programa
Nesse projeto:
nice − n 0 ./web
nice − n 10 ./dadosSensor
Para o cliente TCP é necessário indicar o IP de conexão e o número da porta:
nice − n -20 ./clientetcp 192.168.0.xxx 2000

–8–
A Apêndice

Código 1 WebServer
1 #include<stdio.h> //Biblioteca Basica #include<string.h> //Biblioteca Basica
2 #include<stdlib.h> //Biblioteca Basica
3 #include<unistd.h> // Biblioteca para constantes simbolicas como NULL
4 #include<netdb.h> //Biblioteca para operacoes de base de dados na internet
5 #include<signal.h> // Biblioteca para receber e manipular sinais
6 #include<fcntl.h> //Biblioteca para controle de opcoes de arquivos - O_RDONLY
7 #include<sys/types.h> //Biblioteca para manipular dados e threads
8 #include<sys/stat.h> //Biblioteca para usar a funcao stat
9 #include<sys/socket.h> //Biblioteca para o uso de sockets
10 #include<arpa/inet.h> //Biblioteca para operacoes na internet
11 #define MAX 5000 // Número máximo de conexões do servidor
12 #define BYTES 1024 // Tamanho máximo da mensagem a ser enviada do servidor para o cliente
13

14 char *ROOT; //usado para armazenar o caminho do diretorio


15 int listenfd, clients[MAX];
16 void error(char *);//funcao de erro
17 void Server(char *); // funcao para iniciar o servidor
18 void resposta(int); // funcao para ser executada quando alguem for conectado
19

20 int main(int argc, char* argv[])


21 {
22 struct sockaddr_in clientaddr; //struct para socket
23 socklen_t addrlen;
24 char c;
25

26 char PORT[2];//porta utilizada


27 ROOT = getenv("PWD");// caminho do diretório atual
28 strcpy(PORT,"80"); // porta utilizada, caso a porta 80 esteja em uso
29 // no yocto usar: netstat -tulpn | grep :80 para descorbir o processo e depois mata-lo
30

–9–
43 {
44 addrlen = sizeof(clientaddr);
45 clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
46

47 if (clients[slot]<0)
48 error ("erro no accept() ");
49 else
50 {
51 //processo de forks para cada cliente conectado, executa a funcao resposta
52 if ( fork()==0 )
53 {
54 resposta(slot);
55 exit(0);
56 }
57 }
58

59 while (clients[slot]!=-1) slot = (slot+1)%MAX;


60 //se um slot ja tiver sido utilizado por um cliente, ele utiliza o slot+1%MAX
61

62 }
63

64 return 0;
65 }
66

67 //inicia servidor
68

69 void Server(char *port)


70 {
71 struct addrinfo hints, *res, *p;
72

73 // Adquiri informacoes do host conectado


74 memset (&hints, 0, sizeof(hints));
75 hints.ai_family = AF_INET;//IPV4
76 hints.ai_socktype = SOCK_STREAM;//tipo de conexao para usar listen/accept
77 hints.ai_flags = AI_PASSIVE;//flag para poder usar bind()/liste()/accept()
78 if (getaddrinfo( NULL, port, &hints, &res) != 0)
79 {
80 perror ("erro no getaddrinfo()");
81 exit(1);
82 }

– 10 –
83 // funcoes socket e bind
84 for (p = res; p!=NULL; p=p->ai_next)
85 {
86 listenfd = socket (p->ai_family, p->ai_socktype, 0);
87 if (listenfd == -1) continue;
88 if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break;
89 }
90 if (p==NULL)
91 {
92 perror ("erro no socket() ou no bind()");
93 exit(1);
94 }
95

96 freeaddrinfo(res);
97

98 // funcao listen
99 if ( listen (listenfd, 1000000) != 0 )
100 {
101 perror("erro no listen()");
102 exit(1);
103 }
104 }
105

106 //funcao de conexao com o cliente


107 void resposta(int n)
108 {
109 char mesg[99999], arquivo[99999], data_to_send[BYTES], path[99999];
110 int rcvd, fd, bytes_read;
111

112 memset( (void*)mesg, (int)’\0’, 99999 );


113 strcpy(arquivo, "/index.html");//passa index.html para a string que sera enviada
114 rcvd=recv(clients[n], mesg, 99999, 0);

– 11 –
115

116

117 if (rcvd<0) // caso erro


118 fprintf(stderr,("erro no recv()\n"));
119 else if (rcvd==0) // se o socket for fechado
120 fprintf(stderr,"Cliente desconectado.\n");
121 else // mostra as informacoes do cliente
122 {
123 printf("%s", mesg);
124

125 strcpy(path, ROOT);


126 strcpy(&path[strlen(ROOT)], arquivo);
127 //adiciona os dados do diretorio da mensagem que vai ser enviada
128

129 if ( (fd=open(path, O_RDONLY))!=-1 )//aberto apenas para leitura


130 {
131 send(clients[n], "HTTP/1.0 200 OK\n\n", 17, 0);// envia os dados
132 while ( (bytes_read=read(fd, data_to_send, BYTES))>0 )
133 write (clients[n], data_to_send, bytes_read);
134

135 }
136

137 }
138

139

140 //Fechando socket


141 shutdown (clients[n], SHUT_RDWR);
142 close(clients[n]);
143 clients[n]=-1;
144 }

– 12 –
Código 2 Cliente TCP
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <netdb.h>
9 #include <time.h>
10

11 #define BUFSIZE 1024


12

13

14 void error(char *msg) {


15 perror(msg);
16 exit(0);
17 }
18

19 int main(int argc, char **argv) {


20 // int main() {
21 int sockfd, portno, n, segAux;
22 struct sockaddr_in serveraddr;
23 struct hostent *server;
24 char *hostname;
25 char buf[BUFSIZE];
26

27 segAux=61;
28

29 while(1){
30

31

32 // Definição de variáveis
33 int seg;
34 struct tm *local;
35 time_t t;
36 // Para obter o horário e data atual do sistema
37 t = time(NULL);
38 local=localtime(&t);

– 13 –
40 // dia=local->tm_mday;
41 // mes=local->tm_mon+1;
42 // ano=local->tm_year+1900;
43

44 seg=local -> tm_sec;


45

46 if(seg!=segAux){
47 segAux = seg;
48 // checkando argumentos passados
49 if (argc != 3) {
50 fprintf(stderr,"uso da %s <hostname> <port>\n", argv[0]);
51 exit(0);
52 }
53 hostname = argv[1];
54 portno = atoi(argv[2]);
55

56 // hostname = "192.168.0.191";
57 // portno = 2000;
58

59 // socket: criando o socket


60 sockfd = socket(AF_INET, SOCK_STREAM, 0);
61 if (sockfd < 0)
62 error("ERROR abrindo socket");
63

64 // gethostbyname: pegando o DNS


65 server = gethostbyname(hostname);
66 if (server == NULL) {
67 fprintf(stderr,"ERROR, este Host nao existe %s\n", hostname);
68 exit(0);
69 }
70

71 // criando o endereco do servidor na internet */


72 bzero((char *) &serveraddr, sizeof(serveraddr));
73 serveraddr.sin_family = AF_INET;
74 bcopy((char *)server->h_addr,
75 (char *)&serveraddr.sin_addr.s_addr, server->h_length);
76 serveraddr.sin_port = htons(portno);

– 14 –
77

78 // connect: criando conexao com o servidor


79 if (connect(sockfd, &serveraddr, sizeof(serveraddr)) < 0)
80 error("ERRO de conexao");
81

82

83 bzero(buf, BUFSIZE);
84

85 FILE * pFile;// Define pFile2 como arquivo


86 pFile = fopen ( "log.txt" , "r+" );// Abre o arquivo log.txt com tipo de acesso r+
87 fgets( buf, 25, pFile );
88 fclose ( pFile );// Fecha arquivo
89

90 n = write(sockfd, buf, strlen(buf));


91

92 }
93 else{}
94 }
95

96

97

98 }

– 15 –
Código 3 Servidor TCP
1 // * tcpserver.c
2

3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <netdb.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12

13 #define BUFSIZE 1024


14

15 // endereço da Internet
16 struct in_addr {
17 unsigned int s_addr;
18 };
19

20 // tipo de endereço socket


21 struct sockaddr_in {
22 unsigned short int sin_family; /* endereço family */
23 unsigned short int sin_port; /*número da porta */
24 struct in_addr sin_addr; /* endereço IP */
25 unsigned char sin_zero[...]; /* pega o tamanho da ’struct sockaddr’ */
26 };
27

28 // Struct exportada de netdb.h


29

30

31 // Domain name service (DNS) acesso host


32 struct hostent {
33 char *h_name; /* nome oficial do host */
34 char **h_aliases; /* lista alias */
35 int h_addrtype; /* tipo de endereço host
36 int h_length; /* tamnaho do endereço */

– 16 –
37 char **h_addr_list; /* list of addresses */
38 }
39 #endif
40

41 // *erro
42

43 void error(char *msg) {


44 perror(msg);
45 exit(1);
46 }
47

48 int main(int argc, char **argv) {


49 int parentfd; ///* socket pai */
50 int childfd; ///* socket filho */
51 int portno; ///* porta de escuta */
52 int clientlen; ///* tamanho de bytes do endereço do cliente */
53 struct sockaddr_in serveraddr;// /* addr do servidor */
54 struct sockaddr_in clientaddr; ///* addr do cliente */
55 struct hostent *hostp; ///*informações do host do cliente */
56 char buf[BUFSIZE]; ///* buffer de messagem */
57 char *hostaddrp; ///* host addr string */
58 int optval; ///* valor da flag for setsockopt */
59 int n; ///* tamanho dos bytes da mensageme */
60

61 // confere os argumentos da linha de comando


62

63 if (argc != 2) {
64 fprintf(stderr, "usando: %s <port>\n", argv[0]);
65 exit(1);
66 }
67 portno = atoi(argv[1]);
68

69

70 // * socket:cria o socket pai


71

72 parentfd = socket(AF_INET, SOCK_STREAM, 0);


73 if (parentfd < 0)
74 error("ERRO abrindo socket");
75

76 // setsockopt: truque depuração útil

– 17 –
77 // que nos permite executar o servidor imediatamente após matá-lo;
78 // Caso contrário, temos que esperar cerca de 20 segundos.
79

80

81 optval = 1;
82 setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR,
83 (const void *)&optval , sizeof(int));
84

85 //
86 // constroi o servidor web
87 //
88 bzero((char *) &serveraddr, sizeof(serveraddr));
89

90 // Este é um endereço web


91 serveraddr.sin_family = AF_INET;
92

93 // Deixa o Sistema identificar o endereço IP */


94 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
95

96 // Esta é a porta que vai receber a chamada */


97 serveraddr.sin_port = htons((unsigned short)portno);
98

99 //
100 // bind: associa o socket pai com a porta
101 //
102 if (bind(parentfd, (struct sockaddr *) &serveraddr,
103 sizeof(serveraddr)) < 0)
104 error("ERRO no binding");
105

106 //
107 // listen: prepara o socket para aceitar requisição de conecção
108 //
109 if (listen(parentfd, 5) < 0) /*permite 5 requests para a fila */
110 error("ERRO no listen");
111

112 //
113 // main loop: espera por uma requisição de conecção, da linha de entrada echo,
114 // tentão fecha a conecção.
115 //
116 clientlen = sizeof(clientaddr);
117 int cont = 0;
118 while (1) {
119

120 //

– 18 –
121 // accept: espera por requisição de conecção.
122 //
123 childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen);
124 if (childfd < 0)
125 error("ERRO no accept");
126

127

128 // gethostbyaddr: determina quem envia a mensagem


129

130 hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,


131 sizeof(clientaddr.sin_addr.s_addr), AF_INET);
132 if (hostp == NULL)
133 error("ERRO no gethostbyaddr");
134 hostaddrp = inet_ntoa(clientaddr.sin_addr);
135 if (hostaddrp == NULL)
136 error("ERRO no inet_ntoa\n");
137 printf("server conectado em %s (%s)\n",
138 hostp->h_name, hostaddrp);
139

140

141 // read: lê a entrada string do cliente


142

143 bzero(buf, BUFSIZE);


144 n = read(childfd, buf, BUFSIZE);
145

146

147 fprintf(stdout,"%s",buf);
148

149 FILE * pFile;// Define pFile2 como arquivo


150 pFile = fopen ( "log2.txt" , "r+" );// Abre o arquivo log.txt com tipo de acesso r+
151 if (cont==0){
152 fseek ( pFile , cont*24 , SEEK_SET );// Procura no arquivo na posição
153 fputs ( buf , pFile );
154 fseek ( pFile , 24 , SEEK_SET );// Procura no arquivo na posição
155 fputs ( ";\n" , pFile );
156 }
157 else if (cont==1){
158 fseek ( pFile , 24+2 , SEEK_SET );// Procura no arquivo na posição
159 fputs ( buf , pFile ); // Substitui por
160 fseek ( pFile , 24+26 , SEEK_SET );// Procura no arquivo na posição
161 fputs ( ";\n" , pFile );// Substitui por"
162 }

– 19 –
163 else {
164 fseek ( pFile , (cont*24)+2*cont , SEEK_SET );// Procura no arquivo na posição
165 fputs ( buf , pFile );// Substitui por
166 fseek ( pFile , (cont*24)+24+2*cont , SEEK_SET );// Procura no arquivo na posição
167 fputs ( ";\n" , pFile );// Substitui por"
168 }
169 fclose ( pFile );// Fecha arquivo
170 cont=cont+1;
171

172 if (n < 0)
173

174 error("ERRO socket");


175

176 // close(childfd);
177 }
178 }

– 20 –
Código 4 Código dos Sensores
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5 #include "mraa.h"
6 int horario[2];
7

8 // Função que retorna a leitura de Lux


9 int leLux(void){
10 // Define o pino ADC_A0 como Analog PIN
11 mraa_aio_context adc_a0;
12 // Definição de variavel tipo Integer para valor de Lux
13 uint16_t luxSensor = 0;
14 // Inicialização do pino Analogico ADC_A0
15 adc_a0 = mraa_aio_init(0);
16

17 // Verificação de conteúdo
18 if (adc_a0 == NULL) {
19 return 1;
20 }
21

22 // Leitura do pino A0
23 luxSensor = mraa_aio_read(adc_a0);
24

25 // Conversão do valor Analógico para Lux


26 // Como foi verificado, os valores de Lux são
27 //não-lineares para diferentes intensidades de luz no Sensor LDR
28 // Com isto, foi necessário implementar
29 //diversos if e else if para corrigir essa não-linearidade
30 if (luxSensor <= 350){
31 luxSensor = 0;
32 }
33 else if (luxSensor>350 && luxSensor<=590){
34 luxSensor = luxSensor*0.1375 - 350*0.1375;
35 }
36 else if (luxSensor>590 && luxSensor<=690){
37 luxSensor = luxSensor*0.37 - 590*0.37 + 33;
38 }

– 21 –
39 else if (luxSensor>690 && luxSensor<=750){
40 luxSensor = luxSensor*1.166666667 - 690*1.166666667 + 70;
41 }
42 else if (luxSensor>750 && luxSensor<=830){
43 luxSensor = luxSensor*1.75 - 750*1.75 + 140;
44 }
45 else if (luxSensor>830){
46 luxSensor = luxSensor*4.61538461538461 - 830*4.61538461538461 + 280;
47 }
48

49 // Termina a inicialização no pino A0


50 mraa_aio_close(adc_a0);
51 // return MRAA_SUCCESS;
52 // Retorna valor tipo Integer
53 return luxSensor;
54 }
55

56 // Função que envia o valor de Lux no tipo String para o index.html


57 void enviaLux(int luxInt, int cont){
58 // Define variavel tipo char para criação do String
59 char luxSensorStr[6];
60 int luxPos = 21;
61 // Substitui por "espaço" no index.html caso o valor de Lux seja menor que 100
62 if(luxInt<=100){
63 FILE * pFile; // Define pFile como arquivo
64 pFile = fopen ( "index.html" , "r+" );
65 // Abre o arquivo index.html com tipo de acesso r+
66 fseek ( pFile , 408 , SEEK_SET );
67 // Procura no arquivo a posição 408
68 fputs ( " " , pFile ); // Substitui por "espaço"
69 fclose ( pFile ); // Fecha arquivo
70 }
71

72 // Converte Integer para String, base numérica decimal (10).


73 snprintf(luxSensorStr, 10, "%d", luxInt);
74 // Imprime no terminal o valor de Lux no tipo String (Debugg)
75 fprintf(stdout, "Lux = %s\n", luxSensorStr);
76

– 22 –
77 FILE * pFile; // Define pFile como arquivo
78 pFile = fopen ( "index.html" , "r+" );
79 // Abre o arquivo index.html com tipo de acesso r+
80 fseek ( pFile , 406 , SEEK_SET ); // Procura no arquivo a posição 406
81 fputs ( luxSensorStr , pFile ); // Substitui por "espaço"
82 fclose ( pFile ); // Fecha arquivo
83

84 FILE * pFile2; // Define pFile2 como arquivo


85 pFile2 = fopen ( "log.txt" , "r+" );
86 // Abre o arquivo log.txt com tipo de acesso r+
87 fseek ( pFile , luxPos-4 , SEEK_SET ); // Procura no arquivo na posição
88 fputs ( "Lux=" , pFile ); // Substitui por
89 fseek ( pFile , luxPos , SEEK_SET ); // Procura no arquivo na posição
90 fputs ( luxSensorStr , pFile ); // Substitui por
91 if (luxInt<100){
92 fseek ( pFile , luxPos+2 , SEEK_SET ); // Procura no arquivo na posição
93 fputs ( " " , pFile ); // Substitui por "espaço"
94 }
95 fclose ( pFile ); // Fecha arquivo
96 }
97

98 // Função que le o Horario Atual do Sistema


99 void leHora(void){
100 // Definição de variáveis
101 int dia, mes, ano, hor, min, seg;
102 struct tm *local;
103 time_t t;
104 // Para obter o horário e data atual do sistema
105 t = time(NULL);
106 local=localtime(&t);
107

108 // dia=local->tm_mday;
109 // mes=local->tm_mon+1;
110 // ano=local->tm_year+1900;

– 23 –
111

112 hor=local -> tm_hour;


113 min=local -> tm_min;
114 seg=local -> tm_sec;
115

116 horario[0]=hor;
117 horario[1]=min;
118 horario[2]=seg;
119 }
120

121 // Função que envia o Horário atual no tipo String para o index.html
122 void enviaHora(int hor, int min, int seg, int cont){
123 // Definição de variáveis
124 int horPos,minPos,segPos;
125 horPos = 0;
126 minPos = 3;
127 segPos = 6;
128 char diac[5],mesc[5],anoc[8],horc[5],minc[5],segc[5];
129 // Conversão de Integer para String
130 // snprintf(diac, 10, "%d", dia);
131 // snprintf(mesc, 10, "%d", mes);
132 // snprintf(anoc, 10, "%d", ano);
133 snprintf(horc, 10, "%d", hor);
134 snprintf(minc, 10, "%d", min);
135 snprintf(segc, 10, "%d", seg);
136

137 // Para reoganizar as posições de horário caso hora, min, seg esteja entre
138 // 0 e 9, para ser exibido assim 19:05:09 invés de 19:5 :9 .
139 if (hor<10){
140 int i;
141 for(i=4;i>0;i--){
142 horc[i] = horc[i-1];
143 }
144 horc[0] = ’0’;
145 }
146 if (min<10){
147 int i;
148 for(i=4;i>0;i--){
149 minc[i] = minc[i-1];
150 }
151 minc[0] = ’0’;
152 }

– 24 –
153 if (seg<10){
154 int i;
155 for(i=4;i>0;i--){
156 segc[i] = segc[i-1];
157 }
158 segc[0] = ’0’;
159 }
160

161 // Imprime no terminal a data e a hora atual do sistema (Debugg)


162 // fprintf(stdout,"Data: %s/%s/%s\n",diac,mesc,anoc);
163 fprintf(stdout,"Hora: %s:%s:%s\n",horc,minc,segc);
164

165 FILE * pFile; // Define pFile como arquivo


166 pFile = fopen ( "index.html" , "r+" );
167 // Abre o arquivo index.html com tipo de acesso r+
168 fseek ( pFile , 497 , SEEK_SET ); // Procura no arquivo a posição 497
169 fputs ( horc , pFile ); // Substitui por hora
170 fseek ( pFile , 500 , SEEK_SET ); // Procura no arquivo a posição 500
171 fputs ( minc , pFile ); // Substitui por min
172 fseek ( pFile , 503 , SEEK_SET ); // Procura no arquivo a posição 503
173 fputs ( segc , pFile ); // Substitui por seg
174 fclose ( pFile ); // Fecha arquivo
175

176 FILE * pFile2; // Define pFile2 como arquivo


177 pFile2 = fopen ( "log.txt" , "r+" );
178 // Abre o arquivo log.txt com tipo de acesso r+
179 fseek ( pFile , horPos , SEEK_SET ); // Procura no arquivo na posição
180 fputs ( horc , pFile ); // Substitui por hora
181 fseek ( pFile , minPos , SEEK_SET ); // Procura no arquivo na posição
182 fputs ( minc , pFile ); // Substitui por min
183 fseek ( pFile , segPos , SEEK_SET ); // Procura no arquivo na posição
184 fputs ( segc , pFile ); // Substitui por seg
185 fseek ( pFile , segPos+2 , SEEK_SET ); // Procura no arquivo na posição
186 fputs ( "_" , pFile ); // Substitui por "_"
187 fclose ( pFile ); // Fecha arquivo
188

189 }
190

– 25 –
191 // Função que le o valor do Sensor de Temperatura do Galileo
192 int leTemp(void){
193 // Define variáveis
194 char scale[4];
195 char raw[4];
196 char offset[4];
197 int raw_i;
198 int scale_i;
199 int offset_i;
200

201 // Define pFile como arquivo


202 FILE * fp_raw;
203 // Abre o arquivo
204 fp_raw = fopen("/sys/bus/iio/devices/iio:device0/in_temp0_raw", "r");
205 // Abre o arquivo
206 // Le o valor raw de temperatura
207 fgets(raw, 4, fp_raw);
208 // Fecha arquivo
209 fclose(fp_raw);
210

211 // Define pFile como arquivo


212 FILE * fp_scale;
213 // Abre o arquivo
214 fp_scale = fopen("/sys/bus/iio/devices/iio:device0/in_temp0_scale", "r");
215 // Le o valor de escala de temperatura
216 fgets(scale, 4, fp_scale);
217 // Fecha arquivo
218 fclose(fp_scale);
219

220 // Define pFile como arquivo


221 FILE * fp_offset;
222 // Abre o arquivo
223 fp_offset = fopen("/sys/bus/iio/devices/iio:device0/in_temp0_offset", "r");
224 // Le o valor de offset de temperatura
225 fgets(offset, 4, fp_offset);
226 // Fecha arquivo
227 fclose(fp_offset);
228

– 26 –
229 // Conversão de Char para Integer
230 raw_i = atoi(raw);
231 scale_i = atoi(scale);
232 offset_i = atoi(offset);
233

234 // Cálculo da temperatura atual, pois a temperatura está


235 //em miligraus celsius e fora de escala + offset
236 int temp = (raw_i + offset_i) * scale_i;
237 temp /= 1000;
238 // Retorna o valor de temperatura atual no tipo Integer
239 return temp;
240

241 }
242

243 // Função que envia o valor de Temperatura no tipo String para o index.html
244 void enviaTemp(int temp, int cont) {
245 // Define variáveis
246 char tempc[5];
247 int tempPos = 14;
248

249 // Conversão de Integer para String


250 snprintf(tempc, 10, "%d", temp);
251 // Imprime o valor atual de temperatura (Debugg)
252 fprintf(stdout, "Temperatura: %s o C\n", tempc);
253

254 FILE * pFile; // Define pFile como arquivo


255 pFile = fopen ( "index.html" , "r+" );
256 // Abre o arquivo index.html com tipo de acesso r+
257 fseek ( pFile , 309 , SEEK_SET );// Procura no arquivo a posição 309
258 fputs ( tempc , pFile );// Substitui por valor de temperatura
259 fclose ( pFile ); // Fecha arquivo
260

261 FILE * pFile2; // Define pFile2 como arquivo


262 pFile2 = fopen ( "log.txt" , "r+" );
263 // Abre o arquivo log.txt com tipo de acesso r+
264 fseek ( pFile , tempPos-5 , SEEK_SET ); // Procura no arquivo na posição
265 fputs ( "Temp=" , pFile ); // Substitui por "Temp="
266 fseek ( pFile , tempPos , SEEK_SET ); // Procura no arquivo na posição
267 fputs ( tempc , pFile ); // Substitui por temperatura
268 fseek ( pFile , tempPos+2 , SEEK_SET ); // Procura no arquivo na posição
269 fputs ( "_" , pFile ); // Substitui por "_"
270 fclose ( pFile );// Fecha arquivo
271

272 }

– 27 –
273

274 // Função que verifica a medição a cada 1 segundo,


275 //habilitando ou não a medição/envio dos valores dos sensores
276 int verificaMedicao(int auxCont){
277 // Comparacao necessária para realizar a medição dos sensores a cada 1 segundo
278 if(auxCont != horario[2]){
279 return 1;
280 }
281 else{
282 return 0;
283 }
284 }
285

286 // Função que envia o valor do Número de Medição para o index.html


287 void enviaContagem(int cont){
288 char contc[10];
289 // Conversão de Integer para String
290 snprintf(contc, 10, "%d", cont);
291 // Imprime o valor atual de temperatura (Debugg)
292 fprintf(stdout, "Numero da medicao: %s \n", contc);
293

294 FILE * pFile; // Define pFile como arquivo


295 pFile = fopen ( "index.html" , "r+" );
296 // Abre o arquivo index.html com tipo de acesso r+
297 fseek ( pFile , 464 , SEEK_SET ); // Procura no arquivo a posição 309
298 fputs ( contc , pFile ); // Substitui por valor de temperatura
299

300 if (cont<10){
301 fseek ( pFile , 465 , SEEK_SET ); // Procura no arquivo a posição
302 fputs ( " " , pFile ); // Substitui por "espaços"
303 }
304 else if (cont<100){
305 fseek ( pFile , 466 , SEEK_SET ); // Procura no arquivo a posição
306 fputs ( " " , pFile ); // Substitui por "espaços"
307 }
308 else if (cont<1000){
309 fseek ( pFile , 467 , SEEK_SET ); // Procura no arquivo a posição
310 fputs ( " " , pFile ); // Substitui por "espaços"
311 }
312 else if (cont<10000){
313 fseek ( pFile , 468 , SEEK_SET ); // Procura no arquivo a posição
314 fputs ( " " , pFile ); // Substitui por "espaços"
315 }
316 fclose ( pFile ); // Fecha arquivo
317 }

– 28 –
319 // Função Principal
320 int main()
321 {
322 // Define variável para Lux
323 int luxSensorInt, tempInt, auxCont, cont;
324 // Contador inicia em zero
325 cont = 0;
326 // Le a hora atual e atualiza a variavel global horario
327 leHora();
328 // Armazena os segundos do horario atual para variavel auxiliar
329 auxCont = horario[2];
330

331

332 // Loop infinito para envio dos valores dos Sensores e Horário atual
333 for (;;) {
334 if (verificaMedicao(auxCont) == 1){
335

336 // Atualiza variavel auxiliar


337 auxCont = horario[2];
338

339 // Le o valor de Lux atual


340 luxSensorInt = leLux();
341 // Envia o valor de Lux
342 enviaLux(luxSensorInt,cont);
343

344 // Le o horário atual


345 leHora();
346 // Envia o horário atual
347 enviaHora(horario[0],horario[1],horario[2],cont);
348

349 // Le o valor de temperatura


350 tempInt = leTemp();
351 // Envia o valor de temperatura
352 enviaTemp(tempInt,cont);
353

354 // Incrementa contagem de medição


355 cont++;
356 // Envia Contagem de Medição
357 enviaContagem(cont);
358

359 }
360 else{
361 leHora();
362 // Espera atualizar a variavel global horario para comparação com auxCont
363 }
364 }
365

366 }

– 29 –
Código 5 Código da página HTML
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8"/>
5 <meta http-equiv="refresh" content="1; url=index.html">
6 <p>Servidor WEB Galileo</p>
7 <h1 style="color: #5e9ca0; text-align: center;"><strong>Servidor WEB GALILEO YOCTO
8 </strong></h1>
9 <p>&nbsp;</p><h1 style="color: #5e9ca0; text-align: center;"><strong>Temperatura:
10 __&nbsp;&deg;
11 C</strong></h1><h1 style="color: #5e9ca0; text-align: center;"><strong>Luminosidade:
12 ___ lux<br />
13 <br />Medi&ccedil;&atilde;o de n&uacute;mero:______&nbsp;
14 <br />Hor&aacute;rio:__:__:__</strong></h1>
15 <p>&nbsp;</p><p>&nbsp;</p><p><strong>
16 <img style="display: block; margin-left: auto; margin-right: auto;"src=
17 "http://www.embarcados.com.br/wp-content/uploads/2014/03/galileo2.png"
18 alt="" width="229"height="99" />
19 <img style="display: block; margin-left: auto; margin-right: auto;" src=
20 "http://www.ufpr.br/portalufpr/wp-content/uploads/2015/11/ufpr_alta.jpg"
21 alt="" width="172"
22 height="116" />
23 </strong></p><p style="text-align: center;">&nbsp;</p><p><strong>
24 <img style="display: block; margin-left: auto; margin-right: auto;"src=
25 "http://www.yoctoproject.org/docs/current/yocto-project-qs/figures/
26 yocto-project-transp.png"
27 alt="Yocto" width="208" height="79" /></strong></p>
28 </html>

– 30 –
Referências

[1] F. K. Santoso, Securing IoT for Smart Home System. Singapore: IEEE, 2015.
[2] “Yocto project,” October 2016, https://www.yoctoproject.org/about.
[3] “Introdução do projeto yocto,” Outubro 2016,
http://www.decom.ufop.br/imobilis/projeto-yocto-introducao-ao-m2m/.
[4] “Como funcionam os sensores fotoelétricos,” Outubro 2016,
http://www.newtoncbraga.com.br/index.php/como-funciona/4883-art644.
[5] “Web developer notes,” October 2016, http://www.webdevelopers.com/what-is-web-server.
[6] “Como funciona um servidor web,” Outubro 2016,
http://portaleducacao.com.br/informatica/artigos/17165/como-funciona-um-servidor-web.
[7] “Sockets,” October 2016, http://www.inf.pucrs.br/ fldotti/redes/982/sockets.htm.

– 31 –

Das könnte Ihnen auch gefallen