Usando modem GSM/3G/4G no Linux Embarcado

modem

A necessidade de equipamentos embarcados conectados à internet continua crescendo a cada dia. Uma ótima opção quando não se tem internet cabeada ou Wi-Fi é buscar cobertura das redes de telefonia móvel. Sendo assim, este tutorial apresenta as configurações necessárias para conectar uma placa utilizando Linux Embarcado à internet por meio do link PPP (Point-to-Point Protocol).

 

Equipamento Utilizado

 

Para este tutorial foi utilizado o módulo Colibri iMX6S em conjunto com a placa Colibri Evaluation Board, ambos da Toradex. A Colibri Evaluation é uma placa recomendada para desenvolvimento de projetos, que disponibiliza uma variedade de interfaces de conectividade, incluindo USB 2.0, 100 Mbit Fast Ethernet, I2C, SPI, RS232, RS485 e CAN. As interfaces multimídia disponíveis incluem áudio analógico, HDMI, LVDS, VGA e LCD TFT.

 

Para realizar a conexão com a internet, é possivel executar todo o tutorial com qualquer modem USB ou Serial. Atente-se apenas a adaptar a interface usada do “/dev” e aos comandos “ATs” devido ao fato de que cada modem tem sua própria lista de comandos.

 

No nosso caso, nos baseamos em um modem 3G da Huawei modelo E173s, com um SIM card da Operadora Vivo.

 

Preparando o KERNEL

 

Para utilizar modens USB por meio do protocolo PPP, é necessário que o kernel Linux possua suporte a algumas funcionalidades. Sendo assim, caso não esteja pré-selecionado no kernel, será necessário adicionar alguns itens. Para compilar o Kernel, sugiro que usem o artigo abaixo como base:

 

http://developer.toradex.com/software-resources/arm-family/linux/board-support-package/build-u-boot-and-linux-kernel-from-source-code


Basicamente o processo para compilar o kernel se resume nos seguintes passos:

  • Configuração da toolchain;
  • Baixar o kernel do repositório;
  • Configurar as características padrão do processador (defconfig);
  • Alterá-las para sua aplicação;
  • Compilar.

 

Quando você estiver no passo de alterar as configurações padrões, entre no menuconfig e certifique-se de habilitar as seguintes opções:

 

CONFIG_PPP:
PPP (Point to Point Protocol) is a newer and better SLIP.  It serves the same purpose: sending Internet traffic over telephone (and other serial) lines.  Ask your access provider if they support it, because otherwise you can't use it; most Internet access providers these days support PPP rather than SLIP. 
Device Drivers  ---> 
    [*] Network device support  --->
        <*>   PPP (point-to-point protocol) support
        <*>     PPP BSD-Compress compression
        <*>     PPP Deflate compression 
        [*]     PPP filtering
        <*>     PPP MPPE compression (encryption)
        [*]     PPP multilink support 
        <*>     PPP over Ethernet  
        <*>     PPP support for async serial ports
        <*>     PPP support for sync tty ports

CONFIG_USB_ACM:
This driver supports USB modems and ISDN adapters which support the
Communication Device Class Abstract Control Model interface.
Please read <file:Documentation/usb/acm.txt> for details.      

Device Drivers  --->
    [*] USB support  --->
        <*>     USB Modem (CDC ACM) support 

 

 

Programas necessários

 

Para configurar e conectar o modem à internet, o Linux utiliza além dos drivers do kernel, um software a nível de aplicação que gerência a conexão. Normalmente as imagens da Toradex já vem com o PPP instalado.

 

Caso você não tenha o programa "ppp" instalado, e você tenha uma imagem baseada em Yocto ou Openembedded, adicione ao arquivo “local.conf” o pacote PPP:

 

IMAGE_INSTALL_append = " ppp"

 

 

Testando comunicação com Modem

 

Após ter instalado todos os drivers e programas necessários, é possível identificar se sua placa reconheceu o modem através do /dev. Basicamente o driver simula a conexão USB em várias conexões seriais.

 

Execute o comando para buscar as interfaces /dev/ttyUSB.

 

$ ls -l /dev/ttyUSB*

 

Se os arquivos ttyUSB0, ttyUSB1 … e ttyUSB2 forem encontrados, o modem USB foi reconhecido.

 

Caso você queira ir mais a fundo nos testes, é possível usar um terminal serial como "minicom" para iniciar a comunicação com o modem e validar a comunicação com o mesmo.

 

No meu caso o meu modem estava configurado com velocidade 115200.

 

$ minicom -D /dev/ttyACM0
___________________________
AT
OK
___________________________

 

 

Configurando os Arquivos do PPP

 

