import csv
import os
import pprint
import subprocess
from base import Write
DRY_RUN = False
SCRIPT = os.path.relpath(__file__, os.getcwd()).replace("\\", "/")
REMAP_MODES = {
"DEFAULT": "RemapDefault",
"PARTIAL_REMAP": "RemapPartial1",
"PARTIAL_REMAP1": "RemapPartial1",
"PARTIAL_REMAP2": "RemapPartial2",
"FULL_REMAP": "RemapFull",
"REMAP": "RemapFull",
}
CFG_TABLE = {
"TIM1": '#[cfg(any(feature = "f100", feature = "f103", feature = "connectivity"))]',
"TIM4": '#[cfg(feature = "medium")]',
"TIM5": '#[cfg(any(feature = "high", feature = "connectivity"))]',
"TIM6": '#[cfg(any(feature = "f100", feature = "high", feature = "connectivity"))]',
"TIM7": '#[cfg(any(all(feature = "high", any(feature = "f101", feature = "f103")),any(feature = "f100", feature = "connectivity")))]',
"TIM8": '#[cfg(all(feature = "f103", feature = "high"))]',
"TIM9": '#[cfg(feature = "xl")]',
"TIM10": '#[cfg(feature = "xl")]',
"TIM11": '#[cfg(feature = "xl")]',
"TIM12": '#[cfg(any(feature = "xl", all(feature = "f100", feature = "high",)))]',
"TIM13": '#[cfg(any(feature = "xl", all(feature = "f100", feature = "high",)))]',
"TIM14": '#[cfg(any(feature = "xl", all(feature = "f100", feature = "high",)))]',
"TIM15": '#[cfg(feature = "f100")]',
"TIM16": '#[cfg(feature = "f100")]',
"TIM17": '#[cfg(feature = "f100")]',
"SPI3": '#[cfg(feature = "connectivity")]',
}
def match_filter(filter: str, name: str) -> bool:
if filter == "UART":
return name.startswith("UART") or name.startswith("USART")
return name.startswith(filter)
def func_pin_name(filter: str, func: str) -> str:
return filter[0] + filter[1:].lower() + func[0] + func[1:].lower() + "Pin"
REG_OP_TEMPLATE = """impl RemapMode<{peri}> for {mode}<{peri}> {{
fn remap(afio: &mut Afio) {{
{op}
}}
}}
"""
def write_reg_operation(d: dict, filter: str, w: Write) -> None:
w.write("\n// Register operations ------------\n\n")
for peri, remap_modes in sorted(d.items()):
if match_filter(filter, peri):
for mode_name, mode_info in sorted(remap_modes.items()):
mode = REMAP_MODES[mode_name]
reg = mode_info["reg"]
bits: str = mode_info["bits"]
if reg == "none":
op = ""
elif peri == "TIM5":
b = "set_bit" if bits[2] == "1" else "clear_bit"
op = f"afio.{reg}.modify_mapr(|_, w| w.{peri.lower()}ch4_iremap().{b}());"
elif len(bits) == 3:
b = "set_bit" if bits[2] == "1" else "clear_bit"
op = f"afio.{reg}.modify_mapr(|_, w| w.{peri.lower()}_remap().{b}());"
elif len(bits) == 4:
b = f"unsafe {{|_, w| w.{peri.lower()}_remap().bits({bits})}}"
op = f"afio.{reg}.modify_mapr({b});"
else:
continue
w.write(CFG_TABLE.get(peri, ""))
w.write(REG_OP_TEMPLATE.format(mode=mode, peri=peri, op=op))
BIND_ALT_TYPE = """pub trait {func}<REMAP> {{
type P;
fn into_alternate(self) -> Self::P;
"""
BIND_IS_PIN = """ fn is_pin(&self) -> bool {
true
}
}
"""
def write_binder_type(d: dict, filter: str, w: Write) -> None:
w.write("\n// Binder types ------------------\n\n")
func_list: list[str] = []
for peri, remap_modes in d.items():
if match_filter(filter, peri):
for mode_info in remap_modes.values():
for pin_func in mode_info["pins"].keys():
func_list.append(pin_func)
func_list = sorted(list(set(func_list)))
for func in func_list:
name = func_pin_name(filter, func)
if filter == "I2C" or name in ["SpiSckPin", "SpiNssPin"]:
w.write(BIND_ALT_TYPE.format(func=name) + "}")
elif name.startswith("TimCh") or name in ["UartTxPin", "UartCkPin", "SpiMosiPin"]:
w.write(BIND_ALT_TYPE.format(func=name) + BIND_IS_PIN)
w.write(f"impl_for_none_pin_into!({name});")
elif filter in ["UART", "TIM"]:
w.write("pub trait {}<REMAP> {{".format(name) + BIND_IS_PIN)
w.write(f"impl_for_none_pin!({name});")
else:
w.write(f"pub trait {name}<REMAP>{{}}")
w.write("\n")
BIND_PIN = """impl {func}<{remap}<{peri}>> for {pin}<Input> {{
type P = {pin}<Alternate<{alt}>>;
fn into_alternate(self) -> Self::P {{
self.into_mode(&mut Cr)
}}
}}
"""
IMPL_TEMPLATE_LIST = [
(
["UartRxPin", "SpiMisoPin"],
"impl<UP: UpMode> {func}<{remap}<{peri}>> for {pin}<Input<UP>>{{}}",
"",
),
(
[
"UartTxPin",
"UartCkPin",
"TimCh1Pin",
"TimCh2Pin",
"TimCh3Pin",
"TimCh4Pin",
"SpiSckPin",
"SpiMosiPin",
"SpiNssPin",
],
BIND_PIN,
"PushPull",
),
(["I2cSclPin", "I2cSdaPin"], BIND_PIN, "OpenDrain"),
]
def get_impl_template(func: str) -> tuple[str, str]:
for item in IMPL_TEMPLATE_LIST:
if func in item[0]:
return (item[1], item[2])
return ("", "")
def write_item(filter: str, peri: str, remap: str, pins: dict[str, str], w: Write) -> None:
for pin_func, pin in sorted(pins.items()):
func = func_pin_name(filter, pin_func)
(impl, alt) = get_impl_template(func)
if impl:
cfg = CFG_TABLE.get(peri, "")
if cfg:
w.write(cfg)
w.write(impl.format(func=func, remap=remap, peri=peri, pin=pin, alt=alt))
def write_table(d: dict, filter: str, csv_file: str, target_file: str) -> None:
with open(target_file, "r", encoding="utf-8") as f:
code = f.read()
i = code.find("// table") + len("// table")
before = code[:i]
code = code[i:]
w = Write(target_file, DRY_RUN)
w.write(before)
w.write("\n// Do NOT manually modify the code.\n")
w.write(
f"// It's generated by {SCRIPT} from {csv_file}\n",
)
write_binder_type(d, filter, w)
w.write("\n// Bind pins ---------------------\n\n")
for peri, remap_modes in sorted(d.items()):
if match_filter(filter, peri):
for mode_name, mode_info in sorted(remap_modes.items()):
remap = REMAP_MODES[mode_name]
write_item(filter, peri, remap, mode_info["pins"], w)
w.write("\n")
write_reg_operation(d, filter, w)
w.close()
subprocess.run(["rustfmt", target_file])
def parse_remap_info(row: list[str], ret_d: dict) -> None:
peripheral = row[0]
reg = row[1]
remap_mode = row[2]
reg_bits = row[3]
pins: dict[str, str] = {}
for pin in row[4:]:
if pin:
(func, pin) = pin.split(":")
if "/" in func:
(f1, f2) = func.split("/")
pins[f1] = pin
pins[f2] = pin
else:
pins[func] = pin
p = ret_d.setdefault(peripheral, {})
p[remap_mode] = {
"reg": reg,
"bits": reg_bits,
"pins": pins,
}
def csv_to_code(csv_file: str, show: bool = False) -> None:
print(csv_file)
d: dict = {}
with open(csv_file, newline="", encoding="utf-8") as f:
reader = csv.reader(f, delimiter=",", quotechar='"')
for row in reader:
if row[0]:
parse_remap_info(row, d)
if show:
pprint.pprint(d)
write_table(d, "UART", csv_file, "src/afio/uart_remap.rs")
write_table(d, "TIM", csv_file, "src/afio/timer_remap.rs")
write_table(d, "I2C", csv_file, "src/afio/i2c_remap.rs")
write_table(d, "SPI", csv_file, "src/afio/spi_remap.rs")
if __name__ == "__main__":
csv_to_code("scripts/table/stm32f1_remap_peripheral.csv")