first commit
This commit is contained in:
222
MultiMicphoneLocat.ioc
Normal file
222
MultiMicphoneLocat.ioc
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
#MicroXplorer Configuration settings - do not modify
|
||||||
|
CAD.formats=[]
|
||||||
|
CAD.pinconfig=Dual
|
||||||
|
CAD.provider=Component Search Engine
|
||||||
|
DFSDM2.Filter_regChannel_FIL0=DFSDM_CHANNEL_0
|
||||||
|
DFSDM2.Filter_regChannel_FIL1=DFSDM_CHANNEL_1
|
||||||
|
DFSDM2.Filter_regChannel_FIL2=DFSDM_CHANNEL_2
|
||||||
|
DFSDM2.IPParameters=Filter_regChannel_FIL0,Filter_regChannel_FIL1,Filter_regChannel_FIL2,Selection
|
||||||
|
DFSDM2.Selection=DFSDM_CHANNEL_OUTPUT_CLOCK_SYSTEM
|
||||||
|
Dma.DFSDM2_FLT0.0.Direction=DMA_PERIPH_TO_MEMORY
|
||||||
|
Dma.DFSDM2_FLT0.0.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||||
|
Dma.DFSDM2_FLT0.0.Instance=DMA2_Stream0
|
||||||
|
Dma.DFSDM2_FLT0.0.MemDataAlignment=DMA_MDATAALIGN_WORD
|
||||||
|
Dma.DFSDM2_FLT0.0.MemInc=DMA_MINC_ENABLE
|
||||||
|
Dma.DFSDM2_FLT0.0.Mode=DMA_NORMAL
|
||||||
|
Dma.DFSDM2_FLT0.0.PeriphDataAlignment=DMA_PDATAALIGN_WORD
|
||||||
|
Dma.DFSDM2_FLT0.0.PeriphInc=DMA_PINC_DISABLE
|
||||||
|
Dma.DFSDM2_FLT0.0.Priority=DMA_PRIORITY_LOW
|
||||||
|
Dma.DFSDM2_FLT0.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||||
|
Dma.DFSDM2_FLT1.1.Direction=DMA_PERIPH_TO_MEMORY
|
||||||
|
Dma.DFSDM2_FLT1.1.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||||
|
Dma.DFSDM2_FLT1.1.Instance=DMA2_Stream1
|
||||||
|
Dma.DFSDM2_FLT1.1.MemDataAlignment=DMA_MDATAALIGN_WORD
|
||||||
|
Dma.DFSDM2_FLT1.1.MemInc=DMA_MINC_ENABLE
|
||||||
|
Dma.DFSDM2_FLT1.1.Mode=DMA_NORMAL
|
||||||
|
Dma.DFSDM2_FLT1.1.PeriphDataAlignment=DMA_PDATAALIGN_WORD
|
||||||
|
Dma.DFSDM2_FLT1.1.PeriphInc=DMA_PINC_DISABLE
|
||||||
|
Dma.DFSDM2_FLT1.1.Priority=DMA_PRIORITY_LOW
|
||||||
|
Dma.DFSDM2_FLT1.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||||
|
Dma.DFSDM2_FLT2.2.Direction=DMA_PERIPH_TO_MEMORY
|
||||||
|
Dma.DFSDM2_FLT2.2.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||||
|
Dma.DFSDM2_FLT2.2.Instance=DMA2_Stream2
|
||||||
|
Dma.DFSDM2_FLT2.2.MemDataAlignment=DMA_MDATAALIGN_WORD
|
||||||
|
Dma.DFSDM2_FLT2.2.MemInc=DMA_MINC_ENABLE
|
||||||
|
Dma.DFSDM2_FLT2.2.Mode=DMA_NORMAL
|
||||||
|
Dma.DFSDM2_FLT2.2.PeriphDataAlignment=DMA_PDATAALIGN_WORD
|
||||||
|
Dma.DFSDM2_FLT2.2.PeriphInc=DMA_PINC_DISABLE
|
||||||
|
Dma.DFSDM2_FLT2.2.Priority=DMA_PRIORITY_LOW
|
||||||
|
Dma.DFSDM2_FLT2.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||||
|
Dma.Request0=DFSDM2_FLT0
|
||||||
|
Dma.Request1=DFSDM2_FLT1
|
||||||
|
Dma.Request2=DFSDM2_FLT2
|
||||||
|
Dma.RequestsNb=3
|
||||||
|
File.Version=6
|
||||||
|
GPIO.groupedBy=Group By Peripherals
|
||||||
|
KeepUserPlacement=false
|
||||||
|
Mcu.CPN=STM32F413RGT6
|
||||||
|
Mcu.Family=STM32F4
|
||||||
|
Mcu.IP0=DFSDM2
|
||||||
|
Mcu.IP1=DMA
|
||||||
|
Mcu.IP2=NVIC
|
||||||
|
Mcu.IP3=RCC
|
||||||
|
Mcu.IP4=SPI1
|
||||||
|
Mcu.IP5=SYS
|
||||||
|
Mcu.IP6=USART1
|
||||||
|
Mcu.IPNb=7
|
||||||
|
Mcu.Name=STM32F413R(G-H)Tx
|
||||||
|
Mcu.Package=LQFP64
|
||||||
|
Mcu.Pin0=PH0 - OSC_IN
|
||||||
|
Mcu.Pin1=PH1 - OSC_OUT
|
||||||
|
Mcu.Pin10=PB3
|
||||||
|
Mcu.Pin11=PB4
|
||||||
|
Mcu.Pin12=PB5
|
||||||
|
Mcu.Pin13=VP_SYS_VS_Systick
|
||||||
|
Mcu.Pin2=PA7
|
||||||
|
Mcu.Pin3=PC5
|
||||||
|
Mcu.Pin4=PB10
|
||||||
|
Mcu.Pin5=PC9
|
||||||
|
Mcu.Pin6=PA9
|
||||||
|
Mcu.Pin7=PA10
|
||||||
|
Mcu.Pin8=PA13
|
||||||
|
Mcu.Pin9=PA14
|
||||||
|
Mcu.PinsNb=14
|
||||||
|
Mcu.ThirdPartyNb=0
|
||||||
|
Mcu.UserConstants=
|
||||||
|
Mcu.UserName=STM32F413RGTx
|
||||||
|
MxCube.Version=6.16.1
|
||||||
|
MxDb.Version=DB.6.0.161
|
||||||
|
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.DMA2_Stream0_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
|
||||||
|
NVIC.DMA2_Stream1_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
|
||||||
|
NVIC.DMA2_Stream2_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
|
||||||
|
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.ForceEnableDMAVector=true
|
||||||
|
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||||
|
NVIC.SPI1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
||||||
|
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
|
||||||
|
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
|
PA10.Mode=Asynchronous
|
||||||
|
PA10.Signal=USART1_RX
|
||||||
|
PA13.Mode=Serial_Wire
|
||||||
|
PA13.Signal=SYS_JTMS-SWDIO
|
||||||
|
PA14.Mode=Serial_Wire
|
||||||
|
PA14.Signal=SYS_JTCK-SWCLK
|
||||||
|
PA7.Signal=S_DATAIN1DFSDM2
|
||||||
|
PA9.Mode=Asynchronous
|
||||||
|
PA9.Signal=USART1_TX
|
||||||
|
PB10.Signal=S_CKOUTDFSDM2
|
||||||
|
PB3.Locked=true
|
||||||
|
PB3.Mode=Full_Duplex_Slave
|
||||||
|
PB3.Signal=SPI1_SCK
|
||||||
|
PB4.Locked=true
|
||||||
|
PB4.Mode=Full_Duplex_Slave
|
||||||
|
PB4.Signal=SPI1_MISO
|
||||||
|
PB5.Mode=Full_Duplex_Slave
|
||||||
|
PB5.Signal=SPI1_MOSI
|
||||||
|
PC5.Signal=S_DATAIN2DFSDM2
|
||||||
|
PC9.Signal=S_DATAIN3DFSDM2
|
||||||
|
PCC.Checker=false
|
||||||
|
PCC.Line=STM32F413/423
|
||||||
|
PCC.MCU=STM32F413R(G-H)Tx
|
||||||
|
PCC.PartNumber=STM32F413RGTx
|
||||||
|
PCC.Series=STM32F4
|
||||||
|
PCC.Temperature=25
|
||||||
|
PCC.Vdd=1.7
|
||||||
|
PH0\ -\ OSC_IN.Mode=HSE-External-Oscillator
|
||||||
|
PH0\ -\ OSC_IN.Signal=RCC_OSC_IN
|
||||||
|
PH1\ -\ OSC_OUT.Mode=HSE-External-Oscillator
|
||||||
|
PH1\ -\ OSC_OUT.Signal=RCC_OSC_OUT
|
||||||
|
PinOutPanel.RotationAngle=0
|
||||||
|
ProjectManager.AskForMigrate=true
|
||||||
|
ProjectManager.BackupPrevious=false
|
||||||
|
ProjectManager.CompilerLinker=GCC
|
||||||
|
ProjectManager.CompilerOptimize=6
|
||||||
|
ProjectManager.ComputerToolchain=false
|
||||||
|
ProjectManager.CoupleFile=false
|
||||||
|
ProjectManager.CustomerFirmwarePackage=
|
||||||
|
ProjectManager.DefaultFWLocation=true
|
||||||
|
ProjectManager.DeletePrevious=true
|
||||||
|
ProjectManager.DeviceId=STM32F413RGTx
|
||||||
|
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3
|
||||||
|
ProjectManager.FreePins=false
|
||||||
|
ProjectManager.FreePinsContext=
|
||||||
|
ProjectManager.HalAssertFull=false
|
||||||
|
ProjectManager.HeapSize=0x200
|
||||||
|
ProjectManager.KeepUserCode=true
|
||||||
|
ProjectManager.LastFirmware=true
|
||||||
|
ProjectManager.LibraryCopy=0
|
||||||
|
ProjectManager.MainLocation=Core/Src
|
||||||
|
ProjectManager.NoMain=false
|
||||||
|
ProjectManager.PreviousToolchain=
|
||||||
|
ProjectManager.ProjectBuild=false
|
||||||
|
ProjectManager.ProjectFileName=MultiMicphoneLocat.ioc
|
||||||
|
ProjectManager.ProjectName=MultiMicphoneLocat
|
||||||
|
ProjectManager.ProjectStructure=
|
||||||
|
ProjectManager.RegisterCallBack=
|
||||||
|
ProjectManager.StackSize=0x400
|
||||||
|
ProjectManager.TargetToolchain=MDK-ARM V5.32
|
||||||
|
ProjectManager.ToolChainLocation=
|
||||||
|
ProjectManager.UAScriptAfterPath=
|
||||||
|
ProjectManager.UAScriptBeforePath=
|
||||||
|
ProjectManager.UnderRoot=false
|
||||||
|
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_DFSDM2_Init-DFSDM2-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_USART1_UART_Init-USART1-false-HAL-true
|
||||||
|
RCC.AHBFreq_Value=100000000
|
||||||
|
RCC.APB1CLKDivider=RCC_HCLK_DIV2
|
||||||
|
RCC.APB1Freq_Value=50000000
|
||||||
|
RCC.APB1TimFreq_Value=100000000
|
||||||
|
RCC.APB2Freq_Value=100000000
|
||||||
|
RCC.APB2TimFreq_Value=100000000
|
||||||
|
RCC.CortexFreq_Value=100000000
|
||||||
|
RCC.DFSDM2AudioFreq_Value=48000000
|
||||||
|
RCC.DFSDM2Freq_Value=100000000
|
||||||
|
RCC.DFSDMAudioFreq_Value=48000000
|
||||||
|
RCC.DFSDMFreq_Value=100000000
|
||||||
|
RCC.FCLKCortexFreq_Value=100000000
|
||||||
|
RCC.FMPI2C1Freq_Value=50000000
|
||||||
|
RCC.FamilyName=M
|
||||||
|
RCC.HCLKFreq_Value=100000000
|
||||||
|
RCC.HSE_VALUE=8000000
|
||||||
|
RCC.I2S1Freq_Value=48000000
|
||||||
|
RCC.I2S2Freq_Value=48000000
|
||||||
|
RCC.IPParameters=AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,DFSDM2AudioFreq_Value,DFSDM2Freq_Value,DFSDMAudioFreq_Value,DFSDMFreq_Value,FCLKCortexFreq_Value,FMPI2C1Freq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,I2S1Freq_Value,I2S2Freq_Value,LPTimerFreq_Value,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLM,PLLN,PLLP,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLRoutputFreq_Value,PLLSourceVirtual,PWRFreq_Value,RNGFreq_Value,SAI1AFreq_Value,SAI1BFreq_Value,SDIOFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,USBFreq_Value,VCOI2SInputFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value
|
||||||
|
RCC.LPTimerFreq_Value=50000000
|
||||||
|
RCC.MCO2PinFreq_Value=100000000
|
||||||
|
RCC.PLLCLKFreq_Value=100000000
|
||||||
|
RCC.PLLI2SQCLKFreq_Value=48000000
|
||||||
|
RCC.PLLI2SRCLKFreq_Value=48000000
|
||||||
|
RCC.PLLM=8
|
||||||
|
RCC.PLLN=400
|
||||||
|
RCC.PLLP=RCC_PLLP_DIV4
|
||||||
|
RCC.PLLQCLKFreq_Value=200000000
|
||||||
|
RCC.PLLQoutputFreq_Value=200000000
|
||||||
|
RCC.PLLRCLKFreq_Value=200000000
|
||||||
|
RCC.PLLRoutputFreq_Value=200000000
|
||||||
|
RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
|
||||||
|
RCC.PWRFreq_Value=100000000
|
||||||
|
RCC.RNGFreq_Value=200000000
|
||||||
|
RCC.SAI1AFreq_Value=8000000
|
||||||
|
RCC.SAI1BFreq_Value=8000000
|
||||||
|
RCC.SDIOFreq_Value=200000000
|
||||||
|
RCC.SYSCLKFreq_VALUE=100000000
|
||||||
|
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||||
|
RCC.USBFreq_Value=200000000
|
||||||
|
RCC.VCOI2SInputFreq_Value=500000
|
||||||
|
RCC.VCOI2SOutputFreq_Value=96000000
|
||||||
|
RCC.VCOInputFreq_Value=1000000
|
||||||
|
RCC.VCOOutputFreq_Value=400000000
|
||||||
|
SH.S_CKOUTDFSDM2.0=DFSDM2_CKOUT,PDM_SPI_Input_from_ch01_and_Internal_Clock
|
||||||
|
SH.S_CKOUTDFSDM2.1=DFSDM2_CKOUT,CKOUT
|
||||||
|
SH.S_CKOUTDFSDM2.2=DFSDM2_CKOUT,PDM_SPI_Input_from_ch12_and_Internal_Clock
|
||||||
|
SH.S_CKOUTDFSDM2.3=DFSDM2_CKOUT,PDM_SPI_Input_from_ch23_and_Internal_Clock
|
||||||
|
SH.S_CKOUTDFSDM2.ConfNb=4
|
||||||
|
SH.S_DATAIN1DFSDM2.0=DFSDM2_DATIN1,PDM_SPI_Input_from_ch01_and_Internal_Clock
|
||||||
|
SH.S_DATAIN1DFSDM2.ConfNb=1
|
||||||
|
SH.S_DATAIN2DFSDM2.0=DFSDM2_DATIN2,PDM_SPI_Input_from_ch12_and_Internal_Clock
|
||||||
|
SH.S_DATAIN2DFSDM2.ConfNb=1
|
||||||
|
SH.S_DATAIN3DFSDM2.0=DFSDM2_DATIN3,PDM_SPI_Input_from_ch23_and_Internal_Clock
|
||||||
|
SH.S_DATAIN3DFSDM2.ConfNb=1
|
||||||
|
SPI1.Direction=SPI_DIRECTION_2LINES
|
||||||
|
SPI1.IPParameters=VirtualType,Mode,Direction
|
||||||
|
SPI1.Mode=SPI_MODE_SLAVE
|
||||||
|
SPI1.VirtualType=VM_SLAVE
|
||||||
|
USART1.IPParameters=VirtualMode
|
||||||
|
USART1.VirtualMode=VM_ASYNC
|
||||||
|
VP_SYS_VS_Systick.Mode=SysTick
|
||||||
|
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
|
||||||
|
board=custom
|
||||||
57
stm32-cubemx-ioc-reader/SKILL.md
Normal file
57
stm32-cubemx-ioc-reader/SKILL.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# STM32CubeMX IOC Reader
|
||||||
|
|
||||||
|
## Use this skill when
|
||||||
|
|
||||||
|
- The user asks to read, analyze, summarize, or validate an STM32CubeMX `.ioc` file.
|
||||||
|
- The user wants pin mapping, clock config, peripheral setup, middleware settings, or project metadata from `.ioc`.
|
||||||
|
- The user wants a machine-readable export (JSON) of `.ioc` content.
|
||||||
|
|
||||||
|
## Do not use this skill when
|
||||||
|
|
||||||
|
- The request is about generated C code (`main.c`, `stm32xx_hal_msp.c`) and not `.ioc` itself.
|
||||||
|
- The file is not an STM32CubeMX `.ioc` file.
|
||||||
|
|
||||||
|
## What this skill does
|
||||||
|
|
||||||
|
- Parses `.ioc` key-value entries.
|
||||||
|
- Groups configuration by domain: MCU, pins, RCC/clock, peripherals, middleware, and project manager.
|
||||||
|
- Produces readable summaries for fast review.
|
||||||
|
- Optionally exports structured JSON for tooling.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Confirm the target `.ioc` path.
|
||||||
|
2. Run parser script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/parse_ioc.py --ioc <path/to/project.ioc>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. For JSON output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/parse_ioc.py --ioc <path/to/project.ioc> --json
|
||||||
|
```
|
||||||
|
|
||||||
|
4. For saved JSON file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/parse_ioc.py --ioc <path/to/project.ioc> --json --out parsed_ioc.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response style guidelines
|
||||||
|
|
||||||
|
- Start with a concise project overview (MCU, board, toolchain, project name).
|
||||||
|
- Then list enabled peripherals and notable pin assignments.
|
||||||
|
- Then call out clock source and important RCC settings.
|
||||||
|
- Mention anomalies (empty values, duplicate keys, unknown domains).
|
||||||
|
|
||||||
|
## Notes about `.ioc` format
|
||||||
|
|
||||||
|
- `.ioc` is an INI-like key-value format (not strict XML).
|
||||||
|
- Typical key prefixes:
|
||||||
|
- `Mcu.` for target MCU/package/family
|
||||||
|
- `PAx`/`PBx`... for pin assignment and signal labels
|
||||||
|
- `RCC.` for clocks
|
||||||
|
- `<PERIPH>.` (for example `USART1.`, `I2C1.`, `TIM3.`) for peripheral settings
|
||||||
|
- `ProjectManager.` for generated project metadata
|
||||||
249
stm32-cubemx-ioc-reader/scripts/parse_ioc.py
Normal file
249
stm32-cubemx-ioc-reader/scripts/parse_ioc.py
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Parse and summarize STM32CubeMX .ioc files."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
|
||||||
|
StrMap = dict[str, str]
|
||||||
|
|
||||||
|
|
||||||
|
class ClassifiedIOC(TypedDict):
|
||||||
|
domains: dict[str, StrMap]
|
||||||
|
peripherals: dict[str, StrMap]
|
||||||
|
other: StrMap
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ioc(ioc_path: Path) -> tuple[StrMap, list[str]]:
|
||||||
|
entries: StrMap = {}
|
||||||
|
anomalies: list[str] = []
|
||||||
|
|
||||||
|
lines = ioc_path.read_text(encoding="utf-8", errors="replace").splitlines()
|
||||||
|
for index, raw in enumerate(lines, start=1):
|
||||||
|
line = raw.strip()
|
||||||
|
if not line or line.startswith("#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if "=" not in line:
|
||||||
|
anomalies.append(f"line {index}: no '=' separator")
|
||||||
|
continue
|
||||||
|
|
||||||
|
key, value = line.split("=", 1)
|
||||||
|
key = key.strip()
|
||||||
|
value = value.strip()
|
||||||
|
|
||||||
|
if not key:
|
||||||
|
anomalies.append(f"line {index}: empty key")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if key in entries:
|
||||||
|
anomalies.append(f"line {index}: duplicate key '{key}' (last value kept)")
|
||||||
|
|
||||||
|
entries[key] = value
|
||||||
|
|
||||||
|
return entries, anomalies
|
||||||
|
|
||||||
|
|
||||||
|
def classify(entries: StrMap) -> ClassifiedIOC:
|
||||||
|
domains: dict[str, StrMap] = {
|
||||||
|
"mcu": {},
|
||||||
|
"rcc": {},
|
||||||
|
"project_manager": {},
|
||||||
|
"pins": {},
|
||||||
|
"middleware": {},
|
||||||
|
}
|
||||||
|
peripherals: dict[str, StrMap] = defaultdict(dict)
|
||||||
|
other: StrMap = {}
|
||||||
|
|
||||||
|
middleware_roots = {
|
||||||
|
"freertos",
|
||||||
|
"fatfs",
|
||||||
|
"lwip",
|
||||||
|
"usb",
|
||||||
|
"touchgfx",
|
||||||
|
"azure_rtos",
|
||||||
|
"threadx",
|
||||||
|
"netxduo",
|
||||||
|
"filex",
|
||||||
|
"ux_device",
|
||||||
|
"ux_host",
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in entries.items():
|
||||||
|
if key.startswith("Mcu."):
|
||||||
|
domains["mcu"][key] = value
|
||||||
|
continue
|
||||||
|
if key.startswith("RCC."):
|
||||||
|
domains["rcc"][key] = value
|
||||||
|
continue
|
||||||
|
if key.startswith("ProjectManager."):
|
||||||
|
domains["project_manager"][key] = value
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Pin records usually look like PA0.Mode, PA0.Signal, PB6.GPIO_Label...
|
||||||
|
if len(key) >= 3 and key[0] == "P" and key[1].isalpha():
|
||||||
|
pin = key.split(".", 1)[0]
|
||||||
|
if len(pin) >= 3 and pin[2].isdigit():
|
||||||
|
domains["pins"][key] = value
|
||||||
|
continue
|
||||||
|
|
||||||
|
root = key.split(".", 1)[0]
|
||||||
|
root_l = root.lower()
|
||||||
|
if root_l in middleware_roots or root_l.startswith("cmsis"):
|
||||||
|
domains["middleware"][key] = value
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Heuristic: uppercase root token often indicates a peripheral (USART1, I2C1, TIM3...)
|
||||||
|
if root and root.upper() == root and any(ch.isdigit() for ch in root):
|
||||||
|
peripherals[root][key] = value
|
||||||
|
continue
|
||||||
|
|
||||||
|
other[key] = value
|
||||||
|
|
||||||
|
return {
|
||||||
|
"domains": domains,
|
||||||
|
"peripherals": dict(sorted(peripherals.items())),
|
||||||
|
"other": other,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def summarize(classified: ClassifiedIOC, ioc_path: Path, anomalies: list[str]) -> str:
|
||||||
|
domains = classified["domains"]
|
||||||
|
peripherals = classified["peripherals"]
|
||||||
|
other = classified["other"]
|
||||||
|
|
||||||
|
mcu = domains["mcu"]
|
||||||
|
project_manager = domains["project_manager"]
|
||||||
|
rcc = domains["rcc"]
|
||||||
|
pins = domains["pins"]
|
||||||
|
middleware = domains["middleware"]
|
||||||
|
|
||||||
|
lines: list[str] = []
|
||||||
|
lines.append(f"IOC file: {ioc_path}")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
lines.append("== Project Overview ==")
|
||||||
|
lines.append(f"- MCU keys: {len(mcu)}")
|
||||||
|
lines.append(f"- ProjectManager keys: {len(project_manager)}")
|
||||||
|
lines.append(f"- RCC keys: {len(rcc)}")
|
||||||
|
|
||||||
|
top_overview = [
|
||||||
|
"Mcu.Name",
|
||||||
|
"Mcu.Package",
|
||||||
|
"Mcu.Family",
|
||||||
|
"Mcu.UserName",
|
||||||
|
"ProjectManager.ProjectName",
|
||||||
|
"ProjectManager.ToolChain",
|
||||||
|
"ProjectManager.TargetToolchain",
|
||||||
|
]
|
||||||
|
for key in top_overview:
|
||||||
|
if key in mcu:
|
||||||
|
lines.append(f"- {key}: {mcu[key]}")
|
||||||
|
elif key in project_manager:
|
||||||
|
lines.append(f"- {key}: {project_manager[key]}")
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
lines.append("== Peripherals ==")
|
||||||
|
lines.append(f"- Count: {len(peripherals)}")
|
||||||
|
if peripherals:
|
||||||
|
lines.append("- Enabled/peripheral roots: " + ", ".join(peripherals.keys()))
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
lines.append("== Pins ==")
|
||||||
|
lines.append(f"- Pin-related keys: {len(pins)}")
|
||||||
|
|
||||||
|
# Extract a compact map of pin -> signal
|
||||||
|
pin_signals: dict[str, str] = {}
|
||||||
|
for key, value in pins.items():
|
||||||
|
if key.endswith(".Signal"):
|
||||||
|
pin = key.split(".", 1)[0]
|
||||||
|
pin_signals[pin] = value
|
||||||
|
if pin_signals:
|
||||||
|
preview = sorted(pin_signals.items())[:20]
|
||||||
|
for pin, signal in preview:
|
||||||
|
lines.append(f"- {pin}: {signal}")
|
||||||
|
if len(pin_signals) > len(preview):
|
||||||
|
lines.append(f"- ... ({len(pin_signals) - len(preview)} more)")
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
lines.append("== Middleware ==")
|
||||||
|
lines.append(f"- Middleware keys: {len(middleware)}")
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
lines.append("== Diagnostics ==")
|
||||||
|
lines.append(f"- Other keys: {len(other)}")
|
||||||
|
lines.append(f"- Anomalies: {len(anomalies)}")
|
||||||
|
if anomalies:
|
||||||
|
for item in anomalies[:20]:
|
||||||
|
lines.append(f"- {item}")
|
||||||
|
if len(anomalies) > 20:
|
||||||
|
lines.append(f"- ... ({len(anomalies) - 20} more)")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def build_json(
|
||||||
|
ioc_path: Path,
|
||||||
|
entries: StrMap,
|
||||||
|
classified: ClassifiedIOC,
|
||||||
|
anomalies: list[str],
|
||||||
|
) -> dict[str, object]:
|
||||||
|
return {
|
||||||
|
"ioc_path": str(ioc_path),
|
||||||
|
"counts": {
|
||||||
|
"entries": len(entries),
|
||||||
|
"mcu": len(classified["domains"]["mcu"]),
|
||||||
|
"rcc": len(classified["domains"]["rcc"]),
|
||||||
|
"project_manager": len(classified["domains"]["project_manager"]),
|
||||||
|
"pins": len(classified["domains"]["pins"]),
|
||||||
|
"middleware": len(classified["domains"]["middleware"]),
|
||||||
|
"peripherals": len(classified["peripherals"]),
|
||||||
|
"other": len(classified["other"]),
|
||||||
|
"anomalies": len(anomalies),
|
||||||
|
},
|
||||||
|
"domains": classified["domains"],
|
||||||
|
"peripherals": classified["peripherals"],
|
||||||
|
"other": classified["other"],
|
||||||
|
"anomalies": anomalies,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Read and summarize STM32CubeMX .ioc files"
|
||||||
|
)
|
||||||
|
parser.add_argument("--ioc", required=True, help="Path to .ioc file")
|
||||||
|
parser.add_argument("--json", action="store_true", help="Print JSON output")
|
||||||
|
parser.add_argument(
|
||||||
|
"--out", help="Optional output file path (for --json or text summary)"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
ioc_path = Path(args.ioc)
|
||||||
|
if not ioc_path.exists() or not ioc_path.is_file():
|
||||||
|
raise SystemExit(f"error: ioc file not found: {ioc_path}")
|
||||||
|
|
||||||
|
entries, anomalies = parse_ioc(ioc_path)
|
||||||
|
classified = classify(entries)
|
||||||
|
|
||||||
|
if args.json:
|
||||||
|
payload = build_json(ioc_path, entries, classified, anomalies)
|
||||||
|
rendered = json.dumps(payload, ensure_ascii=True, indent=2)
|
||||||
|
else:
|
||||||
|
rendered = summarize(classified, ioc_path, anomalies)
|
||||||
|
|
||||||
|
if args.out:
|
||||||
|
Path(args.out).write_text(rendered + "\n", encoding="utf-8")
|
||||||
|
else:
|
||||||
|
print(rendered)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user