Este artigo faz parte da série Primeiros Passos com o ESP32 e NuttX e mostra como aplicações podem ser criadas, adaptadas e integradas ao NuttX, facilitando o uso de códigos já existentes. Especificamente, será integrada ao NuttX a aplicação RTP Tools como uma continuação do projeto Servidor de Som: Raspberry Pi + Home Theater DIY. A utilização do RTP Tools será explorada mais adiante no artigo.
O processo de compilação de uma aplicação no NuttX, seja ela uma aplicação própria ou uma já existente em outros sistemas operacionais, segue os princípios do sistema de build do NuttX. Embora a documentação do NuttX aborde aspectos do processo de compilação de aplicações, exploraremos algumas opções desta etapa mais profundamente neste artigo.
Para quem não estiver habituado com o NuttX, recomendo a leitura dos artigos Primeiros Passos com o ESP32 e o NuttX e O que é o RTOS NuttX e por que você deve se importar? ou, ainda, o Getting Started da documentação oficial do NuttX. Estes documentos destacam o grande diferencial do NuttX: ser um sistema “POSIX-compliant” permite que muitas aplicações sejam facilmente integradas ao sistema. Com isso, vale aquela máxima: “Não reinventem a roda. Alguém já deve ter desenvolvido uma aplicação para resolver seu ‘problema’”! Neste sentido, o desenvolvimento de um produto com o NuttX é extremamente facilitado ao aproveitarmos aplicações e bibliotecas comumente utilizadas que podem ser adaptadas sem grande esforço ao NuttX (se, é claro, isso já não tiver sido feito antes). Desta forma, o desenvolvedor pode concentrar-se no desenvolvimento da aplicação fim do produto a partir de aplicações e bibliotecas largamente testadas, validadas e com vasta documentação disponível.
Neste artigo explicamos como aplicações e bibliotecas podem ser integradas ao NuttX através do sistema de build e, partindo dessa explicação, iremos integrar da aplicação RTP Tools para o NuttX. Esta aplicação é, na verdade, uma série de utilitários que, dentre outras coisas, permite receber pacotes RTP (Real Time Protocol) pela rede. A aplicação que utilizará o RTP Tools será posteriormente detalhada em outro artigo, que será a continuação de Servidor de Som: Raspberry Pi + Home Theater DIY. Adiantando um pouco o assunto: já pensaram que legal seria fazer de um ESP32 um servidor de som de baixíssimo custo e alta-fidelidade? Pois bem, talvez precisemos do RTP Tools pra isso 😉
Criando uma Aplicação no NuttX
As aplicações do NuttX são separadas do código-fonte do kernel do sistema operacional. Assim como em outros sistemas operacionais, elas interagem com o kernel do NuttX através de APIs públicas compatíveis com o padrão POSIX. Vale a pena observar, porém, que as aplicações precisam utilizar o build system do NuttX para serem agregadas ao firmware final. Para essa finalidade, o projeto Apache NuttX disponibiliza também o repositório nuttx-apps, que é um compilado de aplicações que estão disponíveis para serem compiladas no NuttX. As aplicações e bibliotecas disponíveis neste repositório são públicas e podem ser utilizadas por qualquer usuário da comunidade. O NuttX fornece, também, meios de compilar aplicações fora deste repositório, permitindo que aplicações proprietárias (e, por vezes, não públicas) sejam agregadas ao sistema.
Nota: não é toda aplicação que precisa ser disponibilizada publicamente no nuttx-apps. É possível manter aplicações não públicas, mas isso é assunto para outro artigo (ou, se estiver muito curioso, consulte a documentação oficial).
Hello World!
A aplicação mais utilizada como exemplo por sistemas operacionais e linguagens de programação é, talvez, o “Hello World!”: uma aplicação que imprime estas palavras na interface com o usuário. Com o NuttX não é diferente e esta aplicação pode ser encontrada em apps/examples/hello, de nuttx-apps.
A seção Application Configuration File (do repositório nuttx-apps) e a seção Extend the apps/ directory to include a new custom directory, do guia “Custom Apps How-to” (da documentação oficial) explicam um pouco do sistema de build do NuttX e, principalmente, de como agregar uma aplicação ao NuttX. Com base nestes documentos, explicamos aqui sobre a compilação da aplicação Hello World!.
O diretório apps/examples/hello contém os seguintes arquivos:
./examples/hello
├── hello_main.c
├── Kconfig
├── Make.defs
└── Makefile
O arquivo hello_main.c é o código-fonte da aplicação. Os demais estão relacionados ao sistema de build do NuttX, que configura e seleciona esta aplicação para que seja compilada e agregada ao NuttX.
O Sistema de Build
O NuttX utiliza o kconfig-frontends (ou, mais recentemente, a kconfiglib) para gerar o arquivo de configuração do NuttX (.config) no diretório raiz do repositório do sistema operacional do NuttX. Por exemplo, ao compilar o exemplo do Hello World!, uma das opções que este arquivo terá é:
CONFIG_EXAMPLES_HELLO=y
Mas, de onde vem esta opção e como registramos esta aplicação para ser compilada no NuttX?
Kconfig
A configuração CONFIG_EXAMPLES_HELLO=y é disponibilizada para ser selecionada pelo sistema de build através do arquivo apps/examples/hello/Kconfig do repositório de aplicações. Assim, é este arquivo que – através da linha config EXAMPLES_HELLO (como veremos a seguir) – permite que o sistema de build do NuttX saiba da existência dessa aplicação. O arquivo Kconfig da aplicação Hello World! possui o seguinte conteúdo:
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config EXAMPLES_HELLO
tristate "\"Hello, World!\" example"
default n
---help---
Enable the \"Hello, World!\" example
if EXAMPLES_HELLO
config EXAMPLES_HELLO_PROGNAME
string "Program name"
default "hello"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config EXAMPLES_HELLO_PRIORITY
int "Hello task priority"
default 100
config EXAMPLES_HELLO_STACKSIZE
int "Hello stack size"
default DEFAULT_TASK_STACKSIZE
endif
Vale notar que todas as opções adicionadas pelo Kconfig terão o prefixo CONFIG_ quando acessadas pela aplicação e outros arquivos de build. Por exemplo, o valor da configuração EXAMPLES_HELLO_PROGNAME poderá ser acessado utilizando a definição CONFIG_EXAMPLES_HELLO_PROGNAME. Essas definições estão disponibilizadas para aplicações através da inclusão do header nuttx/config.h.
Make.defs
Com base nesta configuração, o sistema de build do NuttX incluirá o arquivo apps/examples/Make.defs que, por sua vez, adiciona o diretório apps/examples/hello à variável CONFIGURED_APPS da seguinte forma:
ifneq ($(CONFIG_EXAMPLES_HELLO),)
CONFIGURED_APPS += $(APPDIR)/examples/hello
endif
Uma vez adicionado o diretório da aplicação à variável CONFIGURED_APPS, o arquivo apps/examples/hello/Makefile é incluído no sistema de build.
Makefile
Finalmente, o arquivo apps/examples/hello/Makefile fornece as diretrizes para compilação da aplicação no NuttX. Para o Hello World!, o conteúdo do arquivo é:
include $(APPDIR)/Make.defs
# Hello, World! built-in application info
PROGNAME = $(CONFIG_EXAMPLES_HELLO_PROGNAME)
PRIORITY = $(CONFIG_EXAMPLES_HELLO_PRIORITY)
STACKSIZE = $(CONFIG_EXAMPLES_HELLO_STACKSIZE)
MODULE = $(CONFIG_EXAMPLES_HELLO)
# Hello, World! Example
MAINSRC = hello_main.c
# Build with WebAssembly when CONFIG_INTERPRETERS_WAMR is enabled
WASM_BUILD = y
# Mode of WebAssembly Micro Runtime
WAMR_MODE = AOT
include $(APPDIR)/Application.mk
Note que a receita (o arquivo Makefile) define algumas variáveis como, por exemplo, PROGNAME, PRIORITY, STACKSIZE e MODULE. Estas variáveis são definidas por valores configurados pelo Kconfig.
No entanto, o mais importante é a definição da variável MAINSRC, que define qual será o arquivo fonte (.c) a ser compilado (no caso, hello_main.c). Observe que, embora não presente neste exemplo, outras variáveis podem ser definidas, como CSRCS, que inclui outros códigos C auxiliares, e ASRCS, que inclui arquivos assembly (*.asm), por exemplo.
A Aplicação de Exemplo
O último arquivo no diretório apps/examples/hello é, finalmente, o código fonte da aplicação. O conteúdo de hello_world.c é o seguinte:
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* hello_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
printf("Hello, World!!\n");
return 0;
}
Observe que o código fonte desta aplicação não necessita de nenhuma alteração para ser compilado quando comparado a qualquer outro sistema operacional com suporte à linguagem C e a POSIX. O ponto de entrada da aplicação é definido de modo semelhante, sendo representado pela função main().
Integrando Aplicações Externas
O exemplo Hello World! é uma ótima introdução de como o sistema de build do NuttX permite a compilação de aplicações de forma rápida e simples. No entanto, note que o código fonte da aplicação (hello_main.c, no caso) está integrado ao repositório de aplicações e, assim, poderíamos inferir que a aplicação de exemplo foi escrita para o NuttX (embora seja muito semelhante a uma aplicação genérica). Assim sendo, vamos explorar nesta seção a integração de uma aplicação/biblioteca externa cujo código fonte tenha sido concebido – originalmente – para outros sistemas baseado em Unix. Sendo assim, como poderíamos compilar no NuttX, por exemplo, o Mbed TLS?
Mbed TLS
O repositório do Mbed TLS a define como, em tradução livre: “Mbed TLS é uma biblioteca C que implementa primitivas criptográficas, manipulação de certificados X.509 e os protocolos SSL/TLS e DTLS. Seu pequeno tamanho de código o torna adequado para sistemas embarcados”. Ou seja, o Mbed TLS é uma biblioteca que, embora possua aplicações próprias, fornece funções criptográficas que podem ser usadas por outras aplicações. Vejamos como ela pode ser integrada ao NuttX!
O diretório apps/crypto/mbedtls/Makefile do repositório de aplicações contém os arquivos que permitem compilar esta aplicação no NuttX:
./crypto/mbedtls
├── Kconfig
├── Make.defs
└── Makefile
Observe que não existe nenhum arquivo fonte (.c) ou de cabeçalho (.h) presente neste repositório! Isso é possível porque o código fonte do Mbed TLS é baixado para ser compilado somente quando a aplicação é selecionada no sistema de build do NuttX. Mas como?
Makefile
O arquivo Makefile disponibilizado no diretório de cada aplicação, além de definir variáveis utilizadas na compilação da aplicação e do sistema NuttX, permite também escrever (e sobrescrever) receitas comumente utilizadas em arquivos Makefile (caso necessário, consulte o manual da aplicação make). Observe o conteúdo do arquivo apps/crypto/mbedtls/Makefile:
include $(APPDIR)/Make.defs
# Mbed TLS crypto library
# Set up build configuration and environment
MBEDTLS_URL ?= "https://github.com/ARMmbed/mbedtls/archive"
MBEDTLS_VERSION = $(patsubst "%",%,$(strip $(CONFIG_MBEDTLS_VERSION)))
MBEDTLS_ZIP = v$(MBEDTLS_VERSION).zip
MBEDTLS_UNPACKNAME = mbedtls
UNPACK ?= unzip -q -o
MBEDTLS_UNPACKLIBDIR = $(MBEDTLS_UNPACKNAME)$(DELIM)library
MBEDTLS_UNPACKPROGDIR = $(MBEDTLS_UNPACKNAME)$(DELIM)programs
# This lets Mbed TLS better use some of the POSIX features we have
CFLAGS += ${DEFINE_PREFIX}__unix__
library/bignum.c_CFLAGS += -fno-lto
ifeq ($(CONFIG_ARCH_SIM),y)
CFLAGS += -O0
endif
CSRCS = $(wildcard $(MBEDTLS_UNPACKLIBDIR)$(DELIM)*.c)
$(MBEDTLS_ZIP):
@echo "Downloading: $(MBEDTLS_URL)/$(MBEDTLS_ZIP)"
$(Q) curl -O -L $(MBEDTLS_URL)/$(MBEDTLS_ZIP)
$(MBEDTLS_UNPACKNAME): $(MBEDTLS_ZIP)
@echo "Unpacking: $(MBEDTLS_ZIP) -> $(MBEDTLS_UNPACKNAME)"
$(Q) $(UNPACK) $(MBEDTLS_ZIP)
$(Q) mv mbedtls-$(MBEDTLS_VERSION) $(MBEDTLS_UNPACKNAME)
$(Q) touch $(MBEDTLS_UNPACKNAME)
# Download and unpack tarball if no git repo found
ifeq ($(wildcard $(MBEDTLS_UNPACKNAME)/.git),)
context:: $(MBEDTLS_UNPACKNAME)
distclean::
$(call DELDIR, $(MBEDTLS_UNPACKNAME))
$(call DELFILE, $(MBEDTLS_ZIP))
endif
# Configuration Applications
ifneq ($(CONFIG_MBEDTLS_APPS),)
MODULE = $(CONFIG_MBEDTLS_APPS)
ifeq ($(CONFIG_MBEDTLS_APP_BENCHMARK),y)
PROGNAME += $(CONFIG_MBEDTLS_APP_BENCHMARK_PROGNAME)
PRIORITY += $(CONFIG_MBEDTLS_APP_BENCHMARK_PRIORITY)
STACKSIZE += $(CONFIG_MBEDTLS_APP_BENCHMARK_STACKSIZE)
MAINSRC += $(MBEDTLS_UNPACKPROGDIR)/test/benchmark.c
endif
ifeq ($(CONFIG_MBEDTLS_APP_SELFTEST),y)
PROGNAME += $(CONFIG_MBEDTLS_APP_SELFTEST_PROGNAME)
PRIORITY += $(CONFIG_MBEDTLS_APP_SELFTEST_PRIORITY)
STACKSIZE += $(CONFIG_MBEDTLS_APP_SELFTEST_STACKSIZE)
MAINSRC += $(MBEDTLS_UNPACKPROGDIR)/test/selftest.c
endif
endif
include $(APPDIR)/Application.mk
Baixando o Código Fonte
De acordo com a seção Built-In Applications (do nuttx-apps), em tradução livre:
“A compilação ocorre em várias fases conforme diferentes destinos de compilação (targets) são executados: (1) contexto (context), (2) dependência (depend) e (3) padrão (todos/all). As informações do aplicativo são coletadas durante a fase de compilação do contexto”.
Note que a receita context é sempre executada pelo sistema de build do NuttX e, geralmente, é ela que prepara a compilação de uma aplicação. Para esta aplicação, do Mbed TLS, ela é dependente do arquivo definido por $(MBEDTLS_UNPACKNAME), que é dependente de outro arquivo definido por $(MBEDTLS_ZIP) que, por sua vez, é baixado pela receita:
$(MBEDTLS_ZIP):
@echo "Downloading: $(MBEDTLS_URL)/$(MBEDTLS_ZIP)"
$(Q) curl -O -L $(MBEDTLS_URL)/$(MBEDTLS_ZIP)
Desta forma, o sistema de build é capaz de baixar um arquivo compactado que contém o código fonte do Mbed TLS diretamente do repositório do próprio projeto. Uma vez baixado, este código será descompactado em uma pasta e estará disponível para ser compilado e integrado pelo NuttX.
Aplicações e Biblioteca
Diferentemente do exemplo anterior, podemos observar que este Makefile acrescenta arquivos fonte também à variável CSRCS:
MBEDTLS_UNPACKLIBDIR = $(MBEDTLS_UNPACKNAME)$(DELIM)library
CSRCS = $(wildcard $(MBEDTLS_UNPACKLIBDIR)$(DELIM)*.c)Desta forma, arquivos fontes da pasta library do Mbed TLS são adicionados à variável CSRCS. Ou seja, arquivos da biblioteca do Mbed TLS serão compilados apesar de não serem – propriamente falando – aplicações executáveis. A biblioteca do Mbed TLS fornece APIs de criptografia a outras aplicações do sistema. Mas, de modo a testar as funcionalidades da biblioteca, o repositório do Mbed TLS fornece também aplicações de teste, que podem ser ativadas através das configurações em apps/crypto/mbedtls/Kconfig. O registro da aplicação executável de benchmark é realizado na seguinte seção do arquivo Makefile:
MBEDTLS_UNPACKPROGDIR = $(MBEDTLS_UNPACKNAME)$(DELIM)programs
# Configuration Applications
ifneq ($(CONFIG_MBEDTLS_APPS),)
MODULE = $(CONFIG_MBEDTLS_APPS)
ifeq ($(CONFIG_MBEDTLS_APP_BENCHMARK),y)
PROGNAME += $(CONFIG_MBEDTLS_APP_BENCHMARK_PROGNAME)
PRIORITY += $(CONFIG_MBEDTLS_APP_BENCHMARK_PRIORITY)
STACKSIZE += $(CONFIG_MBEDTLS_APP_BENCHMARK_STACKSIZE)
MAINSRC += $(MBEDTLS_UNPACKPROGDIR)/test/benchmark.c
endif
Esta porção do Makefile compila, se selecionado, a aplicação de benchmark do Mbed TLS. Observe que, se CONFIG_MBEDTLS_APP_BENCHMARK=y, o código fonte em [programs/test/benchmark.c](https://github.com/Mbed-TLS/mbedtls/blob/v3.0.0/programs/test/benchmark.c) será acrescentado à MAINSRC. De forma semelhante, a aplicação de auto-teste em [programs/test/selftest.c](https://github.com/Mbed-TLS/mbedtls/blob/v3.0.0/programs/test/selftest.c) pode ser compilada se CONFIG_MBEDTLS_APP_SELFTEST=y.
Kconfig
O arquivo Kconfig do Mbed TLS, por exemplo, seleciona – além da versão da biblioteca a ser baixada – as aplicações de teste que também serão compiladas. O conteúdo do Kconfig pode ser visualizado a seguir:
menuconfig CRYPTO_MBEDTLS
bool "Mbed TLS Cryptography Library"
default n
---help---
Enable support for Mbed TLS.
if CRYPTO_MBEDTLS
config MBEDTLS_VERSION
string "Mbed TLS Version"
default "3.0.0"
menuconfig MBEDTLS_APPS
tristate "Mbed TLS Applications"
default n
---help---
Enable Mbed TLS Applications
if MBEDTLS_APPS
config MBEDTLS_DEFAULT_TASK_STACKSIZE
int "Mbed TLS app default stack size"
default 8192
config MBEDTLS_APP_BENCHMARK
bool "Mbed TLS benchmark"
default n
---help---
Enable the Mbed TLS self test
if MBEDTLS_APP_BENCHMARK
config MBEDTLS_APP_BENCHMARK_PROGNAME
string "Program name"
default "mbedbenchmark"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config MBEDTLS_APP_BENCHMARK_PRIORITY
int "Benchmark task priority"
default 100
config MBEDTLS_APP_BENCHMARK_STACKSIZE
int "Benchmark stack size"
default MBEDTLS_DEFAULT_TASK_STACKSIZE
endif
config MBEDTLS_APP_SELFTEST
bool "Mbed TLS Self Test"
default n
---help---
Enable the Mbed TLS self test
if MBEDTLS_APP_SELFTEST
config MBEDTLS_APP_SELFTEST_PROGNAME
string "Program name"
default "mbedselftest"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config MBEDTLS_APP_SELFTEST_PRIORITY
int "Self test task priority"
default 100
config MBEDTLS_APP_SELFTEST_STACKSIZE
int "Self test stack size"
default MBEDTLS_DEFAULT_TASK_STACKSIZE
endif
endif
endif # CRYPTO_MBEDTLS
Make.defs
Finalmente, o último arquivo presente na pasta é o Make.defs. A grande diferença em relação ao arquivo do exemplo Hello World! é que ele disponibiliza os arquivos de cabeçalho (.h) da biblioteca do Mbed TLS para serem usados por outras aplicações do NuttX, adicionando-se o conteúdo da pasta mbedtls/include do Mbed TLS às variáveis CFLAGS e CXXFLAGS do sistema de build do NuttX:
ifneq ($(CONFIG_CRYPTO_MBEDTLS),)
CONFIGURED_APPS += $(APPDIR)/crypto/mbedtls
# Allows `<mbedtls/<>.h>` import.
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/crypto/mbedtls/mbedtls/include
CXXFLAGS += ${INCDIR_PREFIX}$(APPDIR)/crypto/mbedtls/mbedtls/include
CFLAGS += ${DEFINE_PREFIX}MBEDTLS_CONFIG_FILE="<crypto/mbedtls_config.h>"
CXXFLAGS += ${DEFINE_PREFIX}MBEDTLS_CONFIG_FILE="<crypto/mbedtls_config.h>"
endif
RTP Tools
Agora que temos uma ideia de como uma aplicação externa pode ser integrada ao NuttX, podemos integrar o RTP Tools ao NuttX (e, claro, disponibilizá-lo para os demais usuários do repositório nuttx-apps).
Segundo o próprio repositório do RTP Tools, em tradução livre: “O RTP Tools deve compilar e executar em qualquer sistema compatível com POSIX, bem como no Windows. Alguns sistemas operacionais também fornecem um pacote pré-compilado do RTP Tools. No UNIX, o usual ./configure && make deve funcionar”. Esta passagem nos traz algumas informações. A mais importante é o fato da biblioteca ser compatível com sistemas que adotam o padrão POSIX (pontos para o NuttX!). A segunda informação importante é que, no Linux, o primeiro passo do processo de build consiste em executar o comando ./configure. Precisaremos descobrir o que este comando faz antes de prosseguirmos.
Compilando o RTP Tools no Linux
Precisamos conferir o que o comando ./configure do RTP Tools gera para, então, planejarmos a mesma ação no NuttX, se necessário. Assim, tentaremos compilar a aplicação no Linux para verificarmos: 1) a função do comando ./configure e 2) confirmar que a compilação em um sistema Unix esteja funcionando, conforme esperado.
$ ./configure
config.log: writing...
configure.local: no (fully automatic configuration)
err: yes
getopt: yes
gettimeofday: yes
progname: no
strtonum: no
bigendian: no
msgcontrol: yes
gethostbyname-lnsl: yes
socket-lsocket: no
windows: no
config.h: written
Makefile.local: written
E, para compilar o RTP Tools no Linux:
$ make
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c utils.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c payload.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c rd.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c rtpdump.c
rtpdump.c: In function ‘packet_handler’:
rtpdump.c:578:10: warning: this statement may fall through [-Wimplicit-fallthrough=]
578 | if (ctrl == 0) {
| ^
rtpdump.c:590:5: note: here
590 | case F_rtcp:
| ^~~~
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c compat-err.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c compat-getopt.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c compat-gettimeofday.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c compat-progname.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c compat-strtonum.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c winsocklib.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -o rtpdump utils.o payload.o rd.o rtpdump.o compat-err.o compat-getopt.o compat-gettimeofday.o compat-progname.o compat-strtonum.o winsocklib.o -lnsl
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c notify.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c multimer.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c rtpplay.c
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -o rtpplay utils.o notify.o multimer.o payload.o rd.o rtpplay.o compat-err.o compat-getopt.o compat-gettimeofday.o compat-progname.o compat-strtonum.o winsocklib.o -lnsl
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c rtpsend.c
In file included from rtpsend.c:48:
rtpsend.c: In function ‘rtcp_rr’:
rtp.h:130:25: warning: comparison of unsigned expression in ‘< 0’ is always false [-Wtype-limits]
130 | (rp)->lost_sb = (v) < 0 ? (1) : (0); \
| ^
rtpsend.c:371:9: note: in expansion of macro ‘RTCP_SET_LOST’
371 | RTCP_SET_LOST(rr, n->num);
| ^~~~~~~~~~~~~
rtpsend.c: In function ‘rtp’:
rtpsend.c:718:11: warning: variable ‘dummy’ set but not used [-Wunused-but-set-variable]
718 | int dummy;
| ^~~~~
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -o rtpsend utils.o notify.o multimer.o rtpsend.o compat-err.o compat-getopt.o compat-gettimeofday.o compat-progname.o compat-strtonum.o winsocklib.o -lnsl
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -c rtptrans.c
rtptrans.c: In function ‘socket_handler’:
rtptrans.c:318:49: warning: comparison of integer expressions of different signedness: ‘ssize_t’ {aka ‘long int’} and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
318 | if ((sendmsg(side[i][2].sock, &msg,0))!=
| ^~
rtptrans.c:248:17: warning: this statement may fall through [-Wimplicit-fallthrough=]
248 | samples = (samples/33)*160;
| ~~~~~~~~^~~~~~~~~~~~~~~~~~
rtptrans.c:250:7: note: here
250 | case VAT_AUDF_MULAW8:
| ^~~~
cc -g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter -o rtptrans utils.o notify.o multimer.o rtptrans.o compat-err.o compat-getopt.o compat-gettimeofday.o compat-progname.o compat-strtonum.o winsocklib.o -lnsl
Ignorando por ora os warnings da compilação, verificamos que, além dos arquivos resultantes da compilação, foram criados os seguintes arquivos:
config.h;config.log;Makefile.local
Verificamos também, analisando o código fonte do RTP Tools, que config.h é um arquivo de cabeçalho utilizado por diversos arquivos do código fonte. Assim, verificamos que ./configure analisa o sistema operacional para gerar um header – de configuração – personalizado de acordo com as características do sistema operacional em que o RTP Tools está sendo compilado. Como iremos compilar o RTP Tools no NuttX, precisaremos verificar quais são estas configurações e fornecer um arquivo semelhante para a aplicação. O conteúdo de config.h gerado no Linux (x86/64) é:
#ifdef __cplusplus
#error "Do not use C++"
#endif
#if !defined(__GNUC__) || (__GNUC__ < 4)
#define __attribute__(x)
#endif
#if defined(__linux__) || defined(__MINT__)
#define _GNU_SOURCE /* See have-*.c for what needs this. */
#endif
#define HAVE_ERR 1
#define HAVE_GETOPT 1
#define HAVE_GETTIMEOFDAY 1
#define HAVE_PROGNAME 0
#define HAVE_STRTONUM 0
/*
#define HAVE_NTOHL
#define HAVE_REALLOCARRAY
#define HAVE_RECALLOCARRAY
#define HAVE_STRCASESTR
#define HAVE_STRINGLIST
#define HAVE_STRLCAT
#define HAVE_STRLCPY
#define HAVE_STRNDUP
*/
#define RTP_BIG_ENDIAN 0
#define HAVE_MSGCONTROL 1
extern const char *getprogname(void);
extern void setprogname(const char *);
extern long long strtonum(const char *, long long, long long, const char **);O arquivo config.h, como pode ser observado, é criado dinamicamente a partir do comando ./configure. A própria descrição do repositório do RTP Tools observa que, em tradução livre: “O script ./configure é acompanhado por um conjunto de programas simples que detectam automaticamente a disponibilidade das funções do sistema (por exemplo, have-err.c) e se bibliotecas extras precisam ser envolvidas (por exemplo, -lnsl para have-gethostbyname.c)”.
Desta forma, verificaremos cada uma destas aplicações have-x.c (disponibilizadas no repositório do RTP Tools) para verificar quais são os testes executados e, assim, verificar se estas funções estão presentes no NuttX.
Compilando o RTP Tools no NuttX
O Código Fonte
O repositório do RTP Tools possui os seguintes arquivos:
├── bark.rtp
├── ChangeLog.html
├── compat-err.c
├── compat-getopt.c
├── compat-gettimeofday.c
├── compat-progname.c
├── compat-strtonum.c
├── configure
├── configure.local.example
├── have-bigendian.c
├── have-err.c
├── have-gethostbyname.c
├── have-getopt.c
├── have-gettimeofday.c
├── have-msgcontrol.c
├── have-progname.c
├── have-socket.c
├── have-strtonum.c
├── have-windows.c
├── index.html
├── LICENSE
├── Makefile
├── Makefile.depend
├── multidump
├── multidump.1
├── multimer.c
├── multimer.h
├── multiplay
├── multiplay.1
├── notify.c
├── notify.h
├── payload.c
├── payload.h
├── rd.c
├── README.md
├── rtpdump.1
├── rtpdump.c
├── rtpdump.h
├── rtp.h
├── rtpplay.1
├── rtpplay.c
├── rtpsend.1
├── rtpsend.c
├── rtptools.spec
├── rtptrans.1
├── rtptrans.c
├── style.css
├── sysdep.h
├── utils.c
├── vat.h
├── win
│ ├── rtpdump.vcxproj
│ ├── rtpplay.vcxproj
│ ├── rtpsend.vcxproj
│ ├── rtptools.sln
│ └── rtptrans.vcxproj
└── winsocklib.c
Gerando o Arquivo config.h
Observe que o arquivo config.h não está presente no repositório: ao executar o script ./configure, alguns testes são executados no sistema operacional para verificar a disponibilidade de algumas funções e, de acordo com o resultado dos testes, o arquivo config.h é gerado dinamicamente. Os arquivos have-<function>.c executam testes que definem as macros presentes em config.h.
De forma semelhante, precisaremos verificar quais são estas funções e analisar se são também implementadas pelo NuttX. Além disso, o arquivo config.h define a macro #define RTP_BIG_ENDIAN 0 que, considerando o NuttX, dependerá do dispositivo selecionado para compilação. Assim, as configurações em config.h, no NuttX, também devem ser analisadas dinamicamente, a depender da configuração da arquitetura para a qual o NuttX será compilado. Criaremos, assim, o nosso arquivo config.h:
Endianess
Embora exista um teste (have-bigendian.c) para verificar o endianness do sistema, precisaríamos compilá-lo no NuttX, executá-lo no dispositivo alvo para, então, descobrir se é um sistema big-endian ou little-endian. Trabalhoso, né?
Felizmente, o sistema de build do NuttX já possui uma configuração que identifica o endianness do dispositivo: CONFIG_ENDIAN_BIG. Desta forma, poderíamos incluir a seguinte verificação em nosso arquivo config.h:
#ifdef CONFIG_ENDIAN_BIG
#define RTP_BIG_ENDIAN 1
#else
#define RTP_BIG_ENDIAN 0
#endif
have-err.c
Executa o seguinte teste:
#include <err.h>
int
main(void)
{
warnx("%d. warnx", 1);
warn("%d. warn", 2);
err(0, "%d. err", 3);
/* NOTREACHED */
return 1;
}
Procurando pelas funções warnx, warn e err no NuttX, verificamos que estão definidas em nuttx/libs/libc/misc/lib_err.c e independem de qualquer configuração para serem selecionadas. Assim, podemos definir #define HAVE_ERR 1. No entanto, procurando pela macro HAVE_ERR no código do RTP Tools, verificamos que ela é avaliada somente no arquivo compat-err.c para que, caso seu valor seja 0, compile uma versão das funções testadas. Como o valor dela no NuttX é 1, não precisaremos compilar compat-err.c e, assim, sequer seria necessário defini-la em nosso arquivo config.h.
have-gethostbyname.c
Executa o seguinte teste:
#include <netdb.h>
int
main(void)
{
struct hostent* host;
host = gethostbyname("localhost");
/* We only care whether the function exists. */
return 0;
}
A função gethostbyname é definida, no NuttX, por nuttx/libs/libc/netdb/lib_gethostbyname.c. Procurando por este arquivo nos arquivos do NuttX, verificamos que (em nuttx/libs/libc/netdb/Make.defs):
ifeq ($(CONFIG_LIBC_NETDB),y)
# Add the netdb C files to the build
CSRCS += lib_netdb.c lib_gethostbyname.c lib_gethostbynamer.c
Ou seja, o arquivo lib_gethostbyname.c depende da configuração CONFIG_LIBC_NETDB. Desta forma, precisaremos selecioná-la ao compilar o RTP Tools no NuttX.
have-getopt.c
Checa a seguinte função:
#include <unistd.h>
#include <stdlib.h>
int
main(int argc, char** argv)
{
getopt(argc, argv, "ab:c");
return 0;
}
getopt é implementado pelo NuttX em libs/libc/unistd/lib_getopt.c. De forma semelhante, poderíamos incluir #define HAVE_GETOPT 1 no config.h mas, igualmente, não é necessário já que nenhuma versão alternativa será compilada.
have-gettimeofday.c
Semelhantemente, este arquivo testa se a função gettimeofday existe. No NuttX, ela é definida em libs/libc/time/lib_gettimeofday.c. Portanto, #define HAVE_GETTIMEOFDAY 1 (novamente, não será necessário porque esta macro é usada para compilar uma versão alternativa da função se é definida com o valor 0).
have-msgcontrol.c
O código fonte do teste é:
#include <sys/socket.h>
int
main(void)
{
struct msghdr hdr;
hdr.msg_control = (void*)42;
return 0;
}
Basicamente, o teste verifica se há uma estrutura (struct) de msghdr. Esta estrutura está definida em include/sys/socket.h no NuttX e, portanto, também está implementada no nosso sistema operacional. Podemos, assim, definir #define HAVE_MSGCONTROL 1 no arquivo config.h. Ao contrário das demais declarações, a macro HAVE_MSGCONTROL é utilizada no código fonte do RTP Tools em rtptrans.c e, portanto, deve ser definida no arquivo config.h.
have-progname.c
Testa a função getprogname. No entanto, esta função não é utilizada por nenhum código do RTP Tools atualmente e, portanto, pode ser ignorada em nosso config.h.
have-socket.c
Implementa o seguinte teste:
#include <sys/socket.h>
int
main(void)
{
int sock;
if (-1 == (sock = socket(AF_INET, SOCK_DGRAM, 0)))
return 1;
return 0;
}
Este teste verifica, basicamente, o suporte à sockets do tipo SOCK_DGRAM. Este tipo de socket é usado pelo RTP Tools e deve ser disponibilizado pelo sistema operacional. O NuttX implementa este tipo de socket em net/local/local_sockif.c se a macro CONFIG_NET_LOCAL_DGRAM estiver selecionada. Precisamos garantir que esteja!
have-strtonum.c
Testa se a função strtonum é implementada. Esta função, porém, não está sendo utilizada pelo código fonte do RTP Tools atualmente e, portanto, pode ser ignorada.
have-windows.c
Testa se estamos preparando para compilar o RTP Tools em um ambiente Microsoft Windows. Claramente não estamos (Apache NuttX wins!)
config.h
O arquivo config.h gerado para o NuttX, a partir da análise do testes acima, terá o seguinte conteúdo:
/****************************************************************************
* apps/netutils/rtptools/config.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_ENDIAN_BIG
#define RTP_BIG_ENDIAN 1
#else
#define RTP_BIG_ENDIAN 0
#endif
#define HAVE_MSGCONTROL 1
Este arquivo deverá ser disponibilizado juntamente com a receita para compilação do RTP Tools no NuttX, a qual iremos definir a seguir.
Adicionando o RTP Tools ao NuttX
Analisados aspectos inerentes à compilação do RTP Tools, podemos integrá-lo ao repositório nuttx-apps. A organização deste repositório é exibida a seguir:
├── Application.mk
├── audioutils
├── benchmarks
├── boot
├── build_linux.txt
├── builtin
├── canutils
├── config.nims
├── crypto
├── Directory.mk
├── examples
├── fsutils
├── games
├── gpsutils
├── graphics
├── import
├── include
├── industry
├── interpreters
├── Kconfig
├── libapps.a
├── LICENSE
├── logging
├── Make.defs
├── Makefile
├── math
├── mlearning
├── modbus
├── netutils
├── NOTICE
├── nshlib
├── platform
├── README.md
├── sdr
├── staging
├── system
├── testing
├── tools
└── wireless
Como pode ser observado, as aplicações estão organizadas por pastas “temáticas”. O RTP Tools, por sua vez, pode ser inserido na pasta netutils, conforme:
./netutils/
├── chat
├── cjson
├── codecs
├── cwebsocket
├── dhcp6c
├── dhcpc
├── dhcpd
├── discover
├── esp8266
├── ftpc
├── ftpd
├── iperf
├── Kconfig
├── libcurl4nx
├── Make.defs
├── Makefile
├── mqttc
├── netcat
├── netinit
├── netlib
├── nng
├── ntpclient
├── ping
├── pppd
├── README.md
├── rexec
├── rexecd
├── rtptools
├── smtp
├── telnetc
├── telnetd
├── tftpc
├── thttpd
├── wakeonlan
├── webclient
├── webserver
└── xmlrpc
A partir da criação da pasta rtptools no nuttx-apps, é necessário criar as estruturas básicas para que o RTP Tools possa ser compilado no NuttX. Tal como fizemos em Integrando Aplicações Externas, criaremos uma estrutura que permita baixar o código fonte do repositório do RTP Tools e compilá-lo no NuttX. Os arquivos presentes neste diretório serão:
config.h
Tal como o arquivo gerado através do comando ./configure ao compilar o RTP Tools no Linux, adicionamos o arquivo config.h que define os macros aplicáveis ao NuttX, como explicado em config.h.
Makefile
O arquivo Makefile inclui as etapas de download do código do RTP Tools do repositório remoto, da compilação dos arquivos fontes comuns e dos arquivos fontes das aplicações do RTP Tools, que podem ser selecionadas pelo arquivo Kconfig (como será demonstrado mais adiante). O conteúdo do arquivo é o seguinte:
############################################################################
# apps/netutils/rtptools/Makefile
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
RTPTOOLS_VERSION := $(patsubst "%",%,$(CONFIG_NETUTILS_RTPTOOLS_VERSION))
RTPTOOLS_TARBALL = $(RTPTOOLS_VERSION).tar.gz
RTPTOOLS_UNPACK = rtptools
RTPTOOLS_SRCDIR = $(RTPTOOLS_UNPACK)
DEPPATH += --dep-path $(RTPTOOLS_SRCDIR)
VPATH += :$(RTPTOOLS_SRCDIR)
CFLAGS += -Wno-strict-prototypes -Wno-unused-function -Wno-format -Wno-shadow
# Workaround for clang.
#
# error: unknown warning option '-Wno-maybe-uninitialized'; did you mean '-Wno-uninitialized'? [-Werror,-Wunknown-warning-option]
# make[3]: *** [multimer.c.Users.runner.work.nuttx.nuttx.sources.apps.netutils.rtptools.o] Error 1
#
# It's possible to use only '-Wno-uninitialized' instead, however, it isn't
# recommended as it could mask erroneous code.
#
ifneq ($(shell $(CC) --version | grep clang),)
CFLAGS += -Wno-uninitialized
else
CFLAGS += -Wno-maybe-uninitialized
endif
CSRCS += multimer.c
CSRCS += notify.c
CSRCS += payload.c
CSRCS += rd.c
CSRCS += utils.c
ifneq ($(CONFIG_RTPTOOLS_APPS),)
MODULE = $(CONFIG_RTPTOOLS_APPS)
ifeq ($(CONFIG_NETUTILS_RTPTOOLS_RTPPLAY),y)
PROGNAME += $(CONFIG_NETUTILS_RTPTOOLS_RTPPLAY_PROGNAME)
PRIORITY += $(CONFIG_NETUTILS_RTPTOOLS_RTPPLAY_PRIORITY)
STACKSIZE += $(CONFIG_NETUTILS_RTPTOOLS_RTPPLAY_STACKSIZE)
MAINSRC += $(RTPTOOLS_UNPACK)/rtpplay.c
endif
ifeq ($(CONFIG_NETUTILS_RTPTOOLS_RTPSEND),y)
PROGNAME += $(CONFIG_NETUTILS_RTPTOOLS_RTPSEND_PROGNAME)
PRIORITY += $(CONFIG_NETUTILS_RTPTOOLS_RTPSEND_PRIORITY)
STACKSIZE += $(CONFIG_NETUTILS_RTPTOOLS_RTPSEND_STACKSIZE)
MAINSRC += $(RTPTOOLS_UNPACK)/rtpsend.c
endif
ifeq ($(CONFIG_NETUTILS_RTPTOOLS_RTPDUMP),y)
PROGNAME += $(CONFIG_NETUTILS_RTPTOOLS_RTPDUMP_PROGNAME)
PRIORITY += $(CONFIG_NETUTILS_RTPTOOLS_RTPDUMP_PRIORITY)
STACKSIZE += $(CONFIG_NETUTILS_RTPTOOLS_RTPDUMP_STACKSIZE)
MAINSRC += $(RTPTOOLS_UNPACK)/rtpdump.c
endif
ifeq ($(CONFIG_NETUTILS_RTPTOOLS_RTPTRANS),y)
PROGNAME += $(CONFIG_NETUTILS_RTPTOOLS_RTPTRANS_PROGNAME)
PRIORITY += $(CONFIG_NETUTILS_RTPTOOLS_RTPTRANS_PRIORITY)
STACKSIZE += $(CONFIG_NETUTILS_RTPTOOLS_RTPTRANS_STACKSIZE)
MAINSRC += $(RTPTOOLS_UNPACK)/rtptrans.c
endif
endif
# Download and unpack tarball if no git repo found
ifeq ($(wildcard $(RTPTOOLS_UNPACK)/.git),)
$(RTPTOOLS_UNPACK)$(DELIM)config.h: $(RTPTOOLS_UNPACK)
$(Q) cp config.h $@
else
$(RTPTOOLS_UNPACK)$(DELIM)config.h:
$(Q) cp config.h $@
endif
$(RTPTOOLS_TARBALL):
@echo "Downloading: $(RTPTOOLS_TARBALL)"
$(Q) curl -O -L https://github.com/irtlab/rtptools/archive/$(RTPTOOLS_TARBALL)
$(RTPTOOLS_UNPACK): $(RTPTOOLS_TARBALL)
$(Q) echo "Unpacking: $(RTPTOOLS_TARBALL) -> $(RTPTOOLS_UNPACK)"
$(Q) tar zxf $(RTPTOOLS_TARBALL)
$(Q) mv $(RTPTOOLS_UNPACK)-$(RTPTOOLS_VERSION) $(RTPTOOLS_UNPACK)
$(Q) touch $(RTPTOOLS_UNPACK)
context:: $(RTPTOOLS_UNPACK)$(DELIM)config.h
# Download and unpack tarball if no git repo found
ifeq ($(wildcard $(RTPTOOLS_UNPACK)/.git),)
distclean::
$(call DELFILE, $(RTPTOOLS_TARBALL))
$(call DELDIR, $(RTPTOOLS_UNPACK))
endif
include $(APPDIR)/Application.mk
Como esperado, o arquivo Make.defs é incluído pelo Makefile logo no início do arquivo. A seguir, são definidas as seguintes variáveis RTPTOOLS_VERSION, RTPTOOLS_TARBALL, RTPTOOLS_UNPACK e RTPTOOLS_SRCDIR que serão usadas para definir o pacote com os arquivos fonte que será baixado do repositório do projeto. A seguir, adicionam-se arquivos fonte às variáveis CSRCS: estes arquivos não são aplicações de fato, mas servem a outros arquivos fontes que implementam as aplicações em si. Finalmente, as aplicações que compõem o RTP Tools são marcadas para serem compiladas de acordo com as configurações selecionadas via arquivo Kconfig. Entre as aplicações do RTP Tools, o rtpdump, por exemplo, é selecionado através da configuração CONFIG_NETUTILS_RTPTOOLS_RTPDUMP que, se selecionada, inclui o arquivo fonte da aplicação (que contém a função main) à variável MAINSRC.
Até agora, no entanto, não falamos de como o código fonte é obtido. Esse processo se inicia pela receita context. Esta receita depende do arquivo config.h disponível dentro do diretório de compilação (RTPTOOLS_UNPACK), junto com os demais arquivos fonte do RTP Tools. Isso, por sua vez, depende da existência do diretório RTPTOOLS_UNPACK que, finalmente, depende da existência do arquivo com o código fonte compactado do RTP Tools. Em suma, temos as seguintes ações:
- O código fonte do RTP Tools é baixado do repositório no github como um arquivo compactado, na versão definida por
RTPTOOLS_VERSION(que, por sua vez, pode ser definido porCONFIG_NETUTILS_RTPTOOLS_VERSION); - A seguir, este arquivo é descompactado em
RTPTOOLS_UNPACK; - Finalmente, o arquivo
config.hé copiado paraRTPTOOLS_UNPACK;
Kconfig
O arquivo Kconfig permite configurar aspectos do RTP Tools no NuttX e possui o seguinte conteúdo:
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config NETUTILS_RTPTOOLS
bool "Enable RTP Tools"
default n
---help---
RTP Tools is a set of small applications
that can be used for processing RTP data.
if NETUTILS_RTPTOOLS
config NETUTILS_RTPTOOLS_VERSION
string "RTP Tools version"
default "9356740cb0c264577e0f9505e682e53a1e0996d5"
menuconfig RTPTOOLS_APPS
tristate "RTP Tools Applications"
default y
---help---
Enable RTP Tools Applications
if RTPTOOLS_APPS
config NETUTILS_RTPTOOLS_DEFAULT_TASK_STACKSIZE
int "RTP Tools apps default stack size"
default 12288
config NETUTILS_RTPTOOLS_RTPPLAY
bool "Enable rtpplay"
default n
---help---
Play back RTP sessions recorded by rtpdump.
if NETUTILS_RTPTOOLS_RTPPLAY
config NETUTILS_RTPTOOLS_RTPPLAY_PROGNAME
string "Program name"
default "rtpplay"
---help---
This is the name of the program that will be used.
config NETUTILS_RTPTOOLS_RTPPLAY_PRIORITY
int "rtpplay task priority"
default 100
config NETUTILS_RTPTOOLS_RTPPLAY_STACKSIZE
int "rtpplay stack size"
default NETUTILS_RTPTOOLS_DEFAULT_TASK_STACKSIZE
endif # NETUTILS_RTPTOOLS_RTPPLAY
config NETUTILS_RTPTOOLS_RTPSEND
bool "Enable rtpsend"
default n
---help---
Generate RTP packets from textual description,
generated by hand or rtpdump.
if NETUTILS_RTPTOOLS_RTPSEND
config NETUTILS_RTPTOOLS_RTPSEND_PROGNAME
string "Program name"
default "rtpsend"
---help---
This is the name of the program that will be used.
config NETUTILS_RTPTOOLS_RTPSEND_PRIORITY
int "rtpsend task priority"
default 100
config NETUTILS_RTPTOOLS_RTPSEND_STACKSIZE
int "rtpsend stack size"
default NETUTILS_RTPTOOLS_DEFAULT_TASK_STACKSIZE
endif # NETUTILS_RTPTOOLS_RTPSEND
config NETUTILS_RTPTOOLS_RTPDUMP
bool "Enable rtpdump"
default y
---help---
Parse and print RTP packets, generating output
files suitable for rtpplay and rtpsend.
if NETUTILS_RTPTOOLS_RTPDUMP
config NETUTILS_RTPTOOLS_RTPDUMP_PROGNAME
string "Program name"
default "rtpdump"
---help---
This is the name of the program that will be used.
config NETUTILS_RTPTOOLS_RTPDUMP_PRIORITY
int "rtpdump task priority"
default 100
config NETUTILS_RTPTOOLS_RTPDUMP_STACKSIZE
int "rtpdump stack size"
default NETUTILS_RTPTOOLS_DEFAULT_TASK_STACKSIZE
endif # NETUTILS_RTPTOOLS_RTPDUMP
config NETUTILS_RTPTOOLS_RTPTRANS
bool "Enable rtptrans"
default n
---help---
RTP translator between unicast and multicast networks.
if NETUTILS_RTPTOOLS_RTPTRANS
config NETUTILS_RTPTOOLS_RTPTRANS_PROGNAME
string "Program name"
default "rtptrans"
---help---
This is the name of the program that will be used.
config NETUTILS_RTPTOOLS_RTPTRANS_PRIORITY
int "rtptrans task priority"
default 100
config NETUTILS_RTPTOOLS_RTPTRANS_STACKSIZE
int "rtptrans stack size"
default NETUTILS_RTPTOOLS_DEFAULT_TASK_STACKSIZE
endif # NETUTILS_RTPTOOLS_RTPTRANS
endif # RTPTOOLS_APPS
endif # NETUTILS_RTPTOOLS
```
NETUTILS_RTPTOOLS seleciona a compilação do RTP Tools. As aplicações do RTP Tools a serem compiladas, no entanto, podem ser selecionadas individualmente como, por exemplo, NETUTILS_RTPTOOLS_RTPDUMP. Para cada aplicação, podemos definir o tamanho da pilha e também a prioridade de execução através de, por exemplo, NETUTILS_RTPTOOLS_RTPDUMP_STACKSIZE e NETUTILS_RTPTOOLS_RTPDUMP_PRIORITY, respectivamente. Finalmente, NETUTILS_RTPTOOLS_VERSION define uma versão a ser baixada do repositório do RTP Tools (que pode ser definida por uma tag ou, simplesmente, um hash que representa um commit).
Make.defs
O conteúdo do arquivo Make.defs é tão simples quanto:
ifneq ($(CONFIG_NETUTILS_RTPTOOLS),)
CONFIGURED_APPS += $(APPDIR)/netutils/rtptools
endif
A estrutura final da pasta que adiciona o RTP Tools como uma aplicação no nuttx-apps é, então:
./rtptools
├── config.h
├── Kconfig
├── Make.defs
└── Makefile
1, 2, 3, Testando…
Embora as aplicações sejam adicionadas no repositório nuttx-apps, a seleção das mesmas – para serem compiladas junto ao NuttX – é através do repositório do NuttX. Um teste rápido de compilação pode ser efetuado através do uso do simulador do NuttX. Convém lembrar, porém, que o RTP Tools é uma aplicação de rede e, portanto, devemos partir de uma configuração (defconfig) que habilita as funcionalidades de rede.
Referindo-se à documentação do NuttX, encontramos a seção Accessing the Network que utiliza, por exemplo, a configuração sim:tcpblaster para testar as funcionalidades de rede do NuttX com o simulador. Partindo-se dela, iremos selecionar o RTP Tools para ser compilado. Para tal:
make distclean
./tools/configure.sh sim:tcpblaster
make menuconfig
Pelo utilitário do menuconfig, navegue até: Application Configuration → Network Utilities. Nesta tela, selecione a opção Enable RTP Tools. Uma vez selecionada a opção, é possível selecionar as aplicações do RTP Tools que serão compiladas, conforme imagem a seguir:
A seguir, salve as configurações feitas pelo menuconfig e, para compilar, execute:
make -j
O rtpdump, do RTP Tools, foi compilado com sucesso? Parabéns! Temos uma aplicação POSIX-compliant compilada para o NuttX (até que não foi tão difícil, né?).
Para executar o simulador, execute ./nuttx. A seguir, execute help e verifique se o rtpdump está disponível.
Nota: um defconfig específico para compilar o RTP Tools com o simulador foi criado para o processo ser facilitado. Tente executar:
make distclean
./tools/configure.sh sim:rtptools
make -j
Conclusão
O objetivo deste artigo é aprofundar-se, justamente, no sistema de build do NuttX. Não falamos ainda: 1) do porquê o RTP Tools foi portado para o NuttX 2) como que o simulador fornece uma grande interface de teste e debugging de aplicações e 3) de como é possível contribuir com o projeto NuttX. Fique ligado para conferir os próximos artigos desta série. Dúvidas, críticas e sugestões? Deixe seu comentário na página 😉
Referências
- Primeiros Passos com o ESP32 e NuttX. Embarcados, 2020. Disponível em: <https://embarcados.com.br/serie/primeiros-passos-com-o-esp32-e-o-nuttx/>. Acesso em: 20 de junho de 2023.
- SERRANO, Tiago Medicci. Servidor de Som: Raspberry Pi + Home Theater DIY. Embarcados, 2021. Disponível em: <https://embarcados.com.br/servidor-de-som-raspberry-pi-home-theater-diy/>. Acesso em: 20 de junho de 2023.
- MONTEIRO, Sara. Primeiros Passos com o ESP32 e o NuttX. Embarcados, 2020. Disponível em: <https://embarcados.com.br/primeiros-passos-com-o-esp32-e-o-nuttx-parte-1/>. Acesso em: 1 de junho de 2023.
- DE ASSIS, Alan Carvalho. O que é o RTOS NuttX e por que você deve se importar? Embarcados, 2018. Disponível em: <https://embarcados.com.br/o-que-e-o-rtos-nuttx/>. Acesso em: 1 de junho de 2023.
- Getting Started. NuttX, 2023. Disponível em: <https://nuttx.apache.org/docs/latest/quickstart/index.html>. Acesso em: 2 de junho de 2023.
- Repositório RTP Tools. GitHub – irtlab/rtptools, 2023. Disponível em: <https://github.com/irtlab/rtptools>. Acesso em: 2 de junho de 2023.
- Repositório de Aplicações do Apache Nuttx. GitHub – apache/nuttx-apps, 2023. Disponível em: <https://github.com/apache/nuttx-apps>. Acesso em: 2 de junho de 2023.
- Custom Apps How-to. Nuttx, 2023. Disponível em: <https://nuttx.apache.org/docs/latest/guides/customapps.html>. Acesso em: 02 de junho de 2023.
- Repositório do Sistema Operacional do Apache Nuttx. GitHub – apache/nuttx, 2023. Disponível em: <https://github.com/apache/nuttx>. Acesso em: 2 de junho de 2023.
- Repositório de Mbed-TLS. GitHub – Mbed-TLS/mbedtls, 2023. Disponível em: <https://github.com/Mbed-TLS/mbedtls>. Acesso em: 3 de junho de 2023.
- Accessing the Network. NuttX, 2023. Disponível em: <https://nuttx.apache.org/docs/latest/guides/simulator.html#accessing-the-network>. Acesso em: 4 de junho de 2023.
Agradecimentos
Agradecimento especial aos revisores do artigo: Alan Carvalho de Assis, Lucas Saavedra Vaz e Ricardo Tafas.









