from pathlib import Path
import shutil
R=Path(__file__).resolve().parent;B=R.parent;S=B/'sleep_gpio_A32/firmware/固件';D=R/'firmware/固件'
shutil.copytree(S,D,dirs_exist_ok=True,ignore=shutil.ignore_patterns('build','__pycache__'))
p=D/'drill_driver/drv8316.c';s=p.read_text().replace('return r->last_header ? DRV_DEVICE_FAULT : DRV_OK;','/* IC_STAT bit3 NPOR=1 means no power reset, not a fault.\n     * Reject every other bit, including unexpected reserved bit7. */\n    return (r->last_header & 0xf7u) ? DRV_DEVICE_FAULT : DRV_OK;')
s=s.replace('static drv8316_result read_status(const drv8316_hal *h, drv8316_report *r) {','static drv8316_result read_status(const drv8316_hal *h, drv8316_report *r,\n                                  bool require_no_por) {').replace('if (r->status[i]) return DRV_DEVICE_FAULT;','if (r->status[i] & (i == 0u ? 0xf7u : 0xffu))\n            return DRV_DEVICE_FAULT;')
s=s.replace('    return DRV_OK;\n}\nstatic drv8316_result write_check','    /* Startup alone permits the reset-latched zero. After CLR_FLT,\n     * NPOR must be one in both the data and each status header. */\n    if (require_no_por && (!(r->status[0] & 0x08u) ||\n                           !(r->last_header & 0x08u)))\n        return DRV_DEVICE_FAULT;\n    return DRV_OK;\n}\nstatic drv8316_result write_check')
s=s.replace('return data == val ? DRV_OK : DRV_READBACK;','/* Control2 CLR_FLT is W1C and self-clears; it is not read back as one. */\n    uint8_t expected = addr == 0x04u ? (uint8_t)(val & 0xfeu) : val;\n    return data == expected ? DRV_OK : DRV_READBACK;')
s=s.replace('read_status(h, r);','read_status(h, r, true);',2) # initial then final
s=s.replace('drv8316_result s = read_status(h, r, true);\n    if (s != DRV_OK) return stop(h, r, s);\n    static','drv8316_result s = read_status(h, r, false);\n    if (s != DRV_OK) return stop(h, r, s);\n    static')
s=s.replace('read_status(h, r);','read_status(h, r, true);').replace('{0x04, 0x42}, /* preserve reserved bit6; open-drain SDO; 6x PWM cycle-by-cycle current limit */','{0x04, 0x43}, /* reserved bit6; open-drain SDO; 6x CBC; W1C CLR_FLT acknowledges startup NPOR */')
p.write_text(s)
p=D/'drill_driver/test_drv8316.c';s=p.read_text().replace('if(addr==3 || m->regs[3]==3) m->regs[addr]=(uint8_t)tx;','''if(addr==3 || m->regs[3]==3) {
            m->regs[addr]=(uint8_t)tx;
            if(addr==4 && (tx&1u)) {
                m->regs[4]&=0xfeu; /* real Control2 W1C self-clears */
                m->regs[0]=0x08u; /* Table8-13 no power reset after CLR_FLT */
                m->regs[1]=m->regs[2]=0;
            }
        }''').replace('*rx=previous; /* write response intentionally OLD value */','*rx=(uint16_t)(((uint16_t)m->regs[0]<<8)|previous); /* status header + OLD write data */')
s=s.replace('    unsigned count=m.calls;','    assert(report.status[0]==0x08u && report.last_header==0x08u);\n    unsigned count=m.calls;')
s=s.replace('    zh.transfer16=NULL;', '''    /* Subsequent VM POR must invalidate config, even with no positive fault bits. */
    z.regs[0]=0;
    assert(drv8316_poll_faults(&zh,&report)==DRV_DEVICE_FAULT);
    assert(!report.configured && z.off && !z.awake && z.enable_calls==0);
    assert(drv8316_configure_off(&zh,&report)==DRV_OK);
    zh.transfer16=NULL;''')
s=s.replace('3 fault registers; output never enabled.','3 fault registers; normal NPOR headers/data; W1C self-clear; runtime POR rejected; output never enabled.')
p.write_text(s)
shutil.copyfile(B/'sleep_gpio_A32/build_target.sh',R/'build_target.sh')