Após ter validado a conexão serial com o modem é hora de criar os arquivos de configuração para conexão com a internet.

 

Você deverá ser capaz de encontrar a pasta "/etc/ppp". Iremos criar alguns arquivos dentro dela para realizar a conexão.

 

Primeiro, iremos criar o arquivo de configuração do PPP:

 

$ vi /etc/ppp/options
_____________________________________
auth
crtscts
lock
hide-password
modem
mru 296
mtu 296
lcp-echo-interval 30
lcp-echo-failure 4
noipx
persist
asyncmap 0xa0000
mru 1500
refuse-chap
ipcp-max-failure 30
logfile /home/root/ppp
_____________________________________

 

No meu caso iremos usar o arquivo de autenticação PAP (variam em relação à operadora).

 

$ vi /etc/ppp/pap-secrets
_____________________________________
#    *      password
vivo vivo vivo
_____________________________________

 

O próximo passo foi criar o arquivo dentro da pasta /etc/ppp/peer.

 

Nele estão as configurações para cara operadora e o caminho para o arquivo chat.

 

Para a Vivo foi criado o seguinte arquivo:

 

$ vi /etc/ppp/peers/vivo-3g.provider
_____________________________________
hide-password
noauth
debug
defaultroute
noipdefault
user vivo
remotename vivo
ipparam vivo
persist
usepeerdns
/dev/ttyUSB0 115200 crtscts
replacedefaultroute
connect 'chat -v -f /etc/ppp/chat/vivo-3g.chat'

 

Agora iremos criar o arquivo responsável por enviar os comandos AT para o módulo 3G estabelecer a conexão com a internet. Esse arquivo varia conforme o módulo usado.

 

$ vi /etc/ppp/chat/vivo-3g.chat
_____________________________________
ECHO
ON
ABORT
'BUSY'
ABORT
'NO CARRIER'
ABORT
'ERROR'
""
ATZ OK
\d\dAT+CGDCONT=1,"IP","zap.vivo.com.br" OK
\d\d\dATDT*99# CONNECT
_____________________________________

 

 

Conectando à Internet

 

Em seguida iremos executar o programa PPP e analisar os log’s para verificar a execução de cada comando AT.

 

$ pon vivo-3g.provider

 

Após executado, abra o arquivo de LOG.

 

$ tail -f "ARQUIVO"
$ tail -f ppp

 

No meu caso obtive o seguinte resultado:

 

