from pathlib import Path
import shutil,re,subprocess
ROOT=Path(__file__).resolve().parent;BASE=ROOT.parent;SRC=BASE/'drill_interface_A31/firmware/固件';DST=ROOT/'firmware/固件'
# Sources are local bytes, not iCloud placeholders; retain originals unchanged.
for n in ['drill_target','drill_driver','drill_charge']:shutil.copytree(SRC/n,DST/n,dirs_exist_ok=True,ignore=shutil.ignore_patterns('build','__pycache__'))
for n in ['CMSIS','include']:shutil.copytree(SRC/'lamp_target'/n,DST/'lamp_target'/n,dirs_exist_ok=True)
p=DST/'drill_target/src/main.c'
s=p.read_text().replace('A1 pin map','A32 PF1 pin map').replace('gpio_c_outputs = (1u << 14u)','gpio_f_outputs = (1u << 1u)').replace('GPIOC->','GPIOF->').replace('gpio_c_outputs','gpio_f_outputs').replace('RCC_AHB2ENR_GPIOCEN','RCC_AHB2ENR_GPIOFEN')
s=s.replace('void drill_safe_boot(void) {', '''void drill_safe_boot(void) {
    /* PF1 is OSC_OUT: this image requires cold-reset HSI operation.
     * Reject HSE-enabled entry before changing the shared pad function. */
    if (RCC->CR & (RCC_CR_HSEON | RCC_CR_HSEBYP)) wait_safe();''')
