shibosoftwaredev/f1c100s-linux-nema17-stepper-controller

Compact four-layer NEMA 17 carrier PCB combining an F1C100S Linux SoC, USB-C PD power and buck regulation, W5500 10/100 Ethernet, STM32 safety/motion control, and DRV8825 stepper-driver hardware with protection, sensing, connectors, and dual-sided SMT assembly.

Version
0.4.15
License
unset
Stars
0

assembly-metadata.ts

import modelMap from './assembly-models.json'
import partMap from './assembly-parts.json'

/** Restore assembly metadata after the imported module is inflated. This changes
 * only source part identifiers and CAD records, never pads, copper, or DRC. */
export function applyPartMetadata(board: any) {
  const parts=partMap as Record<string, any>
  const walk=(node:any)=>{
    const part=parts[node.props?.name]
    if(part){Object.assign(node.props,part);Object.assign(node._parsedProps,part)}
    for(const child of node.children??[])walk(child)
  }
  walk(board)
  for(const c of board.root.db.source_component.list()) {
    const part=parts[c.name]
    if(part)board.root.db.source_component.update(c.source_component_id,{
      manufacturer_part_number:part.manufacturerPartNumber,
      supplier_part_numbers:part.supplierPartNumbers,
    })
  }
}

export function applyCadMetadata(board:any) {
  const db=board.root.db, models=modelMap as Record<string,any>
  for(const c of db.source_component.list()) {
    // Bare debug holes are copper features and have no fitted 3D body.
    if(c.ftype==='simple_test_point') {
      const cad=db.cad_component.getWhere({source_component_id:c.source_component_id})
      if(cad)db.cad_component.delete(cad.cad_component_id)
      continue
    }
    const pcb=db.pcb_component.getWhere({source_component_id:c.source_component_id})
    const previous=db.cad_component.getWhere({source_component_id:c.source_component_id})
    // DNP items such as mounting holes, test pads and the cuttable boot link
    // are fabricated copper/mechanical features, not physical 3D bodies.
    if(pcb?.do_not_place) {
      if(previous)db.cad_component.delete(previous.cad_component_id)
      continue
    }
    const specification=models[c.name];if(!specification)continue
    const {rotationOffset=0,kind,model_source,...model}=specification
    if(!pcb)continue
    const bottom=pcb.layer==='bottom'
    const data={...model,show_as_bounding_box:false,
      source_component_id:c.source_component_id,pcb_component_id:pcb.pcb_component_id,
      position:{x:pcb.center.x,y:pcb.center.y,z:(bottom?-1:1)*0.7},
      rotation:{x:0,y:bottom?180:0,z:bottom?-(pcb.rotation+rotationOffset):pcb.rotation+rotationOffset},
      model_origin_alignment:'center_of_component_on_board_surface',
      anchor_alignment:'center_of_component_on_board_surface',
    }
    if(previous)db.cad_component.update(previous.cad_component_id,data)
    else db.cad_component.insert(data)
  }
}

/** Through-hole headers and bare breakout holes are not paste-in-hole parts.
 * Keep SMT paste on the same face as its pad; this board is intentionally
 * assembled on both faces to fit the NEMA 17 motor-back envelope. */
export function applyAssemblyPasteMetadata(board:any) {
  const db=board.root.db
  for(const paste of db.pcb_solder_paste.list()) {
    const pad=paste.pcb_smtpad_id ? db.pcb_smtpad.get(paste.pcb_smtpad_id) : undefined
    const component=pad ? db.pcb_component.get(pad.pcb_component_id) : undefined
    if(!pad || component?.do_not_place) {
      db.pcb_solder_paste.delete(paste.pcb_solder_paste_id)
      continue
    }
    if(pad.layer!==paste.layer)
      throw new Error(`Solder-paste layer ${paste.layer} does not match pad layer ${pad.layer}`)
  }
}