__________________________________________
tail -f ppp.log 
Sent 3940 bytes, received 2843 bytes.
restoring old default route to eth0 [192.168.10.1]
restore default route ioctl(SIOCADDRT): Network is unreachable(101)
Script /etc/ppp/ip-down started (pid 778)
sent [LCP TermReq id=0x2 "User request"]
rcvd [LCP TermAck id=0x2]
Connection terminated.
Script /etc/ppp/ip-down finished (pid 778), status = 0x0
ATZ
OK
AT+CGDCONT=1,"IP","zap.vivo.com.br"
OK
ATDT*99#
CONNECT
Script chat -v -f /etc/ppp/chat/vivo-3g.chat finished (pid 795), status = 0x0
Serial connection established.
using channel 2
Using interface ppp0
Connect: ppp0 <--> /dev/ttyACM0
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <auth pap> <magic 0x96baf40f> <pcomp> <accomp>]
sent [LCP ConfReq id=0x1 <asyncmap 0xa0000> <magic 0xa068db01> <pcomp> <accomp>]
sent [LCP ConfAck id=0x1 <asyncmap 0x0> <auth pap> <magic 0x96baf40f> <pcomp> <accomp>]
rcvd [LCP ConfAck id=0x1 <asyncmap 0xa0000> <magic 0xa068db01> <pcomp> <accomp>]
sent [LCP EchoReq id=0x0 magic=0xa068db01]
sent [PAP AuthReq id=0x1 user="vivo" password=<hidden>]
rcvd [LCP EchoRep id=0x0 magic=0x96baf40f]
rcvd [PAP AuthAck id=0x1 ""]
PAP authentication succeeded
sent [CCP ConfReq id=0x1 <deflate 15> <deflate(old#) 15> <bsd v1 15>]
sent [IPCP ConfReq id=0x1 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 0.0.0.0> <ms-dns2 0.0.0.0>]
rcvd [LCP ProtRej id=0x2 80 fd 01 01 00 0f 1a 04 78 00 18 04 78 00 15]
Protocol-Reject for 'Compression Control Protocol' (0x80fd) received
rcvd [IPCP ConfNak id=0x1 <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
sent [IPCP ConfReq id=0x2 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
rcvd [IPCP ConfNak id=0x2 <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
sent [IPCP ConfReq id=0x3 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
rcvd [IPCP ConfNak id=0x3 <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
sent [IPCP ConfReq id=0x4 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
rcvd [IPCP ConfNak id=0x4 <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
sent [IPCP ConfReq id=0x5 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
rcvd [IPCP ConfNak id=0x5 <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
sent [IPCP ConfReq id=0x6 <compress VJ 0f 01> <addr 0.0.0.0> <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
rcvd [IPCP ConfReq id=0x1]
sent [IPCP ConfNak id=0x1 <addr 0.0.0.0>]
rcvd [IPCP ConfRej id=0x6 <compress VJ 0f 01>]
sent [IPCP ConfReq id=0x7 <addr 0.0.0.0> <ms-dns1 10.11.12.13> <ms-dns2 10.11.12.14>]
rcvd [IPCP ConfReq id=0x2 <addr 179.133.47.109>]
sent [IPCP ConfAck id=0x2 <addr 179.133.47.109>]
rcvd [IPCP ConfNak id=0x7 <addr 179.133.47.109> <ms-dns1 187.100.246.254> <ms-dns2 187.100.246.251>]
sent [IPCP ConfReq id=0x8 <addr 179.133.47.109> <ms-dns1 187.100.246.254> <ms-dns2 187.100.246.251>]
rcvd [IPCP ConfAck id=0x8 <addr 179.133.47.109> <ms-dns1 187.100.246.254> <ms-dns2 187.100.246.251>]
local  IP address 179.133.47.109
remote IP address 179.133.47.109
primary   DNS address 187.100.246.254
secondary DNS address 187.100.246.251
Script /etc/ppp/ip-up started (pid 805)
Script /etc/ppp/ip-up finished (pid 805), status = 0x0
______________________________________________________

 

Conforme visto no log, o script chat é executado passo a passo até obter:

 

ATDT*99#
CONNECT

 

Você pode validar a sequência de comando necessária para chegar até o connect por meio do terminal serial. Uma vez validado você pode gerar seu chat script personalizado.

 

Após verificar que foi possível obter um IP da operadora, veja se a interface de rede ppp0 está ativa:

 

[email protected]:/etc/ppp# ifconfig 
eth0      Link encap:Ethernet  HWaddr 00:14:2D:C0:00:4C  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:1181 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1223 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:107025 (104.5 KiB)  TX bytes:149841 (146.3 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:22 errors:0 dropped:0 overruns:0 frame:0
          TX packets:22 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1536 (1.5 KiB)  TX bytes:1536 (1.5 KiB)

ppp0      Link encap:Point-to-Point Protocol  
          inet addr:179.133.47.109  P-t-P:179.133.47.109  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:296  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:35 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:3 
          RX bytes:1330 (1.2 KiB)  TX bytes:2131 (2.0 KiB)

 

 

Testando a conexão

 

Em seguida, teste a conexão com a internet pingando algum IP externo:

 

[email protected]:/etc/ppp# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=45 time=182.304 ms
64 bytes from 8.8.8.8: seq=1 ttl=45 time=34164.126 ms
64 bytes from 8.8.8.8: seq=2 ttl=45 time=33164.085 ms

 

Para configurar o DNS podemos usar o comando a seguir, e então “pingar” uma URL. Por exemplo:

 

$ echo nameserver 8.8.8.8 > /etc/resolv.conf
$ ping google.com

 

Setup para teste de conexão com modem
Figura 1 - Setup para teste de conexão

 

Podemos evitar que o arquivo resolv.conf seja reescrito quando a placa é reiniciada com o comando:

 

$ chattr +i /etc/resolv.conf

 

Agora é possível acessar a placa via SSH de um computador externo conectado na internet usando o comando a seguir:

 

$ ssh [email protected]

 

 

Configurando um nome Host para nosso IP

 

Outra coisa que podemos fazer é dar ao nosso IP um nome host. Para isso utilizamos o serviço do site NoIP. Foi criada uma conta gratuita e adicionado um Host. No nosso caso foi escolhido toradex.noip.me.

 

Configurando um nome Host para nosso IP usando modem 3G
Figura 2 - Configurando um nome Host para nosso IP

 

Após criado um host no site podemos acessar a placa com o comando:

 

$ ssh [email protected]

 

No nosso caso, sempre que reiniciamos a conexão ou o modem 3G, recebemos um novo endereço IP. Então se tentarmos conectar com a placa novamente, vamos notar que não temos mais acesso. Para contornar esse problema, existe o método chamado DNS Dinâmico (Dynamic Domain Name System). O site noip.me também oferece o serviço de DNS Dinâmico. Algumas informações para realizar esse processo de troca de IP podem ser encontradas aqui. Basicamente precisamos fazer um http request para o site deles contendo informações como IP, nome do host, nome de usuário e senha.

 

Para fazer esse request foi feito um programa em Python, que é executado quando iniciamos a conexão do modem, e basicamente segue a seguinte sequência:

 

Fluxograma do programa em Python - modem 3G
Figura 3 - Fluxograma do programa em Python

 

#!/usr/bin/python

import sys
import requests
import netifaces as ni

user = 'xxxxxxx'
pswd = 'xxxxxxx'

ni.ifaddresses('ppp0')
ip = ni.ifaddresses('ppp0')[2][0]['addr']
myhostname = 'toradex.noip.me'

payload = {'hostname' : myhostname , 'myip' : ip}
r = requests.get("http://dynupdate.no-ip.com/nic/update", params=payload, auth=(user,pswd))

print " " 
if "good" in r.text:
	print "Hello", user, "!"
	print "Your IP was successfully updated to:", ip
	print myhostname, "is up and running!"
if "nochg" in r.text:
	print "Hello", user, "!"
	print "Your IP", ip, "is still active, no change needed"
if "nohost" in r.text:
print "The given Host name", myhostname, "does not exist under specified account"
	print "Please review your Host name and try again"
if "badauth" in r.text:
	print "Login and/or Username incorrect"
	print "Please correct your credentials and try again"
if "911" in r.text:
	print "Sorry for the incovenience but we are experiencing some problems right now"
	print "Please try again later"
print "noip.com says:", r.text
print " "

 

Após criado o programa em python e tornado o mesmo executável com o comando chmod +x, podemos colocá-lo na pasta /etc/ppp/ip-up.d/ que é a pasta onde se encontram os scripts executados após o link da conexão ppp ser estabelecido ou criar dentro dessa pasta um pequeno script que chama nossa aplicação em Python.

 

No diretório /etc/ppp/ se encontram os arquivos como ip-down, ip-up, ppp_on_boot e também os arquivos que criamos no início do artigo. Sinta-se livre para abrir esses arquivos e verificar o que cada um faz.

 

O ip-up é o script que chama outro script ou programa em python localizado dentro da pasta ip-up.d.

 

No nosso caso criamos um pequeno script dentro da pasta ip-up.d:

 

#!/bin/bash
python /home/root/noipReq.py > /home/root/noipLog.log

 

Obs: O script não tem a terminação .sh.

 

Note que todos os comandos print dentro do programa em python podem ser vistos depois no arquivo de log.

 

[email protected]:~# cat noipLog.log 
 
Hello giovannibauer !
Your IP was successfully updated to: 179.92.172.193
toradex.noip.me is up and running!
noip.com says: good 179.92.172.193

 

Se tudo foi configurado corretamente, sempre que recebemos um novo IP da Vivo ao realizarmos uma nova conexão, o sistema automaticamente atualiza o nosso Host criado no noip.com, tornando possível o acesso à placa qualquer que seja o seu endereço IP.

 

A partir disso, é possivel realizar muitas outras atividades com relação a redes. Uma delas é compartilhar a internet da placa em que temos conectado o modem 3G USB com algum outro computador via ethernet. Para isso configuramos uma rede LAN básica entre dois computadores e usamos o seguinte comando na placa:

 

iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

 

Além do compartilhamento de internet também é possível fazer port forwarding e muitas outras funções de rede.

 

 

Considerações Finais

 

Conforme visto no tutorial, o sistema operacional Linux te traz diversas funcionalidades já prontas. Sendo assim, basta apenas configurá-las corretamente para obter acesso à interface de rede ppp0. Outro ponto importante é que, independentemente da interface de rede usada, o modo de programar é o mesmo e o gerenciamento do meio (eth0, wlan0 ou ppp0) pelo qual a conexão vai ser estabelecida é feito automaticamente pelo Linux dependendo das rotas. Para aqueles que requerem o uso de redes em projetos e prezam pela flexibilidade do sistema, a utilização do Linux em sistemas embarcados traz uma grande facilidade.

 

 

Referências

 

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Raul Muñoz
Raul Rosetto Muñoz é graduado em Engenharia Elétrica pela Universidade São Francisco. Desde 2008, tem trabalhando na área de sistemas embarcados. No começo da sua carreira trabalhou com desenvolvimento de software para microcontroladores. Nos últimos 8 anos, tem focado no desenvolvimento e customização de Linux embarcado. Atualmente é engenheiro de aplicação e vendas na empresa Toradex Brasil, empresa global com matriz na Suíça qual desenvolve computadores em módulo de alta performance.
recentes antigos mais votados
Notificar
trackback

[…] Artigo: Usando modem GSM/3G/4G no Linux Embarcado […]