"use client"; import { useState, useMemo, useRef } from "react"; import { usePathname } from "next/navigation"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; import PageHero from "@/components/PageHero"; import * as diagnosticoPt from "@/lib/diagnosticoData"; import * as diagnosticoEn from "@/lib/data/en/diagnostico"; import * as diagnosticoEs from "@/lib/data/es/diagnostico"; import * as diagnosticoFr from "@/lib/data/fr/diagnostico"; import * as diagnosticoDe from "@/lib/data/de/diagnostico"; import { Activity, AlertTriangle, Check, CheckCircle2, ChevronDown, Copy, Cpu, ExternalLink, HelpCircle, Layers, LayoutGrid, RotateCcw, Search, ShieldAlert, Terminal, Wifi, Wrench, X, XCircle, Zap, } from "lucide-react"; /** Os rótulos dos sintomas vêm com emoji nos dados; a interface usa só texto e ícones. */ const semEmoji = (texto) => texto.replace(/^[\p{Extended_Pictographic}\uFE0F\s]+/u, ""); const ICONES = { Zap, Cpu, Layers, Activity, Terminal, Wifi }; const EXEMPLOS_LOG_PT = [ ["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"], ["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"], ["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"], ["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"], ]; const EXEMPLOS_LOG_EN = [ ["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"], ["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"], ["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"], ["TLS Handshake", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"], ]; const EXEMPLOS_LOG_ES = [ ["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"], ["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"], ["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"], ["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"], ]; const EXEMPLOS_LOG_FR = [ ["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"], ["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"], ["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"], ["Handshake TLS", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"], ]; const EXEMPLOS_LOG_DE = [ ["Brownout", "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13"], ["LoadProhibited", "Guru Meditation Error: Core 0 panic'ed (LoadProhibited).\nEXCVADDR: 0x00000000"], ["Task watchdog", "Task watchdog got triggered. The following tasks/users did not reset the watchdog: - IDLE0"], ["TLS-Handshake", "mbedtls_ssl_handshake returned -0x2700\nThe certificate is not yet valid"], ]; const GRAVIDADE = { "Crítica": "text-danger", "Critical": "text-danger", "Critique": "text-danger", "Kritisch": "text-danger", Alta: "text-gold", High: "text-gold", "Élevée": "text-gold", Hoch: "text-gold", "Média": "text-accent", Medium: "text-accent", Media: "text-accent", Moyenne: "text-accent", Mittel: "text-accent", }; const CHECKLISTS_PT = [ { icon: Zap, titulo: "Hardware e alimentação", itens: [ "Capacitor de 10 µF a 100 µF de baixo ESR no VCC, mais um cerâmico de 100 nF junto ao chip.", "LDO dimensionado para picos de 600 mA a 1 A, com folga térmica.", "Nenhum periférico forçando nível lógico nos pinos de strapping durante o boot.", "Capacitor de 10 µF ou 1 µF no pino EN (RST) para auto-reset estável na gravação.", ], }, { icon: Layers, titulo: "Firmware e FreeRTOS", itens: [ "Toda tarefa FreeRTOS cede a CPU com vTaskDelay, filas ou semáforos.", "Toda ISR marcada com IRAM_ATTR e sem chamadas bloqueantes.", "Sem uso contínuo de String do Arduino em laços, para evitar fragmentação do heap.", "Horário sincronizado por SNTP antes de abrir conexões TLS/HTTPS.", ], }, ]; const CHECKLISTS_EN = [ { icon: Zap, titulo: "Hardware and Power Supply", itens: [ "10 µF to 100 µF low-ESR capacitor on VCC, plus a 100 nF ceramic capacitor close to the chip.", "LDO regulator sized for 600 mA to 1 A current spikes, with adequate thermal margin.", "No external peripherals forcing logic levels on strapping pins during reset and boot.", "10 µF or 1 µF capacitor on the EN (RST) pin for stable auto-reset flashing.", ], }, { icon: Layers, titulo: "Firmware and FreeRTOS", itens: [ "Every FreeRTOS task yields CPU time with vTaskDelay, queues, or semaphores.", "Every ISR marked with IRAM_ATTR with zero blocking calls.", "Avoid continuous heap reallocations using Arduino Strings in tight loops.", "Clock synchronized via SNTP before attempting TLS/HTTPS handshakes.", ], }, ]; const CHECKLISTS_ES = [ { icon: Zap, titulo: "Hardware y alimentación", itens: [ "Condensador de 10 µF a 100 µF de bajo ESR en VCC, más uno cerámico de 100 nF junto al chip.", "Regulador LDO dimensionado para picos de 600 mA a 1 A, con margen térmico.", "Ningún periférico forzando niveles lógicos en los pines de strapping durante el arranque.", "Condensador de 10 µF o 1 µF en el pin EN (RST) para auto-reset estable durante la programación.", ], }, { icon: Layers, titulo: "Firmware y FreeRTOS", itens: [ "Cada tarea de FreeRTOS cede la CPU con vTaskDelay, colas o semáforos.", "Cada ISR marcada con IRAM_ATTR y sin llamadas bloqueantes.", "Sin uso continuo de String de Arduino en bucles para evitar la fragmentación del heap.", "Hora sincronizada mediante SNTP antes de abrir conexiones TLS/HTTPS.", ], }, ]; const CHECKLISTS_FR = [ { icon: Zap, titulo: "Matériel et alimentation", itens: [ "Condensateur de 10 µF à 100 µF à faible ESR sur VCC, plus un céramique de 100 nF près de la puce.", "Régulateur LDO dimensionné pour des pointes de 600 mA à 1 A, avec marge thermique.", "Aucun périphérique ne forçant de niveau logique sur les broches de strapping pendant le boot.", "Condensateur de 10 µF ou 1 µF sur la broche EN (RST) pour un auto-reset stable au flashage.", ], }, { icon: Layers, titulo: "Firmware et FreeRTOS", itens: [ "Chaque tâche FreeRTOS cède la CPU avec vTaskDelay, des files ou des sémaphores.", "Chaque ISR marquée avec IRAM_ATTR et exempte d'appels bloquants.", "Pas d'usage continu de String d'Arduino dans les boucles, afin d'éviter la fragmentation du tas.", "Horloge synchronisée par SNTP avant d'ouvrir des connexions TLS/HTTPS.", ], }, ]; const CHECKLISTS_DE = [ { icon: Zap, titulo: "Hardware und Spannungsversorgung", itens: [ "10 µF bis 100 µF Low-ESR-Kondensator an VCC, plus ein 100-nF-Keramikkondensator nah am Chip.", "LDO-Regler ausgelegt für 600 mA bis 1 A Stromspitzen mit thermischer Reserve.", "Keine Peripheriegeräte, die beim Booten Logikpegel an Strapping-Pins erzwingen.", "10 µF- oder 1 µF-Kondensator am EN-Pin (RST) für zuverlässigen Auto-Reset beim Flashen.", ], }, { icon: Layers, titulo: "Firmware und FreeRTOS", itens: [ "Jeder FreeRTOS-Task gibt CPU-Zeit mit vTaskDelay, Queues oder Semaphoren ab.", "Jede ISR mit IRAM_ATTR versehen und frei von blockierenden Aufrufen.", "Keine fortlaufende Verwendung von Arduino-Strings in Schleifen zur Vermeidung von Heap-Fragmentierung.", "Uhrzeit vor dem Aufbau von TLS/HTTPS-Verbindungen per SNTP synchronisiert.", ], }, ]; export default function DiagnosticoPage() { const pathname = usePathname(); const isEn = pathname?.startsWith("/en"); const isEs = pathname?.startsWith("/es"); const isFr = pathname?.startsWith("/fr"); const isDe = pathname?.startsWith("/de"); const { categoriasDiagnostico, sintomasRapidos, errosCatalogo, regrasDecodificadorLog } = isEs ? diagnosticoEs : isEn ? diagnosticoEn : isFr ? diagnosticoFr : isDe ? diagnosticoDe : diagnosticoPt; const exemplosLog = isEs ? EXEMPLOS_LOG_ES : isEn ? EXEMPLOS_LOG_EN : isFr ? EXEMPLOS_LOG_FR : isDe ? EXEMPLOS_LOG_DE : EXEMPLOS_LOG_PT; const checklists = isEs ? CHECKLISTS_ES : isEn ? CHECKLISTS_EN : isFr ? CHECKLISTS_FR : isDe ? CHECKLISTS_DE : CHECKLISTS_PT; const [termoBusca, setTermoBusca] = useState(""); const [categoriaAtiva, setCategoriaAtiva] = useState("todos"); const [sintomaAtivo, setSintomaAtivo] = useState(null); const [cardAberto, setCardAberto] = useState(null); const [linguagemCodigo, setLinguagemCodigo] = useState({}); // { [id]: 'arduino' | 'espidf' } const [copiadoId, setCopiadoId] = useState(null); const searchInputRef = useRef(null); // Estado do Analisador de Logs const [logInput, setLogInput] = useState(""); const [resultadoLog, setResultadoLog] = useState(null); // Função de Análise do Log const analisarLog = (texto) => { setLogInput(texto); if (!texto || texto.trim() === "") { setResultadoLog(null); return; } for (const regra of regrasDecodificadorLog) { if (regra.padrao.test(texto)) { setResultadoLog(regra); return; } } setResultadoLog( isEs ? { titulo: "Patrón de error no categorizado automáticamente", tipo: "Desconocido", explicacao: "No identificamos una firma clásica de Guru Meditation o Brownout en este fragmento. Verifique que la velocidad de baudios (ej: 115200) sea correcta y si el encabezado 'rst:' o 'panic' está presente.", acaoRecomendada: "Busque palabras clave como 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' o 'panic' en la consola serie.", } : isEn ? { titulo: "Error pattern not automatically classified", tipo: "Unknown", explicacao: "We could not identify a classic Guru Meditation or Brownout signature in this snippet. Verify that the baud rate (e.g. 115200) is correct and whether the 'rst:' or 'panic' header is present.", acaoRecomendada: "Look for keywords such as 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog', or 'panic' in the serial output.", } : isFr ? { titulo: "Modèle d'erreur non catégorisé automatiquement", tipo: "Inconnu", explicacao: "Nous n'avons pas identifié de signature classique de Guru Meditation ou Brownout dans cet extrait. Vérifiez que la vitesse en bauds (ex. : 115200) est correcte et si l'en-tête 'rst:' ou 'panic' est présent.", acaoRecomendada: "Recherchez des mots-clés tels que 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' ou 'panic' dans la console série.", } : isDe ? { titulo: "Fehlermuster nicht automatisch kategorisiert", tipo: "Unbekannt", explicacao: "Wir konnten in diesem Ausschnitt keine klassische Guru-Meditation- oder Brownout-Signatur erkennen. Prüfen Sie, ob die Baudrate (z. B. 115200) korrekt ist und ob der Header 'rst:' oder 'panic' vorhanden ist.", acaoRecomendada: "Suchen Sie in der seriellen Konsole nach Begriffen wie 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' oder 'panic'.", } : { titulo: "Padrão de erro não categorizado automaticamente", tipo: "Desconhecido", explicacao: "Não identificamos uma assinatura clássica de Guru Meditation ou Brownout neste trecho. Verifique se a taxa de baud rate (ex: 115200) está correta e se o cabeçalho 'rst:' ou 'panic' está presente.", acaoRecomendada: "Procure por palavras-chave como 'Guru Meditation', 'rst:', 'LoadProhibited', 'watchdog' ou 'panic' no console serial.", } ); }; const copiarParaClipboard = (texto, id) => { navigator.clipboard.writeText(texto); setCopiadoId(id); setTimeout(() => setCopiadoId(null), 2000); }; // Filtragem dos erros const errosFiltrados = useMemo(() => { const termo = termoBusca.toLowerCase().trim(); return errosCatalogo.filter((erro) => { const matchCategoria = categoriaAtiva === "todos" || erro.categoria === categoriaAtiva; const matchSintoma = !sintomaAtivo || erro.sintomas.includes(sintomaAtivo); const matchBusca = !termo || erro.titulo.toLowerCase().includes(termo) || erro.resumo.toLowerCase().includes(termo) || erro.causaRaiz.toLowerCase().includes(termo) || erro.logSerial.toLowerCase().includes(termo); return matchCategoria && matchSintoma && matchBusca; }); }, [categoriaAtiva, sintomaAtivo, termoBusca, errosCatalogo]); const temFiltroAtivo = termoBusca.trim() !== "" || categoriaAtiva !== "todos" || sintomaAtivo !== null; const limparTodosFiltros = () => { setTermoBusca(""); setCategoriaAtiva("todos"); setSintomaAtivo(null); searchInputRef.current?.focus(); }; const toggleCard = (id) => { setCardAberto((prev) => (prev === id ? null : id)); }; const setLang = (id, lang) => { setLinguagemCodigo((prev) => ({ ...prev, [id]: lang })); }; const totalFiltros = (termoBusca.trim() ? 1 : 0) + (categoriaAtiva !== "todos" ? 1 : 0) + (sintomaAtivo ? 1 : 0); return (
{isEs ? "Basado en el artículo de Ciência Embarcada" : isEn ? "Based on article by Ciência Embarcada" : isFr ? "D'après l'article de Ciência Embarcada" : isDe ? "Basierend auf dem Artikel von Ciência Embarcada" : "Baseado no artigo do Ciência Embarcada"}

{isEs ? "Pegue el registro y descubra la causa" : isEn ? "Paste the log to see the cause" : isFr ? "Collez le journal et découvrez la cause" : isDe ? "Log einfügen und Ursache ermitteln" : "Cole o log e veja a causa"}

{isEs ? "Copie el fragmento del monitor serie. El diagnóstico aparece al instante." : isEn ? "Copy the serial monitor output snippet. Diagnostics appear instantly." : isFr ? "Copiez l'extrait du moniteur série. Le diagnostic apparaît immédiatement." : isDe ? "Kopieren Sie den Ausschnitt aus dem seriellen Monitor. Die Diagnose erscheint sofort." : "Copie o trecho do monitor serial. O diagnóstico aparece na hora."}

{isEs ? "Probar con" : isEn ? "Test with" : isFr ? "Tester avec" : isDe ? "Testen mit" : "Testar com"} {exemplosLog.map(([rotulo, texto]) => ( ))}