<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>lwIP - MCU &amp; FPGA</title>
	<atom:link href="https://mcu.tec.br/categorias/protoclos/lwip/feed/" rel="self" type="application/rss+xml" />
	<link>https://mcu.tec.br</link>
	<description>Microcontroladores &#38; FPGA</description>
	<lastBuildDate>Wed, 14 Jan 2026 14:07:01 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://mcu.tec.br/wp-content/uploads/2025/02/Robo-para-o-site-MCU.tec_.br-512x512-1-150x150.png</url>
	<title>lwIP - MCU &amp; FPGA</title>
	<link>https://mcu.tec.br</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>FreeRTOS com lwIP: Arquitetura, Boas Práticas e Exemplos Reais de Sistemas Embarcados em Rede</title>
		<link>https://mcu.tec.br/rtos/freertos-com-lwip-arquitetura-boas-praticas-e-exemplos-reais-de-sistemas-embarcados-em-rede/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=freertos-com-lwip-arquitetura-boas-praticas-e-exemplos-reais-de-sistemas-embarcados-em-rede</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Fri, 06 Mar 2026 09:25:08 +0000</pubDate>
				<category><![CDATA[lwIP]]></category>
		<category><![CDATA[RTOS]]></category>
		<category><![CDATA[freertos]]></category>
		<category><![CDATA[LWIP]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=1082</guid>

					<description><![CDATA[<p>Este artigo apresenta um guia completo e aprofundado sobre o uso do FreeRTOS em sistemas embarcados que utilizam a pilha de rede lwIP. O conteúdo aborda desde os fundamentos arquiteturais da integração entre RTOS e TCP/IP até padrões de projeto aplicados em firmware de produção. São exploradas as APIs do lwIP (RAW, Netconn e BSD Sockets), a função da TCP/IP thread, o uso correto de mailboxes, semáforos e filas do FreeRTOS, além de exemplos práticos em C envolvendo servidores TCP, arquitetura Gatekeeper, produtor/consumidor, framing de protocolos TCP, múltiplos clientes, timeouts, keepalive, backpressure e integração com Task Monitor e Watchdog. O artigo é voltado a desenvolvedores de sistemas embarcados que buscam robustez, previsibilidade temporal e boas práticas para aplicações conectadas em microcontroladores Cortex-M, ESP32 e plataformas similares, indo além de exemplos simplificados e focando em soluções aplicáveis ao ambiente industrial e de campo.</p>
<p>The post <a href="https://mcu.tec.br/rtos/freertos-com-lwip-arquitetura-boas-praticas-e-exemplos-reais-de-sistemas-embarcados-em-rede/">FreeRTOS com lwIP: Arquitetura, Boas Práticas e Exemplos Reais de Sistemas Embarcados em Rede</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<h3 class="wp-block-heading"><strong>Introdução: FreeRTOS em sistemas com lwIP</strong></h3>



<p class="wp-block-paragraph">A combinação do <strong>FreeRTOS</strong> com a pilha de rede <strong>lwIP (Lightweight IP)</strong> é hoje uma das arquiteturas mais comuns em sistemas embarcados conectados, especialmente em microcontroladores Cortex-M (STM32, NXP, RP2040 com stack externa, ESP32 quando abstraído), onde há restrição severa de memória, tempo real e consumo energético. O FreeRTOS fornece o <strong>modelo concorrente determinístico</strong> (tarefas, prioridades, sincronização), enquanto o lwIP entrega uma <strong>implementação enxuta da pilha TCP/IP</strong>, compatível com IPv4, IPv6, TCP, UDP, ICMP, ARP, DHCP, DNS e HTTP, entre outros protocolos.</p>



<p class="wp-block-paragraph">O ponto crítico — e frequentemente negligenciado — é que o lwIP <strong>não é apenas uma biblioteca de rede</strong>, mas sim um <em>framework cooperativo</em> que precisa ser corretamente integrado ao <strong>modelo de execução do RTOS</strong>. Dependendo da configuração (RAW API, Netconn API ou BSD Sockets API), o lwIP pode operar de forma <strong>event-driven</strong>, <strong>thread-safe</strong> ou <strong>thread-aware</strong>, exigindo decisões arquiteturais bem fundamentadas. Uma escolha inadequada costuma resultar em <em>deadlocks</em>, <em>stack overflow</em>, perda de pacotes, latências imprevisíveis ou até <em>hard faults</em> difíceis de diagnosticar.</p>



<p class="wp-block-paragraph">Em sistemas com FreeRTOS, o lwIP normalmente é encapsulado em <strong>uma ou mais tarefas dedicadas</strong>, além de callbacks executados a partir de interrupções (ETH IRQ, DMA RX/TX) ou timers de software. Isso cria um ambiente híbrido onde <strong>código de interrupção, tarefas e a pilha TCP/IP</strong> precisam cooperar com rigor: uso correto de semáforos, mutexes, mailboxes (queues), buffers e prioridades. O entendimento dessa interação é essencial para construir aplicações robustas como <strong>servidores HTTP, MQTT brokers/clients, WebSockets, OTA, Modbus/TCP, Profinet sobre TCP/IP</strong>, entre outras.</p>



<p class="wp-block-paragraph">Nesta série de artigos, este material assume um <strong>cenário típico e realista</strong>:</p>



<ul class="wp-block-list">
<li>FreeRTOS rodando como sistema operacional principal</li>



<li>lwIP configurado com <strong>TCP/IP thread dedicada</strong></li>



<li>Interface Ethernet (MAC + PHY) ou driver de rede equivalente</li>



<li>Comunicação entre tarefas da aplicação e a pilha de rede</li>



<li>Ênfase em <strong>boas práticas, arquitetura correta e exemplos práticos em C</strong></li>
</ul>



<p class="wp-block-paragraph">Nas próximas seções, vamos avançar progressivamente, começando pela <strong>arquitetura interna do lwIP quando integrado ao FreeRTOS</strong>, passando pelas <strong>formas de integração (RAW, Netconn e Sockets)</strong>, até chegar a <strong>exemplos completos</strong> como servidor HTTP, cliente TCP e sincronização entre tarefas da aplicação e a pilha de rede.</p>



<h3 class="wp-block-heading"><strong>Arquitetura do lwIP em sistemas com FreeRTOS</strong></h3>



<p class="wp-block-paragraph">Quando o lwIP é integrado a um sistema com FreeRTOS, ele deixa de ser apenas uma pilha TCP/IP “passiva” e passa a fazer parte ativa do <strong>modelo concorrente do sistema</strong>. O ponto central dessa arquitetura é a chamada <strong>TCP/IP thread</strong> (normalmente criada por <code>tcpip_init()</code>), que se torna o <strong>contexto exclusivo e soberano</strong> para quase todas as operações internas do lwIP. Isso significa que estruturas críticas como <em>PCB (Protocol Control Blocks)</em>, buffers <code>pbuf</code>, timers TCP e estados de conexão <strong>não são thread-safe por padrão</strong> e devem ser manipulados apenas dentro desse contexto controlado.</p>



<p class="wp-block-paragraph">Na prática, o lwIP organiza seu funcionamento em três grandes domínios de execução: <strong>interrupções de hardware</strong>, <strong>TCP/IP thread</strong> e <strong>tarefas da aplicação</strong>. As interrupções normalmente vêm do driver Ethernet (IRQ do MAC ou DMA RX/TX), cujo papel é mínimo: sinalizar que há pacotes recebidos ou buffers liberados, evitando qualquer processamento pesado. Essas interrupções acordam a TCP/IP thread por meio de <em>semaphores</em> ou <em>mailboxes</em>, garantindo que todo o processamento de protocolos ocorra fora do contexto de ISR, preservando determinismo e estabilidade do sistema.</p>



<p class="wp-block-paragraph">A TCP/IP thread funciona como um <strong>dispatcher de eventos de rede</strong>. Ela processa pacotes recebidos, executa timers periódicos (TCP retransmission, ARP aging, DHCP renewal), gerencia conexões e chama callbacks registrados pela aplicação. É aqui que reside uma armadilha comum: <strong>callbacks do lwIP não executam no contexto da task da aplicação</strong>, mas sim dentro da TCP/IP thread. Isso exige extremo cuidado ao acessar recursos compartilhados, como filas do FreeRTOS, buffers globais ou drivers de periféricos, sob pena de criar condições de corrida difíceis de rastrear.</p>



<p class="wp-block-paragraph">As tarefas da aplicação, por sua vez, <strong>nunca devem acessar diretamente estruturas internas do lwIP</strong>, exceto quando se utiliza APIs explicitamente thread-safe (como Netconn ou Sockets). Quando a arquitetura é bem desenhada, as tasks da aplicação se comunicam com a TCP/IP thread usando <strong>mensagens, filas ou chamadas assíncronas</strong>, mantendo uma separação clara entre lógica de negócio e infraestrutura de rede. Esse desacoplamento é um dos fatores-chave para escalabilidade e manutenibilidade do firmware.</p>



<p class="wp-block-paragraph">Do ponto de vista conceitual, pense no lwIP como um <strong>ator central</strong> que serializa todo o tráfego de rede, enquanto o FreeRTOS fornece o <strong>orquestrador de concorrência</strong> ao redor dele. Quando esse modelo é respeitado, o sistema se comporta de forma previsível mesmo sob carga elevada de rede. Quando é violado — por exemplo, chamando funções RAW do lwIP a partir de tasks arbitrárias — os sintomas surgem como bugs intermitentes, travamentos aleatórios ou degradação severa de desempenho.</p>



<p class="wp-block-paragraph">Na próxima seção, vamos entrar em um dos pontos mais críticos e confusos para quem trabalha com lwIP:<br><strong>as três APIs disponíveis (RAW API, Netconn API e BSD Sockets API)</strong>, explicando quando usar cada uma, suas vantagens, limitações e impactos diretos na arquitetura FreeRTOS.</p>



<h3 class="wp-block-heading"><strong>As APIs do lwIP no contexto do FreeRTOS: RAW, Netconn e Sockets</strong></h3>



<p class="wp-block-paragraph">Um dos pontos que mais geram confusão — e erros arquiteturais — no uso do lwIP com FreeRTOS é a existência de <strong>três APIs distintas</strong>, cada uma com <strong>modelos mentais, custos e implicações completamente diferentes</strong>. A escolha da API não é apenas uma questão de preferência sintática; ela define <strong>como as tasks interagem com a pilha TCP/IP</strong>, quais garantias de <em>thread-safety</em> existem e qual será o impacto em latência, uso de memória e complexidade do sistema.</p>



<p class="wp-block-paragraph">A <strong>RAW API</strong> é a forma mais direta e eficiente de usar o lwIP. Ela é totalmente <strong>event-driven</strong>, baseada em callbacks, e opera <strong>exclusivamente no contexto da TCP/IP thread</strong>. Não existe bloqueio, não existem semáforos implícitos, nem cópia adicional de buffers. Cada evento de rede — conexão estabelecida, dados recebidos, erro ou fechamento — dispara uma função de callback registrada previamente. Isso torna a RAW API ideal para sistemas com <strong>restrições severas de RAM e tempo real rígido</strong>, mas ao custo de maior complexidade cognitiva. Em sistemas FreeRTOS, a RAW API <strong>não deve ser chamada diretamente a partir de tasks da aplicação</strong>; qualquer interação precisa ser mediada por mensagens ou funções como <code>tcpip_callback()</code>.</p>



<p class="wp-block-paragraph">Já a <strong>Netconn API</strong> atua como uma camada intermediária entre a RAW API e o modelo tradicional de threads. Ela encapsula a lógica baseada em callbacks dentro de uma API <strong>bloqueante e thread-safe</strong>, usando <em>mailboxes</em> e <em>semaphores</em> internos. Para o desenvolvedor FreeRTOS, isso significa poder escrever código sequencial — <code>netconn_accept()</code>, <code>netconn_recv()</code>, <code>netconn_write()</code> — dentro de uma task, sem violar as regras internas do lwIP. O custo disso é um pequeno aumento de consumo de memória e latência, além de menos controle fino sobre eventos de baixo nível. Em projetos industriais, a Netconn API costuma ser um <strong>equilíbrio muito saudável entre robustez e simplicidade</strong>.</p>



<p class="wp-block-paragraph">A <strong>BSD Sockets API</strong>, por sua vez, é a mais familiar para quem vem do mundo Linux ou POSIX. Ela oferece funções como <code>socket()</code>, <code>bind()</code>, <code>listen()</code>, <code>accept()</code>, <code>recv()</code> e <code>send()</code>, com semântica muito próxima à de sistemas operacionais completos. Internamente, ela é construída sobre a Netconn API, herdando suas características e custos. Em FreeRTOS, a Sockets API facilita a portabilidade de código legado e acelera o desenvolvimento inicial, mas frequentemente induz a <strong>arquiteturas pobres</strong>, com tasks bloqueantes demais, pilha grande e baixa previsibilidade temporal se não for bem planejada.</p>



<p class="wp-block-paragraph">A decisão correta normalmente segue este raciocínio: se o sistema é <strong>altamente restrito e orientado a eventos</strong>, use RAW API; se precisa de <strong>clareza, robustez e integração limpa com FreeRTOS</strong>, use Netconn; se o foco é <strong>portabilidade e velocidade de desenvolvimento</strong>, a Sockets API pode ser aceitável — desde que o impacto em recursos seja cuidadosamente controlado. Em sistemas críticos, misturar APIs sem critério é uma receita certa para problemas difíceis de depurar.</p>



<p class="wp-block-paragraph">Na próxima seção, vamos aprofundar exatamente <strong>como o FreeRTOS e o lwIP se comunicam internamente</strong>, explorando <em>mailboxes</em>, <em>semaphores</em>, timers e a função <code>tcpip_init()</code>, com diagramas conceituais e exemplos práticos em C.</p>



<h3 class="wp-block-heading"><strong>Integração interna entre FreeRTOS e lwIP: mailboxes, semáforos e <code>tcpip_init()</code></strong></h3>



<p class="wp-block-paragraph">A espinha dorsal da integração entre FreeRTOS e lwIP é o <strong>mecanismo de mensagens assíncronas</strong> que garante que todo o processamento da pilha TCP/IP ocorra em um <strong>único contexto controlado</strong>. Esse contexto é criado pela chamada a <code>tcpip_init()</code>, responsável por inicializar o lwIP e criar a <strong>TCP/IP thread</strong>, além de suas estruturas de sincronização internas. Entender exatamente o que acontece aqui é essencial para evitar violações de <em>thread-safety</em> e erros sutis de concorrência.</p>



<p class="wp-block-paragraph">Quando <code>tcpip_init()</code> é chamada, o lwIP cria internamente uma task do FreeRTOS (normalmente chamada de <code>tcpip_thread</code>) e associa a ela uma <strong>mailbox principal</strong>. Essa mailbox funciona como uma fila de mensagens do RTOS, por onde chegam eventos como pacotes recebidos, timers expirados ou callbacks solicitados por outras tasks. O modelo é deliberadamente serial: a TCP/IP thread processa <strong>uma mensagem por vez</strong>, garantindo que as estruturas internas do lwIP nunca sejam acessadas concorrentemente.</p>



<p class="wp-block-paragraph">As <strong>interrupções de rede</strong> (por exemplo, RX DMA do Ethernet MAC) não processam protocolos diretamente. Em vez disso, elas apenas notificam o sistema — geralmente liberando um semáforo ou enviando um ponteiro de buffer para uma mailbox. O driver Ethernet, então, acorda a TCP/IP thread, que passa a processar os pacotes no contexto correto. Esse desenho é fundamental para manter <strong>latência previsível</strong> e evitar execução de código pesado em ISR, algo especialmente crítico em sistemas com FreeRTOS.</p>



<p class="wp-block-paragraph">Para permitir que tasks da aplicação interajam com o lwIP sem violar esse modelo, o lwIP fornece funções como <code>tcpip_callback()</code> e <code>tcpip_try_callback()</code>. Essas funções permitem que uma task qualquer solicite a execução de uma função <strong>dentro da TCP/IP thread</strong>, de forma assíncrona. Esse padrão é a base de arquiteturas seguras quando se utiliza a RAW API, pois impede acessos diretos às estruturas internas da pilha a partir de múltiplos contextos.</p>



<p class="wp-block-paragraph">A Netconn e a Sockets API se apoiam nesse mesmo mecanismo, mas encapsulam toda essa complexidade. Quando uma task chama <code>netconn_recv()</code>, por exemplo, o que acontece por baixo dos panos é um diálogo entre <strong>mailboxes internas</strong>, semáforos e a TCP/IP thread. A task da aplicação fica bloqueada de forma controlada, enquanto o lwIP continua operando normalmente. Isso explica por que essas APIs são thread-safe, mas também por que consomem mais RAM e stack.</p>



<p class="wp-block-paragraph">Um erro clássico em projetos é tentar “otimizar” esse fluxo acessando diretamente buffers, chamando funções RAW a partir de tasks comuns ou usando mutexes do FreeRTOS para proteger estruturas do lwIP. Essa abordagem <strong>não funciona</strong> e quebra premissas internas do stack. O modelo correto não é proteger o lwIP com mutexes, mas <strong>respeitar o confinamento de contexto imposto pela TCP/IP thread</strong>.</p>



<p class="wp-block-paragraph">Na próxima seção, vamos aplicar esses conceitos de forma concreta, construindo um <strong>exemplo prático de inicialização do lwIP com FreeRTOS</strong>, incluindo criação de tarefas, configuração do driver Ethernet e verificação do fluxo de dados.</p>



<h3 class="wp-block-heading"><strong>Exemplo prático: inicialização do lwIP em um sistema FreeRTOS</strong></h3>



<p class="wp-block-paragraph">Nesta seção vamos sair do plano conceitual e entrar no <strong>código real</strong>, mostrando como um sistema típico FreeRTOS + lwIP é inicializado. O objetivo aqui não é apenas “fazer funcionar”, mas <strong>entender por que cada passo existe</strong>, qual o contexto de execução envolvido e quais são os erros clássicos que devem ser evitados.</p>



<p class="wp-block-paragraph">Assumiremos um cenário bastante comum em projetos industriais:</p>



<ul class="wp-block-list">
<li>FreeRTOS já inicializado</li>



<li>Interface Ethernet com driver próprio (MAC + PHY)</li>



<li>lwIP configurado para uso com <strong>TCP/IP thread dedicada</strong></li>



<li>Uso futuro de Netconn ou Sockets API</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>5.1 Ordem correta de inicialização</strong></h4>



<p class="wp-block-paragraph">A ordem de inicialização é <strong>crítica</strong>. Um erro frequente é criar tasks de aplicação que usam rede <strong>antes</strong> do lwIP estar totalmente operacional.</p>



<p class="wp-block-paragraph">A sequência correta, em alto nível, é:</p>



<ol class="wp-block-list">
<li>Inicializar hardware básico (clock, GPIO, PHY, MAC)</li>



<li>Inicializar o lwIP (<code>tcpip_init</code>)</li>



<li>Configurar interface de rede (<code>netif</code>)</li>



<li>Subir a interface (<code>netif_set_up</code>)</li>



<li>Só então criar tasks da aplicação que usam rede</li>



<li>Iniciar o scheduler do FreeRTOS</li>
</ol>



<p class="wp-block-paragraph">Essa ordem garante que nenhuma task tente acessar a pilha TCP/IP fora do contexto correto.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>5.2 Inicializando o lwIP (<code>tcpip_init</code>)</strong></h4>



<p class="wp-block-paragraph">O primeiro ponto de integração direta entre FreeRTOS e lwIP é a chamada a <code>tcpip_init()</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "lwip/tcpip.h"

static void lwip_init_done(void *arg)
{
    /* Callback chamado quando a TCP/IP thread está pronta */
    (void)arg;
}

void lwip_stack_init(void)
{
    tcpip_init(lwip_init_done, NULL);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/tcpip.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">lwip_init_done</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* Callback chamado quando a TCP/IP thread está pronta */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    (</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">arg</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">lwip_stack_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">tcpip_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">lwip_init_done</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">O que acontece aqui, de fato:</p>



<ul class="wp-block-list">
<li>O lwIP cria internamente a <strong>TCP/IP thread</strong> como uma task do FreeRTOS</li>



<li>São criadas mailboxes internas para troca de mensagens</li>



<li>Timers internos do TCP/IP são registrados</li>



<li>O callback <code>lwip_init_done()</code> é executado <strong>no contexto da TCP/IP thread</strong>, não na task chamadora</li>
</ul>



<p class="wp-block-paragraph">Esse detalhe é importante: qualquer código executado nesse callback já está em um <strong>contexto seguro para chamadas RAW</strong>, caso necessário.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>5.3 Configuração da interface de rede (<code>netif</code>)</strong></h4>



<p class="wp-block-paragraph">Após a inicialização do lwIP, precisamos registrar a interface de rede:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/dhcp.h"

static struct netif netif_eth;

void netif_config(void)
{
    ip4_addr_t ipaddr;
    ip4_addr_t netmask;
    ip4_addr_t gw;

    IP4_ADDR(&amp;ipaddr, 0, 0, 0, 0);   /* DHCP */
    IP4_ADDR(&amp;netmask, 0, 0, 0, 0);
    IP4_ADDR(&amp;gw, 0, 0, 0, 0);

    netif_add(&amp;netif_eth,
              &amp;ipaddr,
              &amp;netmask,
              &amp;gw,
              NULL,
              ethernetif_init,
              tcpip_input);

    netif_set_default(&amp;netif_eth);
    netif_set_up(&amp;netif_eth);

    dhcp_start(&amp;netif_eth);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/netif.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/ip_addr.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/dhcp.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">netif</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">netif_eth</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">netif_config</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">ip4_addr_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ipaddr</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">ip4_addr_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">netmask</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">ip4_addr_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gw</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">IP4_ADDR</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ipaddr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">   </span><span style="color: #616E88">/* DHCP */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">IP4_ADDR</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">netmask</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">IP4_ADDR</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">gw</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">netif_add</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">netif_eth</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ipaddr</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">netmask</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">gw</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #D8DEE9">ethernetif_init</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #D8DEE9">tcpip_input</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">netif_set_default</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">netif_eth</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">netif_set_up</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">netif_eth</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">dhcp_start</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">netif_eth</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Aqui aparecem alguns pontos arquiteturais importantes:</p>



<ul class="wp-block-list">
<li><code>ethernetif_init</code> é o <strong>driver de baixo nível</strong>, responsável por integrar MAC/PHY ao lwIP</li>



<li><code>tcpip_input</code> garante que pacotes recebidos sejam entregues <strong>à TCP/IP thread</strong>, e não processados no contexto errado</li>



<li>O uso de DHCP é opcional, mas comum em sistemas conectados</li>
</ul>



<p class="wp-block-paragraph">Essa função normalmente é chamada <strong>após</strong> <code>tcpip_init()</code> e <strong>antes</strong> da criação das tasks de aplicação.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>5.4 Criação das tasks da aplicação</strong></h4>



<p class="wp-block-paragraph">Somente depois que a pilha está pronta é que criamos tasks que usam rede:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>void network_task(void *argument)
{
    /* A partir daqui, é seguro usar Netconn ou Sockets API */
    for (;;)
    {
        /* Lógica de rede */
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void app_start(void)
{
    xTaskCreate(network_task,
                "NetTask",
                1024,
                NULL,
                tskIDLE_PRIORITY + 2,
                NULL);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">network_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">argument</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* A partir daqui, é seguro usar Netconn ou Sockets API */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* Lógica de rede */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">1000</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_start</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">network_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">NetTask</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #B48EAD">1024</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">tskIDLE_PRIORITY</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Note que:</p>



<ul class="wp-block-list">
<li>A task <strong>não interage diretamente com estruturas RAW</strong></li>



<li>O tamanho da stack já precisa considerar buffers de rede</li>



<li>A prioridade deve ser pensada em conjunto com a TCP/IP thread</li>
</ul>



<p class="wp-block-paragraph">Um erro comum é dar prioridade muito baixa para a TCP/IP thread e alta para tasks de aplicação, o que resulta em <strong>timeouts, perda de pacotes e conexões instáveis</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>5.5 Erros clássicos nesta fase</strong></h4>



<p class="wp-block-paragraph">Alguns problemas recorrentes que surgem exatamente nesse ponto:</p>



<ul class="wp-block-list">
<li>Criar sockets antes do <code>netif_set_up</code></li>



<li>Chamar funções RAW a partir de tasks comuns</li>



<li>Executar processamento pesado no driver Ethernet (ISR)</li>



<li>Stack insuficiente para tasks de rede</li>



<li>Prioridade inadequada da TCP/IP thread</li>
</ul>



<p class="wp-block-paragraph">Todos esses erros levam a sintomas difíceis de diagnosticar, como travamentos aleatórios ou falhas intermitentes de comunicação.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Na próxima seção, vamos construir um <strong>exemplo completo de servidor TCP/HTTP</strong>, mostrando como uma task FreeRTOS usa a <strong>Netconn ou Sockets API</strong> corretamente, com explicação detalhada de cada chamada.</p>



<h3 class="wp-block-heading"><strong>Exemplo completo: servidor TCP usando Sockets API em uma task FreeRTOS</strong></h3>



<p class="wp-block-paragraph">Aqui vamos montar um servidor TCP simples (estilo “echo server” + base para HTTP) rodando em uma <strong>task do FreeRTOS</strong> usando a <strong>BSD Sockets API do lwIP</strong>. A ideia é te dar um esqueleto real que funciona em 80% dos firmwares conectados: uma task aceita conexões, recebe dados, responde e fecha. Em seguida, vou apontar onde normalmente você evolui para HTTP, MQTT, Modbus/TCP etc.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>6.1 Requisitos e premissas</strong></h4>



<p class="wp-block-paragraph">Para usar Sockets no lwIP você normalmente precisa ter (no <code>lwipopts.h</code>):</p>



<ul class="wp-block-list">
<li><code>LWIP_SOCKET=1</code></li>



<li><code>LWIP_NETCONN=1</code> (sockets geralmente dependem dela)</li>



<li><code>LWIP_TCP=1</code></li>



<li><code>LWIP_DNS=1</code> (se quiser resolver nomes)</li>



<li><code>LWIP_DHCP=1</code> (se usar DHCP)</li>
</ul>



<p class="wp-block-paragraph">E lembrar do modelo: <strong>a task de sockets é sua</strong>, mas o lwIP continua processando rede na <strong>TCP/IP thread</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>6.2 Código do servidor TCP (com comentários didáticos)</strong></h4>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "FreeRTOS.h"
#include "task.h"

#include "lwip/sockets.h"
#include "lwip/inet.h"
#include &lt;string.h>
#include &lt;stdio.h>

/* Ajuste conforme sua aplicação */
#define SERVER_PORT     5000
#define RX_BUF_SIZE     1024
#define LISTEN_BACKLOG  4

static void tcp_server_task(void *arg)
{
    (void)arg;

    int listen_fd = -1;
    int client_fd = -1;

    struct sockaddr_in addr;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);

    /* Buffer local: cuidado com stack! */
    char rx_buf&#91;RX_BUF_SIZE&#93;;

    /* 1) Criar socket TCP */
    listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listen_fd &lt; 0) {
        /* Em sistemas embarcados: logue e reinicie a task ou sinalize falha */
        vTaskDelete(NULL);
    }

    /* 2) Preencher estrutura de endereço */
    memset(&amp;addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY); /* escuta em todas interfaces */

    /* 3) Bind: amarra o socket à porta */
    if (bind(listen_fd, (struct sockaddr *)&amp;addr, sizeof(addr)) &lt; 0) {
        closesocket(listen_fd);
        vTaskDelete(NULL);
    }

    /* 4) Listen: coloca em modo servidor */
    if (listen(listen_fd, LISTEN_BACKLOG) &lt; 0) {
        closesocket(listen_fd);
        vTaskDelete(NULL);
    }

    for (;;)
    {
        /* 5) Accept: bloqueia esperando cliente */
        client_fd = accept(listen_fd, (struct sockaddr *)&amp;client_addr, &amp;client_len);
        if (client_fd &lt; 0) {
            /* Se accept falhar, normalmente você continua tentando */
            vTaskDelay(pdMS_TO_TICKS(100));
            continue;
        }

        /* 6) Loop de recepção */
        for (;;)
        {
            int n = recv(client_fd, rx_buf, sizeof(rx_buf) - 1, 0);
            if (n &lt;= 0) {
                /* n == 0 -> cliente fechou; n &lt; 0 -> erro */
                break;
            }

            rx_buf&#91;n&#93; = '\0';

            /* 7) Aqui entra a lógica da aplicação.
                  Para um echo server: devolve os bytes recebidos. */
            send(client_fd, rx_buf, n, 0);

            /* Exemplo: se quiser encerrar ao receber "quit" */
            if (strncmp(rx_buf, "quit", 4) == 0) {
                break;
            }
        }

        /* 8) Fecha conexão do cliente */
        closesocket(client_fd);
        client_fd = -1;
    }
}

/* Função de arranque */
void start_tcp_server(void)
{
    /* Stack precisa ser dimensionada: sockets + buffer local */
    xTaskCreate(tcp_server_task,
                "TCPServer",
                2048,                  /* ajuste real conforme seu MCU/heap */
                NULL,
                tskIDLE_PRIORITY + 2,  /* prioridade média */
                NULL);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">task.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/sockets.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/inet.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdio</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/* Ajuste conforme sua aplicação */</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SERVER_PORT</span><span style="color: #D8DEE9FF">     </span><span style="color: #B48EAD">5000</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">RX_BUF_SIZE</span><span style="color: #D8DEE9FF">     </span><span style="color: #B48EAD">1024</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">LISTEN_BACKLOG</span><span style="color: #D8DEE9FF">  </span><span style="color: #B48EAD">4</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">tcp_server_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    (</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">arg</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sockaddr_in</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sockaddr_in</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_addr</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">socklen_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_addr</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* Buffer local: cuidado com stack! */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rx_buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">RX_BUF_SIZE</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* 1) Criar socket TCP */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">socket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">AF_INET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SOCK_STREAM</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">IPPROTO_TCP</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* Em sistemas embarcados: logue e reinicie a task ou sinalize falha */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* 2) Preencher estrutura de endereço */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">memset</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">addr</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sin_family</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">AF_INET</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sin_port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">htons</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">SERVER_PORT</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sin_addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">s_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">htonl</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">INADDR_ANY</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">/* escuta em todas interfaces */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* 3) Bind: amarra o socket à porta */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">bind</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sockaddr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">addr</span><span style="color: #D8DEE9FF">)) </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* 4) Listen: coloca em modo servidor */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">listen</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">LISTEN_BACKLOG</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* 5) Accept: bloqueia esperando cliente */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">accept</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sockaddr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">client_addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">client_len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* Se accept falhar, normalmente você continua tentando */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">100</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">continue;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* 6) Loop de recepção */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">recv</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rx_buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rx_buf</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #616E88">/* n == 0 -&gt; cliente fechou; n &lt; 0 -&gt; erro */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">break;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">rx_buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #EBCB8B">\0</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* 7) Aqui entra a lógica da aplicação.</span></span>
<span class="line"><span style="color: #616E88">                  Para um echo server: devolve os bytes recebidos. */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">send</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rx_buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* Exemplo: se quiser encerrar ao receber &quot;quit&quot; */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">strncmp</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rx_buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">quit</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">break;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* 8) Fecha conexão do cliente */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/* Função de arranque */</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">start_tcp_server</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* Stack precisa ser dimensionada: sockets + buffer local */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tcp_server_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">TCPServer</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #B48EAD">2048</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                  </span><span style="color: #616E88">/* ajuste real conforme seu MCU/heap */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">tskIDLE_PRIORITY</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">/* prioridade média */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>6.3 Pontos críticos (onde a maioria erra)</strong></h4>



<p class="wp-block-paragraph">A primeira armadilha é stack. Repare que <code>rx_buf[1024]</code> está na stack da task. Em Cortex-M, 2 KB de stack pode ficar apertado se você começar a montar respostas HTTP grandes, fazer parsing pesado ou usar <code>printf</code>. Uma prática robusta é mover buffers grandes para heap/estático e deixar stack para variáveis pequenas.</p>



<p class="wp-block-paragraph">A segunda armadilha é bloqueio infinito. <code>accept()</code> e <code>recv()</code> bloqueiam. Isso pode ser OK em um servidor dedicado, mas se você precisa de shutdown limpo, watchdog cooperativo ou multiplexar atividades, você vai querer <strong>timeouts</strong> via <code>setsockopt()</code> com <code>SO_RCVTIMEO</code> e <code>SO_SNDTIMEO</code>, ou usar <code>select()</code> para multiplexar.</p>



<p class="wp-block-paragraph">A terceira armadilha é “fazer tudo nessa task”. Em firmware sério, o servidor de sockets vira um <strong>front-end</strong> que entrega payloads para outras tasks via <strong>queues</strong> (produtor/consumidor), mantendo o servidor leve e previsível. Caso contrário, você mistura rede + lógica de negócio + acesso a periféricos no mesmo contexto e cria latência ruim e travamentos em cascata.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>6.4 Melhorando com timeouts (essencial para robustez)</strong></h4>



<p class="wp-block-paragraph">Um exemplo direto para evitar travar em <code>recv()</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &amp;tv, sizeof(tv));
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">timeval</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tv</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tv_sec</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tv_usec</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SOL_SOCKET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SO_RCVTIMEO</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tv</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Com isso, <code>recv()</code> retorna erro após 5 s sem dados, e você pode encerrar a conexão ou apenas continuar.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Na próxima seção, vamos fazer exatamente o que transforma esse exemplo em arquitetura “de produção”:</p>



<ul class="wp-block-list">
<li><strong>Task de sockets como Gatekeeper</strong></li>



<li>Entrega de dados para uma <strong>fila FreeRTOS</strong></li>



<li>Um ou mais <strong>consumidores</strong> processando requisições</li>



<li>Resposta retornando ao cliente de forma segura</li>
</ul>



<h3 class="wp-block-heading"><strong>Arquitetura de produção: servidor de sockets como Gatekeeper + filas FreeRTOS (produtor/consumidor)</strong></h3>



<p class="wp-block-paragraph">Quando você coloca lwIP + FreeRTOS em um produto real, a pergunta não é “como abrir um socket”, mas sim: <strong>como garantir previsibilidade, isolamento de falhas e escalabilidade</strong> quando há múltiplas conexões, parsing de protocolo, acesso a periféricos e regras de negócio rodando ao mesmo tempo. O padrão mais sólido aqui é tratar a task de rede como um <strong>Gatekeeper</strong> (porteiro): ela faz o mínimo necessário (I/O de rede e framing básico), empacota mensagens e entrega para a aplicação via <strong>Queue</strong>. As tasks de aplicação, por sua vez, consomem essas mensagens e devolvem respostas por um caminho igualmente controlado.</p>



<p class="wp-block-paragraph">A razão técnica é simples: a pilha de rede precisa de tempo de CPU para manter conexões (ACKs, retransmissões, janelas TCP), e isso pode ser prejudicado se você faz parsing pesado, acesso a flash, escrita em SD, controle de motores ou logs complexos dentro da mesma task que está segurando o socket. Além disso, erros na lógica de negócio não podem derrubar a infraestrutura de rede. Com Gatekeeper + filas, você desacopla os domínios: rede continua estável, aplicação pode reiniciar tasks de processamento, e o sistema ganha uma arquitetura “defensiva”.</p>



<p class="wp-block-paragraph">A seguir, vamos montar um exemplo funcional e didático. Ele não é “o menor possível”: ele é “o mais correto possível” para firmware.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>7.1 Estruturas de mensagem e filas</strong></h4>



<p class="wp-block-paragraph">Vamos definir duas filas:</p>



<ul class="wp-block-list">
<li><code>rxQueue</code>: mensagens recebidas da rede para a aplicação</li>



<li><code>txQueue</code>: respostas da aplicação para serem transmitidas pela task de rede</li>
</ul>



<p class="wp-block-paragraph">Cada mensagem precisa carregar, no mínimo:</p>



<ul class="wp-block-list">
<li><strong>identificador da conexão</strong> (socket do cliente ou um handle abstrato)</li>



<li><strong>payload</strong> (bytes recebidos)</li>



<li><strong>tamanho</strong></li>



<li><strong>metadados</strong> (opcional: IP/porta, timestamp etc.)</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "FreeRTOS.h"
#include "queue.h"
#include &lt;stdint.h>

#define MAX_PAYLOAD 512

typedef struct
{
    int client_fd;                 /* Identifica a conexão */
    uint16_t len;
    uint8_t payload&#91;MAX_PAYLOAD&#93;;  /* Mensagem "copiada" para trânsito seguro */
} NetMessage_t;

static QueueHandle_t rxQueue;
static QueueHandle_t txQueue;

void net_queues_init(void)
{
    rxQueue = xQueueCreate(8, sizeof(NetMessage_t));
    txQueue = xQueueCreate(8, sizeof(NetMessage_t));
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">queue.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdint</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MAX_PAYLOAD</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">512</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">                 </span><span style="color: #616E88">/* Identifica a conexão */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">payload</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">MAX_PAYLOAD</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">/* Mensagem &quot;copiada&quot; para trânsito seguro */</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">QueueHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rxQueue</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">QueueHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">txQueue</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">net_queues_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">rxQueue</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">xQueueCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">8</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">txQueue</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">xQueueCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">8</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Observação crítica:</strong> aqui estamos usando cópia de payload. Em sistemas mais exigentes, você pode migrar para <em>zero-copy</em> com <code>pbuf</code> (RAW API) ou pool de buffers. Mas começar com cópia é geralmente a forma mais estável de construir algo robusto e debugar rápido.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>7.2 Task Gatekeeper: recebe do socket e entrega na <code>rxQueue</code></strong></h4>



<p class="wp-block-paragraph">A task de rede agora vira uma “central de I/O”: aceita conexões, recebe dados e empacota mensagens para a fila.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include "lwip/sockets.h"
#include "lwip/inet.h"
#include &lt;string.h>

#define SERVER_PORT 5000

static void socket_gatekeeper_task(void *arg)
{
    (void)arg;

    int listen_fd;
    struct sockaddr_in addr;

    listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listen_fd &lt; 0) vTaskDelete(NULL);

    memset(&amp;addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(listen_fd, (struct sockaddr *)&amp;addr, sizeof(addr)) &lt; 0) {
        closesocket(listen_fd);
        vTaskDelete(NULL);
    }

    if (listen(listen_fd, 4) &lt; 0) {
        closesocket(listen_fd);
        vTaskDelete(NULL);
    }

    for (;;)
    {
        int client_fd = accept(listen_fd, NULL, NULL);
        if (client_fd &lt; 0) {
            vTaskDelay(pdMS_TO_TICKS(50));
            continue;
        }

        /* Exemplo simples: atende 1 cliente por vez.
           Em produção você pode criar uma task por cliente OU usar select(). */
        for (;;)
        {
            NetMessage_t msg;
            int n = recv(client_fd, msg.payload, MAX_PAYLOAD, 0);
            if (n &lt;= 0) break;

            msg.client_fd = client_fd;
            msg.len = (uint16_t)n;

            /* Entrega para aplicação: se a fila estiver cheia, você precisa decidir política:
               - descartar
               - bloquear por tempo limitado
               - desconectar cliente
            */
            if (xQueueSend(rxQueue, &amp;msg, pdMS_TO_TICKS(20)) != pdPASS) {
                /* Política simples: descarta e segue */
            }

            /* Antes de receber mais, veja se há resposta pronta para este cliente */
            NetMessage_t out;
            if (xQueueReceive(txQueue, &amp;out, 0) == pdPASS) {
                if (out.client_fd == client_fd &amp;&amp; out.len > 0) {
                    send(client_fd, out.payload, out.len, 0);
                } else {
                    /* Se veio resposta de outro cliente, em produção você
                       rotearia corretamente (mapa de conexões, etc.) */
                }
            }
        }

        closesocket(client_fd);
    }
}

void start_socket_gatekeeper(void)
{
    xTaskCreate(socket_gatekeeper_task,
                "NetGate",
                2048,
                NULL,
                tskIDLE_PRIORITY + 3, /* Um pouco acima da aplicação */
                NULL);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">task.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">queue.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/sockets.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">lwip/inet.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SERVER_PORT</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5000</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">socket_gatekeeper_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    (</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">arg</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">listen_fd</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sockaddr_in</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">socket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">AF_INET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SOCK_STREAM</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">IPPROTO_TCP</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">memset</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">addr</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sin_family</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">AF_INET</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sin_port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">htons</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">SERVER_PORT</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sin_addr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">s_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">htonl</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">INADDR_ANY</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">bind</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sockaddr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">addr</span><span style="color: #D8DEE9FF">)) </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">listen</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">accept</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">50</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">continue;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* Exemplo simples: atende 1 cliente por vez.</span></span>
<span class="line"><span style="color: #616E88">           Em produção você pode criar uma task por cliente OU usar select(). */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">msg</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">recv</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">msg</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MAX_PAYLOAD</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">break;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">msg</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">msg</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">n</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* Entrega para aplicação: se a fila estiver cheia, você precisa decidir política:</span></span>
<span class="line"><span style="color: #616E88">               - descartar</span></span>
<span class="line"><span style="color: #616E88">               - bloquear por tempo limitado</span></span>
<span class="line"><span style="color: #616E88">               - desconectar cliente</span></span>
<span class="line"><span style="color: #616E88">            */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">xQueueSend</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rxQueue</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">msg</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">20</span><span style="color: #D8DEE9FF">)) </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pdPASS</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #616E88">/* Política simples: descarta e segue */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* Antes de receber mais, veja se há resposta pronta para este cliente */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">xQueueReceive</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">txQueue</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pdPASS</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">send</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">/* Se veio resposta de outro cliente, em produção você</span></span>
<span class="line"><span style="color: #616E88">                       rotearia corretamente (mapa de conexões, etc.) */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">start_socket_gatekeeper</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">socket_gatekeeper_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">NetGate</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #B48EAD">2048</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">tskIDLE_PRIORITY</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">/* Um pouco acima da aplicação */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Por que esse desenho é bom?</strong> Porque o Gatekeeper mantém I/O simples e previsível: ele não interpreta protocolo nem acessa hardware. Ele apenas “empurra bytes”.</p>



<p class="wp-block-paragraph"><strong>Crítica (importante):</strong> este exemplo atende um cliente por vez. Para múltiplos clientes, as duas opções típicas são:</p>



<ol class="wp-block-list">
<li><strong>uma task por conexão</strong> (mais simples, mas consome RAM/stack)</li>



<li><strong><code>select()</code></strong> com um loop único multiplexando sockets (mais eficiente, mais complexo)</li>
</ol>



<p class="wp-block-paragraph">Na próxima seção eu te mostro os dois modelos, mas antes precisamos fechar o ciclo com o consumidor.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>7.3 Task consumidora: processa mensagem e devolve resposta</strong></h4>



<p class="wp-block-paragraph">Agora a lógica de aplicação recebe mensagens da <code>rxQueue</code>, interpreta e devolve uma resposta pela <code>txQueue</code>.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include &lt;string.h>

static void app_worker_task(void *arg)
{
    (void)arg;

    for (;;)
    {
        NetMessage_t in;
        if (xQueueReceive(rxQueue, &amp;in, portMAX_DELAY) == pdPASS)
        {
            NetMessage_t out;
            memset(&amp;out, 0, sizeof(out));

            out.client_fd = in.client_fd;

            /* Exemplo de "protocolo": comandos ASCII */
            if (in.len >= 4 &amp;&amp; memcmp(in.payload, "ping", 4) == 0) {
                const char *resp = "pong\n";
                out.len = (uint16_t)strlen(resp);
                memcpy(out.payload, resp, out.len);
            } else {
                const char *resp = "unknown\n";
                out.len = (uint16_t)strlen(resp);
                memcpy(out.payload, resp, out.len);
            }

            /* Envia resposta para o Gatekeeper transmitir */
            (void)xQueueSend(txQueue, &amp;out, pdMS_TO_TICKS(50));
        }
    }
}

void start_app_worker(void)
{
    xTaskCreate(app_worker_task,
                "AppWorker",
                2048,
                NULL,
                tskIDLE_PRIORITY + 2,
                NULL);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">task.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">queue.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_worker_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    (</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">arg</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">in;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">xQueueReceive</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rxQueue</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;in</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMAX_DELAY</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pdPASS</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">NetMessage_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">memset</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">out</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">in</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">client_fd</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* Exemplo de &quot;protocolo&quot;: comandos ASCII */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">in</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">memcmp</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">in</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ping</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> *resp </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">pong</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #88C0D0">strlen</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">resp</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #88C0D0">memcpy</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">resp</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> *resp </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">unknown</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #88C0D0">strlen</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">resp</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #88C0D0">memcpy</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">resp</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* Envia resposta para o Gatekeeper transmitir */</span></span>
<span class="line"><span style="color: #D8DEE9FF">            (</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #88C0D0">xQueueSend</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">txQueue</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">out</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">50</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">start_app_worker</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">app_worker_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">AppWorker</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #B48EAD">2048</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">tskIDLE_PRIORITY</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Aqui você ganhou algo decisivo: se o parsing for pesado, você pode criar <strong>vários workers consumidores</strong> (ou uma pool) sem mexer na task de rede. E se um worker travar, você pode reiniciá-lo sem derrubar a rede (principalmente se tiver Task Monitor/Watchdog como você já vem tratando na série).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>7.4 Ajustes essenciais para “produção”</strong></h4>



<p class="wp-block-paragraph">O exemplo acima é a forma didática mais direta, mas em firmware real você geralmente aplica melhorias:</p>



<ul class="wp-block-list">
<li><strong>Roteamento de respostas por conexão:</strong> em vez de uma <code>txQueue</code> única, você cria uma fila por cliente (ou um mapa de conexões).</li>



<li><strong>Política de backpressure:</strong> se <code>rxQueue</code> enche, você reduz leitura do socket, aplica <code>recv</code> com timeout, ou desconecta cliente.</li>



<li><strong>Framing:</strong> TCP é stream, não pacote. Seu “comando” pode vir partido em múltiplos <code>recv()</code>. Então você implementa <em>framing</em> (por delimitador <code>\n</code>, por tamanho fixo, ou por header com length).</li>



<li><strong>Stack e heap:</strong> payload copiado custa RAM; quando necessário, migra para pool de buffers.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Na próxima seção, vamos atacar exatamente o que separa “demo” de “produto”:<br><strong>TCP é stream — então precisamos de framing e parser robusto</strong>, além de <strong>timeouts</strong> e <strong>manuseio de múltiplos clientes</strong>.</p>



<h3 class="wp-block-heading"><strong> TCP é stream: framing robusto + múltiplos clientes (task por conexão vs <code>select()</code>)</strong></h3>



<p class="wp-block-paragraph">Se tem um erro conceitual que derruba sistemas FreeRTOS + lwIP “do nada”, é tratar <code>recv()</code> como se cada chamada retornasse uma mensagem completa. <strong>TCP não entrega mensagens — entrega um fluxo (stream)</strong>. Isso significa que um comando <code>ping\n</code> pode chegar como <code>p</code>, depois <code>ing\n</code>, ou pode chegar junto com outro comando colado, ou pode vir com bytes extras. Se você não implementar <strong>framing</strong>, sua aplicação vai funcionar em bancada e falhar sob carga, ruído de rede, latência variável ou retransmissões.</p>



<p class="wp-block-paragraph">A solução arquitetural é definir um protocolo com framing claro. Os dois modelos mais comuns em firmware são: (1) <strong>delimitador</strong> (por exemplo <code>\n</code>) e (2) <strong>length-prefix</strong> (header com tamanho). Vou te mostrar os dois, e em seguida mostro como isso muda quando você tem múltiplos clientes: ou você cria <strong>uma task por conexão</strong> (simples, mais RAM) ou usa <strong><code>select()</code></strong> (eficiente, mais complexo).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>8.1 Framing por delimitador (<code>\n</code>)</strong></h4>



<p class="wp-block-paragraph">Esse é o mais simples: você acumula bytes num buffer até achar <code>\n</code>. Cada linha vira um comando. É ótimo para console TCP, debug remoto, protocolos ASCII e comandos humanos. O cuidado é evitar overflow: se o cliente mandar uma linha enorme sem <code>\n</code>, você precisa cortar, descartar ou desconectar.</p>



<p class="wp-block-paragraph">Exemplo de acumulador por conexão:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;string.h>
#include &lt;stdint.h>

#define LINE_BUF_SZ 256

typedef struct
{
    uint8_t buf&#91;LINE_BUF_SZ&#93;;
    uint16_t used;
} LineFramer_t;

/**
 * @brief Alimenta o framer com bytes recebidos e extrai 0..N linhas completas.
 *        Retorna 1 quando extraiu uma linha, 0 quando ainda não tem linha.
 */
static int framer_try_get_line(LineFramer_t *f, const uint8_t *data, uint16_t len,
                               uint8_t *out_line, uint16_t *out_len)
{
    /* Copia com proteção */
    uint16_t space = (LINE_BUF_SZ - 1) - f->used;
    if (len > space) {
        /* Política simples: reset (em produção: desconectar cliente) */
        f->used = 0;
        return 0;
    }

    memcpy(&amp;f->buf&#91;f->used&#93;, data, len);
    f->used += len;
    f->buf&#91;f->used&#93; = 0;

    /* Procura delimitador */
    uint8_t *nl = (uint8_t*)memchr(f->buf, '\n', f->used);
    if (!nl) return 0;

    uint16_t line_len = (uint16_t)(nl - f->buf) + 1; /* inclui '\n' */
    memcpy(out_line, f->buf, line_len);
    *out_len = line_len;

    /* Remove a linha do buffer (shift) */
    uint16_t remaining = f->used - line_len;
    memmove(f->buf, &amp;f->buf&#91;line_len&#93;, remaining);
    f->used = remaining;

    return 1;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdint</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">LINE_BUF_SZ</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">256</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">LINE_BUF_SZ</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">used</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">LineFramer_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Alimenta o framer com bytes recebidos e extrai 0..N linhas completas.</span></span>
<span class="line"><span style="color: #616E88"> *        Retorna 1 quando extraiu uma linha, 0 quando ainda não tem linha.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">framer_try_get_line</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">LineFramer_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">f</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                               </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out_line</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out_len</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* Copia com proteção */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">space</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">LINE_BUF_SZ</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">space</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* Política simples: reset (em produção: desconectar cliente) */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">memcpy</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* Procura delimitador */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">nl</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #88C0D0">memchr</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&#39;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9">nl</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line_len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF">)(</span><span style="color: #D8DEE9">nl</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">/* inclui &#39;\n&#39; */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">memcpy</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">out_line</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line_len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out_len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line_len</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* Remove a linha do buffer (shift) */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">remaining</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line_len</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">memmove</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">line_len</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">remaining</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">remaining</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Uso típico no loop do socket: você chama <code>recv()</code>, joga os bytes no framer e enquanto ele conseguir extrair linhas você envia para a fila (<code>rxQueue</code>).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>8.2 Framing por header com tamanho (length-prefix)</strong></h4>



<p class="wp-block-paragraph">Esse é o padrão de protocolos binários robustos. Você define, por exemplo:</p>



<ul class="wp-block-list">
<li>2 bytes: <code>len</code> (big-endian)</li>



<li><code>len</code> bytes: payload</li>
</ul>



<p class="wp-block-paragraph">Vantagem: não depende de delimitador e funciona bem com binário. Desvantagem: você precisa validar tamanho, lidar com endianess e limites.</p>



<p class="wp-block-paragraph">Estrutura de parsing por estados:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdint.h>
#include &lt;string.h>

#define MAX_FRAME 512

typedef enum { ST_LEN1, ST_LEN2, ST_PAYLOAD } ParseState_t;

typedef struct
{
    ParseState_t st;
    uint16_t expected;
    uint16_t got;
    uint8_t payload&#91;MAX_FRAME&#93;;
} LenFramer_t;

static void lenframer_init(LenFramer_t *f)
{
    f->st = ST_LEN1;
    f->expected = 0;
    f->got = 0;
}

/**
 * @brief Consome bytes e extrai frames completos. Retorna 1 quando extrai um frame.
 */
static int lenframer_feed(LenFramer_t *f, const uint8_t *data, uint16_t len,
                          uint8_t *out_payload, uint16_t *out_len)
{
    for (uint16_t i = 0; i &lt; len; i++)
    {
        uint8_t b = data&#91;i&#93;;

        switch (f->st)
        {
            case ST_LEN1:
                f->expected = ((uint16_t)b) &lt;&lt; 8;
                f->st = ST_LEN2;
                break;

            case ST_LEN2:
                f->expected |= b;
                if (f->expected == 0 || f->expected > MAX_FRAME) {
                    /* Frame inválido: reset (em produção: desconectar) */
                    lenframer_init(f);
                    break;
                }
                f->got = 0;
                f->st = ST_PAYLOAD;
                break;

            case ST_PAYLOAD:
                f->payload&#91;f->got++&#93; = b;
                if (f->got >= f->expected) {
                    memcpy(out_payload, f->payload, f->expected);
                    *out_len = f->expected;
                    lenframer_init(f);
                    return 1; /* extraiu 1 frame */
                }
                break;
        }
    }
    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdint</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MAX_FRAME</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">512</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">enum</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_LEN1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_LEN2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_PAYLOAD</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ParseState_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">ParseState_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">st</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">expected</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">got</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">payload</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">MAX_FRAME</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">LenFramer_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">lenframer_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">LenFramer_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">f</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">st</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_LEN1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">got</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Consome bytes e extrai frames completos. Retorna 1 quando extrai um frame.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">lenframer_feed</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">LenFramer_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">f</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                          </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out_payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out_len</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">b</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">switch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">st</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_LEN1</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> ((</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">b</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">st</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_LEN2</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">break;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_LEN2</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">b</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MAX_FRAME</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">/* Frame inválido: reset (em produção: desconectar) */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">lenframer_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">f</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">break;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">got</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">st</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_PAYLOAD</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">break;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ST_PAYLOAD</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">payload</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">got</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">b</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">got</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">memcpy</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">out_payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">payload</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out_len</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">expected</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">lenframer_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">f</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">/* extraiu 1 frame */</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">break;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Esse modelo é extremamente estável em ambiente real porque mantém o protocolo bem definido.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>8.3 Múltiplos clientes: duas arquiteturas</strong></h4>



<p class="wp-block-paragraph">Agora vem o ponto de engenharia de firmware: <strong>como atender N conexões</strong> sem destruir RAM e sem perder previsibilidade.</p>



<p class="wp-block-paragraph"><strong>Opção A — Uma task por conexão (modelo simples)</strong></p>



<ul class="wp-block-list">
<li>Ao aceitar um cliente, você cria uma task dedicada para ele.</li>



<li>Cada task tem seu framer + buffer + loop <code>recv()</code>.</li>



<li>Fácil de entender e depurar.</li>



<li>Custo: cada task consome stack e TCB; em MCU pequeno isso vira limite rápido.</li>
</ul>



<p class="wp-block-paragraph">Padrão típico:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static void client_task(void *arg)
{
    int client_fd = (int)(intptr_t)arg;
    LineFramer_t fr;
    fr.used = 0;

    for (;;)
    {
        uint8_t tmp&#91;128&#93;;
        int n = recv(client_fd, tmp, sizeof(tmp), 0);
        if (n &lt;= 0) break;

        uint8_t line&#91;LINE_BUF_SZ&#93;;
        uint16_t line_len;

        while (framer_try_get_line(&amp;fr, tmp, (uint16_t)n, line, &amp;line_len)) {
            /* aqui você empacota e manda para rxQueue */
        }
    }

    closesocket(client_fd);
    vTaskDelete(NULL);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">client_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF">)(</span><span style="color: #D8DEE9">intptr_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">arg</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">LineFramer_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fr</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">fr</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">used</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tmp</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">128</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">recv</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tmp</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tmp</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">n</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">break;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">LINE_BUF_SZ</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line_len</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">framer_try_get_line</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">fr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tmp</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">line</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">line_len</span><span style="color: #D8DEE9FF">)) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">/* aqui você empacota e manda para rxQueue */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">closesocket</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">vTaskDelete</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Opção B — <code>select()</code> (modelo eficiente)</strong></p>



<ul class="wp-block-list">
<li>Uma única task monitora vários sockets ao mesmo tempo.</li>



<li>Melhor uso de RAM (uma task só), bom para dezenas de conexões.</li>



<li>Custo: mais complexo; exige tabela de conexões e estados por cliente.</li>
</ul>



<p class="wp-block-paragraph">Se seu firmware precisa escalar, <code>select()</code> costuma ser o caminho. Se precisa ser simples e você terá poucos clientes, task por conexão é perfeito.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>8.4 Um detalhe que muita gente ignora: prioridade e latência</strong></h4>



<p class="wp-block-paragraph">Não adianta ter framing perfeito se a task que atende sockets fica “no fim da fila” e perde janela TCP. Em geral, uma prática saudável é:</p>



<ul class="wp-block-list">
<li>TCP/IP thread: prioridade média-alta (depende do port e do vendor)</li>



<li>Gatekeeper de sockets: prioridade logo abaixo da TCP/IP thread</li>



<li>Workers de aplicação: prioridade média</li>



<li>Logs/telemetria: prioridade baixa</li>
</ul>



<p class="wp-block-paragraph">Isso evita um cenário em que o processamento de aplicação “engole” a CPU e a rede degrada.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Na próxima seção, vamos fechar a arquitetura com os componentes que tornam isso resiliente em produto:</p>



<ul class="wp-block-list">
<li><strong>timeouts completos</strong> (recv/send/connect/accept)</li>



<li><strong>keepalive TCP</strong></li>



<li><strong>watchdog e task monitor aplicados ao domínio de rede</strong></li>



<li><strong>política de backpressure</strong> quando filas enchem</li>



<li>e um exemplo “quase HTTP” com parser mínimo</li>
</ul>



<h3 class="wp-block-heading"><strong>Robustez em rede: timeouts, keepalive, backpressure e integração com Task Monitor/Watchdog</strong></h3>



<p class="wp-block-paragraph">Até aqui você já tem uma arquitetura correta. Agora entramos no que diferencia <strong>firmware de laboratório</strong> de <strong>firmware de campo</strong>: resiliência. Em sistemas FreeRTOS + lwIP, a maior parte das falhas em produção não vem de bugs óbvios, mas de <strong>bloqueios silenciosos</strong>, <strong>clientes mal-comportados</strong>, <strong>perda intermitente de link</strong>, <strong>filas saturadas</strong> e <strong>tarefas que parecem vivas, mas não fazem progresso</strong>. Esta seção trata exatamente desses pontos — com decisões práticas de engenharia.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>9.1 Timeouts em sockets: nunca confie em bloqueios infinitos</strong></h4>



<p class="wp-block-paragraph">Chamadas como <code>accept()</code>, <code>recv()</code> e <code>send()</code> <strong>bloqueiam por padrão</strong>. Em firmware, isso é perigoso: se um cliente trava no meio de uma transmissão, sua task pode ficar presa indefinidamente, impedindo shutdown limpo, watchdog cooperativo e diagnóstico.</p>



<p class="wp-block-paragraph">A regra é simples: <strong>todo socket deve ter timeout</strong>.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static void socket_set_timeouts(int fd, int sec)
{
    struct timeval tv;
    tv.tv_sec = sec;
    tv.tv_usec = 0;

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &amp;tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &amp;tv, sizeof(tv));
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">socket_set_timeouts</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sec</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">timeval</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tv</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tv_sec</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sec</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">tv_usec</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SOL_SOCKET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SO_RCVTIMEO</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tv</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SOL_SOCKET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SO_SNDTIMEO</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">tv</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">tv</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Use isso logo após <code>accept()</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>int client_fd = accept(listen_fd, NULL, NULL);
if (client_fd >= 0) {
    socket_set_timeouts(client_fd, 5); /* 5s é um bom ponto inicial */
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">accept</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">listen_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">client_fd</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">socket_set_timeouts</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">client_fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">/* 5s é um bom ponto inicial */</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Com isso:</p>



<ul class="wp-block-list">
<li><code>recv()</code> retorna <code>&lt; 0</code> após timeout</li>



<li>você pode <strong>encerrar a conexão</strong>, <strong>reavaliar estado</strong> ou <strong>alimentar watchdog</strong></li>



<li>evita tarefas “zumbis”</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>9.2 TCP Keepalive: detectando clientes mortos</strong></h4>



<p class="wp-block-paragraph">Em redes reais, cliente pode cair sem fechar socket (queda de Wi-Fi, cabo puxado, crash). O TCP keepalive permite detectar isso.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>int enable = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &amp;enable, sizeof(enable));

int idle = 10;    /* segundos ociosos antes do probe */
int interval = 5; /* intervalo entre probes */
int count = 3;    /* probes antes de declarar morto */

setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &amp;idle, sizeof(idle));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &amp;interval, sizeof(interval));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &amp;count, sizeof(count));
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">enable</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SOL_SOCKET</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SO_KEEPALIVE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">enable</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">enable</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">idle</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* segundos ociosos antes do probe */</span></span>
<span class="line"><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">interval</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">/* intervalo entre probes */</span></span>
<span class="line"><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">count</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">/* probes antes de declarar morto */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">IPPROTO_TCP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TCP_KEEPIDLE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">idle</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">idle</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">IPPROTO_TCP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TCP_KEEPINTVL</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">interval</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">interval</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">setsockopt</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">IPPROTO_TCP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TCP_KEEPCNT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">count</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">count</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Nem todos os ports do lwIP suportam todas essas opções, mas quando disponíveis, <strong>reduzem drasticamente conexões zumbis</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>9.3 Backpressure: o que fazer quando as filas enchem</strong></h4>



<p class="wp-block-paragraph">Esse ponto é crítico e raramente tratado em exemplos. Se sua <code>rxQueue</code> enche, <strong>o sistema está dizendo que não consegue processar dados na mesma taxa em que recebe</strong>. Ignorar isso leva a latência crescente e colapso.</p>



<p class="wp-block-paragraph">Existem quatro políticas clássicas:</p>



<ol class="wp-block-list">
<li><strong>Descartar mensagens novas</strong><br>Simples, mas pode quebrar protocolo.</li>



<li><strong>Bloquear o Gatekeeper por tempo limitado</strong><code>if (xQueueSend(rxQueue, &amp;msg, pdMS_TO_TICKS(50)) != pdPASS) { /* timeout: decide política */ }</code></li>



<li><strong>Parar de ler do socket temporariamente</strong><br>Com timeout em <code>recv()</code>, você simplesmente não chama <code>recv</code> por um ciclo.</li>



<li><strong>Desconectar cliente agressivo</strong> (muito comum em produto)<br>Se um cliente gera backpressure constante, ele é o problema.</li>
</ol>



<p class="wp-block-paragraph">Em firmware sério, a política 4 costuma ser a mais segura.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>9.4 Integração com Task Monitor: detectar “tarefas vivas porém travadas”</strong></h4>



<p class="wp-block-paragraph">Uma task bloqueada em <code>recv()</code> <strong>não parece travada</strong> para o scheduler — ela está em estado <em>Blocked</em>. Por isso, Task Monitor precisa ir além de “task rodando ou não”: precisa verificar <strong>progresso lógico</strong>.</p>



<p class="wp-block-paragraph">Modelo simples: <em>heartbeat por domínio</em>.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>volatile uint32_t net_heartbeat = 0;

void socket_gatekeeper_task(void *arg)
{
    for (;;)
    {
        net_heartbeat++;
        /* accept / recv / processamento */
    }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">volatile</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">net_heartbeat</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">socket_gatekeeper_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">net_heartbeat</span><span style="color: #81A1C1">++;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* accept / recv / processamento */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">O Task Monitor verifica:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static uint32_t last_net_hb = 0;

void task_monitor(void)
{
    if (net_heartbeat == last_net_hb) {
        /* rede não progrediu */
        /* ação: reiniciar task, reiniciar interface, logar */
    }
    last_net_hb = net_heartbeat;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">last_net_hb</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">task_monitor</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">net_heartbeat</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">last_net_hb</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* rede não progrediu */</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">/* ação: reiniciar task, reiniciar interface, logar */</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">last_net_hb</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">net_heartbeat</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Isso detecta:</p>



<ul class="wp-block-list">
<li>deadlocks</li>



<li>starvation</li>



<li>loops bloqueados por erro lógico</li>
</ul>



<p class="wp-block-paragraph">Muito mais eficaz que apenas checar se a task existe.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>9.5 Watchdog cooperativo aplicado à rede</strong></h4>



<p class="wp-block-paragraph">Nunca alimente o watchdog <strong>dentro da task de sockets diretamente</strong>. Isso mascara falhas. O correto é:</p>



<ul class="wp-block-list">
<li>task de rede atualiza estado/heartbeat</li>



<li><strong>task de supervisão</strong> decide se o sistema está saudável</li>



<li>só ela alimenta o watchdog</li>
</ul>



<p class="wp-block-paragraph">Exemplo conceitual:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>void supervisor_task(void *arg)
{
    for (;;)
    {
        if (net_ok &amp;&amp; app_ok &amp;&amp; sensors_ok) {
            feed_watchdog();
        }
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">supervisor_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">arg</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">net_ok</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">app_ok</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">sensors_ok</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">feed_watchdog</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">500</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Assim, falhas de rede <strong>resetam o sistema</strong>, em vez de ficarem ocultas.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading"><strong>9.6 Mini-HTTP: aplicação prática dos conceitos</strong></h4>



<p class="wp-block-paragraph">Para fechar, um exemplo conceitual de servidor estilo HTTP minimalista:</p>



<ul class="wp-block-list">
<li>framing por <code>\r\n\r\n</code></li>



<li>timeout curto</li>



<li>parsing mínimo</li>



<li>resposta fixa</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>if (strstr(request, "GET /status")) {
    const char *resp =
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/plain\r\n"
        "Connection: close\r\n"
        "\r\n"
        "OK\n";
    send(fd, resp, strlen(resp), 0);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">strstr</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">request</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">GET /status</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> *resp </span><span style="color: #81A1C1">=</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">HTTP/1.1 200 OK</span><span style="color: #EBCB8B">\r\n</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Content-Type: text/plain</span><span style="color: #EBCB8B">\r\n</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Connection: close</span><span style="color: #EBCB8B">\r\n</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\r\n</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">OK</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">send</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">fd</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">resp</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">resp</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Em firmware, <strong>HTTP raramente precisa ser completo</strong>. Muitas vezes é só um protocolo humano para debug, status e configuração inicial. Quanto mais simples, mais confiável.</p><p>The post <a href="https://mcu.tec.br/rtos/freertos-com-lwip-arquitetura-boas-praticas-e-exemplos-reais-de-sistemas-embarcados-em-rede/">FreeRTOS com lwIP: Arquitetura, Boas Práticas e Exemplos Reais de Sistemas Embarcados em Rede</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1082</post-id>	</item>
		<item>
		<title>Zephyr no ESP32: ADC Contínuo com DMA, VAD e Processamento de Sinais em Tempo Real</title>
		<link>https://mcu.tec.br/rtos/zephyr-no-esp32-adc-continuo-com-dma-vad-e-processamento-de-sinais-em-tempo-real/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zephyr-no-esp32-adc-continuo-com-dma-vad-e-processamento-de-sinais-em-tempo-real</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Tue, 13 Jan 2026 20:01:18 +0000</pubDate>
				<category><![CDATA[lwIP]]></category>
		<category><![CDATA[RTOS]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=1061</guid>

					<description><![CDATA[<p>Aprenda como usar o Zephyr OS no ESP32 para implementar leitura contínua do ADC com DMA, detecção de atividade de voz (VAD) e processamento de sinais em tempo real. Este artigo apresenta uma arquitetura completa baseada em threads produtor/consumidor, configuração do ADC via Device Tree, uso de buffers eficientes com slab e message queue, além de técnicas de DSP para estimar a frequência dominante do sinal coletado. São abordadas estratégias práticas de VAD em software e em hardware (ESP32-P4), priorização de tarefas, diagnóstico de gargalos e boas práticas para sistemas embarcados críticos. Um guia técnico, detalhado e aplicável a projetos de áudio, vibração e análise espectral em microcontroladores ESP32 com Zephyr.</p>
<p>The post <a href="https://mcu.tec.br/rtos/zephyr-no-esp32-adc-continuo-com-dma-vad-e-processamento-de-sinais-em-tempo-real/">Zephyr no ESP32: ADC Contínuo com DMA, VAD e Processamento de Sinais em Tempo Real</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<div class="root-eb-toc-p2mmp wp-block-essential-blocks-table-of-contents"><div class="eb-parent-wrapper eb-parent-eb-toc-p2mmp "><div class="eb-toc-container eb-toc-p2mmp  eb-toc-is-not-sticky eb-toc-not-collapsible eb-toc-initially-not-collapsed eb-toc-scrollToTop style-1 list-style-none" data-scroll-top="false" data-scroll-top-icon="fas fa-angle-up" data-collapsible="false" data-sticky-hide-mobile="false" data-sticky="false" data-scroll-target="scroll_to_toc" data-copy-link="false" data-editor-type="" data-hide-desktop="false" data-hide-tab="false" data-hide-mobile="false" data-itemcollapsed="false" data-highlight-scroll="false"><div class="eb-toc-header"><h2 class="eb-toc-title">Table of Contents</h2></div><div class="eb-toc-wrapper " data-headers="[{&quot;level&quot;:2,&quot;content&quot;:&quot;Vis\u00e3o geral da solu\u00e7\u00e3o no Zephyr para ESP32: ADC cont\u00ednuo (DMA), VAD e pipeline produtor\/consumidor&quot;,&quot;text&quot;:&quot;Vis\u00e3o geral da solu\u00e7\u00e3o no Zephyr para ESP32: ADC cont\u00ednuo (DMA), VAD e pipeline produtor\/consumidor&quot;,&quot;link&quot;:&quot;eb-table-content-0&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;O ponto cr\u00edtico: \u201cZephyr puro\u201d vs \u201cdriver cont\u00ednuo do ESP-IDF\u201d&quot;,&quot;text&quot;:&quot;O ponto cr\u00edtico: \u201cZephyr puro\u201d vs \u201cdriver cont\u00ednuo do ESP-IDF\u201d&quot;,&quot;link&quot;:&quot;eb-table-content-1&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;VAD no ESP32: duas realidades (hardware x software)&quot;,&quot;text&quot;:&quot;VAD no ESP32: duas realidades (hardware x software)&quot;,&quot;link&quot;:&quot;vad-no-esp32-duas-realidades-hardware-x-software&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Pipeline proposta (alto n\u00edvel)&quot;,&quot;text&quot;:&quot;Pipeline proposta (alto n\u00edvel)&quot;,&quot;link&quot;:&quot;eb-table-content-3&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Onde o DeviceTree entra (mesmo usando ADC cont\u00ednuo do ESP-IDF)&quot;,&quot;text&quot;:&quot;Onde o DeviceTree entra (mesmo usando ADC cont\u00ednuo do ESP-IDF)&quot;,&quot;link&quot;:&quot;eb-table-content-4&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;DeviceTree no Zephyr (ESP32): configurando ADC e o \u201cn\u00f3 da aplica\u00e7\u00e3o\u201d para io-channels, + base do projeto&quot;,&quot;text&quot;:&quot;DeviceTree no Zephyr (ESP32): configurando ADC e o \u201cn\u00f3 da aplica\u00e7\u00e3o\u201d para io-channels, + base do projeto&quot;,&quot;link&quot;:&quot;eb-table-content-5&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.1 boards\/esp32s3_devkitc.overlay (exemplo) \u2014 ADC + n\u00f3 da aplica\u00e7\u00e3o&quot;,&quot;text&quot;:&quot;2.1 boards\/esp32s3_devkitc.overlay (exemplo) \u2014 ADC + n\u00f3 da aplica\u00e7\u00e3o&quot;,&quot;link&quot;:&quot;eb-table-content-6&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.2 prj.conf \u2014 drivers e infraestrutura (threads, msgq, ring buffer opcional)&quot;,&quot;text&quot;:&quot;2.2 prj.conf \u2014 drivers e infraestrutura (threads, msgq, ring buffer opcional)&quot;,&quot;link&quot;:&quot;22-prjconf-drivers-e-infraestrutura-threads-msgq-ring-buffer-opcional&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.3 Contrato produtor\/consumidor: bloco de amostras + evento (VAD start\/end)&quot;,&quot;text&quot;:&quot;2.3 Contrato produtor\/consumidor: bloco de amostras + evento (VAD start\/end)&quot;,&quot;link&quot;:&quot;23-contrato-produtorconsumidor-bloco-de-amostras-evento-vad-startend&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.4 Esqueleto funcional das threads (sem DMA\/VAD ainda)&quot;,&quot;text&quot;:&quot;2.4 Esqueleto funcional das threads (sem DMA\/VAD ainda)&quot;,&quot;link&quot;:&quot;24-esqueleto-funcional-das-threads-sem-dmavad-ainda&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Aquisi\u00e7\u00e3o cont\u00ednua \u201ctipo DMA\u201d no ESP32 (ADC continuous mode), VAD delimitando stream e envio para o consumidor&quot;,&quot;text&quot;:&quot;Aquisi\u00e7\u00e3o cont\u00ednua \u201ctipo DMA\u201d no ESP32 (ADC continuous mode), VAD delimitando stream e envio para o consumidor&quot;,&quot;link&quot;:&quot;eb-table-content-10&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3.1 Ajustes de prj.conf para usar o driver cont\u00ednuo do ESP-IDF&quot;,&quot;text&quot;:&quot;3.1 Ajustes de prj.conf para usar o driver cont\u00ednuo do ESP-IDF&quot;,&quot;link&quot;:&quot;eb-table-content-11&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3.2 Produtor com ADC cont\u00ednuo (DMA): inicializa\u00e7\u00e3o + loop de leitura&quot;,&quot;text&quot;:&quot;3.2 Produtor com ADC cont\u00ednuo (DMA): inicializa\u00e7\u00e3o + loop de leitura&quot;,&quot;link&quot;:&quot;eb-table-content-12&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3.3 Encaixe do VAD em hardware (ESP32-P4) no mesmo contrato de eventos&quot;,&quot;text&quot;:&quot;3.3 Encaixe do VAD em hardware (ESP32-P4) no mesmo contrato de eventos&quot;,&quot;link&quot;:&quot;33-encaixe-do-vad-em-hardware-esp32-p4-no-mesmo-contrato-de-eventos&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3.4 Atualizando o main.c para usar o produtor real&quot;,&quot;text&quot;:&quot;3.4 Atualizando o main.c para usar o produtor real&quot;,&quot;link&quot;:&quot;34-atualizando-o-mainc-para-usar-o-produtor-real&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Consumidor: estimando a frequ\u00eancia principal do stream e imprimindo na UART&quot;,&quot;text&quot;:&quot;Consumidor: estimando a frequ\u00eancia principal do stream e imprimindo na UART&quot;,&quot;link&quot;:&quot;eb-table-content-15&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4.1 Par\u00e2metros do DSP&quot;,&quot;text&quot;:&quot;4.1 Par\u00e2metros do DSP&quot;,&quot;link&quot;:&quot;eb-table-content-16&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4.2 Implementa\u00e7\u00e3o do Goertzel + janela Hann (tudo em C puro)&quot;,&quot;text&quot;:&quot;4.2 Implementa\u00e7\u00e3o do Goertzel + janela Hann (tudo em C puro)&quot;,&quot;link&quot;:&quot;eb-table-content-17&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4.3 Consumidor completo: acumulando janela, processando em VOICE_END (e tamb\u00e9m \u201cao vivo\u201d)&quot;,&quot;text&quot;:&quot;4.3 Consumidor completo: acumulando janela, processando em VOICE_END (e tamb\u00e9m \u201cao vivo\u201d)&quot;,&quot;link&quot;:&quot;eb-table-content-18&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4.4 Resultado esperado na UART&quot;,&quot;text&quot;:&quot;4.4 Resultado esperado na UART&quot;,&quot;link&quot;:&quot;44-resultado-esperado-na-uart&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Fechando o projeto: mapeando ADC pelo DeviceTree, janela deslizante com overlap e Goertzel em ponto fixo (Q31)&quot;,&quot;text&quot;:&quot;Fechando o projeto: mapeando ADC pelo DeviceTree, janela deslizante com overlap e Goertzel em ponto fixo (Q31)&quot;,&quot;link&quot;:&quot;fechando-o-projeto-mapeando-adc-pelo-devicetree-janela-deslizante-com-overlap-e-goertzel-em-ponto-fixo-q31&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;5.1 Produtor: traduzindo adc_dt_spec (DeviceTree) para unidade\/canal do ESP-IDF&quot;,&quot;text&quot;:&quot;5.1 Produtor: traduzindo adc_dt_spec (DeviceTree) para unidade\/canal do ESP-IDF&quot;,&quot;link&quot;:&quot;51-produtor-traduzindo-adc_dt_spec-devicetree-para-unidadecanal-do-esp-idf&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;5.2 Consumidor: janela deslizante com overlap (50%) para suavizar a estimativa&quot;,&quot;text&quot;:&quot;5.2 Consumidor: janela deslizante com overlap (50%) para suavizar a estimativa&quot;,&quot;link&quot;:&quot;52-consumidor-janela-deslizante-com-overlap-50-para-suavizar-a-estimativa&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;5.3 Goertzel em ponto fixo (Q31): quando voc\u00ea quer custo determin\u00edstico&quot;,&quot;text&quot;:&quot;5.3 Goertzel em ponto fixo (Q31): quando voc\u00ea quer custo determin\u00edstico&quot;,&quot;link&quot;:&quot;eb-table-content-23&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;5.4 Checklist de integra\u00e7\u00e3o (para voc\u00ea n\u00e3o \u201cperder o fio\u201d)&quot;,&quot;text&quot;:&quot;5.4 Checklist de integra\u00e7\u00e3o (para voc\u00ea n\u00e3o \u201cperder o fio\u201d)&quot;,&quot;link&quot;:&quot;eb-table-content-24&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Pacote \u201ccopi\u00e1vel\u201d: \u00e1rvore de arquivos, CMakeLists.txt, main.c consolidado e calibra\u00e7\u00e3o pr\u00e1tica&quot;,&quot;text&quot;:&quot;Pacote \u201ccopi\u00e1vel\u201d: \u00e1rvore de arquivos, CMakeLists.txt, main.c consolidado e calibra\u00e7\u00e3o pr\u00e1tica&quot;,&quot;link&quot;:&quot;eb-table-content-25&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.1 \u00c1rvore de arquivos sugerida&quot;,&quot;text&quot;:&quot;6.1 \u00c1rvore de arquivos sugerida&quot;,&quot;link&quot;:&quot;eb-table-content-26&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.2 CMakeLists.txt&quot;,&quot;text&quot;:&quot;6.2 CMakeLists.txt&quot;,&quot;link&quot;:&quot;62-cmakeliststxt&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.3 main.c consolidado (2 threads reais)&quot;,&quot;text&quot;:&quot;6.3 main.c consolidado (2 threads reais)&quot;,&quot;link&quot;:&quot;63-mainc-consolidado-2-threads-reais&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.4 app_stream.h (com par\u00e2metros DSP + mensagens)&quot;,&quot;text&quot;:&quot;6.4 app_stream.h (com par\u00e2metros DSP + mensagens)&quot;,&quot;link&quot;:&quot;eb-table-content-29&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.5 Build\/flash (exemplo)&quot;,&quot;text&quot;:&quot;6.5 Build\/flash (exemplo)&quot;,&quot;link&quot;:&quot;65-buildflash-exemplo&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.6 Calibra\u00e7\u00e3o pr\u00e1tica: como fazer \u201cfuncionar de primeira\u201d sem ficar ca\u00e7ando fantasma&quot;,&quot;text&quot;:&quot;6.6 Calibra\u00e7\u00e3o pr\u00e1tica: como fazer \u201cfuncionar de primeira\u201d sem ficar ca\u00e7ando fantasma&quot;,&quot;link&quot;:&quot;eb-table-content-31&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Robustez em campo: prioridades, backpressure (slab\/msgq), telemetria e VAD com histerese&quot;,&quot;text&quot;:&quot;Robustez em campo: prioridades, backpressure (slab\/msgq), telemetria e VAD com histerese&quot;,&quot;link&quot;:&quot;robustez-em-campo-prioridades-backpressure-slabmsgq-telemetria-e-vad-com-histerese&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.1 Prioridades e lat\u00eancia: o produtor precisa ser \u201cquase intoc\u00e1vel\u201d&quot;,&quot;text&quot;:&quot;7.1 Prioridades e lat\u00eancia: o produtor precisa ser \u201cquase intoc\u00e1vel\u201d&quot;,&quot;link&quot;:&quot;eb-table-content-33&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.2 Backpressure: quando slab ou msgq enchem, voc\u00ea precisa saber \u201cpor qu\u00ea\u201d&quot;,&quot;text&quot;:&quot;7.2 Backpressure: quando slab ou msgq enchem, voc\u00ea precisa saber \u201cpor qu\u00ea\u201d&quot;,&quot;link&quot;:&quot;eb-table-content-34&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.3 Uma \u201ctask\u201d leve de diagn\u00f3stico (telemetria na UART sem travar o pipeline)&quot;,&quot;text&quot;:&quot;7.3 Uma \u201ctask\u201d leve de diagn\u00f3stico (telemetria na UART sem travar o pipeline)&quot;,&quot;link&quot;:&quot;eb-table-content-35&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.4 VAD por energia com histerese: reduz \u201cchattering\u201d (entra\/sai toda hora)&quot;,&quot;text&quot;:&quot;7.4 VAD por energia com histerese: reduz \u201cchattering\u201d (entra\/sai toda hora)&quot;,&quot;link&quot;:&quot;74-vad-por-energia-com-histerese-reduz-chattering-entrasai-toda-hora&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.5 Diagn\u00f3stico de \u201cperda de dados\u201d: como interpretar os sintomas&quot;,&quot;text&quot;:&quot;7.5 Diagn\u00f3stico de \u201cperda de dados\u201d: como interpretar os sintomas&quot;,&quot;link&quot;:&quot;eb-table-content-37&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;VAD em hardware (ESP32-P4) vs VAD em software + Conclus\u00e3o e SEO&quot;,&quot;text&quot;:&quot;VAD em hardware (ESP32-P4) vs VAD em software + Conclus\u00e3o e SEO&quot;,&quot;link&quot;:&quot;eb-table-content-38&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;8.1 VAD em hardware (ESP32-P4): quando faz sentido usar&quot;,&quot;text&quot;:&quot;8.1 VAD em hardware (ESP32-P4): quando faz sentido usar&quot;,&quot;link&quot;:&quot;81-vad-em-hardware-esp32-p4-quando-faz-sentido-usar&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;8.2 VAD em software: por que ainda \u00e9 extremamente relevante&quot;,&quot;text&quot;:&quot;8.2 VAD em software: por que ainda \u00e9 extremamente relevante&quot;,&quot;link&quot;:&quot;eb-table-content-40&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;8.3 S\u00edntese arquitetural do artigo&quot;,&quot;text&quot;:&quot;8.3 S\u00edntese arquitetural do artigo&quot;,&quot;link&quot;:&quot;eb-table-content-41&quot;}]" data-visible="[true,true,true,true,true,true]" data-delete-headers="[{&quot;label&quot;:&quot;Vis\u00e3o geral da solu\u00e7\u00e3o no Zephyr para ESP32: ADC cont\u00ednuo (DMA), VAD e pipeline produtor\/consumidor&quot;,&quot;value&quot;:&quot;vis\u00e3o-geral-da-solu\u00e7\u00e3o-no-zephyr-para-esp32-adc-cont\u00ednuo-dma-vad-e-pipeline-produtorconsumidor&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;O ponto cr\u00edtico: \u201cZephyr puro\u201d vs \u201cdriver cont\u00ednuo do ESP-IDF\u201d&quot;,&quot;value&quot;:&quot;o-ponto-cr\u00edtico-zephyr-puro-vs-driver-cont\u00ednuo-do-esp-idf&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;VAD no ESP32: duas realidades (hardware x software)&quot;,&quot;value&quot;:&quot;vad-no-esp32-duas-realidades-hardware-x-software&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Pipeline proposta (alto n\u00edvel)&quot;,&quot;value&quot;:&quot;pipeline-proposta-alto-n\u00edvel&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Onde o DeviceTree entra (mesmo usando ADC cont\u00ednuo do ESP-IDF)&quot;,&quot;value&quot;:&quot;onde-o-devicetree-entra-mesmo-usando-adc-cont\u00ednuo-do-esp-idf&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;DeviceTree no Zephyr (ESP32): configurando ADC e o \u201cn\u00f3 da aplica\u00e7\u00e3o\u201d para io-channels, + base do projeto&quot;,&quot;value&quot;:&quot;devicetree-no-zephyr-esp32-configurando-adc-e-o-n\u00f3-da-aplica\u00e7\u00e3o-para-io-channels-base-do-projeto&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.1 boards\/esp32s3_devkitc.overlay (exemplo) \u2014 ADC + n\u00f3 da aplica\u00e7\u00e3o&quot;,&quot;value&quot;:&quot;21-boardsesp32s3_devkitcoverlay-exemplo-adc-n\u00f3-da-aplica\u00e7\u00e3o&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.2 prj.conf \u2014 drivers e infraestrutura (threads, msgq, ring buffer opcional)&quot;,&quot;value&quot;:&quot;22-prjconf-drivers-e-infraestrutura-threads-msgq-ring-buffer-opcional&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.3 Contrato produtor\/consumidor: bloco de amostras + evento (VAD start\/end)&quot;,&quot;value&quot;:&quot;23-contrato-produtorconsumidor-bloco-de-amostras-evento-vad-startend&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.4 Esqueleto funcional das threads (sem DMA\/VAD ainda)&quot;,&quot;value&quot;:&quot;24-esqueleto-funcional-das-threads-sem-dmavad-ainda&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Aquisi\u00e7\u00e3o cont\u00ednua \u201ctipo DMA\u201d no ESP32 (ADC continuous mode), VAD delimitando stream e envio para o consumidor&quot;,&quot;value&quot;:&quot;aquisi\u00e7\u00e3o-cont\u00ednua-tipo-dma-no-esp32-adc-continuous-mode-vad-delimitando-stream-e-envio-para-o-consumidor&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.1 Ajustes de prj.conf para usar o driver cont\u00ednuo do ESP-IDF&quot;,&quot;value&quot;:&quot;31-ajustes-de-prjconf-para-usar-o-driver-cont\u00ednuo-do-esp-idf&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.2 Produtor com ADC cont\u00ednuo (DMA): inicializa\u00e7\u00e3o + loop de leitura&quot;,&quot;value&quot;:&quot;32-produtor-com-adc-cont\u00ednuo-dma-inicializa\u00e7\u00e3o-loop-de-leitura&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.3 Encaixe do VAD em hardware (ESP32-P4) no mesmo contrato de eventos&quot;,&quot;value&quot;:&quot;33-encaixe-do-vad-em-hardware-esp32-p4-no-mesmo-contrato-de-eventos&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.4 Atualizando o main.c para usar o produtor real&quot;,&quot;value&quot;:&quot;34-atualizando-o-mainc-para-usar-o-produtor-real&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Consumidor: estimando a frequ\u00eancia principal do stream e imprimindo na UART&quot;,&quot;value&quot;:&quot;consumidor-estimando-a-frequ\u00eancia-principal-do-stream-e-imprimindo-na-uart&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.1 Par\u00e2metros do DSP&quot;,&quot;value&quot;:&quot;41-par\u00e2metros-do-dsp&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.2 Implementa\u00e7\u00e3o do Goertzel + janela Hann (tudo em C puro)&quot;,&quot;value&quot;:&quot;42-implementa\u00e7\u00e3o-do-goertzel-janela-hann-tudo-em-c-puro&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.3 Consumidor completo: acumulando janela, processando em VOICE_END (e tamb\u00e9m \u201cao vivo\u201d)&quot;,&quot;value&quot;:&quot;43-consumidor-completo-acumulando-janela-processando-em-voice_end-e-tamb\u00e9m-ao-vivo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.4 Resultado esperado na UART&quot;,&quot;value&quot;:&quot;44-resultado-esperado-na-uart&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Fechando o projeto: mapeando ADC pelo DeviceTree, janela deslizante com overlap e Goertzel em ponto fixo (Q31)&quot;,&quot;value&quot;:&quot;fechando-o-projeto-mapeando-adc-pelo-devicetree-janela-deslizante-com-overlap-e-goertzel-em-ponto-fixo-q31&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.1 Produtor: traduzindo adc_dt_spec (DeviceTree) para unidade\/canal do ESP-IDF&quot;,&quot;value&quot;:&quot;51-produtor-traduzindo-adc_dt_spec-devicetree-para-unidadecanal-do-esp-idf&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.2 Consumidor: janela deslizante com overlap (50%) para suavizar a estimativa&quot;,&quot;value&quot;:&quot;52-consumidor-janela-deslizante-com-overlap-50-para-suavizar-a-estimativa&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.3 Goertzel em ponto fixo (Q31): quando voc\u00ea quer custo determin\u00edstico&quot;,&quot;value&quot;:&quot;53-goertzel-em-ponto-fixo-q31-quando-voc\u00ea-quer-custo-determin\u00edstico&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.4 Checklist de integra\u00e7\u00e3o (para voc\u00ea n\u00e3o \u201cperder o fio\u201d)&quot;,&quot;value&quot;:&quot;54-checklist-de-integra\u00e7\u00e3o-para-voc\u00ea-n\u00e3o-perder-o-fio&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Pacote \u201ccopi\u00e1vel\u201d: \u00e1rvore de arquivos, CMakeLists.txt, main.c consolidado e calibra\u00e7\u00e3o pr\u00e1tica&quot;,&quot;value&quot;:&quot;pacote-copi\u00e1vel-\u00e1rvore-de-arquivos-cmakeliststxt-mainc-consolidado-e-calibra\u00e7\u00e3o-pr\u00e1tica&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.1 \u00c1rvore de arquivos sugerida&quot;,&quot;value&quot;:&quot;61-\u00e1rvore-de-arquivos-sugerida&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.2 CMakeLists.txt&quot;,&quot;value&quot;:&quot;62-cmakeliststxt&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.3 main.c consolidado (2 threads reais)&quot;,&quot;value&quot;:&quot;63-mainc-consolidado-2-threads-reais&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.4 app_stream.h (com par\u00e2metros DSP + mensagens)&quot;,&quot;value&quot;:&quot;64-app_streamh-com-par\u00e2metros-dsp-mensagens&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.5 Build\/flash (exemplo)&quot;,&quot;value&quot;:&quot;65-buildflash-exemplo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.6 Calibra\u00e7\u00e3o pr\u00e1tica: como fazer \u201cfuncionar de primeira\u201d sem ficar ca\u00e7ando fantasma&quot;,&quot;value&quot;:&quot;66-calibra\u00e7\u00e3o-pr\u00e1tica-como-fazer-funcionar-de-primeira-sem-ficar-ca\u00e7ando-fantasma&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Robustez em campo: prioridades, backpressure (slab\/msgq), telemetria e VAD com histerese&quot;,&quot;value&quot;:&quot;robustez-em-campo-prioridades-backpressure-slabmsgq-telemetria-e-vad-com-histerese&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.1 Prioridades e lat\u00eancia: o produtor precisa ser \u201cquase intoc\u00e1vel\u201d&quot;,&quot;value&quot;:&quot;71-prioridades-e-lat\u00eancia-o-produtor-precisa-ser-quase-intoc\u00e1vel&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.2 Backpressure: quando slab ou msgq enchem, voc\u00ea precisa saber \u201cpor qu\u00ea\u201d&quot;,&quot;value&quot;:&quot;72-backpressure-quando-slab-ou-msgq-enchem-voc\u00ea-precisa-saber-por-qu\u00ea&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.3 Uma \u201ctask\u201d leve de diagn\u00f3stico (telemetria na UART sem travar o pipeline)&quot;,&quot;value&quot;:&quot;73-uma-task-leve-de-diagn\u00f3stico-telemetria-na-uart-sem-travar-o-pipeline&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.4 VAD por energia com histerese: reduz \u201cchattering\u201d (entra\/sai toda hora)&quot;,&quot;value&quot;:&quot;74-vad-por-energia-com-histerese-reduz-chattering-entrasai-toda-hora&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.5 Diagn\u00f3stico de \u201cperda de dados\u201d: como interpretar os sintomas&quot;,&quot;value&quot;:&quot;75-diagn\u00f3stico-de-perda-de-dados-como-interpretar-os-sintomas&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;VAD em hardware (ESP32-P4) vs VAD em software + Conclus\u00e3o e SEO&quot;,&quot;value&quot;:&quot;vad-em-hardware-esp32-p4-vs-vad-em-software-conclus\u00e3o-e-seo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;8.1 VAD em hardware (ESP32-P4): quando faz sentido usar&quot;,&quot;value&quot;:&quot;81-vad-em-hardware-esp32-p4-quando-faz-sentido-usar&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;8.2 VAD em software: por que ainda \u00e9 extremamente relevante&quot;,&quot;value&quot;:&quot;82-vad-em-software-por-que-ainda-\u00e9-extremamente-relevante&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;8.3 S\u00edntese arquitetural do artigo&quot;,&quot;value&quot;:&quot;83-s\u00edntese-arquitetural-do-artigo&quot;,&quot;isDelete&quot;:false}]" data-smooth="true" data-top-offset=""><div class="eb-toc__list-wrap"><ul class="eb-toc__list"><li><a href="#eb-table-content-0">Visão geral da solução no Zephyr para ESP32: ADC contínuo (DMA), VAD e pipeline produtor/consumidor</a><ul class="eb-toc__list"><li><a href="#eb-table-content-1">O ponto crítico: “Zephyr puro” vs “driver contínuo do ESP-IDF”</a><li><a href="#vad-no-esp32-duas-realidades-hardware-x-software">VAD no ESP32: duas realidades (hardware x software)</a><li><a href="#eb-table-content-3">Pipeline proposta (alto nível)</a><li><a href="#eb-table-content-4">Onde o DeviceTree entra (mesmo usando ADC contínuo do ESP-IDF)</a></li></ul><li><a href="#eb-table-content-5">DeviceTree no Zephyr (ESP32): configurando ADC e o “nó da aplicação” para io-channels, + base do projeto</a><ul class="eb-toc__list"><li><a href="#eb-table-content-6">2.1 boards/esp32s3_devkitc.overlay (exemplo) — ADC + nó da aplicação</a><li><a href="#22-prjconf-drivers-e-infraestrutura-threads-msgq-ring-buffer-opcional">2.2 prj.conf — drivers e infraestrutura (threads, msgq, ring buffer opcional)</a><li><a href="#23-contrato-produtorconsumidor-bloco-de-amostras-evento-vad-startend">2.3 Contrato produtor/consumidor: bloco de amostras + evento (VAD start/end)</a><li><a href="#24-esqueleto-funcional-das-threads-sem-dmavad-ainda">2.4 Esqueleto funcional das threads (sem DMA/VAD ainda)</a></li></ul><li><a href="#eb-table-content-10">Aquisição contínua “tipo DMA” no ESP32 (ADC continuous mode), VAD delimitando stream e envio para o consumidor</a><ul class="eb-toc__list"><li><a href="#eb-table-content-11">3.1 Ajustes de prj.conf para usar o driver contínuo do ESP-IDF</a><li><a href="#eb-table-content-12">3.2 Produtor com ADC contínuo (DMA): inicialização + loop de leitura</a><li><a href="#33-encaixe-do-vad-em-hardware-esp32-p4-no-mesmo-contrato-de-eventos">3.3 Encaixe do VAD em hardware (ESP32-P4) no mesmo contrato de eventos</a><li><a href="#34-atualizando-o-mainc-para-usar-o-produtor-real">3.4 Atualizando o main.c para usar o produtor real</a></li></ul><li><a href="#eb-table-content-15">Consumidor: estimando a frequência principal do stream e imprimindo na UART</a><ul class="eb-toc__list"><li><a href="#eb-table-content-16">4.1 Parâmetros do DSP</a><li><a href="#eb-table-content-17">4.2 Implementação do Goertzel + janela Hann (tudo em C puro)</a><li><a href="#eb-table-content-18">4.3 Consumidor completo: acumulando janela, processando em VOICE_END (e também “ao vivo”)</a><li><a href="#44-resultado-esperado-na-uart">4.4 Resultado esperado na UART</a></li></ul><li><a href="#fechando-o-projeto-mapeando-adc-pelo-devicetree-janela-deslizante-com-overlap-e-goertzel-em-ponto-fixo-q31">Fechando o projeto: mapeando ADC pelo DeviceTree, janela deslizante com overlap e Goertzel em ponto fixo (Q31)</a><ul class="eb-toc__list"><li><a href="#51-produtor-traduzindo-adc_dt_spec-devicetree-para-unidadecanal-do-esp-idf">5.1 Produtor: traduzindo adc_dt_spec (DeviceTree) para unidade/canal do ESP-IDF</a><li><a href="#52-consumidor-janela-deslizante-com-overlap-50-para-suavizar-a-estimativa">5.2 Consumidor: janela deslizante com overlap (50%) para suavizar a estimativa</a><li><a href="#eb-table-content-23">5.3 Goertzel em ponto fixo (Q31): quando você quer custo determinístico</a><li><a href="#eb-table-content-24">5.4 Checklist de integração (para você não “perder o fio”)</a></li></ul><li><a href="#eb-table-content-25">Pacote “copiável”: árvore de arquivos, CMakeLists.txt, main.c consolidado e calibração prática</a><ul class="eb-toc__list"><li><a href="#eb-table-content-26">6.1 Árvore de arquivos sugerida</a><li><a href="#62-cmakeliststxt">6.2 CMakeLists.txt</a><li><a href="#63-mainc-consolidado-2-threads-reais">6.3 main.c consolidado (2 threads reais)</a><li><a href="#eb-table-content-29">6.4 app_stream.h (com parâmetros DSP + mensagens)</a><li><a href="#65-buildflash-exemplo">6.5 Build/flash (exemplo)</a><li><a href="#eb-table-content-31">6.6 Calibração prática: como fazer “funcionar de primeira” sem ficar caçando fantasma</a></li></ul><li><a href="#robustez-em-campo-prioridades-backpressure-slabmsgq-telemetria-e-vad-com-histerese">Robustez em campo: prioridades, backpressure (slab/msgq), telemetria e VAD com histerese</a><ul class="eb-toc__list"><li><a href="#eb-table-content-33">7.1 Prioridades e latência: o produtor precisa ser “quase intocável”</a><li><a href="#eb-table-content-34">7.2 Backpressure: quando slab ou msgq enchem, você precisa saber “por quê”</a><li><a href="#eb-table-content-35">7.3 Uma “task” leve de diagnóstico (telemetria na UART sem travar o pipeline)</a><li><a href="#74-vad-por-energia-com-histerese-reduz-chattering-entrasai-toda-hora">7.4 VAD por energia com histerese: reduz “chattering” (entra/sai toda hora)</a><li><a href="#eb-table-content-37">7.5 Diagnóstico de “perda de dados”: como interpretar os sintomas</a></li></ul><li><a href="#eb-table-content-38">VAD em hardware (ESP32-P4) vs VAD em software + Conclusão e SEO</a><ul class="eb-toc__list"><li><a href="#81-vad-em-hardware-esp32-p4-quando-faz-sentido-usar">8.1 VAD em hardware (ESP32-P4): quando faz sentido usar</a><li><a href="#eb-table-content-40">8.2 VAD em software: por que ainda é extremamente relevante</a><li><a href="#eb-table-content-41">8.3 Síntese arquitetural do artigo</a></li></ul></ul></div></div></div></div></div>


<h2 class="wp-block-heading">Visão geral da solução no Zephyr para ESP32: ADC contínuo (DMA), VAD e pipeline produtor/consumidor</h2>



<p class="wp-block-paragraph">Quando você tenta fazer “captura de ruidos como da magnectostricção” a partir de ADC no ESP32 com o Zephyr, aparecem três problemas clássicos ao mesmo tempo: </p>



<ol class="wp-block-list">
<li><strong>aquisição contínua em alta taxa</strong> (idealmente com DMA para não “matar” a CPU), </li>



<li><strong>delimitação de trechos úteis</strong> (detectar início/fim de fala para não processar silêncio), e </li>



<li><strong>processamento em tempo real</strong> (calcular alguma métrica — aqui, a frequência principal — e jogar na UART). </li>
</ol>



<p class="wp-block-paragraph">A arquitetura mais robusta para isso, no mundo de sistemas em tempo real, é separar responsabilidades em <em>threads</em> com um canal bem definido de troca de dados (fila/ring buffer), exatamente o tipo de organização que livros de padrões para sistemas em tempo real tratam como base de escalabilidade e diagnósticos previsíveis.</p>



<h3 class="wp-block-heading">O ponto crítico: “Zephyr puro” vs “driver contínuo do ESP-IDF”</h3>



<p class="wp-block-paragraph">O Zephyr tem um caminho bem canônico para ADC via <strong>DeviceTree + ADC API</strong> (por exemplo o sample <code>adc_dt</code>) (<a href="https://docs.zephyrproject.org/latest/samples/drivers/adc/adc_dt/README.html?utm_source=chatgpt.com">docs.zephyrproject.org</a>) e possui binding específico para ADC do ESP32 (<code>espressif,esp32-adc</code>) (<a href="https://docs.zephyrproject.org/latest/build/dts/api/bindings/adc/espressif%2Cesp32-adc.html?utm_source=chatgpt.com">docs.zephyrproject.org</a>). Isso resolve bem leituras “por amostra” e configurações padrão.</p>



<p class="wp-block-paragraph">Só que <strong>voz por ADC</strong> normalmente pede <strong>stream contínuo</strong>, e no ecossistema Espressif a forma “oficial” para isso é o <strong>ADC Continuous Mode driver</strong>, que foi desenhado para conversões contínuas e leitura de resultados em buffer (tipicamente alimentado por DMA) (<a href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/adc_continuous.html?utm_source=chatgpt.com">Espressif Systems</a>). Na prática, para cumprir o requisito (“leitura contínua por DMA do ADC”), o caminho mais realista é:</p>



<ul class="wp-block-list">
<li>usar <strong>Zephyr como RTOS</strong> (threads, filas, logging/uart), <strong>mas</strong></li>



<li>usar o <strong>driver de ADC contínuo do ESP-IDF</strong> por baixo (como “módulo”/componente), expondo para o Zephyr uma API de aquisição contínua.</li>
</ul>



<p class="wp-block-paragraph">Isso evita reinventar o mecanismo de aquisição contínua e te dá taxas estáveis.</p>



<h3 class="wp-block-heading">VAD no ESP32: duas realidades (hardware x software)</h3>



<p class="wp-block-paragraph">Aqui há uma nuance importante:</p>



<ul class="wp-block-list">
<li><strong>ESP32-P4</strong> tem módulo <strong>VAD em hardware</strong> documentado pela Espressif (<a href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/vad.html?utm_source=chatgpt.com">Espressif Systems</a>). Nesse caso, faz sentido “delimitar stream” com evento/flag do próprio periférico.</li>



<li>Em vários outros ESP32 (ex.: ESP32 clássico, S3, etc.), é comum usar <strong>VAD por software</strong> vindo do ecossistema de áudio/speech da Espressif (ex.: ESP-SR/ADF). Há documentação de VAD em software no contexto dessas libs (<a href="https://espressif-docs.readthedocs-hosted.com/projects/esp-adf/en/latest/api-reference/speech-recognition/esp_vad.html?utm_source=chatgpt.com">espressif-docs.readthedocs-hosted.com</a>).</li>
</ul>



<p class="wp-block-paragraph">Eu vou estruturar como se fosse <strong>uma pipeline genérica</strong> onde o “VAD” é um bloco que produz eventos <code>VOICE_START</code>/<code>VOICE_END</code>. A implementação desse bloco pode ser:</p>



<ul class="wp-block-list">
<li><strong>hardware VAD</strong> (se for ESP32-P4), ou</li>



<li><strong>software VAD</strong> (ESP-SR/ADF) quando o chip não oferecer o periférico.</li>
</ul>



<h3 class="wp-block-heading">Pipeline proposta (alto nível)</h3>



<p class="wp-block-paragraph">A solução fica muito limpa com <strong>duas threads</strong> e um “canal” entre elas:</p>



<ol class="wp-block-list">
<li><strong>Thread Produtora (adc_stream_thread)</strong>
<ul class="wp-block-list">
<li>Inicializa ADC contínuo (driver do ESP-IDF) e começa a receber “frames” (blocos) de amostras.</li>



<li>Alimenta o bloco de VAD (hardware ou software).</li>



<li>Quando o VAD indicar <strong>fala ativa</strong>, empacota blocos de amostras e envia para a fila/ring buffer do consumidor.</li>



<li>Quando indicar <strong>fim da fala</strong>, envia um “marcador” (metadado) de fim de stream.</li>
</ul>
</li>



<li><strong>Thread Consumidora (dsp_uart_thread)</strong>
<ul class="wp-block-list">
<li>Recebe blocos do stream “recortado” pelo VAD.</li>



<li>Acumula um buffer mínimo (janela) e calcula a <strong>frequência principal</strong> (pitch/peak espectral) e imprime na UART.</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">Essa separação é a base para desempenho e previsibilidade: a thread de aquisição não fica “presa” em FFT/Goertzel; a thread de DSP não perde amostra porque alguém resolveu imprimir logs demais.</p>



<h3 class="wp-block-heading">Onde o DeviceTree entra (mesmo usando ADC contínuo do ESP-IDF)</h3>



<p class="wp-block-paragraph">Mesmo que o “motor” de aquisição contínua venha do ESP-IDF, você ainda quer o <strong>DeviceTree</strong> como fonte única de verdade para:</p>



<ul class="wp-block-list">
<li>qual ADC está ativo,</li>



<li>quais canais/pinos estão habilitados,</li>



<li>ganho/atenuação/resolução,</li>



<li>e a UART de saída (console).</li>
</ul>



<p class="wp-block-paragraph">O Zephyr já tem binding do ADC do ESP32 (<a href="https://docs.zephyrproject.org/latest/build/dts/api/bindings/adc/espressif%2Cesp32-adc.html?utm_source=chatgpt.com">docs.zephyrproject.org</a>) e o modelo de amostragem por DT é bem estabelecido no sample <code>adc_dt</code> (<a href="https://docs.zephyrproject.org/latest/samples/drivers/adc/adc_dt/README.html?utm_source=chatgpt.com">docs.zephyrproject.org</a>). A ideia prática é: <strong>o DT descreve os canais</strong>, e o o código traduz isso para a configuração do driver contínuo.</p>



<p class="wp-block-paragraph">Na próxima seção), eu vou te entregar:</p>



<ul class="wp-block-list">
<li>um <strong>overlay <code>.overlay</code></strong> de exemplo configurando ADC e um “nó” de aplicação com <code>io-channels</code>,</li>



<li>o esqueleto completo das duas threads (produtor/consumidor) com filas,</li>



<li>e o desenho do contrato de mensagens (bloco de amostras + eventos VAD).</li>
</ul><p>The post <a href="https://mcu.tec.br/rtos/zephyr-no-esp32-adc-continuo-com-dma-vad-e-processamento-de-sinais-em-tempo-real/">Zephyr no ESP32: ADC Contínuo com DMA, VAD e Processamento de Sinais em Tempo Real</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1061</post-id>	</item>
	</channel>
</rss>
