kicad:EasyEDA→KiCad 工程(Board1/Board2)、库、脚本与评审文档(IC 引脚、风扇、热、EDL 供电、布局规则)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,90 @@
|
||||
"""Apply the catalog-backed FAN-R2 part selection to the existing R1 schematic."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from schematic_maintenance import ROOT, parse, children, child, properties
|
||||
from revise_four_wire_fans import prop, quote, uid
|
||||
|
||||
|
||||
def main():
|
||||
selection = json.loads((ROOT/'fan-selection.json').read_text(encoding='utf-8'))
|
||||
path = ROOT/'PhoneRail-Board1/P6-FAN-EDL.kicad_sch'
|
||||
source = path.read_text(encoding='utf-8')
|
||||
if 'SANYO FAN SELECTION R2' in source:
|
||||
print('FAN-R2 already applied; skipped')
|
||||
return
|
||||
assert 'FOUR-WIRE FAN PROTOTYPE R1' in source
|
||||
root = parse(source)
|
||||
edits = []
|
||||
for symbol in children(root, 'symbol'):
|
||||
p = properties(symbol)
|
||||
ref = p['Reference'][2]
|
||||
values = {}
|
||||
if ref in {'J26', 'J27'}:
|
||||
values = {'Value': '1725672', 'MPN': '1725672', 'Manufacturer': 'Phoenix Contact',
|
||||
'LCSC': 'C3816889', 'Footprint': selection['connector']['footprint'],
|
||||
'Datasheet': 'https://item.szlcsc.com/datasheet/1725672/4384563.html',
|
||||
'Fan_MPN': selection['mpn'], 'Fan_LCSC': selection['lcsc'],
|
||||
'Fan_Device_UUID': selection['easyeda_device_uuid'],
|
||||
'Fan_Datasheet': selection['datasheet_url'],
|
||||
'Harness': '1 Black GND; 2 Red +12V_SW; 3 Yellow TACH; 4 Brown PWM',
|
||||
'Description': 'Four-way screw terminal for off-board SANYO fan; fan is in fan-assembly-bom.csv'}
|
||||
if ref in {'R745', 'R749'}:
|
||||
values = {'Value': '15k', 'MPN': '0402WGF1502TCE', 'LCSC': 'C25756'}
|
||||
# C25756 cross-checked through the live catalog on 2026-09-07.
|
||||
x, y = map(float, child(symbol, 'at')[1:3])
|
||||
extra = []
|
||||
for key, value in values.items():
|
||||
if key in p:
|
||||
node = p[key]
|
||||
raw = source[node.start:node.end]
|
||||
old = quote(node[2])
|
||||
prefix = '(property '+quote(key)+' '
|
||||
assert raw.startswith(prefix+old)
|
||||
edits.append((node.start, node.end, prefix+quote(value)+raw[len(prefix+old):]))
|
||||
else:
|
||||
extra.append(prop(key, value, x, y, True))
|
||||
if extra:
|
||||
edits.append((symbol.end-1, symbol.end-1, '\n'.join(extra)))
|
||||
if ref in {'C738', 'D2'}:
|
||||
for key, dy in [('Reference', -2.54), ('Value', 0)]:
|
||||
node = child(p[key], 'at')
|
||||
edits.append((node.start, node.end, f'(at {x+22.86:g} {y+dy:g} 270)'))
|
||||
replacements = {
|
||||
'FOUR-WIRE FAN PROTOTYPE R1': 'SANYO FAN SELECTION R2 / 2x 9G0612P4S001 / C2920592',
|
||||
'2x NF-A6x25 PWM / J26 intake / J27 exhaust. Vendor limits and prototype tests OPEN.':
|
||||
'J26 intake / J27 exhaust. 12V, 60x60x25mm, 25kHz PWM. Startup/thermal verification OPEN.',
|
||||
'Keyed PC fan header: 1 GND / 2 +12V / 3 TACH / 4 PWM.':
|
||||
'Screw terminals: 1 BLACK GND / 2 RED +12V / 3 YELLOW TACH / 4 BROWN PWM.',
|
||||
'Confirm header drawing, key orientation and cable fit before layout.':
|
||||
'Bare AWG26 leads, 300-350mm. No PC-fan plug. 0% PWM still runs at about 3300RPM.',
|
||||
'25kHz target; invert MCU duty: D_gpio = 1 - D_fan. Confirm vendor limits.':
|
||||
'25kHz nominal; invert MCU duty: D_gpio = 1 - D_fan. Family PWM limits: see FAN_CIRCUIT.md.',
|
||||
'RAW high: Vgate ~ Vfan/3. RAW low: Vgate ~ Vtach_low/2.':
|
||||
'R745/R749 = 15k: Vgate high ~ Vfan/3.5; low <=0.24V nominal for RAW <=0.6V.',
|
||||
}
|
||||
for note in children(root, 'text'):
|
||||
if note[1] in replacements:
|
||||
raw = source[note.start:note.end]
|
||||
edits.append((note.start, note.end, raw.replace(quote(note[1]), quote(replacements[note[1]]), 1)))
|
||||
rev = child(child(root, 'title_block'), 'rev')
|
||||
edits.append((rev.start, rev.end, '(rev "FAN-R2")'))
|
||||
for start, end, value in sorted(edits, reverse=True):
|
||||
source = source[:start]+value+source[end:]
|
||||
source = source.replace('FanHeader', 'FanTerminal')
|
||||
parse(source)
|
||||
backup = ROOT/'out/before-sanyo-selection'
|
||||
backup.mkdir(exist_ok=False)
|
||||
shutil.copy2(path, backup/path.name)
|
||||
path.write_text(source, encoding='utf-8', newline='\n')
|
||||
lib = ROOT/'lib/PhoneRail-Fan.kicad_sym'
|
||||
lib.write_text(lib.read_text(encoding='utf-8').replace('FanHeader', 'FanTerminal'), encoding='utf-8', newline='\n')
|
||||
name = selection['connector']['footprint'].split(':')[1]
|
||||
fp = Path('D:/KiCad/share/kicad/footprints/TerminalBlock_Phoenix.pretty')/(name+'.kicad_mod')
|
||||
shutil.copy2(fp, ROOT/'lib/PhoneRail-Fan.pretty'/fp.name)
|
||||
print('Applied SANYO fan metadata, Phoenix terminals and 15k TACH gate resistors')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
在新工单中引用
屏蔽一个用户