from pathlib import Path
import json,hashlib,zipfile,csv,shutil
R=Path(__file__).resolve().parent;B=R.parent;H=B/'engineering_handoff_local'
def sha(p):return hashlib.sha256(p.read_bytes()).hexdigest()
idx=json.loads((H/'LOCAL-PACKAGES.json').read_text());pcb=(H/idx['latest_candidate_sources']['drill_motor']).resolve();ctrl=(H/idx['latest_candidate_sources']['drill_control']).resolve();assert sha(pcb)=='b79e7554a94f0f9ffc7fe775b156f8ead1178ab85efa71b4adb67eb8d00eb0ae';assert sha(ctrl)=='2ad684018be8cb7a7c64660d8f31b225adfa86b646eeacb7aee9c1c9055f3c7a'
hi=22220/(99000+22220);lo=21780/(101000+21780);nom=22000/122000
checks={'status':'A33_DRILL_SPI_NPOR_CORRECTION_HOST_TARGET_PASS_NOT_PHYSICAL','board_hashes':{'motor_A29':sha(pcb),'controller_A32':sha(ctrl)},'CAD_modified':False,'source_pdf':{'url':'https://www.ti.com/lit/ds/symlink/drv8316.pdf','sha256':sha(R/'sources/DRV8316-TI.pdf'),'revision':'SLVSF16B April2022','pages_used':[4,5,8,9,10,19,45,49,53,54,55,58,59,60,63]},'firmware_scope':'Driver configure_off/poll helper corrected and linked; boot main still hard-off only and never calls driver setup or runs motor','NPOR_bit':3,'fault_header_mask':'0xf7 including unexpected reserved bit7; bit3 normal-high excluded','startup':'Reset-latched NPOR=0 permitted only before configuration; Control2=0x43 issues W1C CLR_FLT; expected readback0x42; final NPOR=1 required','runtime':'New NPOR=0 invalidates configuration and asserts off + sleep','tests':{'frames':32768,'init_transfer_failure_positions':22,'init_header_fault_positions':22,'readback_failures':8,'status_bit_cases':23,'header_bit_cases':7,'healthy_NPOR_probe':'PASS','old_A32_negative_control':'FAIL expected, same healthy poll assertion','ASan_UBSan':'PASS'},'ADC_VM_arithmetic':{'R13_ohm':100000,'R14_ohm':22000,'tolerance_percent':1,'nominal_ratio':nom,'worst_low_ratio':lo,'worst_high_ratio':hi,'VM_scenario_V':[16.8,18,22,24,35],'ADC_worst_high_V':[round(v*hi,6) for v in [16.8,18,22,24,35]],'VM_limit_for_3_3V_ADC_only_V':3.3/hi,'VM_limit_for_assumed_3_135V_ADC_only_V':3.135/hi,'assumptions':'Static divider only; actual VDDA, source impedance/sampling time, transient/protection and power sequencing not qualified. 16.8V is a scenario, not established battery rating.'},'manufacturing_status':'FABRICATION_HOLD','physical_validation':'NOT_RUN_NO_SAMPLE'}
(R/'checks.json').write_text(json.dumps(checks,ensure_ascii=False,indent=2)+'\n')
rows=[('VM input','J2 and U1 VM9/10/11','PIN_NET_FUNCTION_MATCH','Board-wide supply range unknown; ADC divider and bus-energy path cannot inherit IC35V rating','TI pp4-6'),('VM bypass','C1-C6 0.1u; C7/C8 22u; C9 220u35V','NOMINAL_TOPOLOGY_MATCH','DC bias,ripple,regeneration,voltage margin,layout and thermal open','TI p19'),('charge pump','C10 CP/VM1u25V; C11 CPH/CPL47n50V','NOMINAL_TOPOLOGY_MATCH','Effective capacitance,placement and waveform open','TI p19,p31'),('AVDD','C12 1u16V to GND','NOMINAL_TOPOLOGY_MATCH','Required 0.7-1.3u effective capacitance at3.3V across temperature not proven','TI p19,p30'),('mixed buck','R1 22R SW_BK/FB_BK; C13 22u10V','RESISTOR_TOPOLOGY_SUPPORTED_BY_MANUFACTURER','Not a missing-inductor defect; startup effective capacitance,current/power and waveform open; helper disables buck only after wake','TI pp8-9,p53'),('off gate','R15 AVDD/DRV_OFF10k; Q1 BSS138BK','SCHEMATIC_DEFAULT_OFF_CANDIDATE','Rise/fall,unpowered MCU,separate-rail sequencing and hot/cold not measured','TI p10,p53; A29'),('sleep','A32 PF1 to J1pin9; R4 100k pulldown','CAD_FIRMWARE_MATCH','Actual VOH/VOL/load/cable and HSI clock plan open','TI p10; A32'),('fault','R7 AVDD to nFAULT5.1k; controllerPA6','PULLUP_PRESENT','Power-up nFAULT test-mode condition,MCU unpowered injection and fault path not measured','TI p19,p53'),('SPI MISO','R9 CTRL3V3 pullup; controllerPB14','PULLUP_PRESENT','Driver defaults push-pull then helper selects open-drain; rail sequencing and RC timing require measurement','TI pp5,24,63'),('VREF/ILIM','R2 11.3k/R3 10k; C14 10n','MODE_DEPENDENT_APPLICATION','Pin37 defaults VREF in6x mode; helper changes to6xCBC ILIM before accepting config. Current profile and thresholds must be selected for actual motor','TI pp5,45,63'),('ADC current','SOA/B/C via100R/1n toPA0/PA1/PA2','PIN_NET_MATCH','Actual AVDD/VDDA,swing,ADC settings,offset/gain calibration,blanking open','TI pp5,45'),('ADC bus','R13 100k1%/R14 22k1% toPA3','RANGE_GATE_OPEN','At24V worst divider4.399V; chip35V range is not board allowable input. Actual bus,VDDA and energy clamp must be fixed together','Computed in checks.json'),('SPI NPOR','IC_STAT and response header bit3','FIRMWARE_CORRECTED_AND_HOST_TESTED','Register-model proof only; no hardware SPI run','TI pp54-55,58,63')]
with (R/'power_interface_audit.csv').open('w',newline='',encoding='utf-8-sig') as f:
 w=csv.writer(f);w.writerow(['Item','ActualCandidate','Finding','OpenQualification','Evidence']);w.writerows(rows)
