AnasSarkiz/muse-voice-remote

Muse Voice Remote — bare ESP32-S3R8, 155 TOP JLCPCB parts with real supplier CAD, native 3D assembly and GLB exports. Revised 17 mm case allocation; 0.30 mm via drill /0.45 mm pad. Checked prototype PCB; mechanical, RF and MUSE qualification pending.

Version
1.3.2
License
unset
Stars
0

design/catalog.ts

// Reference datasheet pin-role maps from the earlier design.
// Active geometry/components come exclusively from the selected JLCPCB imports.
import type { Part } from "./parts"
import selection from "../docs/jlcpcb-import-selection.json"
import pinmaps from "../vendor/pinmaps.json"

const R = "Resistor_SMD/R_0603_1608Metric"
const C = "Capacitor_SMD/C_0603_1608Metric"
export const libraries: Record<string, string> = {
  "ESP32-S3-WROOM-1": "RF_Module/ESP32-S3-WROOM-1",
  "SPH0645LM4H-B": "Sensor_Audio/Knowles_SPH0645LM4H-6_3.5x2.65mm",
  "SOT-23-5": "Package_TO_SOT_SMD/SOT-23-5",
  "USB-C": "Connector_USB/USB_C_Receptacle_HRO_TYPE-C-31-M-12",
  BQ24074: "Package_DFN_QFN/VQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm",
  TPS63001: "Package_SON/Texas_DRC0010J",
  MAX98357A: "Package_DFN_QFN/TQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm",
}
export const fixedCatalog: Record<string, { mpn: string; library: string; pins?: Record<string,string> }> = {
  J_LCD: { mpn: "5-1734839-0", library: "Connector_FFC-FPC/TE_5-1734839-0_1x50-1MP_P0.5mm_Horizontal" },
  U_LCD_POWER: { mpn: "TLV75528PDBVR", library: "Package_TO_SOT_SMD/SOT-23-5",
    pins: { "1":"IN", "2":"GND", "3":"EN", "4":"NC", "5":"OUT" } },
  U_BACKLIGHT: { mpn: "TPS61169DCKR", library: "Package_TO_SOT_SMD/SOT-353_SC-70-5",
    pins: { "1":"SW", "2":"GND", "3":"FB", "4":"CTRL", "5":"VIN" } },
  Q_BL_OFF: { mpn: "BSS138LT1G", library: "Package_TO_SOT_SMD/SOT-23",
    pins: { "1":"G", "2":"S", "3":"D" } },
  L_BL: { mpn: "LPS4018-103MRC", library: "Inductor_SMD/L_Coilcraft_LPS4018" },
  C_BL_OUT: { mpn: "C1206C475K5RACTU", library: "Capacitor_SMD/C_1206_3216Metric" },
  D_BL: { mpn: "SS16", library: "Diode_SMD/D_SMA" },
  U1: { mpn: "ESP32-S3R8", library: "JLCPCB/C2913194" },
  U_CHARGE: { mpn: "BQ24074RGTR", library: libraries.BQ24074 },
  U_AMP: { mpn: "MAX98357AETE+T", library: libraries.MAX98357A },
  MIC1: { mpn: "ICS-43434", library: "Sensor_Audio/InvenSense_ICS-43434-6_3.5x2.65mm",
    pins: { "1":"WS", "2":"SELECT", "3":"GND", "4":"BCLK", "5":"VDD", "6":"DATA" } },
  MIC2: { mpn: "ICS-43434", library: "Sensor_Audio/InvenSense_ICS-43434-6_3.5x2.65mm",
    pins: { "1":"WS", "2":"SELECT", "3":"GND", "4":"BCLK", "5":"VDD", "6":"DATA" } },
  J_USB: { mpn: "USB4105-GF-A", library: "Connector_USB/USB_C_Receptacle_GCT_USB4105-xx-A_16P_TopMnt_Horizontal" },
  R_ISET: { mpn: "CRCW06034K42FKEA", library: R },
  SW_PRIVACY: { mpn: "JS202011JCQN", library: "Button_Switch_SMD/SW_DPDT_CK_JS202011JCQN",
    pins: { "1":"PWR_ON", "2":"PWR_COM", "3":"PWR_OFF", "4":"OE_ON", "5":"OE_COM", "6":"OE_OFF" } },
  SW_POWER: { mpn: "PCM12SMTR", library: "Button_Switch_SMD/SW_SPDT_PCM12",
    pins: { "1":"ON", "2":"COM", "3":"OFF" } },
  SW_TALK: { mpn: "TL3305AF160QG", library: "Button_Switch_SMD/SW_SPST_TL3305A" },
  SW_BOOT: { mpn: "TL3305AF160QG", library: "Button_Switch_SMD/SW_SPST_TL3305A" },
  SW_RESET: { mpn: "TL3305AF160QG", library: "Button_Switch_SMD/SW_SPST_TL3305A" },
  J_SPK: { mpn: "SM02B-SRSS-TB", library: "Connector_JST/JST_SH_SM02B-SRSS-TB_1x02-1MP_P1.00mm_Horizontal" },
  J_MOTOR: { mpn: "SM02B-SRSS-TB", library: "Connector_JST/JST_SH_SM02B-SRSS-TB_1x02-1MP_P1.00mm_Horizontal" },
  J_BAT: { mpn: "S3B-PH-SM4-TB(LF)(SN)", library: "Connector_JST/JST_PH_S3B-PH-SM4-TB_1x03-1MP_P2.00mm_Horizontal" },
  Q_MOTOR: { mpn: "AO3400A", library: "Package_TO_SOT_SMD/SOT-23" },
  Q_BAT_SENSE: { mpn: "AO3401A", library: "Package_TO_SOT_SMD/SOT-23" },
  Q_BAT_EN: { mpn: "MMBT3904", library: "Package_TO_SOT_SMD/SOT-23" },
  D_USB_ESD: { mpn: "USBLC6-2SC6", library: "Package_TO_SOT_SMD/SOT-23-6" },
  F_USB: { mpn: "1206L050YR", library: "Fuse/Fuse_1206_3216Metric" },
}
const resistorSuffix: Record<string,string> = { "5.1k":"5K1", "22":"22R", "10k":"10K", "100k":"100K",
  "5.1":"5R1", "4.42k":"4K42", "3.24k":"3K24", "2.94k":"2K94", "46.4k":"46K4", "100":"100R", "1k":"1K", "3.3":"3R3" }