p.write_text(s)
T=ROOT/'host_boot_test' ;T.mkdir(exist_ok=True)
h=(DST/'drill_target/Device/Include/stm32g431xx.h').read_text();h=re.sub(r'^#include "(?:core_cm4|system_stm32g4xx)\.h"[^\n]*','',h,flags=re.M)
(T/'device_registers.h').write_text('#include <stdint.h>\n#define __IO volatile\n#define __I volatile const\n#define __O volatile\n'+h)
(T/'stm32g4xx.h').write_text('''#include "device_registers.h"
#undef RCC
#undef GPIOA
#undef GPIOB
#undef GPIOF
#undef GPIOC
extern RCC_TypeDef host_rcc;
extern GPIO_TypeDef host_gpio_a,host_gpio_b,host_gpio_f,host_gpio_c;
#define RCC (&host_rcc)
#define GPIOA (&host_gpio_a)
#define GPIOB (&host_gpio_b)
#define GPIOF (&host_gpio_f)
#define GPIOC (&host_gpio_c)
#define __DSB() ((void)0)
#define __WFI() ((void)0)
''')
(T/'test_boot.c').write_text('''#include "stm32g4xx.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
void drill_safe_boot(void);
RCC_TypeDef host_rcc;
GPIO_TypeDef host_gpio_a,host_gpio_b,host_gpio_f,host_gpio_c;
static void check(GPIO_TypeDef *p,unsigned pin,unsigned high) {
 unsigned b=1u<<pin;
 assert(((p->MODER>>(2*pin))&3)==1);
 assert((p->OTYPER&b)==0);
 assert(((p->OSPEEDR>>(2*pin))&3)==0);
 assert(((p->PUPDR>>(2*pin))&3)==0);
 assert((p->BSRR&(high?b:b<<16))!=0);
 assert((p->BSRR&(high?b<<16:b))==0);
}
int main(void) {
 for(unsigned prior=0;prior<2;prior++) {
  memset(&host_rcc,0,sizeof host_rcc);
  memset(&host_gpio_a,prior?255:0,sizeof host_gpio_a);
  memset(&host_gpio_b,prior?255:0,sizeof host_gpio_b);
  memset(&host_gpio_f,prior?255:0,sizeof host_gpio_f);
  unsigned a=host_gpio_a.MODER,b=host_gpio_b.MODER,c=host_gpio_f.MODER;
  drill_safe_boot();
  /* Independent expected physical pins from netlist and DS12589 LQFP48. */
  check(&host_gpio_a,5,0); /* U1pin13 RUN request to connector10 */
  check(&host_gpio_f,1,0); /* U1pin6 PF1 sleep to connector9 */
  check(&host_gpio_a,8,0);check(&host_gpio_a,9,0);check(&host_gpio_a,10,0);
  check(&host_gpio_a,7,0);check(&host_gpio_b,0,0);check(&host_gpio_b,1,0);
  check(&host_gpio_a,12,1); /* U1pin34 charger enable_N default disabled */
  assert((host_rcc.AHB2ENR&(RCC_AHB2ENR_GPIOAEN|RCC_AHB2ENR_GPIOBEN|RCC_AHB2ENR_GPIOFEN))==(RCC_AHB2ENR_GPIOAEN|RCC_AHB2ENR_GPIOBEN|RCC_AHB2ENR_GPIOFEN));
  unsigned am=(3u<<10)|(3u<<14)|(3u<<16)|(3u<<18)|(3u<<20)|(3u<<24);
  unsigned bm=3u|(3u<<2),cm=3u<<2;
  assert((host_gpio_a.MODER&~am)==(a&~am));assert((host_gpio_b.MODER&~bm)==(b&~bm));assert((host_gpio_f.MODER&~cm)==(c&~cm));
 }
 puts("PASS: actual drill_safe_boot writes physical RUN/sleep/PWM-off and charger-disable pins from both prior register states; unrelated GPIO modes preserved. No physical voltages measured.");
}
''')
h=(T/'stm32g4xx.h').read_text().replace('#define __WFI() ((void)0)','void host_wait(void);\n#define __WFI() host_wait()');(T/'stm32g4xx.h').write_text(h)
t=(T/'test_boot.c').read_text().replace('#include <string.h>','#include <string.h>\n#include <setjmp.h>\n#include <stdlib.h>\nstatic jmp_buf sleep_return;\nstatic int expect_sleep;\nvoid host_wait(void) { if(expect_sleep) longjmp(sleep_return,1); abort(); }')
t=t.replace('int main(void) {','int main(void) {\n for(unsigned mode=0;mode<2;mode++) {\n  memset(&host_rcc,0,sizeof host_rcc);\n  memset(&host_gpio_f,0,sizeof host_gpio_f);\n  host_rcc.CR=mode?RCC_CR_HSEBYP:RCC_CR_HSEON;\n  expect_sleep=1;\n  if(setjmp(sleep_return)==0) { drill_safe_boot(); assert(0); }\n  expect_sleep=0;\n  assert(host_rcc.AHB2ENR==0); assert(host_gpio_f.MODER==0); assert(host_gpio_f.BSRR==0);\n }')
t=t.replace('  drill_safe_boot();','  memset(&host_gpio_c,255,sizeof host_gpio_c);\n  drill_safe_boot();\n  assert(host_gpio_c.MODER==0xffffffffu); assert(host_gpio_c.BSRR==0xffffffffu);')
t=t.replace(' for(unsigned mode=0;mode<2;mode++) {','#ifndef NEGATIVE_CONTROL\n for(unsigned mode=0;mode<2;mode++) {').replace(' for(unsigned prior=0;prior<2;prior++) {','#endif\n for(unsigned prior=0;prior<2;prior++) {')
t=t.replace('  assert(host_gpio_c.MODER==0xffffffffu); assert(host_gpio_c.BSRR==0xffffffffu);','').replace('  check(&host_gpio_f,1,0); /* U1pin6 PF1 sleep to connector9 */','  check(&host_gpio_f,1,0); /* U1pin6 PF1 sleep to connector9 */\n  assert(host_gpio_c.MODER==0xffffffffu); assert(host_gpio_c.BSRR==0xffffffffu);')
(T/'test_boot.c').write_text(t)
cmd=['cc','-std=c11','-Wall','-Wextra','-Werror','-I'+str(T),'-I'+str(DST/'drill_target/src')]
source=(DST/'drill_target/src/main.c').read_text();source=source[:source.index('int main(void)')];(T/'target_boot_translation_unit.c').write_text(source)
subprocess.run(cmd+['-c',str(T/'target_boot_translation_unit.c'),'-o',str(T/'target_main.o')],check=True)
subprocess.run(cmd+[str(T/'test_boot.c'),str(DST/'drill_target/src/drill_safe_gpio.c'),str(T/'target_main.o'),'-o',str(T/'test_boot')],check=True)
p=subprocess.run([str(T/'test_boot')],capture_output=True,text=True,check=True);(ROOT/'boot_register_test.log').write_text(p.stdout);print(p.stdout)
s=(BASE/'drill_interface_A31/build_target.sh').read_text();s=re.sub(r"ROOT='[^']+'",'ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/firmware" && pwd)',s,count=1);s=re.sub(r"OUT='[^']+'",'OUT="$TARGET/build"',s,count=1);(ROOT/'build_target.sh').write_text(s)

old=(SRC/'drill_target/src/main.c').read_text();old=old[:old.index('int main(void)')];(T/'old_boot.c').write_text(old)
subprocess.run(cmd+['-DNEGATIVE_CONTROL',str(T/'test_boot.c'),str(DST/'drill_target/src/drill_safe_gpio.c'),str(T/'old_boot.c'),'-o',str(T/'old_negative')],check=True)
p=subprocess.run([str(T/'old_negative')],capture_output=True,text=True)
assert p.returncode!=0, 'Original PC14 image must fail PF1 physical-pin expectations'
(ROOT/'negative_control.log').write_text('PASS: original A31 PC14 boot fails A32 U1pin6/PF1 expectation.\n'+p.stderr)
print('PASS: old PC14 implementation rejected by PF1 host-register expectations')
