abse/smartwatch-flex-top-only

Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.

Version
0.2.22
License
unset
Stars
0

components/PrintedReceiverCoil.tsx

import React from 'react'
import type {InductorProps} from '@tscircuit/props'

// PCB winding, not a purchased coil. Three series-aiding rectangular spirals.
// Inner1 remains available for narrow PPG signal/power escape traces.
// 21.6 x 18mm outer copper, 6 turns/layer, .60mm trace, .15mm spacing.
// Inductance in free space is only an analytical estimate. Final resonance,
// AC Q, ferrite losses, charging temperature and FOD require measurement.
export const coilGeometry={turns:6,width:.6,spacing:.15,outerCopper:21.6,outerHeight:18,
  windingLayers:['top','inner2','bottom'],join1:{x:-5.7,y:3.5},join2:{x:11.25,y:8.7},
  terminal1:{x:-11.25,y:8.7},terminal2:{x:5.6,y:-3.5}}
const base: {x:number,y:number}[]=[{x:-10.5,y:8.7}]
for(let i=0;i<6;i++){
  const rx=10.5-i*.75,ry=8.7-i*.75
  base.push({x:rx,y:ry},{x:rx,y:-ry},{x:-rx,y:-ry},{x:-rx,y:ry-.75})
}
base.at(-1)!.y=3.5
const path=(layer:string,points:{x:number,y:number}[])=>points.map(p=>({...p,route_type:'wire',width:.6,layer}))
const top=path('top',[coilGeometry.terminal1,...base,coilGeometry.join1])
const inner=path('inner2',[coilGeometry.join1,...base.map(p=>({x:-p.x,y:p.y})).reverse(),coilGeometry.join2])
const bottom=path('bottom',[coilGeometry.join2,{x:11.25,y:-8.7},...base.map(p=>({x:-p.x,y:-p.y})),coilGeometry.terminal2])
const transition=(p:{x:number,y:number},from_layer:string,to_layer:string)=>({route_type:'via',...p,from_layer,to_layer,via_diameter:.45,via_hole_diameter:.3})
export const windingRoute=[...top,transition(coilGeometry.join1,'top','inner2'),...inner,
  transition(coilGeometry.join2,'inner2','bottom'),...bottom]
// Core's PcbTrace footprint primitive emits copper but not drill records.
// Add the two manufacturing vias to the owning trace during primitive render.
// This emits geometry and ownership; it changes no source nets or DRC checks.
const WindingCopper=()=>React.createElement('pcbtrace',{
  route:windingRoute,
  ref:(instance:any)=>{
    if(!instance||instance.__coilViasInstalled)return
    instance.__coilViasInstalled=true
    const render=instance.doInitialPcbPrimitiveRender.bind(instance)
    instance.doInitialPcbPrimitiveRender=()=>{
      render()
      const trace=instance.root.db.pcb_trace.get(instance.pcb_trace_id)
      // Source and pin checks disable PCB primitives; no copper trace exists
      // in that mode, so there is no owning trace to receive drill records.
      if(!trace)return
      for(const p of trace.route.filter((p:any)=>p.route_type==='via'))instance.root.db.pcb_via.insert({
        pcb_trace_id:trace.pcb_trace_id,x:p.x,y:p.y,hole_diameter:.3,outer_diameter:.45,
        layers:['top','inner1','inner2','bottom'],from_layer:'top',to_layer:'bottom',
        tented_on_top:true,tented_on_bottom:true,subcircuit_id:trace.subcircuit_id,
      })
    }
  },
})
export const PrintedReceiverCoil=(props:Omit<InductorProps,'inductance'>)=><inductor
  {...props} inductance="11uH" doNotPlace
  footprint={<footprint>
    <smtpad portHints={['pin1']} pcbX={-11.25} pcbY={8.7} shape="rect" width={.6} height={.6} />
    <platedhole portHints={['pin2']} pcbX={5.6} pcbY={-3.5} shape="circle" holeDiameter={.3} outerDiameter={.6} coveredWithSolderMask />
    {/* PCB winding has an empty sensor window, not a solid purchased body.
        Reserve its copper frame and the separate inner terminal, +0.127mm. */}
    <courtyardrect pcbX={-9} width={5.354} height={18.254}/>
    <courtyardrect pcbX={9} width={5.354} height={18.254}/>
    <courtyardrect pcbY={6.1} width={12.646} height={6.054}/>
    <courtyardrect pcbY={-6.825} width={12.646} height={4.604}/>
    <courtyardrect pcbX={5.6} pcbY={-3.5} width={.854} height={.854}/>
    <WindingCopper/>
  </footprint>}/>

// Service copper replaces the unpopulated tall UART connector in this local
// prototype. It retains all five electrical terminals and avoids the frame hole.
export const UartServicePads=(props:any)=><connector doNotPlace pinLabels={{pin1:['RX'],pin2:['GND'],pin3:['TX'],pin4:['GND4'],pin5:['GND5']}}
  footprint={<footprint insertionDirection="from_above"><courtyardrect width={1.254} height={4.554}/>{[1,2,3,4,5].map(i=><React.Fragment key={i}><smtpad portHints={[`pin${i}`]}
    pcbY={(i-3)*.9} width={1} height={.7} shape="rect" /></React.Fragment>)}</footprint>} {...props}/>