report=H/'A33-drill-driver-and-power-review.md';report.write_text('''# A33 电磨驱动状态修正与电源接口审核

状态：固件本地主机与 ARM 静态构建通过；制造 FABRICATION_HOLD，物理验证 NOT_RUN_NO_SAMPLE。仍未达到链接产品功能效果一致。

## 已修正的确定性问题

DRV8316 IC_STAT / SPI 状态头的 NPOR bit3 = 1 表示没有电源复位，不是正逻辑故障。旧代码把全部非零状态头和状态数据当作故障；旧模拟器又没有模拟 NPOR、状态头及 CLR_FLT 自清行为。因此旧测试不能证明与实际器件状态一致。

A33 排除正常 NPOR bit3，保留其他故障和异常保留位的拒绝处理。启动只在配置前允许复位锁存 NPOR=0；在 DRVOFF 保持关闭时，用 Control2=0x43 执行 CLR_FLT，按 W1C 自清检查读回0x42。最终配置要求 NPOR=1；运行轮询若 NPOR 再变0，即失效配置并断开输出、进入睡眠。没有添加电机使能函数。

测试覆盖32768个帧、22个初始化传输位置的I/O失败和状态头故障、8个读回错误、23个状态位和7个非NPOR状态头位；ASan/UBSan通过。独立健康状态探针向实际轮询函数返回0x0808/0x0800帧，新代码通过，旧A32代码在同一个断言失败。模拟器只证明协议/软件路径，没有测硬件 SPI。

ARM源码干净构建通过。该映像仍从 main 进入关闭输出等待，DRV8316助手虽已链接但未在运行路径调用，FOC对象未链接。不能把这次驱动助手修正说成电机已经能转。CAD、BOM未修改；继续配对 A29电机板、A32 PF1控制板。

## 电源接口审核结果

13项审核详见power_interface_audit.csv。22Ω串联的buck网络由TI支持，不能误判为缺少电感；其启动、有效电容和热条件仍未验证。AVDD、CP、CPL和主要旁路的名义连接与器件功能相符，不代表全部应用合格。

现有VM采样是100k/22k、各1%。上端电阻偏低与下端偏高时比值约0.183303；假设VDDA为3.3V，仅静态采样满量程对应VM约18.003V。24V输入会得到约4.39927V。此处3.3V及16.8V算例都不是已验证的实际电源；完整数值和假设见checks.json。既有22V驱动OVP设置不能替代控制器ADC输入保护。必须结合实际电池/适配器、再生制动能量、VDDA最小值、分压/限幅与采样设置确定整机母线范围。

nFAULT拉升存在，VREF/ILIM随PWM模式改变，SPI SDO默认推挽再由助手改成开漏；这些接口还需测不同上电顺序、睡眠/唤醒、未上电MCU、实际线束与温度条件。电机拓扑、额定参数、50000rpm带载与约10小时续航仍缺参考机与样机证据。

原厂依据：https://www.ti.com/lit/ds/symlink/drv8316.pdf ，SLVSF16B。源PDF保存在本地sources，仅记录哈希，不在交付ZIP再分发。没有下单、联系供应商或物理上电。三款每款1000台整机成本仍待完整BOM与工厂报价。
''',encoding='utf-8')
T=R/'release';T.mkdir(exist_ok=True);shutil.copytree(R/'firmware',T/'firmware',dirs_exist_ok=True,ignore=shutil.ignore_patterns('__pycache__'))
for n in ['checks.json','power_interface_audit.csv','driver_test.log','healthy_header_test.log','negative_control.log','target_build.log','build_target.sh','test_healthy_header.c','run_driver_tests.sh']:shutil.copyfile(R/n,T/n)
shutil.copyfile(B/'sleep_gpio_A32/firmware/固件/drill_driver/drv8316.c',T/'original_A32_drv8316.c');shutil.copyfile(report,T/report.name)
files=sorted(p for p in T.rglob('*') if p.is_file());manifest=''.join(sha(p)+'  A33/'+p.relative_to(T).as_posix()+'\n' for p in files);zp=H/'Drill-SPI-NPOR-and-power-review-A33.zip'
with zipfile.ZipFile(zp,'w',zipfile.ZIP_DEFLATED) as z:
 for p in files:z.write(p,'A33/'+p.relative_to(T).as_posix())
 z.writestr('A33/SHA256SUMS.txt',manifest)
with zipfile.ZipFile(zp) as z:
 assert z.testzip() is None
 for ln in z.read('A33/SHA256SUMS.txt').decode().splitlines():
  dig,n=ln.split('  ',1);assert hashlib.sha256(z.read(n)).hexdigest()==dig
(H/'A33-SHA256SUMS.txt').write_text(manifest);binpath=R/'firmware/固件/drill_target/build/drill_control_g431cb.bin';entry={'archive':zp.name,'sha256':sha(zp),'bytes':zp.stat().st_size,'zip_entries':len(files)+1,'manifest_entries':len(files),'zip_crc':'PASS','manifest_readback':'PASS','host_driver_tests':'PASS ASan/UBSan + independent normal NPOR probe; old driver rejected','target_build':'STATIC_PASS_OUTPUTS_OFF','CAD_changed':False,'physical_validation':'NOT_RUN_NO_SAMPLE','manufacturing_status':'FABRICATION_HOLD'}
idx['packages']=[x for x in idx['packages'] if x.get('archive')!=zp.name]+[entry];idx.update({'status':'A33_DRILL_NPOR_DRIVER_CORRECTION_AND_POWER_AUDIT_FABRICATION_HOLD','latest_report':report.name,'latest_machine_report':'../drill_power_audit_A33/checks.json','latest_manifest':'A33-SHA256SUMS.txt'});idx['latest_drill_safe_firmware_A33']={'source':'../drill_power_audit_A33/firmware/固件/drill_target','binary_sha256':sha(binpath),'board_pair':'A29 motor + A32 PF1 controller','output_enabled':False,'runtime_driver_helper_called':False,'physical_test_release':False};idx['drill_ADC_VM_gate_A33']=checks['ADC_VM_arithmetic'];idx['manufacturing_exclusions']['drill_A32_driver_helper']='NPOR=1 incorrectly rejected as fault; A33 corrects status parsing and CLR_FLT acknowledgement. Both images remain hard-off, not physically qualified.';(H/'LOCAL-PACKAGES.json').write_text(json.dumps(idx,ensure_ascii=False,indent=2)+'\n');print(json.dumps({'package':entry,'firmware_bin':sha(binpath),'ADC':checks['ADC_VM_arithmetic']},ensure_ascii=False,indent=2))
