NuttX: Criando (ou Copiando!) uma Aplicação para o NuttX

Desenvolvendo um Projeto com Aplicações Existentes
Este post faz parte da série Primeiros Passos com o ESP32 e NuttX

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:

  1. 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 por CONFIG_NETUTILS_RTPTOOLS_VERSION);
  2. A seguir, este arquivo é descompactado em RTPTOOLS_UNPACK;
  3. Finalmente, o arquivo config.h é copiado para RTPTOOLS_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:

Aplicação para o NuttX

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

Agradecimentos

Agradecimento especial aos revisores do artigo: Alan Carvalho de Assis, Lucas Saavedra Vaz e Ricardo Tafas.

Primeiros Passos com o ESP32 e NuttX

Executando NuttX em um ESP32 emulado com QEMU NuttX: Usando o Simulador para Testes e Debugging de Aplicações
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
0 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Home » Software » NuttX: Criando (ou Copiando!) uma Aplicação para o NuttX

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: