from pathlib import Path
import hashlib,json,zipfile,shutil
R=Path(__file__).resolve().parent;B=R.parent;H=B/'engineering_handoff_local';T=R/'firmware/固件/lamp_target'
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
build=json.loads((T/'build/build_verification.json').read_text())
assert build['ADC_raw_sampling_bound'] and not build['led_output_enabled'] and not build['ADC_calibrated_safety_permissions_bound']
assert 'PASS: 72' in (R/'actual_ADC_test.log').read_text()
assert 'Assertion' in (R/'premature_start_ADC_test.log').read_text()
board=B/'lamp_IR_PCB_A39/board/lamp_safety_evt_a3_IR_PCB.kicad_pcb'
assert sha(board)=='28d30b5912cce3053ae881a847a66ca13b682c405096475c5e9af943584e2686'
shutil.copy2(B/'ADC_channel_ready_A41/lamp_ADC_hardware_mapping_A41.csv',R/'lamp_ADC_hardware_mapping.csv')
checks={'status':'A42_LAMP_NONBLOCKING_RAW_ADC_LOCAL_PASS_FABRICATION_HOLD','board_sha256':sha(board),'build':build,'raw_frame_delay_wrap_cases':72,'stage_faults_tested':['calibration','ADRDY','CCRDY','EOC_EOS','overrun'],'negative_control':'Synthetic skipped-CCRDY mutant rejected by channel-ready assertion','sanitizers':'ASAN_UBSAN_PASS','clock':'Cold HSI16 with no HSI/AHB/APB divider; ADC synchronous8MHz','waits':'regulator+VREFINT startup2 ticks; calibration-complete to ADEN2 ticks; no busywait','stage_timeout_ms':5,'maximum_poll_gap_ms':5,'frame_oldest_timestamp_age_limit_ms':20,'timing_qualification':'Candidate parameters on SysTick; no measured CPU, latency or oscillator timing evidence','ADC_safety_fields_ready':False,'LED_outputs_enabled':False,'BOM_CAD_changed':False,'physical_verified_requirements':0,'reference_requirements':20,'physical_test_release':False}
(R/'checks.json').write_text(json.dumps(checks,ensure_ascii=False,indent=2)+'\n')
refs={'reference_manual':'https://www.st.com/resource/en/reference_manual/rm0454-stm32g0x0-advanced-armbased-32bit-mcus-stmicroelectronics.pdf','reference_manual_local_hash':'NOT_AVAILABLE; official indexed text used, not downloaded here','ST_LL_source':'https://raw.githubusercontent.com/STMicroelectronics/stm32g0xx-hal-driver/master/Inc/stm32g0xx_ll_adc.h','ST_LL_local_sha256':sha(R/'ST_ll_adc_reference.h'),'LL_literals':{'regulator_stabilization_us':20,'VREFINT_stabilization_us':12,'post_calibration_ADC_cycles':2,'SMP1_max_cycles':160.5},'device_header_sha256':sha(T/'Device/Include/stm32g030xx.h'),'scope':'Manufacturer timing/order reference; not measured hardware behavior'}
(R/'source_references.json').write_text(json.dumps(refs,indent=2)+'\n')
report=f'''# 美甲灯非阻塞原始ADC接入 A42

状态：本地主机测试与ARM完整构建通过，FABRICATION_HOLD。新增实际ADC采样实现，不代表通电验证、温度校准或与原产品效果一致。三款整机20项验收仍0项实测确认。

## 本轮实际变更

A39 PCA9956B灯具安全板 U1.8/PA1/ADC_IN1采集NTC接口，U1.12/PA5/ADC_IN5采集LED_V_SENSE，U1.13/PA6/ADC_IN6采集LED_I_SENSE，最后采集通道13内部VREFINT。采样GPIO只改PA1/5/6模拟模式及上下拉，保留其他引脚与输出锁存。未改变PCB、BOM或新增器件。

`lamp_adc_init`在SysTick初始化完成后由实际main调用；`lamp_adc_poll/get_frame/failed`由原有安全采样路径调用，主循环及每个完整串口消息处理前可达。采样器只有主循环一个所有者，不在中断中操作ADC。初始化只复位ADC外设，不复位RTC/红外GPIO。

状态机分别处理稳压器/VREF启动、校准、校准后等待、ADRDY、写CHSELR后CCRDY、ADSTART后EOC/EOS、四通道完整帧发布。每次poll执行固定有限操作，函数中没有等待循环或软件延时。参考ST官方LL要求：稳压器20us、VREF12us、校准后2ADC时钟，候选采用分开的2个SysTick刻度等待以覆盖tick相位。限制正常冷启动HSI16、无HSI/AHB/APB分频，同步ADC时钟PCLK/2为8MHz；SMP1=160.5周期。运行时复核时钟、外设配置和引脚，异常进入不可恢复失败态，需重新初始化。

转换各阶段5ms候选超时、轮询间隔超过5ms失效、完整帧最早时间超过20ms失效；迟到完成标志不能覆盖超时。过载/部分帧不发布，失败时撤销有效状态，转换进行中请求停止。四个原始12bit值、帧首/完成时间及序号在完整帧时一次发布。`get_frame`失败时不改调用者数据；调试器中旧帧可能仍保留，必须同时检查`lamp_debug_adc_valid`、`lamp_debug_adc_failed`和时间戳，不可把残留值当实时值。20ms是原始数据诊断边界，不是已测安全关断时延。

## 当前验证

- 72组校准/就绪/通道配置/转换延迟与32bit回绕组合，使用实际厂商寄存器布局和实际驱动源代码；仅模拟W1C、配置事件和硬件完成时序。
- 四通道顺序、GPIO其他位保留、没有部分帧、过期/间隔/倒退时间拒绝，校准/ADRDY/CCRDY/EOC超时，溢出、时钟分频变化、ADC关闭、模式/上拉/引脚锁定、配置被改均验证。
- 故意跳过CCRDY等待的合成负对照被真实通道准备断言拒绝；不是实际板卡或旧二进制通电结果。
- ASan/UBSan及全部已有启动、IR、票据、UART/UI、guard和输出适配器回归通过。实际ELF反汇编检查main到ADC初始化、采样路径到poll/get_frame/failed的调用可达性；同时保留IR绑定和输出禁用检查。
- BIN {build['flash_binary_bytes']} B，FLASH链接使用{build['flash_binary_bytes']}/32768，RAM链接使用2776/8192；BIN SHA256 `{build['sha256_bin']}`。这是静态链接内存统计，未测运行时栈峰值或CPU占用。
- 配对A39 PCB SHA256 `{sha(board)}`，本轮只复核本地板文件hash；未改变CAD或重跑其native检查。A39历史ERC/DRC/未连线/原理图一致性为0，仍无工厂DFM或通电证据。

## 未完成的功能门槛

原始ADC值不会直接转为`temperature_ok/supply_ok/led_driver_ok`，相关字段仍false，guard未配置/授权，LED三路硬件控制保持关断，外部看门狗不踢。

NTC精确MPN、曲线/公差/安装与过温阈值仍未建立；LED电压/电流接口在A39是外部已调理0–3V输入，实际上游分压、分流器/增益/偏置未绑定并验证。不得把LED主电源直接接到该ADC口，也不能把raw count说成已校准电压、电流或温度。VREFINT本轮只采原始值，尚未读取工厂校准或授予VDDA范围通过。ADC输入源阻抗、启动/热漂、参考/噪声/多通道串扰、转换精度、采样时序与引脚电压实机证据全部待测。即使软件数值合理也不能授权输出。

下一步闭合实际NTC器件与LED电压/电流前端，再实现校准后的安全判据和LED驱动状态回读。仍需三款实际负载/结构、电磨转速扭矩、吸尘风量噪声、美甲灯光学固化/热与AI链路测试，以及每款1000台完整整机BOM/工厂报价，不能由本轮软件回归替代。未采购、联系供应商、烧录、通电或下单。

## 复核方式

包内完整可编辑源代码、目标ELF/BIN/MAP、测试与日志、ST LL参考文件和SHA清单；运行`sh run_checks.sh`需要cc/Python3及arm-none-eabi工具链。ADC主机模拟只仪器化硬件W1C与CHSELR写事件，不能证明真实模拟精度。包内继承的芯片/模块资料不是产品效果验收报告；以本README和checks.json的当前边界为准。
'''
(R/'README.md').write_text(report);(H/'A42-lamp-nonblocking-raw-ADC.md').write_text(report)
files=[p for p in R.rglob('*') if p.is_file() and p.name!='package.py' and not p.name.startswith('.') and 'adc_host_test' not in p.parts and 'host_test' not in p.parts and p.suffix in ['.c','.h','.s','.ld','.sh','.py','.md','.json','.log','.txt','.csv','.elf','.bin','.map']]
manifest=''.join(f'{sha(p)}  {p.relative_to(R).as_posix()}\n' for p in sorted(files))
(H/'A42-SHA256SUMS.txt').write_text(manifest)
z=H/'Lamp-nonblocking-raw-ADC-review-A42.zip'
with zipfile.ZipFile(z,'w',zipfile.ZIP_DEFLATED) as a:
 for p in files:a.write(p,p.relative_to(R).as_posix())
 a.writestr('SHA256SUMS.txt',manifest)
with zipfile.ZipFile(z) as a:
 assert a.testzip() is None
 for line in manifest.splitlines():
  digest,name=line.split('  ',1);assert hashlib.sha256(a.read(name)).hexdigest()==digest
 count=len(a.namelist())
ip=H/'LOCAL-PACKAGES.json';idx=json.loads(ip.read_text())
idx.update(status=checks['status'],latest_report='A42-lamp-nonblocking-raw-ADC.md',latest_machine_report='../lamp_ADC_target_A42/checks.json',latest_manifest='A42-SHA256SUMS.txt')
entry={'archive':z.name,'sha256':sha(z),'bytes':z.stat().st_size,'zip_entries':count,'manifest_entries':len(files),'zip_crc':'PASS','manifest_readback':'PASS','manufacturing_status':'FABRICATION_HOLD'}
idx['packages']=[p for p in idx['packages'] if p.get('archive')!=z.name]+[entry]
idx['latest_lamp_safe_firmware_A42']={'source':'../lamp_ADC_target_A42/firmware/固件/lamp_target','binary_sha256':build['sha256_bin'],'board_pair':'A39 PCA lamp_safety_evt_a3_IR_PCB','IR_GPIO_binding':True,'ADC_raw_sampling_bound':True,'ADC_calibrated_safety_permissions_bound':False,'led_output_enabled':False,'physical_test_release':False}
idx['latest_lamp_IR_hardware_A39']['bound_firmware_candidate']='../lamp_ADC_target_A42/firmware/固件/lamp_target'
idx['latest_lamp_IR_policy_A35']['linked_candidate']='../lamp_ADC_target_A42/firmware/固件/lamp_target'
idx['lamp_clean_build']={'report':'../lamp_ADC_target_A42/firmware/固件/lamp_target/build/build_verification.json','binary_sha256':build['sha256_bin'],'physical_validation':'NOT_RUN_NO_SAMPLE','led_output_enabled':False,'scope':'A42 current PCA branch hard-off image; IR and diagnostic raw ADC bound; calibrated safety and driver feedback incomplete'}
idx['manufacturing_exclusions']['lamp_A42']='Diagnostic raw ADC implemented and MMIO/target-build checked; calibrated NTC/LED sensing/driver output closure and actual physical validation remain absent; FABRICATION_HOLD.'
idx['ADC_CCRDY_gate_A41']['lamp_ADC_binding']='A42 nonblocking raw ADC implementation only; calibrated safety permissions NOT_BOUND'
ip.write_text(json.dumps(idx,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(entry,indent=2))
