Skip to content

Instantly share code, notes, and snippets.

@nistath
Last active January 23, 2020 01:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nistath/9921d854c27d078424f85225ed15380a to your computer and use it in GitHub Desktop.
Save nistath/9921d854c27d078424f85225ed15380a to your computer and use it in GitHub Desktop.
cubemxcpy is a python script to copy CubeMX generated files in a nice format into your project.
import re
from pathlib import Path
INP_DIR = Path('./cubemx/')
OUT_DIR = Path('./')
comment = r'/\*{}([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/'
any_comment = re.compile(comment.format(''))
user_comment = re.compile(comment.format(' USER'))
empty_comment_title = re.compile(comment.format('') + r'[\s\t\r\n]+(?=/\*)')
bad_comment_space = re.compile(r'/\*(?=\**[^\*\s\t\r\n])')
brackets = re.compile(r'[\s\t\r\n]*{')
multi_newline = re.compile(r'\n[\s\t\r\n]*\n')
trailing_white = re.compile(r'[\s\t]+$')
def fix_style(contents: str) -> str:
contents = contents.replace('{0}', '{}')
contents = contents.replace('/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/', '', 1)
contents = user_comment.sub('', contents)
copy_notice = empty_comment_title.match(contents, pos=1).group(0)
contents = empty_comment_title.sub('', contents)
contents = multi_newline.sub('\n\n', contents)
contents = bad_comment_space.sub('/* ', contents)
contents = brackets.sub(' {', contents)
contents = contents.strip() + '\n' * 3 + copy_notice.strip()
contents = trailing_white.sub('', contents)
contents += '\n'
return contents
def append_after(contents: str, string: str, append: str) -> str:
loc = contents.find(string)
if loc == -1:
raise ValueError('didn\'t find given string')
split = loc + len(string)
return contents[:split] + append + contents[split:]
def padded_comment(comment: str, linelen: int=80) -> str:
return ('/* ' + comment + ' ').ljust(linelen - 2, '-') + '*/'
def get_section(contents: str, begin: str=None, end: str=None, lines: bool=False) -> slice:
start, len_begin = (0, 0) if begin is None else (contents.find(begin), len(begin))
stop = None if end is None else contents.find(end, start + len_begin) + len(end)
if lines:
cstart = contents.rfind('\n', None, start)
start = cstart + 1 if cstart >= 0 else start
if stop:
cstop = contents.find('\n', stop) or stop
stop = cstop if cstop >= 0 else stop
return slice(start, stop)
def sub_section(contents: str, section: slice, sub: str='') -> str:
return contents[:section.start] + sub + contents[section.stop:]
class CubeMX:
entry_function = 'void MX_Init(void)'
it_stem = 'stm32f4xx_it'
msp_file = 'stm32f4xx_hal_msp.c'
system_file = 'system_stm32f4xx.c'
conf_file = 'stm32f4xx_hal_conf.h'
def __init__(self, mxdir: Path, stem: str):
self.mxdir = mxdir
self.stem = stem
with self.mxdir.joinpath('Core', 'Src', 'main.c').open('r', newline=None) as f:
self.source = self.process_main_c(f.read())
with self.mxdir.joinpath('Core', 'Inc', 'main.h').open('r', newline=None) as f:
self.header = self.process_main_h(f.read())
with self.mxdir.joinpath('Core', 'Inc', self.it_stem).with_suffix('.h').open('r', newline=None) as f:
self.it_h = self.process_common(f.read())
with self.mxdir.joinpath('Core', 'Src', self.it_stem).with_suffix('.c').open('r', newline=None) as f:
self.it_c = self.process_common(f.read())
with self.mxdir.joinpath('Core', 'Src', self.msp_file).open('r', newline=None) as f:
self.msp = self.process_common(f.read())
with self.mxdir.joinpath('Core', 'Src', self.system_file).open('r', newline=None) as f:
self.system = f.read()
with self.mxdir.joinpath('Core', 'Inc', self.conf_file).open('r', newline=None) as f:
self.conf = f.read()
def replace_stems(self, contents: str, original: str='main') -> str:
file_f = '{}.'
contents = contents.replace(file_f.format(original), file_f.format(self.stem))
contents = contents.replace(original.upper(), self.stem.upper())
return contents
def process_common(self, contents: str) -> str:
contents = fix_style(contents)
contents = self.replace_stems(contents)
return contents
def process_main_c(self, contents: str) -> str:
contents = contents.rsplit('\n', 31)[0] # last 30 lines have Error_Handler and assert_failed
contents = contents.replace('static ', '')
contents = sub_section(contents, get_section(contents, '/* Infinite loop */', '/* USER CODE END 3 */'))
self.exports = contents[get_section(contents, '/* Private variables', '/* USER', True)]
self.exports = any_comment.sub('', self.exports).strip()
function_section = get_section(contents, '/* Private function', '/* USER', True)
self.functions = contents[function_section]
self.functions = any_comment.sub('', self.functions).strip()
self.functions += '\n' + self.entry_function + ';'
contents = sub_section(contents, function_section)
contents = contents.replace('int main(void)', self.entry_function)
return self.process_common(contents)
def process_main_h(self, contents: str) -> str:
contents = append_after(contents, '#include "stm32f4xx_hal.h"\n', '#include "error.h"\n')
pin_section = get_section(contents, '/* Private defines', '*/')
contents = sub_section(contents, pin_section, padded_comment('Pin defines'))
function_section = get_section(contents, '/* Exported functions', '\n', lines=True)
functions = contents[function_section].split('\n')[0] + '\n'
functions += self.functions
contents = sub_section(contents, function_section, functions)
function_section = get_section(contents, '/* Exported functions', '/*')
export_section = slice(function_section.stop - 2, function_section.stop - 2)
exports = '\n'.join('extern ' + line if line else '' for line in self.exports.split('\n'))
exports = padded_comment('Exported variables') + '\n' + exports
contents = sub_section(contents, export_section, exports)
return self.process_common(contents)
def save_as(self, outdir: Path):
with outdir.joinpath('src', self.stem).with_suffix('.c').open('w') as f:
f.write(self.source)
with outdir.joinpath('inc', self.stem).with_suffix('.h').open('w') as f:
f.write(self.header)
with outdir.joinpath('src', self.it_stem).with_suffix('.c').open('w') as f:
f.write(self.it_c)
with outdir.joinpath('inc', self.it_stem).with_suffix('.h').open('w') as f:
f.write(self.it_h)
with outdir.joinpath('src', self.msp_file).open('w') as f:
f.write(self.msp)
with outdir.joinpath('src', self.system_file).open('w') as f:
f.write(self.system)
with outdir.joinpath('inc', self.conf_file).open('w') as f:
f.write(self.conf)
if __name__ == '__main__':
cubemx = CubeMX(INP_DIR, 'cubemx')
cubemx.save_as(OUT_DIR)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment