modm_data.owl.stmicro
1# Copyright 2022, Niklas Hauser 2# SPDX-License-Identifier: MPL-2.0 3 4from .device import owls, owl_devices, owl_device, load_owl_device 5from .identifier import did_from_string 6from .ontology import create_ontology 7from .model import ( 8 owl_from_datasheet, 9 owl_from_reference_manual, 10 owl_from_doc, 11 owl_from_did, 12 owl_from_cubemx, 13 owl_from_header, 14) 15 16__all__ = [ 17 "owls", 18 "owl_devices", 19 "owl_device", 20 "load_owl_device", 21 "did_from_string", 22 "create_ontology", 23 "owl_from_datasheet", 24 "owl_from_reference_manual", 25 "owl_from_doc", 26 "owl_from_did", 27 "owl_from_cubemx", 28 "owl_from_header", 29]
def
owls():
def
owl_devices():
23def owl_devices(): 24 global _OWL_MAPPING, _OWL_MAPPING_FILE 25 if _OWL_MAPPING is None: 26 if not _OWL_MAPPING_FILE.exists(): 27 _OWL_MAPPING = {} 28 for ds in owls(): 29 if ds.startswith("DS"): 30 owl.store.load(ds) 31 for name in set(i.name for i in owl.Device.instances()): 32 _OWL_MAPPING[name] = ds 33 34 _OWL_MAPPING_FILE.parent.mkdir(parents=True, exist_ok=True) 35 with _OWL_MAPPING_FILE.open("w", encoding="utf-8") as fh: 36 json.dump(_OWL_MAPPING, fh, indent=4) 37 else: 38 with _OWL_MAPPING_FILE.open("r", encoding="utf-8") as fh: 39 _OWL_MAPPING = json.load(fh) 40 return _OWL_MAPPING
def
owl_device(device):
def
load_owl_device(device) -> bool:
8def did_from_string(string) -> DeviceIdentifier: 9 string = string.lower() 10 11 if string.startswith("stm32"): 12 schema = "{platform}{family}{name}{pin}{size}{package}{temperature}{variant}" 13 if "@" in string: 14 schema += "@{core}" 15 i = DeviceIdentifier(schema) 16 i.set("platform", "stm32") 17 i.set("family", string[5:7]) 18 i.set("name", string[7:9]) 19 i.set("pin", string[9]) 20 i.set("size", string[10]) 21 i.set("package", string[11]) 22 i.set("temperature", string[12]) 23 if "@" in string: 24 string, core = string.split("@") 25 i.set("core", core) 26 if len(string) >= 14: 27 i.set("variant", string[13]) 28 else: 29 i.set("variant", "") 30 return i 31 32 raise ValueError(f"Unknown identifier '{string}'!")
def
create_ontology(did):
20def create_ontology(did): 21 store = Store("stmicro", did.string) 22 ontology = store.ontology 23 24 # --------------------------- DEVICE IDENTIFIER --------------------------- 25 class DeviceIdentifier(owl.Thing): 26 namespace = ontology 27 comment = "The unique identifier (part number) of the device." 28 29 class hasDeviceSchema(owl.DataProperty, owl.FunctionalProperty): 30 namespace = ontology 31 comment = "How to format the device identifier." 32 domain = [DeviceIdentifier] 33 range = [str] 34 35 class hasDevicePlatform(owl.DataProperty, owl.FunctionalProperty): 36 namespace = ontology 37 domain = [DeviceIdentifier] 38 range = [str] 39 40 class hasDeviceFamily(owl.DataProperty, owl.FunctionalProperty): 41 namespace = ontology 42 domain = [DeviceIdentifier] 43 range = [str] 44 45 class hasDeviceName(owl.DataProperty, owl.FunctionalProperty): 46 namespace = ontology 47 domain = [DeviceIdentifier] 48 range = [str] 49 50 class hasDevicePin(owl.DataProperty, owl.FunctionalProperty): 51 namespace = ontology 52 domain = [DeviceIdentifier] 53 range = [str] 54 55 class hasDeviceSize(owl.DataProperty, owl.FunctionalProperty): 56 namespace = ontology 57 domain = [DeviceIdentifier] 58 range = [str] 59 60 class hasDevicePackage(owl.DataProperty, owl.FunctionalProperty): 61 namespace = ontology 62 domain = [DeviceIdentifier] 63 range = [str] 64 65 class hasDeviceTemperature(owl.DataProperty, owl.FunctionalProperty): 66 namespace = ontology 67 domain = [DeviceIdentifier] 68 range = [str] 69 70 class hasDeviceVariant(owl.DataProperty, owl.FunctionalProperty): 71 namespace = ontology 72 domain = [DeviceIdentifier] 73 range = [str] 74 75 class hasDeviceCore(owl.DataProperty, owl.FunctionalProperty): 76 namespace = ontology 77 domain = [DeviceIdentifier] 78 range = [str] 79 80 # ------------------------------- MEMORIES -------------------------------- 81 class Memory(owl.Thing): 82 namespace = ontology 83 comment = "Internal memory." 84 85 class hasMemoryStartAddress(owl.DataProperty, owl.FunctionalProperty): 86 namespace = ontology 87 domain = [Memory] 88 range = [int] 89 90 class hasMemorySize(owl.DataProperty, owl.FunctionalProperty): 91 namespace = ontology 92 domain = [Memory] 93 range = [int] 94 95 class hasMemoryAccess(owl.DataProperty, owl.FunctionalProperty): 96 namespace = ontology 97 domain = [Memory] 98 range = [str] 99 100 class hasMemory(DeviceIdentifier >> Memory): 101 namespace = ontology 102 103 # ------------------------------ INTERRUPTS ------------------------------- 104 class InterruptVector(owl.Thing): 105 namespace = ontology 106 comment = "Interrupt vector in the table." 107 108 class hasInterruptVectorPosition(owl.DataProperty, owl.FunctionalProperty): 109 namespace = ontology 110 domain = [InterruptVector] 111 range = [int] 112 113 class hasInterruptVector(owl.ObjectProperty): 114 namespace = ontology 115 domain = [DeviceIdentifier] 116 range = [InterruptVector] 117 118 # --------------------------------- PINS ---------------------------------- 119 class Package(owl.Thing): 120 namespace = ontology 121 comment = "A device package identifier" 122 domain = [DeviceIdentifier] 123 124 class hasPackagePinCount(owl.DataProperty, owl.FunctionalProperty): 125 namespace = ontology 126 domain = [Package] 127 range = [int] 128 129 class hasPackage(DeviceIdentifier >> Package): 130 namespace = ontology 131 132 class Pin(owl.Thing): 133 namespace = ontology 134 comment = "A pin on a package." 135 136 class hasPinType(owl.DataProperty, owl.FunctionalProperty): 137 namespace = ontology 138 domain = [Pin] 139 range = [str] 140 141 class hasPinNumber(owl.DataProperty, owl.FunctionalProperty): 142 namespace = ontology 143 domain = [Pin] 144 range = [int] 145 146 class hasPort(owl.DataProperty, owl.FunctionalProperty): 147 namespace = ontology 148 domain = [Pin] 149 range = [str] 150 151 class hasPin(owl.ObjectProperty): 152 namespace = ontology 153 domain = [Package] 154 range = [Pin] 155 156 class pinPosition(owl.AnnotationProperty): 157 namespace = ontology 158 comment = "The pin position attached to the [Package, hasPin, Pin] relation." 159 160 # -------------------------------- SIGNALS -------------------------------- 161 class Signal(owl.Thing): 162 namespace = ontology 163 comment = "Connects a pin with a peripheral function." 164 165 class AlternateFunction(Signal): 166 namespace = ontology 167 comment = "Connects to a digital peripheral function via multiplexer." 168 169 class AdditionalFunction(Signal): 170 namespace = ontology 171 comment = "Connects to an analog/special peripheral function." 172 173 class hasSignal(owl.ObjectProperty): 174 namespace = ontology 175 domain = [Pin] 176 range = [Signal] 177 178 class alternateFunction(owl.AnnotationProperty): 179 namespace = ontology 180 comment = "The AF number attached to the [Pin, hasSignal, AlternateFunction] relation." 181 182 # ------------------------------ PERIPHERALS ------------------------------ 183 class Peripheral(owl.Thing): 184 namespace = ontology 185 comment = "Internal peripheral." 186 187 class hasPeripheralInstance(owl.DataProperty, owl.FunctionalProperty): 188 namespace = ontology 189 domain = [Peripheral] 190 range = [int] 191 192 class hasPeripheralType(owl.DataProperty, owl.FunctionalProperty): 193 namespace = ontology 194 domain = [Peripheral] 195 range = [str] 196 197 class hasPeripheral(owl.ObjectProperty): 198 namespace = ontology 199 domain = [DeviceIdentifier, Signal] 200 range = [Peripheral] 201 202 # ----------------------------- FLASH LATENCY ----------------------------- 203 class FlashWaitState(owl.Thing): 204 namespace = ontology 205 comment = "Flash Latency for minimum frequency." 206 207 class hasWaitState(owl.DataProperty, owl.FunctionalProperty): 208 namespace = ontology 209 domain = [FlashWaitState] 210 range = [int] 211 212 class hasMaxFrequency(owl.DataProperty, owl.FunctionalProperty): 213 namespace = ontology 214 domain = [FlashWaitState] 215 range = [int] 216 217 class hasMinOperatingVoltage(owl.DataProperty, owl.FunctionalProperty): 218 namespace = ontology 219 domain = [FlashWaitState] 220 range = [float] 221 222 class hasFlashWaitState(owl.ObjectProperty): 223 namespace = ontology 224 domain = [DeviceIdentifier] 225 range = [FlashWaitState] 226 227 # -------------------------------- GENERAL -------------------------------- 228 class hasName(owl.DataProperty, owl.FunctionalProperty): 229 namespace = ontology 230 domain = [Memory, Signal, Peripheral, Package, Pin] 231 range = [str] 232 233 return KeyDict(locals())
def
owl_from_datasheet(onto, ds):
def
owl_from_reference_manual(onto, rm):
13def owl_from_reference_manual(onto, rm): 14 odid = onto.DeviceIdentifier(onto.did.string.lower()) 15 16 dfilter = find_device_filter(onto.did, rm.flash_latencies) 17 table_data = rm.flash_latencies[dfilter] 18 print(dfilter, table_data) 19 for min_voltage, frequencies in table_data.items(): 20 # print(min_voltage, frequencies) 21 for wait_state, max_frequency in enumerate(frequencies): 22 ofreq = onto.FlashWaitState(f"WaitState_{wait_state}_{min_voltage}mV") 23 ofreq.hasWaitState = wait_state 24 ofreq.hasMaxFrequency = int(max_frequency * 1e6) 25 ofreq.hasMinOperatingVoltage = min_voltage / 1000.0 26 odid.hasFlashWaitState.append(ofreq)
def
owl_from_doc(onto, doc):
def
owl_from_did(onto):
36def owl_from_did(onto): 37 # Add device identifiers 38 odid = onto.DeviceIdentifier(onto.did.string.lower()) 39 odid.hasDeviceSchema = onto.did.naming_schema 40 odid.hasDevicePlatform = onto.did.platform 41 odid.hasDeviceFamily = onto.did.family 42 odid.hasDeviceName = onto.did.name 43 odid.hasDevicePin = onto.did.pin 44 odid.hasDeviceSize = onto.did.size 45 odid.hasDevicePackage = onto.did.package 46 odid.hasDeviceTemperature = onto.did.temperature 47 odid.hasDeviceVariant = onto.did.variant 48 if onto.did.get("core", False): 49 odid.hasDeviceCore = onto.did.core
def
owl_from_cubemx(onto, data):
52def owl_from_cubemx(onto, data): 53 odid = onto.DeviceIdentifier(onto.did.string.lower()) 54 55 # Add internal memories 56 for memory in data["memories"]: 57 omem = onto.Memory("Memory_" + memory["name"].upper()) 58 odid.hasMemory.append(omem) 59 omem.hasName = memory["name"].upper() 60 omem.hasMemoryStartAddress = int(memory["start"], 16) 61 omem.hasMemorySize = int(memory["size"]) 62 omem.hasMemoryAccess = memory["access"] 63 64 # Add the peripherals and their type 65 for pbase, name, version, ptype, features, stype in data["modules"]: 66 oper = onto.Peripheral("Peripheral_" + name.upper()) 67 odid.hasPeripheral.append(oper) 68 oper.hasName = name.upper() 69 if pbase != name: 70 oper.hasPeripheralInstance = int(name.replace(pbase, "")) 71 oper.hasPeripheralType = pbase + ptype.replace("stm32", "") 72 73 # Add package 74 opack = onto.Package("Package_" + data["package"]) 75 opack.hasName = str(data["package"]) 76 odid.hasPackage.append(opack) 77 opack.hasPackagePinCount = int(data["pin-count"]) 78 79 # Add pinout for package 80 io_pins = {} 81 for pin in data["pinout"]: 82 opin = onto.Pin("Pin_" + pin["name"]) 83 opin.hasName = pin["name"] 84 opin.hasPinType = pin["type"] 85 if pin["type"] == "I/O" and (number := re.search(r"P\w(\d+)", pin["name"])): 86 opin.hasPort = pin["name"][1] 87 opin.hasPinNumber = int(number.group(1)) 88 io_pins[(opin.hasPort.lower(), opin.hasPinNumber)] = opin 89 opack.hasPin.append(opin) 90 onto.pinPosition[opack, onto.hasPin, opin].append(pin["position"]) 91 92 # Add alternate and additional functions to pins 93 for port, number, signals in data["gpios"]: 94 opin = io_pins[(port, int(number))] 95 for signal in signals: 96 peripheral = (signal["driver"] or "").upper() + (signal["instance"] or "") 97 name = signal["name"].upper() 98 af = signal["af"] 99 signame = "Signal_" + peripheral + "_" + name 100 osig = onto.AlternateFunction(signame) if af else onto.AdditionalFunction(signame) 101 osig.hasPeripheral.append(onto.Peripheral("Peripheral_" + peripheral)) 102 osig.hasName = name 103 opin.hasSignal.append(osig) 104 if af: 105 onto.alternateFunction[opin, onto.hasSignal, osig].append(int(af))
def
owl_from_header(onto, header):
108def owl_from_header(onto, header): 109 odid = onto.DeviceIdentifier(onto.did.string.lower()) 110 111 # Add interrupt vector table 112 for interrupt in header.interrupt_table: 113 if interrupt["position"] >= 0: 114 oint = onto.InterruptVector("InterruptVector_" + interrupt["name"]) 115 oint.hasInterruptVectorPosition = interrupt["position"] 116 odid.hasInterruptVector.append(oint)