mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-01-16 21:58:13 +01:00
4c0edf9e93
* Update configure-features.py to match the latest file names. * Update configure-features.py to adopt the latest source tree.
252 lines
7.7 KiB
Python
Executable File
252 lines
7.7 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Grbl_Esp32 configurator
|
|
# Copyright (C) 2020 Michiyasu Odaki
|
|
#
|
|
# This is useful for automated testing, to make sure you haven't broken something
|
|
#
|
|
# Grbl_Esp32 is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Grbl_Esp32 is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Grbl_Esp32. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from __future__ import print_function
|
|
import os, sys, argparse, re
|
|
|
|
configDirName = r'Grbl_Esp32/src'
|
|
configFileName = r'Config.h'
|
|
|
|
validFeatureList = [
|
|
'BLUETOOTH',
|
|
'WIFI',
|
|
'SD_CARD',
|
|
'HTTP',
|
|
'OTA',
|
|
'TELNET',
|
|
'TELNET_WELCOME_MSG',
|
|
'MDNS',
|
|
'SSDP',
|
|
'NOTIFICATIONS',
|
|
'SERIAL2SOCKET_IN',
|
|
'SERIAL2SOCKET_OUT',
|
|
'CAPTIVE_PORTAL',
|
|
'AUTHENTICATION'
|
|
]
|
|
eyecatchBeginString = 'CONFIGURE_EYECATCH_BEGIN'
|
|
eyecatchEndString = 'CONFIGURE_EYECATCH_END'
|
|
enablePrefix = 'ENABLE_'
|
|
|
|
def printValidFeatureList():
|
|
print("valid feature names:")
|
|
for n in sorted(validFeatureList):
|
|
print(" " + n)
|
|
|
|
def usage(parser):
|
|
parser.print_usage()
|
|
printValidFeatureList()
|
|
sys.exit(255)
|
|
|
|
def parseArgs(defaultConfigPath):
|
|
# Argument parser (-h is also available)
|
|
parser = argparse.ArgumentParser(description='Configure Grbl_ESP32 features')
|
|
parser.add_argument('-v', '--verbose', action='store_true')
|
|
parser.add_argument('-c', '--configfile', default=defaultConfigPath)
|
|
parser.add_argument('-e', '--enable', nargs='*'
|
|
,help='specify feature name(ex. WIFI)'
|
|
#, choices=validFeatureList
|
|
)
|
|
parser.add_argument('-d', '--disable', nargs='*'
|
|
,help='specify feature name(ex. BLUETOOTH)'
|
|
#,choices=validFeatureList
|
|
)
|
|
return parser.parse_args(), parser
|
|
|
|
def isValidFeature(feature):
|
|
if feature:
|
|
if feature in validFeatureList:
|
|
return True #valid
|
|
return False #invalid
|
|
|
|
def checkFeatureList(optname, features, verbose=False):
|
|
if features:
|
|
for n in features:
|
|
if isValidFeature(n) is True:
|
|
#if verbose:
|
|
# print("valid " + optname + " feature: " + n)
|
|
pass
|
|
else:
|
|
print("unknown " + optname + " feature: " + n)
|
|
return -1
|
|
else:
|
|
#if verbose:
|
|
# print(optname + " is not specified")
|
|
return 0
|
|
|
|
return len(features)
|
|
|
|
def resolveConflicts(high_priority, low_priority):
|
|
if low_priority:
|
|
for n in low_priority[:]:
|
|
if n in high_priority:
|
|
low_priority.remove(n)
|
|
return
|
|
|
|
def readConfig(path):
|
|
# Read config.h to memory
|
|
try:
|
|
f = open(path)
|
|
except IOError:
|
|
print("unable to open file for read: " + path)
|
|
sys.exit(255)
|
|
else:
|
|
try:
|
|
src = f.readlines()
|
|
except IOError:
|
|
print("file read error: " + path)
|
|
f.close()
|
|
sys.exit(255)
|
|
else:
|
|
f.close()
|
|
return src
|
|
|
|
def writeConfig(path, buf):
|
|
try:
|
|
f = open(path, 'w')
|
|
except IOError:
|
|
print("unable to open file for write: " + path)
|
|
sys.exit(255)
|
|
else:
|
|
try:
|
|
src = f.write(buf)
|
|
except IOError:
|
|
print("file write error: " + path)
|
|
f.close()
|
|
sys.exit(255)
|
|
else:
|
|
f.close()
|
|
|
|
def changeConfig(src, enabled, disabled, verbose=False):
|
|
dst = ""
|
|
numEnabledDic = {}
|
|
for name in enabled:
|
|
numEnabledDic[name] = 0
|
|
regstart = re.compile(r'^\s*//\s*' + eyecatchBeginString)
|
|
regend = re.compile(r'^\s*//\s*' + eyecatchEndString)
|
|
state = 0;
|
|
for line in src:
|
|
if state == 0:
|
|
# out of the defines block to modify
|
|
if regstart.match(line):
|
|
state = 1
|
|
dst += line
|
|
elif state == 1:
|
|
# in the defines block to modify
|
|
if regend.match(line):
|
|
# end of block found
|
|
for name in enabled:
|
|
# add the define to enable if it was not found in the block
|
|
if numEnabledDic[name] == 0:
|
|
dst += "#define " + enablePrefix + name + '\n'
|
|
state = 2
|
|
dst += line
|
|
else:
|
|
dstLine = ""
|
|
if len(enabled) > 0:
|
|
for name in enabled:
|
|
s = enablePrefix + name
|
|
m = re.match(r'^s*(//)*\s*#define\s+(' + s + r'.*)$', line)
|
|
if m:
|
|
dstLine = "#define " + m.group(2) + '\n'
|
|
numEnabledDic[name] += 1
|
|
break
|
|
if len(disabled) > 0:
|
|
for name in disabled:
|
|
s = enablePrefix + name
|
|
m = re.match(r'^\s*#define\s+' + s + r'.*$', line)
|
|
if m:
|
|
dstLine = "//" + line
|
|
break
|
|
if len(dstLine) != 0:
|
|
dst += dstLine
|
|
if verbose:
|
|
print(dstLine.rstrip())
|
|
else:
|
|
dst += line
|
|
if verbose:
|
|
print(line.rstrip())
|
|
elif state == 2:
|
|
dst += line
|
|
if state != 2:
|
|
print("EYECATCH pair not found. Cancel changes.")
|
|
sys.exit(255)
|
|
return dst
|
|
|
|
def main():
|
|
# Concatinate dir and file
|
|
configFilePath = os.path.join(configDirName, configFileName)
|
|
|
|
# Parse arguments
|
|
args, parser = parseArgs(configFilePath)
|
|
|
|
# Set params to local variables
|
|
verbose = args.verbose
|
|
configFilePath = args.configfile
|
|
|
|
# Copy and remove duplicates from enable/disable list
|
|
enabledFeatures = []
|
|
disabledFeatures = []
|
|
if args.enable:
|
|
enabledFeatures = sorted(set(args.enable), key=args.enable.index)
|
|
if args.disable:
|
|
disabledFeatures = sorted(set(args.disable), key=args.disable.index)
|
|
|
|
# If both enable and disable are specified, treat as enable
|
|
# (Remove items from 2nd param if same item in 1st param)
|
|
resolveConflicts(enabledFeatures, disabledFeatures)
|
|
|
|
# Verification (whether or not to use "choice" with argparse)
|
|
numEnables = checkFeatureList("-e", enabledFeatures, verbose)
|
|
numDisables = checkFeatureList("-d", disabledFeatures, verbose)
|
|
#if verbose:
|
|
# print("enables: ", numEnables)
|
|
# print(enabledFeatures)
|
|
# print("disables: ", numDisables)
|
|
# print(disabledFeatures)
|
|
# print("config file: " + configFilePath)
|
|
|
|
# Final checking about args
|
|
if numEnables < 0 or numDisables < 0 or (numEnables == 0 and numDisables == 0):
|
|
usage(parser)
|
|
|
|
# Check if the target file exists
|
|
configFilePathAbs = os.path.abspath(configFilePath)
|
|
if verbose:
|
|
print("Config path: " + configFilePathAbs)
|
|
print()
|
|
if not os.path.isfile(configFilePathAbs):
|
|
print("config file not found: " + configFilePathAbs)
|
|
sys.exit(255)
|
|
|
|
# read config file
|
|
src = readConfig(configFilePathAbs)
|
|
|
|
# Change the specified settings
|
|
dst = changeConfig(src, enabledFeatures, disabledFeatures, verbose)
|
|
|
|
# Write back
|
|
writeConfig(configFilePathAbs, dst)
|
|
|
|
sys.exit(0)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|