My Marlin configs for Fabrikator Mini and CTC i3 Pro B
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

configuration.py 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #
  2. # configuration.py
  3. # Apply options from config.ini to the existing Configuration headers
  4. #
  5. import re, shutil, configparser
  6. from pathlib import Path
  7. verbose = 0
  8. def blab(str,level=1):
  9. if verbose >= level: print(f"[config] {str}")
  10. def config_path(cpath):
  11. return Path("Marlin", cpath)
  12. # Apply a single name = on/off ; name = value ; etc.
  13. # TODO: Limit to the given (optional) configuration
  14. def apply_opt(name, val, conf=None):
  15. if name == "lcd": name, val = val, "on"
  16. # Create a regex to match the option and capture parts of the line
  17. regex = re.compile(rf'^(\s*)(//\s*)?(#define\s+)({name}\b)(\s*)(.*?)(\s*)(//.*)?$', re.IGNORECASE)
  18. # Find and enable and/or update all matches
  19. for file in ("Configuration.h", "Configuration_adv.h"):
  20. fullpath = config_path(file)
  21. lines = fullpath.read_text().split('\n')
  22. found = False
  23. for i in range(len(lines)):
  24. line = lines[i]
  25. match = regex.match(line)
  26. if match and match[4].upper() == name.upper():
  27. found = True
  28. # For boolean options un/comment the define
  29. if val in ("on", "", None):
  30. newline = re.sub(r'^(\s*)//+\s*(#define)(\s{1,3})?(\s*)', r'\1\2 \4', line)
  31. elif val == "off":
  32. newline = re.sub(r'^(\s*)(#define)(\s{1,3})?(\s*)', r'\1//\2 \4', line)
  33. else:
  34. # For options with values, enable and set the value
  35. newline = match[1] + match[3] + match[4] + match[5] + val
  36. if match[8]:
  37. sp = match[7] if match[7] else ' '
  38. newline += sp + match[8]
  39. lines[i] = newline
  40. blab(f"Set {name} to {val}")
  41. # If the option was found, write the modified lines
  42. if found:
  43. fullpath.write_text('\n'.join(lines))
  44. break
  45. # If the option didn't appear in either config file, add it
  46. if not found:
  47. # OFF options are added as disabled items so they appear
  48. # in config dumps. Useful for custom settings.
  49. prefix = ""
  50. if val == "off":
  51. prefix, val = "//", "" # Item doesn't appear in config dump
  52. #val = "false" # Item appears in config dump
  53. # Uppercase the option unless already mixed/uppercase
  54. added = name.upper() if name.islower() else name
  55. # Add the provided value after the name
  56. if val != "on" and val != "" and val is not None:
  57. added += " " + val
  58. # Prepend the new option after the first set of #define lines
  59. fullpath = config_path("Configuration.h")
  60. with fullpath.open() as f:
  61. lines = f.readlines()
  62. linenum = 0
  63. gotdef = False
  64. for line in lines:
  65. isdef = line.startswith("#define")
  66. if not gotdef:
  67. gotdef = isdef
  68. elif not isdef:
  69. break
  70. linenum += 1
  71. lines.insert(linenum, f"{prefix}#define {added} // Added by config.ini\n")
  72. fullpath.write_text('\n'.join(lines))
  73. # Fetch configuration files from GitHub given the path.
  74. # Return True if any files were fetched.
  75. def fetch_example(path):
  76. if path.endswith("/"):
  77. path = path[:-1]
  78. if '@' in path:
  79. path, brch = map(strip, path.split('@'))
  80. url = path.replace("%", "%25").replace(" ", "%20")
  81. if not path.startswith('http'):
  82. url = "https://raw.githubusercontent.com/MarlinFirmware/Configurations/bugfix-2.1.x/config/%s" % url
  83. # Find a suitable fetch command
  84. if shutil.which("curl") is not None:
  85. fetch = "curl -L -s -S -f -o"
  86. elif shutil.which("wget") is not None:
  87. fetch = "wget -q -O"
  88. else:
  89. blab("Couldn't find curl or wget", -1)
  90. return False
  91. import os
  92. # Reset configurations to default
  93. os.system("git reset --hard HEAD")
  94. gotfile = False
  95. # Try to fetch the remote files
  96. for fn in ("Configuration.h", "Configuration_adv.h", "_Bootscreen.h", "_Statusscreen.h"):
  97. if os.system("%s wgot %s/%s >/dev/null 2>&1" % (fetch, url, fn)) == 0:
  98. shutil.move('wgot', config_path(fn))
  99. gotfile = True
  100. if Path('wgot').exists():
  101. shutil.rmtree('wgot')
  102. return gotfile
  103. def section_items(cp, sectkey):
  104. return cp.items(sectkey) if sectkey in cp.sections() else []
  105. # Apply all items from a config section
  106. def apply_ini_by_name(cp, sect):
  107. iniok = True
  108. if sect in ('config:base', 'config:root'):
  109. iniok = False
  110. items = section_items(cp, 'config:base') + section_items(cp, 'config:root')
  111. else:
  112. items = cp.items(sect)
  113. for item in items:
  114. if iniok or not item[0].startswith('ini_'):
  115. apply_opt(item[0], item[1])
  116. # Apply all config sections from a parsed file
  117. def apply_all_sections(cp):
  118. for sect in cp.sections():
  119. if sect.startswith('config:'):
  120. apply_ini_by_name(cp, sect)
  121. # Apply certain config sections from a parsed file
  122. def apply_sections(cp, ckey='all', addbase=False):
  123. blab("[config] apply section key: %s" % ckey)
  124. if ckey == 'all':
  125. apply_all_sections(cp)
  126. else:
  127. # Apply the base/root config.ini settings after external files are done
  128. if addbase or ckey in ('base', 'root'):
  129. apply_ini_by_name(cp, 'config:base')
  130. # Apply historically 'Configuration.h' settings everywhere
  131. if ckey == 'basic':
  132. apply_ini_by_name(cp, 'config:basic')
  133. # Apply historically Configuration_adv.h settings everywhere
  134. # (Some of which rely on defines in 'Conditionals_LCD.h')
  135. elif ckey in ('adv', 'advanced'):
  136. apply_ini_by_name(cp, 'config:advanced')
  137. # Apply a specific config:<name> section directly
  138. elif ckey.startswith('config:'):
  139. apply_ini_by_name(cp, ckey)
  140. # Apply settings from a top level config.ini
  141. def apply_config_ini(cp):
  142. blab("=" * 20 + " Gather 'config.ini' entries...")
  143. # Pre-scan for ini_use_config to get config_keys
  144. base_items = section_items(cp, 'config:base') + section_items(cp, 'config:root')
  145. config_keys = ['base']
  146. for ikey, ival in base_items:
  147. if ikey == 'ini_use_config':
  148. config_keys = [ x.strip() for x in ival.split(',') ]
  149. # For each ini_use_config item perform an action
  150. for ckey in config_keys:
  151. addbase = False
  152. # For a key ending in .ini load and parse another .ini file
  153. if ckey.endswith('.ini'):
  154. sect = 'base'
  155. if '@' in ckey: sect, ckey = ckey.split('@')
  156. other_ini = configparser.ConfigParser()
  157. other_ini.read(config_path(ckey))
  158. apply_sections(other_ini, sect)
  159. # (Allow 'example/' as a shortcut for 'examples/')
  160. elif ckey.startswith('example/'):
  161. ckey = 'examples' + ckey[7:]
  162. # For 'examples/<path>' fetch an example set from GitHub.
  163. # For https?:// do a direct fetch of the URL.
  164. elif ckey.startswith('examples/') or ckey.startswith('http'):
  165. addbase = True
  166. fetch_example(ckey)
  167. # Apply keyed sections after external files are done
  168. apply_sections(cp, 'config:' + ckey, addbase)
  169. if __name__ == "__main__":
  170. #
  171. # From command line use the given file name
  172. #
  173. import sys
  174. args = sys.argv[1:]
  175. if len(args) > 0:
  176. if args[0].endswith('.ini'):
  177. ini_file = args[0]
  178. else:
  179. print("Usage: %s <.ini file>" % sys.argv[0])
  180. else:
  181. ini_file = config_path('config.ini')
  182. if ini_file:
  183. user_ini = configparser.ConfigParser()
  184. user_ini.read(ini_file)
  185. apply_config_ini(user_ini)
  186. else:
  187. #
  188. # From within PlatformIO use the loaded INI file
  189. #
  190. import pioutil
  191. if pioutil.is_pio_build():
  192. Import("env")
  193. try:
  194. verbose = int(env.GetProjectOption('custom_verbose'))
  195. except:
  196. pass
  197. from platformio.project.config import ProjectConfig
  198. apply_config_ini(ProjectConfig())