const capacitors: Record<string,string> = { "100nF":"C0603C104K4RACTU", "10nF":"CL10B103KB8NNNC",
  "1uF":"GRM188R61A105KA61D", "4.7uF":"C0603C475K8PACTU", "10uF":"LMK212BJ106KD-T", "22uF":"GRM219R61A226MEA0D" }
export function legacyCatalogFor(p: Part) {
  if (fixedCatalog[p.name]) return fixedCatalog[p.name]
  if (p.kind === "resistor") {
    if (!resistorSuffix[p.value]) throw new Error(`No catalog resistor for ${p.value}`)
    return { mpn: `RC0603FR-07${resistorSuffix[p.value]}L`, library: R }
  }
  if (p.kind === "capacitor") return { mpn: capacitors[p.value], library: /^(10|22)uF$/.test(p.value) ? "Capacitor_SMD/C_0805_2012Metric" : C }
  if (p.kind === "inductor") return { mpn: "74438357022", library: "Inductor_SMD/L_Wuerth_MAPI-4030" }
  if (p.kind === "diode") return { mpn: "SS14", library: "Diode_SMD/D_SMA" }
  if (p.kind === "led") return { mpn: ({ R:"LTST-C190KRKT", G:"LTST-C190KGKT", B:"LTST-C190TBKT" } as Record<string,string>)[p.value], library: "LED_SMD/LED_0603_1608Metric" }
  if (p.footprint) return { mpn: p.value, library: libraries[p.footprint] }
  throw new Error(`No imported component assigned to ${p.name}`)
}

export function catalogFor(p: Part) {
  const selected = selection.parts.find(item => item.references.includes(p.name))
  if (!selected) throw new Error(`No JLCPCB component import assigned to ${p.name}`)
  const old = p.physicalPins ? { pins:p.physicalPins } : legacyCatalogFor(p)
  const pins: Record<string,string> = { ...(old.pins ?? p.pins ?? (p.footprint ? pinmaps[p.footprint] : {})) }
  if (p.name === "U_AMP") { delete pins.THERMAL; pins["17"] = "GND" }
  if (p.name === "SW_PRIVACY") {
    Object.keys(pins).forEach(key => delete pins[key])
    Object.assign(pins, { "1":"PWR_ON", "2":"PWR_COM", "3":"PWR_OFF", "5":"OE_ON", "6":"OE_COM", "7":"OE_OFF" })
  }
  if (["SW_TALK","SW_BOOT","SW_RESET"].includes(p.name)) {
    Object.assign(pins, { "1":"A", "4":"A", "2":"B", "3":"B" })
  }
  if (p.name === "SW_POWER") pins["4"] = "SHIELD"
  if (["J_SPK","J_MOTOR"].includes(p.name)) { pins["3"]="MOUNT"; pins["4"]="MOUNT" }
  if (p.name === "J_BAT") { pins["4"]="MOUNT"; pins["5"]="MOUNT" }
  if (p.name === "J_LCD") { delete pins.MP; pins["51"]="MP"; pins["52"]="MP" }
  if (p.name === "J_USB") {
    Object.keys(pins).forEach(key => delete pins[key])
    Object.assign(pins, {"1":"SHIELD","2":"SHIELD","3":"SHIELD","4":"SHIELD","5":"SBU2","6":"CC1","7":"DM_B7","8":"DP_A6","9":"DM_A7","10":"DP_B6","11":"SBU1","12":"CC2","13":"GND_A1","14":"GND_B1","15":"VBUS_B4","16":"VBUS_A4"})
  }
  return { mpn:selected.mpn, lcsc:selected.lcsc, manufacturer:selected.manufacturer,
    library:`JLCPCB/${selected.lcsc}`, pins }
}

export function padNetsFor(p: Part): Record<string,string> {
  const catalog = catalogFor(p)
  if (p.kind) return p.kind === "diode" || p.kind === "led" ? {"1":p.nets.pin2,"2":p.nets.pin1} : {"1":p.nets.pin1,"2":p.nets.pin2}
  return Object.fromEntries(Object.entries(catalog.pins).flatMap(([id, name]) => {
    const net = name === "SHIELD" || name === "MOUNT" ? "GND" : p.nets[name]
    return net ? [[id,net]] : []
  }))
}