- Translate content to English across messages/en.json, data/en, lib/data/en, and public/exemplos/en - Implement localized routing, slugs, and language negotiation with fallback to en - Build dedicated search index for English with strict book exclusion - Update components and pages to dynamically render localized strings and datasets - Verify full structural parity and exact 1:1 match on Portuguese pages via comparator Co-Authored-By: Antigravity <noreply@google.com>
237 lines
9.2 KiB
React
237 lines
9.2 KiB
React
import Link from "next/link";
|
|
import {
|
|
AlertTriangle,
|
|
ArrowDownToLine,
|
|
HardDrive,
|
|
Power,
|
|
Bug,
|
|
Usb,
|
|
Zap,
|
|
ArrowRight,
|
|
} from "lucide-react";
|
|
|
|
/**
|
|
* Restrições de pinos por série.
|
|
*
|
|
* Os grupos são DERIVADOS de public/conexoes/<serie>.json, o mesmo arquivo que
|
|
* alimenta o diagrama de conexões. Nada aqui é escrito à mão, então a seção e o
|
|
* diagrama nunca divergem: corrigir um pino no JSON corrige os dois.
|
|
*/
|
|
|
|
const GRUPOS_PT = [
|
|
{
|
|
id: "entrada",
|
|
titulo: "Somente entrada",
|
|
icone: ArrowDownToLine,
|
|
cor: "text-accent",
|
|
explicacao:
|
|
"Aceitam apenas leitura. Não podem ser configurados como saída e não possuem resistores de pull-up ou pull-down internos. Se precisar de um, coloque no circuito.",
|
|
combina: (avisos) => /apenas de entrada|input only/i.test(avisos),
|
|
},
|
|
{
|
|
id: "flash",
|
|
titulo: "Ligados à memória flash/PSRAM",
|
|
icone: HardDrive,
|
|
cor: "text-copper",
|
|
explicacao:
|
|
"Já estão conectados à memória de onde o firmware é lido. Usá-los como GPIO comum normalmente trava o chip ou corrompe a execução. Em módulos com flash interna eles nem chegam ao encapsulamento.",
|
|
combina: (avisos) =>
|
|
/(flash|psram)/i.test(avisos) &&
|
|
/(dedicad|utilizado pela mem|não deve ser utilizado|não é recomendado|connected to|dedicated to|should not be used|not recommended)/i.test(avisos),
|
|
},
|
|
{
|
|
id: "strapping",
|
|
titulo: "Strapping (modo de boot)",
|
|
icone: Power,
|
|
cor: "text-gold",
|
|
explicacao:
|
|
"O chip lê o nível destes pinos no instante do reset para decidir como inicializar. Dá para usá-los depois do boot, mas o circuito externo não pode forçar o nível errado durante o reset, senão a placa não inicia ou entra em modo de gravação sozinha.",
|
|
combina: (avisos, cats) =>
|
|
cats.includes("Strapping") ||
|
|
/strapping|modo de boot|modo de inicialização|boot mode/i.test(avisos),
|
|
},
|
|
{
|
|
id: "debug",
|
|
titulo: "Gravação e depuração",
|
|
icone: Bug,
|
|
cor: "text-accent",
|
|
explicacao:
|
|
"São a UART de gravação e as linhas de JTAG. Continuam utilizáveis como GPIO, mas ao reaproveitá-los você perde o caminho de gravar e depurar a placa sem desconectar o que estiver ali.",
|
|
combina: (avisos, cats) => /debugging|gravação/i.test(avisos) || cats.includes("JTAG"),
|
|
},
|
|
{
|
|
id: "usb",
|
|
titulo: "USB nativo",
|
|
icone: Usb,
|
|
cor: "text-accent",
|
|
explicacao:
|
|
"Saem de fábrica ligados ao USB Serial/JTAG interno. Para usá-los como GPIO é preciso desativar essa função, o que também remove a gravação por USB direto.",
|
|
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/i.test(avisos),
|
|
},
|
|
{
|
|
id: "eletrico",
|
|
titulo: "Não podem ficar flutuando",
|
|
icone: Zap,
|
|
cor: "text-gold",
|
|
explicacao:
|
|
"Precisam de nível definido por hardware: pull-up externo ou circuito RC de atraso. Deixá-los soltos causa reset aleatório ou inicialização instável.",
|
|
combina: (avisos) => /flutuando|floating/i.test(avisos),
|
|
},
|
|
];
|
|
|
|
const GRUPOS_EN = [
|
|
{
|
|
id: "entrada",
|
|
titulo: "Input only",
|
|
icone: ArrowDownToLine,
|
|
cor: "text-accent",
|
|
explicacao:
|
|
"Input only pins. They cannot be configured as outputs and do not have internal pull-up or pull-down resistors. If needed, add them to your external circuit.",
|
|
combina: (avisos) => /apenas de entrada|input only/i.test(avisos),
|
|
},
|
|
{
|
|
id: "flash",
|
|
titulo: "Connected to flash/PSRAM memory",
|
|
icone: HardDrive,
|
|
cor: "text-copper",
|
|
explicacao:
|
|
"Already connected to the memory where firmware is stored and executed. Using them as general-purpose GPIO typically crashes the chip or corrupts execution. In modules with internal flash, they are not brought out to the package pins.",
|
|
combina: (avisos) =>
|
|
/(flash|psram)/i.test(avisos) &&
|
|
/(dedicad|utilizado pela mem|não deve ser utilizado|não é recomendado|connected to|dedicated to|should not be used|not recommended)/i.test(avisos),
|
|
},
|
|
{
|
|
id: "strapping",
|
|
titulo: "Strapping pins (boot mode)",
|
|
icone: Power,
|
|
cor: "text-gold",
|
|
explicacao:
|
|
"The chip samples the logic level of these pins during reset to determine the boot mode. You can use them after booting, but external circuitry must not force the wrong level during reset, or the board will fail to boot or enter download mode unexpectedly.",
|
|
combina: (avisos, cats) =>
|
|
cats.includes("Strapping") ||
|
|
/strapping|modo de boot|modo de inicialização|boot mode/i.test(avisos),
|
|
},
|
|
{
|
|
id: "debug",
|
|
titulo: "Flashing and debugging",
|
|
icone: Bug,
|
|
cor: "text-accent",
|
|
explicacao:
|
|
"These are the flashing UART and JTAG lines. They can still be used as GPIO, but reusing them removes the ability to flash and debug the board without disconnecting connected peripherals.",
|
|
combina: (avisos, cats) => /debugging|gravação/i.test(avisos) || cats.includes("JTAG"),
|
|
},
|
|
{
|
|
id: "usb",
|
|
titulo: "Native USB",
|
|
icone: Usb,
|
|
cor: "text-accent",
|
|
explicacao:
|
|
"Connected by default to the internal USB Serial/JTAG controller. Using them as GPIO requires disabling this peripheral, which also removes direct USB flashing.",
|
|
combina: (avisos) => /usb serial\/jtag|usb_d[+-]/i.test(avisos),
|
|
},
|
|
{
|
|
id: "eletrico",
|
|
titulo: "Must not float",
|
|
icone: Zap,
|
|
cor: "text-gold",
|
|
explicacao:
|
|
"Require a defined hardware logic level: external pull-up or RC delay circuit. Leaving them floating causes random resets or unstable boot behavior.",
|
|
combina: (avisos) => /flutuando|floating/i.test(avisos),
|
|
},
|
|
];
|
|
|
|
/** Nome do pino + o GPIO correspondente, quando o nome é uma função (ex.: SENSOR_VP). */
|
|
function rotuloDoPino(pino) {
|
|
const gpio = (pino.funcoes || []).find((f) => /^GPIO\d+$/.test(f));
|
|
return gpio && gpio !== pino.nome ? `${pino.nome} · ${gpio}` : pino.nome;
|
|
}
|
|
|
|
function derivarGrupos(conexoes, isEn) {
|
|
const listaGrupos = isEn ? GRUPOS_EN : GRUPOS_PT;
|
|
return listaGrupos.map((grupo) => {
|
|
const vistos = new Map();
|
|
for (const pino of conexoes) {
|
|
if (!["io", "analog", "dedicated"].includes(pino.tipo)) continue;
|
|
const avisos = (pino.avisos || []).join(" ").toLowerCase();
|
|
const cats = pino.categorias || [];
|
|
if (grupo.combina(avisos, cats)) {
|
|
const rotulo = rotuloDoPino(pino);
|
|
if (!vistos.has(rotulo)) vistos.set(rotulo, pino);
|
|
}
|
|
}
|
|
return { ...grupo, pinos: [...vistos.keys()] };
|
|
}).filter((g) => g.pinos.length > 0);
|
|
}
|
|
|
|
export default function PinRestrictions({ conexoes, serieKey, isEn = false }) {
|
|
if (!conexoes?.length) return null;
|
|
|
|
const grupos = derivarGrupos(conexoes, isEn);
|
|
if (!grupos.length) return null;
|
|
|
|
const totalPinos = new Set(grupos.flatMap((g) => g.pinos)).size;
|
|
|
|
return (
|
|
<section id="restricoes" aria-labelledby="restricoes-titulo" className="card mt-5 scroll-mt-28 p-5 sm:p-7">
|
|
<h2 id="restricoes-titulo" className="flex items-center gap-3 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
|
|
<span className="grid h-9 w-9 place-items-center rounded-full bg-gold-soft text-gold">
|
|
<AlertTriangle className="h-4 w-4" aria-hidden="true" />
|
|
</span>
|
|
{isEn ? "Pins with usage restrictions" : "Pinos com restrição de uso"}
|
|
</h2>
|
|
|
|
<p className="mt-3 max-w-3xl text-sm leading-relaxed text-muted">
|
|
{isEn ? (
|
|
<>
|
|
Not every pin on the {serieKey} is free for general-purpose use. {totalPinos} of them have conditions: occupied by memory, sampled during boot, or function as input only. Check before finalizing your schematic.
|
|
</>
|
|
) : (
|
|
<>
|
|
Nem todo pino do {serieKey} está livre para uso geral. {totalPinos} deles têm alguma
|
|
condição: já estão ocupados por memória, são lidos durante o boot ou só funcionam
|
|
como entrada. Vale conferir antes de fechar o esquemático.
|
|
</>
|
|
)}
|
|
</p>
|
|
|
|
<div className="mt-6 grid gap-4 md:grid-cols-2">
|
|
{grupos.map(({ id, titulo, icone: Icone, cor: corIcone, explicacao, pinos }) => (
|
|
<div key={id} className="tile">
|
|
<div className="flex items-center gap-2.5">
|
|
<Icone className={`h-4 w-4 shrink-0 ${corIcone}`} aria-hidden="true" />
|
|
<h3 className="text-sm font-semibold text-ink">{titulo}</h3>
|
|
<span className="ml-auto text-xs text-muted tabular-nums">
|
|
{pinos.length} {pinos.length === 1 ? (isEn ? "pin" : "pino") : (isEn ? "pins" : "pinos")}
|
|
</span>
|
|
</div>
|
|
|
|
<ul className="mt-3 flex flex-wrap gap-1.5">
|
|
{pinos.map((p) => (
|
|
<li key={p} className="rounded-md border border-line bg-surface px-2 py-1 font-mono text-xs text-ink-soft">
|
|
{p}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<p className="mt-3 text-sm leading-relaxed text-muted">{explicacao}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-6 flex flex-col justify-between gap-4 border-t border-line pt-5 sm:flex-row sm:items-center">
|
|
<p className="max-w-xl text-sm leading-relaxed text-muted">
|
|
{isEn ? (
|
|
"These groups are derived from the same data as the pinout diagram. There you can see every pin's full functions, power domain, and complete engineering notes."
|
|
) : (
|
|
"Estes grupos vêm dos mesmos dados do diagrama de conexões. Lá você vê pino a pino todas as funções, o domínio de alimentação e os avisos completos."
|
|
)}
|
|
</p>
|
|
<Link href="#connections" className="btn btn-ghost shrink-0">
|
|
{isEn ? "Open pinout diagram" : "Abrir diagrama de pinos"}
|
|
<ArrowRight className="h-4 w-4" aria-hidden="true" />
|
|
</Link>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|