Compare commits

...
Author SHA1 Message Date
d4rks1d33 99ac826a49 Added script to easily add new tables to modulation hopping (depending on which specific modulation you want to use)
Build Dev Firmware / build (push) Successful in 17m30s
2026-06-13 17:12:39 -03:00
+154
View File
@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
Generates delta {reg,val} tables between the 3 hopper presets (AM650, FM476, FM95) for fast hopping without SRES.
Uses CC1101 power-on-reset (POR) values for registers that a preset doesn't explicitly set, since the current flow performs SRES before loading each preset (which resets those registers to their default values).
Sources:
- AM650 = subghz_device_cc1101_preset_ook_650khz_async_regs (cc1101_configs.c)
- FM476 = subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs (cc1101_configs.c)
- FM95 = Custom_preset_data in setting_user
"""
# POR values (CC1101 datasheet Table 23) for records that
# appear in at least one of the 3 presets but not all.
POR_DEFAULTS = {
0x02: 0x3F, # IOCFG0
0x03: 0x07, # FIFOTHR
0x07: 0x04, # PKTCTRL1
0x08: 0x45, # PKTCTRL0
0x0B: 0x0F, # FSCTRL1
0x10: 0x8C, # MDMCFG4
0x11: 0x22, # MDMCFG3
0x12: 0x02, # MDMCFG2
0x13: 0x22, # MDMCFG1
0x14: 0xF8, # MDMCFG0
0x15: 0x47, # DEVIATN
0x18: 0x18, # MCSM0
0x19: 0x14, # FOCCFG
0x1B: 0x03, # AGCCTRL2
0x1C: 0x40, # AGCCTRL1
0x1D: 0x91, # AGCCTRL0
0x20: 0xFB, # WORCTRL
0x21: 0x56, # FREND1
0x22: 0x10, # FREND0
}
# Registers that, if changed, force SCAL (synthesizer recalibration)
FREQ_SYNTH_REGS = {0x0B, 0x0C, 0x0D, 0x0E, 0x0F} # FSCTRL1/0, FREQ2/1/0
# Explicit definitions (only what each preset actually writes)
AM650 = {
0x02: 0x0D, 0x03: 0x07, 0x08: 0x32, 0x0B: 0x06,
0x10: 0x17, 0x11: 0x32, 0x12: 0x30, 0x13: 0x00, 0x14: 0x00,
0x18: 0x18, 0x19: 0x18, 0x1B: 0x07, 0x1C: 0x00, 0x1D: 0x91,
0x20: 0xFB, 0x21: 0xB6, 0x22: 0x11,
}
AM650_PA = [0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
FM476 = {
0x02: 0x0D, 0x07: 0x04, 0x08: 0x32, 0x0B: 0x06,
0x10: 0x67, 0x11: 0x83, 0x12: 0x04, 0x13: 0x02, 0x14: 0x00, 0x15: 0x47,
0x18: 0x18, 0x19: 0x16, 0x1B: 0x07, 0x1C: 0x00, 0x1D: 0x91,
0x20: 0xFB, 0x21: 0x56, 0x22: 0x10,
}
FM476_PA = [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
FM95 = {
0x02: 0x0D, 0x07: 0x04, 0x08: 0x32, 0x0B: 0x06,
0x10: 0x67, 0x11: 0x83, 0x12: 0x04, 0x13: 0x02, 0x15: 0x24,
0x18: 0x18, 0x19: 0x16, 0x1B: 0x07, 0x1C: 0x00, 0x1D: 0x91,
0x20: 0xFB, 0x21: 0x56, 0x22: 0x10,
}
FM95_PA = [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
PRESETS = {
"AM650": (AM650, AM650_PA),
"FM476": (FM476, FM476_PA),
"FM95": (FM95, FM95_PA),
}
# Union of all records played by at least one preset
ALL_REGS = sorted(set().union(*[set(r.keys()) for r, _ in PRESETS.values()]))
def effective(regs):
"""Applies POR defaults to ALL_REGS records not explicitly set."""
out = {}
for reg in ALL_REGS:
if reg in regs:
out[reg] = regs[reg]
elif reg in POR_DEFAULTS:
out[reg] = POR_DEFAULTS[reg]
else:
raise ValueError(f"Reg 0x{reg:02X} without known default POR")
return out
def gen_delta(name_a, name_b):
eff_a = effective(PRESETS[name_a][0])
eff_b = effective(PRESETS[name_b][0])
pa_a, pa_b = PRESETS[name_a][1], PRESETS[name_b][1]
delta = []
needs_scal = False
for reg in ALL_REGS:
if eff_a[reg] != eff_b[reg]:
delta.append((reg, eff_b[reg]))
if reg in FREQ_SYNTH_REGS:
needs_scal = True
pa_changed = (pa_a != pa_b)
return delta, needs_scal, (pa_b if pa_changed else None)
def main():
names = list(PRESETS.keys())
print("// === Auto-generated by gen_preset_delta.py ===")
print("// subghz_preset_delta.c\n")
print('#include <stdint.h>')
print('#include <stddef.h>')
print('#include "subghz_preset_delta.h"\n')
entries = {}
for a in names:
for b in names:
if a == b:
continue
delta, needs_scal, pa = gen_delta(a, b)
sym = f"preset_delta_{a}_to_{b}"
print(f"// {a} -> {b}: {len(delta)} records change"
f"{' (+SCAL)' if needs_scal else ''}"
f"{' (+PA)' if pa else ''}")
print(f"static const uint8_t {sym}[] = {{")
for reg, val in delta:
print(f" 0x{reg:02X}, 0x{val:02X},")
print("};")
if pa:
pa_sym = f"{sym}_pa"
print(f"static const uint8_t {pa_sym}[8] = {{ " +
", ".join(f"0x{x:02X}" for x in pa) + " };")
else:
pa_sym = "NULL"
print()
entries[(a, b)] = (sym, len(delta) * 2, needs_scal, pa_sym)
# Lookup table
print("// Order: HOP_AM650=0, HOP_FM476=1, HOP_FM95=2")
print("const PresetDeltaEntry preset_delta_table[HOP_PRESET_COUNT][HOP_PRESET_COUNT] = {")
for a in names:
print(" {")
for b in names:
if a == b:
print(" {0}, // self, unused")
continue
sym, dlen, scal, pa_sym = entries[(a, b)]
print(f" {{ .delta = {sym}, .delta_len = {dlen}, "
f".needs_scal = {'true' if scal else 'false'}, "
f".pa_table = {pa_sym} }}, // {a} -> {b}")
print(" },")
print("};")
if __name__ == "__main__":
main()