component
TPS16850VMAR - 9 V to 80 V, 20 A eFuse
Public Made by Adomby adom
Texas Instruments TPS16850VMAR: 9 V to 80 V, 20 A stackable integrated hot-swap eFuse with a 3.5 mOhm FET, fast current monitor and auto-retry fault response, LQFN-CLIP-23 (VMA, 6.0 x 5.0 mm). KiCad symbol and footprint, Fusion and Altium libraries, datasheet-built 3D model and datasheet.
main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
#!/usr/bin/env python3
"""Lossless primitive batching for a step2glb chip GLB (uncompressed float accessors), plus an optional graft of
the reviewed Adom.LaserEtch mark from another GLB in the same frame.
* every mesh node keeps its name (body, pins, Adom.LaserEtch); its primitives are joined per material
(positions, normals and indices concatenated; geometry unchanged)
* --etch-from etched.glb copies that file's Adom.LaserEtch mesh node (with its material) into this scene
usage: glb_batch.py in.glb out.glb [--etch-from etched.glb]
prints JSON stats: triangles, primitives, bytes, nodes, bounds (mm)"""
import sys, json, struct
import numpy as np
from pygltflib import GLTF2, Buffer, BufferView, Accessor, Mesh, Primitive, Node, Material, PbrMetallicRoughness, Attributes
CT = {5126: np.float32, 5125: np.uint32, 5123: np.uint16, 5121: np.uint8}
NC = {"SCALAR": 1, "VEC2": 2, "VEC3": 3, "VEC4": 4}
def read(g, blob, ai):
a = g.accessors[ai]; bv = g.bufferViews[a.bufferView]
dt = CT[a.componentType]; n = NC[a.type]
off = (bv.byteOffset or 0) + (a.byteOffset or 0)
stride = bv.byteStride or np.dtype(dt).itemsize * n
if stride == np.dtype(dt).itemsize * n:
return np.frombuffer(blob, dt, a.count * n, off).reshape(a.count, n) if n > 1 else np.frombuffer(blob, dt, a.count, off)
raw = np.frombuffer(blob, np.uint8, stride * (a.count - 1) + np.dtype(dt).itemsize * n, off)
return np.stack([np.frombuffer(raw[i * stride:i * stride + np.dtype(dt).itemsize * n].tobytes(), dt) for i in range(a.count)])
def parts(path):
g = GLTF2().load(path); blob = g.binary_blob()
out = []
for ni, n in enumerate(g.nodes):
if n.mesh is None: continue
by_mat = {}
for p in g.meshes[n.mesh].primitives:
P = read(g, blob, p.attributes.POSITION).astype(np.float32)
N = read(g, blob, p.attributes.NORMAL).astype(np.float32) if p.attributes.NORMAL is not None else None
I = read(g, blob, p.indices).astype(np.uint32) if p.indices is not None else np.arange(len(P), dtype=np.uint32)
by_mat.setdefault(p.material, []).append((P, N, I))
out.append((ni, n.name, by_mat))
return g, out
def main():
src, dst = sys.argv[1], sys.argv[2]
etch = sys.argv[sys.argv.index("--etch-from") + 1] if "--etch-from" in sys.argv else None
g, ps = parts(src)
data = bytearray(); bviews = []; accs = []
def add(arr, target, comp, typ, minmax=False):
nonlocal data
while len(data) % 4: data += b"\0"
off = len(data); b = arr.tobytes(); data += b
bviews.append(BufferView(buffer=0, byteOffset=off, byteLength=len(b), target=target))
a = Accessor(bufferView=len(bviews) - 1, componentType=comp, count=len(arr), type=typ)
if minmax: a.min = arr.min(0).tolist(); a.max = arr.max(0).tolist()
accs.append(a); return len(accs) - 1
def build_mesh(name, by_mat, matmap):
prims = []
for mi, lst in by_mat.items():
Ps, Ns, Is, o = [], [], [], 0
for P, N, I in lst:
Ps.append(P); Ns.append(N if N is not None else np.zeros_like(P)); Is.append(I + o); o += len(P)
P = np.concatenate(Ps); N = np.concatenate(Ns); I = np.concatenate(Is).astype(np.uint32)
pa = add(P, 34962, 5126, "VEC3", True); na = add(N, 34962, 5126, "VEC3")
ia = add(I, 34963, 5125, "SCALAR")
prims.append(Primitive(attributes=Attributes(POSITION=pa, NORMAL=na), indices=ia, material=matmap(mi)))
return Mesh(name=name, primitives=prims)
meshes = []
for ni, name, by_mat in ps:
meshes.append(build_mesh(name, by_mat, lambda m: m)); g.nodes[ni].mesh = len(meshes) - 1
if etch:
ge, pe = parts(etch)
hits = [x for x in pe if (x[1] or "").startswith("Adom.LaserEtch")]
if not hits: sys.exit("ERROR: no Adom.LaserEtch node in " + etch)
for ni, name, by_mat in hits:
def mm(m):
em = ge.materials[m]
g.materials.append(Material(name=em.name, pbrMetallicRoughness=PbrMetallicRoughness(
baseColorFactor=list(em.pbrMetallicRoughness.baseColorFactor), metallicFactor=0.0, roughnessFactor=0.7)))
return len(g.materials) - 1
meshes.append(build_mesh(name, by_mat, mm))
g.nodes.append(Node(name=name, mesh=len(meshes) - 1))
g.nodes[g.scenes[g.scene or 0].nodes[0]].children.append(len(g.nodes) - 1)
g.meshes = meshes; g.accessors = accs; g.bufferViews = bviews
g.buffers = [Buffer(byteLength=len(data))]; g.set_binary_blob(bytes(data))
g.save(dst)
tris = sum(accs[p.indices].count // 3 for m in meshes for p in m.primitives)
allp = np.concatenate([np.array(accs[p.attributes.POSITION].min + accs[p.attributes.POSITION].max).reshape(2, 3) for m in meshes for p in m.primitives])
import os
print(json.dumps({"out": dst, "triangles": tris, "primitives": sum(len(m.primitives) for m in meshes),
"bytes": os.path.getsize(dst), "nodes": [n.name for n in g.nodes if n.mesh is not None],
"boundsMm": [round(v * 1000, 4) for v in list(allp.min(0)) + list(allp.max(0))]}))
main()