mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-22 18:25:18 +00:00
🔨 Newer PlatformIO support
This commit is contained in:
parent
284cc8f4c0
commit
41593c4d1a
@ -28,7 +28,7 @@
|
|||||||
/**
|
/**
|
||||||
* Marlin release version identifier
|
* Marlin release version identifier
|
||||||
*/
|
*/
|
||||||
//#define SHORT_BUILD_VERSION "2.0.9.5"
|
//#define SHORT_BUILD_VERSION "2.0.9.6"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verbose version identifier which should contain a reference to the location
|
* Verbose version identifier which should contain a reference to the location
|
||||||
@ -41,7 +41,7 @@
|
|||||||
* here we define this default string as the date where the latest release
|
* here we define this default string as the date where the latest release
|
||||||
* version was tagged.
|
* version was tagged.
|
||||||
*/
|
*/
|
||||||
//#define STRING_DISTRIBUTION_DATE "2022-07-29"
|
//#define STRING_DISTRIBUTION_DATE "2023-03-25"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a generic printer name to be output to the LCD after booting Marlin.
|
* Defines a generic printer name to be output to the LCD after booting Marlin.
|
||||||
|
211
Marlin/config.ini
Normal file
211
Marlin/config.ini
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#
|
||||||
|
# Marlin Firmware
|
||||||
|
# config.ini - Options to apply before the build
|
||||||
|
#
|
||||||
|
[config:base]
|
||||||
|
ini_use_config = none
|
||||||
|
|
||||||
|
# Load all config: sections in this file
|
||||||
|
;ini_use_config = all
|
||||||
|
# Load config file relative to Marlin/
|
||||||
|
;ini_use_config = another.ini
|
||||||
|
# Download configurations from GitHub
|
||||||
|
;ini_use_config = example/Creality/Ender-5 Plus @ bugfix-2.1.x
|
||||||
|
# Download configurations from your server
|
||||||
|
;ini_use_config = https://me.myserver.com/path/to/configs
|
||||||
|
# Evaluate config:base and do a config dump
|
||||||
|
;ini_use_config = base
|
||||||
|
;config_export = 2
|
||||||
|
|
||||||
|
[config:minimal]
|
||||||
|
motherboard = BOARD_RAMPS_14_EFB
|
||||||
|
serial_port = 0
|
||||||
|
baudrate = 250000
|
||||||
|
|
||||||
|
use_watchdog = on
|
||||||
|
thermal_protection_hotends = on
|
||||||
|
thermal_protection_hysteresis = 4
|
||||||
|
thermal_protection_period = 40
|
||||||
|
|
||||||
|
bufsize = 4
|
||||||
|
block_buffer_size = 16
|
||||||
|
max_cmd_size = 96
|
||||||
|
|
||||||
|
extruders = 1
|
||||||
|
temp_sensor_0 = 1
|
||||||
|
|
||||||
|
temp_hysteresis = 3
|
||||||
|
heater_0_mintemp = 5
|
||||||
|
heater_0_maxtemp = 275
|
||||||
|
preheat_1_temp_hotend = 180
|
||||||
|
|
||||||
|
bang_max = 255
|
||||||
|
pidtemp = on
|
||||||
|
pid_k1 = 0.95
|
||||||
|
pid_max = BANG_MAX
|
||||||
|
pid_functional_range = 10
|
||||||
|
|
||||||
|
default_kp = 22.20
|
||||||
|
default_ki = 1.08
|
||||||
|
default_kd = 114.00
|
||||||
|
|
||||||
|
x_driver_type = A4988
|
||||||
|
y_driver_type = A4988
|
||||||
|
z_driver_type = A4988
|
||||||
|
e0_driver_type = A4988
|
||||||
|
|
||||||
|
x_bed_size = 200
|
||||||
|
x_min_pos = 0
|
||||||
|
x_max_pos = X_BED_SIZE
|
||||||
|
|
||||||
|
y_bed_size = 200
|
||||||
|
y_min_pos = 0
|
||||||
|
y_max_pos = Y_BED_SIZE
|
||||||
|
|
||||||
|
z_min_pos = 0
|
||||||
|
z_max_pos = 200
|
||||||
|
|
||||||
|
x_home_dir = -1
|
||||||
|
y_home_dir = -1
|
||||||
|
z_home_dir = -1
|
||||||
|
|
||||||
|
use_xmin_plug = on
|
||||||
|
use_ymin_plug = on
|
||||||
|
use_zmin_plug = on
|
||||||
|
|
||||||
|
x_min_endstop_inverting = false
|
||||||
|
y_min_endstop_inverting = false
|
||||||
|
z_min_endstop_inverting = false
|
||||||
|
|
||||||
|
default_axis_steps_per_unit = { 80, 80, 400, 500 }
|
||||||
|
axis_relative_modes = { false, false, false, false }
|
||||||
|
default_max_feedrate = { 300, 300, 5, 25 }
|
||||||
|
default_max_acceleration = { 3000, 3000, 100, 10000 }
|
||||||
|
|
||||||
|
homing_feedrate_mm_m = { (50*60), (50*60), (4*60) }
|
||||||
|
homing_bump_divisor = { 2, 2, 4 }
|
||||||
|
|
||||||
|
x_enable_on = 0
|
||||||
|
y_enable_on = 0
|
||||||
|
z_enable_on = 0
|
||||||
|
e_enable_on = 0
|
||||||
|
|
||||||
|
invert_x_dir = false
|
||||||
|
invert_y_dir = true
|
||||||
|
invert_z_dir = false
|
||||||
|
invert_e0_dir = false
|
||||||
|
|
||||||
|
invert_e_step_pin = false
|
||||||
|
invert_x_step_pin = false
|
||||||
|
invert_y_step_pin = false
|
||||||
|
invert_z_step_pin = false
|
||||||
|
|
||||||
|
disable_x = false
|
||||||
|
disable_y = false
|
||||||
|
disable_z = false
|
||||||
|
disable_e = false
|
||||||
|
|
||||||
|
proportional_font_ratio = 1.0
|
||||||
|
default_nominal_filament_dia = 1.75
|
||||||
|
|
||||||
|
junction_deviation_mm = 0.013
|
||||||
|
|
||||||
|
default_acceleration = 3000
|
||||||
|
default_travel_acceleration = 3000
|
||||||
|
default_retract_acceleration = 3000
|
||||||
|
|
||||||
|
default_minimumfeedrate = 0.0
|
||||||
|
default_mintravelfeedrate = 0.0
|
||||||
|
|
||||||
|
minimum_planner_speed = 0.05
|
||||||
|
min_steps_per_segment = 6
|
||||||
|
default_minsegmenttime = 20000
|
||||||
|
|
||||||
|
[config:basic]
|
||||||
|
bed_overshoot = 10
|
||||||
|
busy_while_heating = on
|
||||||
|
default_ejerk = 5.0
|
||||||
|
default_keepalive_interval = 2
|
||||||
|
default_leveling_fade_height = 0.0
|
||||||
|
disable_inactive_extruder = on
|
||||||
|
display_charset_hd44780 = JAPANESE
|
||||||
|
eeprom_boot_silent = on
|
||||||
|
eeprom_chitchat = on
|
||||||
|
endstoppullups = on
|
||||||
|
extrude_maxlength = 200
|
||||||
|
extrude_mintemp = 170
|
||||||
|
host_keepalive_feature = on
|
||||||
|
hotend_overshoot = 15
|
||||||
|
jd_handle_small_segments = on
|
||||||
|
lcd_info_screen_style = 0
|
||||||
|
lcd_language = en
|
||||||
|
max_bed_power = 255
|
||||||
|
mesh_inset = 0
|
||||||
|
min_software_endstops = on
|
||||||
|
max_software_endstops = on
|
||||||
|
min_software_endstop_x = on
|
||||||
|
min_software_endstop_y = on
|
||||||
|
min_software_endstop_z = on
|
||||||
|
max_software_endstop_x = on
|
||||||
|
max_software_endstop_y = on
|
||||||
|
max_software_endstop_z = on
|
||||||
|
preheat_1_fan_speed = 0
|
||||||
|
preheat_1_label = "PLA"
|
||||||
|
preheat_1_temp_bed = 70
|
||||||
|
prevent_cold_extrusion = on
|
||||||
|
prevent_lengthy_extrude = on
|
||||||
|
printjob_timer_autostart = on
|
||||||
|
probing_margin = 10
|
||||||
|
show_bootscreen = on
|
||||||
|
soft_pwm_scale = 0
|
||||||
|
string_config_h_author = "(none, default config)"
|
||||||
|
temp_bed_hysteresis = 3
|
||||||
|
temp_bed_residency_time = 10
|
||||||
|
temp_bed_window = 1
|
||||||
|
temp_residency_time = 10
|
||||||
|
temp_window = 1
|
||||||
|
validate_homing_endstops = on
|
||||||
|
xy_probe_feedrate = (133*60)
|
||||||
|
z_clearance_between_probes = 5
|
||||||
|
z_clearance_deploy_probe = 10
|
||||||
|
z_clearance_multi_probe = 5
|
||||||
|
|
||||||
|
[config:advanced]
|
||||||
|
arc_support = on
|
||||||
|
auto_report_temperatures = on
|
||||||
|
autotemp = on
|
||||||
|
autotemp_oldweight = 0.98
|
||||||
|
bed_check_interval = 5000
|
||||||
|
default_stepper_deactive_time = 120
|
||||||
|
default_volumetric_extruder_limit = 0.00
|
||||||
|
disable_inactive_e = true
|
||||||
|
disable_inactive_x = true
|
||||||
|
disable_inactive_y = true
|
||||||
|
disable_inactive_z = true
|
||||||
|
e0_auto_fan_pin = -1
|
||||||
|
encoder_100x_steps_per_sec = 80
|
||||||
|
encoder_10x_steps_per_sec = 30
|
||||||
|
encoder_rate_multiplier = on
|
||||||
|
extended_capabilities_report = on
|
||||||
|
extruder_auto_fan_speed = 255
|
||||||
|
extruder_auto_fan_temperature = 50
|
||||||
|
fanmux0_pin = -1
|
||||||
|
fanmux1_pin = -1
|
||||||
|
fanmux2_pin = -1
|
||||||
|
faster_gcode_parser = on
|
||||||
|
homing_bump_mm = { 5, 5, 2 }
|
||||||
|
max_arc_segment_mm = 1.0
|
||||||
|
min_arc_segment_mm = 0.1
|
||||||
|
min_circle_segments = 72
|
||||||
|
n_arc_correction = 25
|
||||||
|
serial_overrun_protection = on
|
||||||
|
slowdown = on
|
||||||
|
slowdown_divisor = 2
|
||||||
|
temp_sensor_bed = 0
|
||||||
|
thermal_protection_bed_hysteresis = 2
|
||||||
|
thermocouple_max_errors = 15
|
||||||
|
tx_buffer_size = 0
|
||||||
|
watch_bed_temp_increase = 2
|
||||||
|
watch_bed_temp_period = 60
|
||||||
|
watch_temp_increase = 2
|
||||||
|
watch_temp_period = 20
|
@ -12,7 +12,7 @@ if pioutil.is_pio_build():
|
|||||||
target_filename = "FIRMWARE.CUR"
|
target_filename = "FIRMWARE.CUR"
|
||||||
target_drive = "REARM"
|
target_drive = "REARM"
|
||||||
|
|
||||||
import os,getpass,platform
|
import platform
|
||||||
|
|
||||||
current_OS = platform.system()
|
current_OS = platform.system()
|
||||||
Import("env")
|
Import("env")
|
||||||
@ -26,6 +26,7 @@ if pioutil.is_pio_build():
|
|||||||
|
|
||||||
def before_upload(source, target, env):
|
def before_upload(source, target, env):
|
||||||
try:
|
try:
|
||||||
|
from pathlib import Path
|
||||||
#
|
#
|
||||||
# Find a disk for upload
|
# Find a disk for upload
|
||||||
#
|
#
|
||||||
@ -38,6 +39,7 @@ if pioutil.is_pio_build():
|
|||||||
# Windows - doesn't care about the disk's name, only cares about the drive letter
|
# Windows - doesn't care about the disk's name, only cares about the drive letter
|
||||||
import subprocess,string
|
import subprocess,string
|
||||||
from ctypes import windll
|
from ctypes import windll
|
||||||
|
from pathlib import PureWindowsPath
|
||||||
|
|
||||||
# getting list of drives
|
# getting list of drives
|
||||||
# https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python
|
# https://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python
|
||||||
@ -49,7 +51,7 @@ if pioutil.is_pio_build():
|
|||||||
bitmask >>= 1
|
bitmask >>= 1
|
||||||
|
|
||||||
for drive in drives:
|
for drive in drives:
|
||||||
final_drive_name = drive + ':\\'
|
final_drive_name = drive + ':'
|
||||||
# print ('disc check: {}'.format(final_drive_name))
|
# print ('disc check: {}'.format(final_drive_name))
|
||||||
try:
|
try:
|
||||||
volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT))
|
volume_info = str(subprocess.check_output('cmd /C dir ' + final_drive_name, stderr=subprocess.STDOUT))
|
||||||
@ -59,29 +61,33 @@ if pioutil.is_pio_build():
|
|||||||
else:
|
else:
|
||||||
if target_drive in volume_info and not target_file_found: # set upload if not found target file yet
|
if target_drive in volume_info and not target_file_found: # set upload if not found target file yet
|
||||||
target_drive_found = True
|
target_drive_found = True
|
||||||
upload_disk = final_drive_name
|
upload_disk = PureWindowsPath(final_drive_name)
|
||||||
if target_filename in volume_info:
|
if target_filename in volume_info:
|
||||||
if not target_file_found:
|
if not target_file_found:
|
||||||
upload_disk = final_drive_name
|
upload_disk = PureWindowsPath(final_drive_name)
|
||||||
target_file_found = True
|
target_file_found = True
|
||||||
|
|
||||||
elif current_OS == 'Linux':
|
elif current_OS == 'Linux':
|
||||||
#
|
#
|
||||||
# platformio.ini will accept this for a Linux upload port designation: 'upload_port = /media/media_name/drive'
|
# platformio.ini will accept this for a Linux upload port designation: 'upload_port = /media/media_name/drive'
|
||||||
#
|
#
|
||||||
drives = os.listdir(os.path.join(os.sep, 'media', getpass.getuser()))
|
import getpass
|
||||||
|
user = getpass.getuser()
|
||||||
|
mpath = Path('/media', user)
|
||||||
|
drives = [ x for x in mpath.iterdir() if x.is_dir() ]
|
||||||
if target_drive in drives: # If target drive is found, use it.
|
if target_drive in drives: # If target drive is found, use it.
|
||||||
target_drive_found = True
|
target_drive_found = True
|
||||||
upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), target_drive) + os.sep
|
upload_disk = mpath / target_drive
|
||||||
else:
|
else:
|
||||||
for drive in drives:
|
for drive in drives:
|
||||||
try:
|
try:
|
||||||
files = os.listdir(os.path.join(os.sep, 'media', getpass.getuser(), drive))
|
fpath = mpath / drive
|
||||||
|
filenames = [ x.name for x in fpath.iterdir() if x.is_file() ]
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if target_filename in files:
|
if target_filename in filenames:
|
||||||
upload_disk = os.path.join(os.sep, 'media', getpass.getuser(), drive) + os.sep
|
upload_disk = mpath / drive
|
||||||
target_file_found = True
|
target_file_found = True
|
||||||
break
|
break
|
||||||
#
|
#
|
||||||
@ -97,26 +103,28 @@ if pioutil.is_pio_build():
|
|||||||
#
|
#
|
||||||
# platformio.ini will accept this for a OSX upload port designation: 'upload_port = /media/media_name/drive'
|
# platformio.ini will accept this for a OSX upload port designation: 'upload_port = /media/media_name/drive'
|
||||||
#
|
#
|
||||||
drives = os.listdir('/Volumes') # human readable names
|
dpath = Path('/Volumes') # human readable names
|
||||||
|
drives = [ x for x in dpath.iterdir() if x.is_dir() ]
|
||||||
if target_drive in drives and not target_file_found: # set upload if not found target file yet
|
if target_drive in drives and not target_file_found: # set upload if not found target file yet
|
||||||
target_drive_found = True
|
target_drive_found = True
|
||||||
upload_disk = '/Volumes/' + target_drive + '/'
|
upload_disk = dpath / target_drive
|
||||||
for drive in drives:
|
for drive in drives:
|
||||||
try:
|
try:
|
||||||
filenames = os.listdir('/Volumes/' + drive + '/') # will get an error if the drive is protected
|
fpath = dpath / drive # will get an error if the drive is protected
|
||||||
|
filenames = [ x.name for x in fpath.iterdir() if x.is_file() ]
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if target_filename in filenames:
|
if target_filename in filenames:
|
||||||
if not target_file_found:
|
upload_disk = dpath / drive
|
||||||
upload_disk = '/Volumes/' + drive + '/'
|
|
||||||
target_file_found = True
|
target_file_found = True
|
||||||
|
break
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set upload_port to drive if found
|
# Set upload_port to drive if found
|
||||||
#
|
#
|
||||||
if target_file_found or target_drive_found:
|
if target_file_found or target_drive_found:
|
||||||
env.Replace(UPLOAD_PORT=upload_disk)
|
env.Replace(UPLOAD_PORT=str(upload_disk))
|
||||||
print('\nUpload disk: ', upload_disk, '\n')
|
print('\nUpload disk: ', upload_disk, '\n')
|
||||||
else:
|
else:
|
||||||
print_error('Autodetect Error')
|
print_error('Autodetect Error')
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
* Release version. Leave the Marlin version or apply a custom scheme.
|
* Release version. Leave the Marlin version or apply a custom scheme.
|
||||||
*/
|
*/
|
||||||
#ifndef SHORT_BUILD_VERSION
|
#ifndef SHORT_BUILD_VERSION
|
||||||
#define SHORT_BUILD_VERSION "2.0.9.5"
|
#define SHORT_BUILD_VERSION "2.0.9.6"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +42,7 @@
|
|||||||
* version was tagged.
|
* version was tagged.
|
||||||
*/
|
*/
|
||||||
#ifndef STRING_DISTRIBUTION_DATE
|
#ifndef STRING_DISTRIBUTION_DATE
|
||||||
#define STRING_DISTRIBUTION_DATE "2022-07-29"
|
#define STRING_DISTRIBUTION_DATE "2023-03-25"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
# Examples:
|
# Examples:
|
||||||
# use_example_configs
|
# use_example_configs
|
||||||
# use_example_configs Creality/CR-10/CrealityV1
|
# use_example_configs Creality/CR-10/CrealityV1
|
||||||
# use_example_configs release-2.0.9.5:Creality/CR-10/CrealityV1
|
# use_example_configs release-2.0.9.6:Creality/CR-10/CrealityV1
|
||||||
#
|
#
|
||||||
# If a configpath has spaces (or quotes) escape them or enquote the path
|
# If a configpath has spaces (or quotes) escape them or enquote the path
|
||||||
#
|
#
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
|
|
||||||
import os
|
|
||||||
Import("env", "projenv")
|
Import("env", "projenv")
|
||||||
|
|
||||||
flash_size = 0
|
flash_size = 0
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os
|
|
||||||
from os.path import join
|
from os.path import join
|
||||||
from os.path import expandvars
|
from os.path import expandvars
|
||||||
Import("env")
|
Import("env")
|
||||||
|
@ -3,30 +3,29 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,shutil,marlin
|
import shutil,marlin
|
||||||
from SCons.Script import DefaultEnvironment
|
from pathlib import Path
|
||||||
from platformio import util
|
|
||||||
|
|
||||||
env = DefaultEnvironment()
|
Import("env")
|
||||||
platform = env.PioPlatform()
|
platform = env.PioPlatform()
|
||||||
board = env.BoardConfig()
|
board = env.BoardConfig()
|
||||||
|
|
||||||
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoststm32-maple")
|
FRAMEWORK_DIR = Path(platform.get_package_dir("framework-arduinoststm32-maple"))
|
||||||
assert os.path.isdir(FRAMEWORK_DIR)
|
assert FRAMEWORK_DIR.is_dir()
|
||||||
|
|
||||||
source_root = os.path.join("buildroot", "share", "PlatformIO", "variants")
|
source_root = Path("buildroot/share/PlatformIO/variants")
|
||||||
assert os.path.isdir(source_root)
|
assert source_root.is_dir()
|
||||||
|
|
||||||
variant = board.get("build.variant")
|
variant = board.get("build.variant")
|
||||||
variant_dir = os.path.join(FRAMEWORK_DIR, "STM32F1", "variants", variant)
|
variant_dir = FRAMEWORK_DIR / "STM32F1/variants" / variant
|
||||||
|
|
||||||
source_dir = os.path.join(source_root, variant)
|
source_dir = source_root / variant
|
||||||
assert os.path.isdir(source_dir)
|
assert source_dir.is_dir()
|
||||||
|
|
||||||
if os.path.isdir(variant_dir):
|
if variant_dir.is_dir():
|
||||||
shutil.rmtree(variant_dir)
|
shutil.rmtree(variant_dir)
|
||||||
|
|
||||||
if not os.path.isdir(variant_dir):
|
if not variant_dir.is_dir():
|
||||||
os.mkdir(variant_dir)
|
variant_dir.mkdir()
|
||||||
|
|
||||||
marlin.copytree(source_dir, variant_dir)
|
marlin.copytree(source_dir, variant_dir)
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,random,struct,uuid,marlin
|
import struct,uuid,marlin
|
||||||
# Relocate firmware from 0x08000000 to 0x08008800
|
|
||||||
marlin.relocate_firmware("0x08008800")
|
board = marlin.env.BoardConfig()
|
||||||
|
|
||||||
def calculate_crc(contents, seed):
|
def calculate_crc(contents, seed):
|
||||||
accumulating_xor_value = seed;
|
accumulating_xor_value = seed;
|
||||||
@ -105,13 +105,22 @@ if pioutil.is_pio_build():
|
|||||||
|
|
||||||
# Encrypt ${PROGNAME}.bin and save it as 'update.cbd'
|
# Encrypt ${PROGNAME}.bin and save it as 'update.cbd'
|
||||||
def encrypt(source, target, env):
|
def encrypt(source, target, env):
|
||||||
firmware = open(target[0].path, "rb")
|
from pathlib import Path
|
||||||
update = open(target[0].dir.path + '/update.cbd', "wb")
|
|
||||||
length = os.path.getsize(target[0].path)
|
|
||||||
|
|
||||||
encrypt_file(firmware, update, length)
|
fwpath = Path(target[0].path)
|
||||||
|
fwsize = fwpath.stat().st_size
|
||||||
|
|
||||||
firmware.close()
|
enname = board.get("build.crypt_chitu")
|
||||||
update.close()
|
enpath = Path(target[0].dir.path)
|
||||||
|
|
||||||
|
fwfile = fwpath.open("rb")
|
||||||
|
enfile = (enpath / enname).open("wb")
|
||||||
|
|
||||||
|
print(f"Encrypting {fwpath} to {enname}")
|
||||||
|
encrypt_file(fwfile, enfile, fwsize)
|
||||||
|
fwfile.close()
|
||||||
|
enfile.close()
|
||||||
|
fwpath.unlink()
|
||||||
|
|
||||||
|
marlin.relocate_firmware("0x08008800")
|
||||||
marlin.add_post_action(encrypt);
|
marlin.add_post_action(encrypt);
|
||||||
|
@ -2,17 +2,18 @@
|
|||||||
# common-cxxflags.py
|
# common-cxxflags.py
|
||||||
# Convenience script to apply customizations to CPP flags
|
# Convenience script to apply customizations to CPP flags
|
||||||
#
|
#
|
||||||
|
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
cxxflags = [
|
cxxflags = [
|
||||||
#"-Wno-incompatible-pointer-types",
|
# "-Wno-incompatible-pointer-types",
|
||||||
#"-Wno-unused-const-variable",
|
# "-Wno-unused-const-variable",
|
||||||
#"-Wno-maybe-uninitialized",
|
# "-Wno-maybe-uninitialized",
|
||||||
#"-Wno-sign-compare"
|
# "-Wno-sign-compare"
|
||||||
]
|
]
|
||||||
if "teensy" not in env['PIOENV']:
|
if "teensy" not in env["PIOENV"]:
|
||||||
cxxflags += ["-Wno-register"]
|
cxxflags += ["-Wno-register"]
|
||||||
env.Append(CXXFLAGS=cxxflags)
|
env.Append(CXXFLAGS=cxxflags)
|
||||||
|
|
||||||
@ -20,8 +21,8 @@ if pioutil.is_pio_build():
|
|||||||
# Add CPU frequency as a compile time constant instead of a runtime variable
|
# Add CPU frequency as a compile time constant instead of a runtime variable
|
||||||
#
|
#
|
||||||
def add_cpu_freq():
|
def add_cpu_freq():
|
||||||
if 'BOARD_F_CPU' in env:
|
if "BOARD_F_CPU" in env:
|
||||||
env['BUILD_FLAGS'].append('-DBOARD_F_CPU=' + env['BOARD_F_CPU'])
|
env["BUILD_FLAGS"].append("-DBOARD_F_CPU=" + env["BOARD_F_CPU"])
|
||||||
|
|
||||||
# Useful for JTAG debugging
|
# Useful for JTAG debugging
|
||||||
#
|
#
|
||||||
@ -29,8 +30,14 @@ if pioutil.is_pio_build():
|
|||||||
# It useful to keep two live versions: a debug version for debugging and another for
|
# It useful to keep two live versions: a debug version for debugging and another for
|
||||||
# release, for flashing when upload is not done automatically by jlink/stlink.
|
# release, for flashing when upload is not done automatically by jlink/stlink.
|
||||||
# Without this, PIO needs to recompile everything twice for any small change.
|
# Without this, PIO needs to recompile everything twice for any small change.
|
||||||
if env.GetBuildType() == "debug" and env.get('UPLOAD_PROTOCOL') not in ['jlink', 'stlink', 'custom']:
|
if env.GetBuildType() == "debug" and env.get("UPLOAD_PROTOCOL") not in ["jlink", "stlink", "custom"]:
|
||||||
env['BUILD_DIR'] = '$PROJECT_BUILD_DIR/$PIOENV/debug'
|
env["BUILD_DIR"] = "$PROJECT_BUILD_DIR/$PIOENV/debug"
|
||||||
|
|
||||||
|
def on_program_ready(source, target, env):
|
||||||
|
import shutil
|
||||||
|
shutil.copy(target[0].get_abspath(), env.subst("$PROJECT_BUILD_DIR/$PIOENV"))
|
||||||
|
|
||||||
|
env.AddPostAction("$PROGPATH", on_program_ready)
|
||||||
|
|
||||||
# On some platform, F_CPU is a runtime variable. Since it's used to convert from ns
|
# On some platform, F_CPU is a runtime variable. Since it's used to convert from ns
|
||||||
# to CPU cycles, this adds overhead preventing small delay (in the order of less than
|
# to CPU cycles, this adds overhead preventing small delay (in the order of less than
|
||||||
|
@ -67,6 +67,7 @@ if pioutil.is_pio_build():
|
|||||||
for dep in re.split(r',\s*', line):
|
for dep in re.split(r',\s*', line):
|
||||||
lib_name = re.sub(r'@([~^]|[<>]=?)?[\d.]+', '', dep.strip()).split('=').pop(0)
|
lib_name = re.sub(r'@([~^]|[<>]=?)?[\d.]+', '', dep.strip()).split('=').pop(0)
|
||||||
lib_re = re.compile('(?!^' + lib_name + '\\b)')
|
lib_re = re.compile('(?!^' + lib_name + '\\b)')
|
||||||
|
if not 'lib_deps' in feat: feat['lib_deps'] = {}
|
||||||
feat['lib_deps'] = list(filter(lib_re.match, feat['lib_deps'])) + [dep]
|
feat['lib_deps'] = list(filter(lib_re.match, feat['lib_deps'])) + [dep]
|
||||||
blab("[%s] lib_deps = %s" % (feature, dep), 3)
|
blab("[%s] lib_deps = %s" % (feature, dep), 3)
|
||||||
|
|
||||||
|
240
buildroot/share/PlatformIO/scripts/configuration.py
Normal file
240
buildroot/share/PlatformIO/scripts/configuration.py
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
#
|
||||||
|
# configuration.py
|
||||||
|
# Apply options from config.ini to the existing Configuration headers
|
||||||
|
#
|
||||||
|
import re, shutil, configparser
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
verbose = 0
|
||||||
|
def blab(str,level=1):
|
||||||
|
if verbose >= level: print(f"[config] {str}")
|
||||||
|
|
||||||
|
def config_path(cpath):
|
||||||
|
return Path("Marlin", cpath, encoding='utf-8')
|
||||||
|
|
||||||
|
# Apply a single name = on/off ; name = value ; etc.
|
||||||
|
# TODO: Limit to the given (optional) configuration
|
||||||
|
def apply_opt(name, val, conf=None):
|
||||||
|
if name == "lcd": name, val = val, "on"
|
||||||
|
|
||||||
|
# Create a regex to match the option and capture parts of the line
|
||||||
|
regex = re.compile(rf'^(\s*)(//\s*)?(#define\s+)({name}\b)(\s*)(.*?)(\s*)(//.*)?$', re.IGNORECASE)
|
||||||
|
|
||||||
|
# Find and enable and/or update all matches
|
||||||
|
for file in ("Configuration.h", "Configuration_adv.h"):
|
||||||
|
fullpath = config_path(file)
|
||||||
|
lines = fullpath.read_text(encoding='utf-8').split('\n')
|
||||||
|
found = False
|
||||||
|
for i in range(len(lines)):
|
||||||
|
line = lines[i]
|
||||||
|
match = regex.match(line)
|
||||||
|
if match and match[4].upper() == name.upper():
|
||||||
|
found = True
|
||||||
|
# For boolean options un/comment the define
|
||||||
|
if val in ("on", "", None):
|
||||||
|
newline = re.sub(r'^(\s*)//+\s*(#define)(\s{1,3})?(\s*)', r'\1\2 \4', line)
|
||||||
|
elif val == "off":
|
||||||
|
newline = re.sub(r'^(\s*)(#define)(\s{1,3})?(\s*)', r'\1//\2 \4', line)
|
||||||
|
else:
|
||||||
|
# For options with values, enable and set the value
|
||||||
|
newline = match[1] + match[3] + match[4] + match[5] + val
|
||||||
|
if match[8]:
|
||||||
|
sp = match[7] if match[7] else ' '
|
||||||
|
newline += sp + match[8]
|
||||||
|
lines[i] = newline
|
||||||
|
blab(f"Set {name} to {val}")
|
||||||
|
|
||||||
|
# If the option was found, write the modified lines
|
||||||
|
if found:
|
||||||
|
fullpath.write_text('\n'.join(lines), encoding='utf-8')
|
||||||
|
break
|
||||||
|
|
||||||
|
# If the option didn't appear in either config file, add it
|
||||||
|
if not found:
|
||||||
|
# OFF options are added as disabled items so they appear
|
||||||
|
# in config dumps. Useful for custom settings.
|
||||||
|
prefix = ""
|
||||||
|
if val == "off":
|
||||||
|
prefix, val = "//", "" # Item doesn't appear in config dump
|
||||||
|
#val = "false" # Item appears in config dump
|
||||||
|
|
||||||
|
# Uppercase the option unless already mixed/uppercase
|
||||||
|
added = name.upper() if name.islower() else name
|
||||||
|
|
||||||
|
# Add the provided value after the name
|
||||||
|
if val != "on" and val != "" and val is not None:
|
||||||
|
added += " " + val
|
||||||
|
|
||||||
|
# Prepend the new option after the first set of #define lines
|
||||||
|
fullpath = config_path("Configuration.h")
|
||||||
|
with fullpath.open(encoding='utf-8') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
linenum = 0
|
||||||
|
gotdef = False
|
||||||
|
for line in lines:
|
||||||
|
isdef = line.startswith("#define")
|
||||||
|
if not gotdef:
|
||||||
|
gotdef = isdef
|
||||||
|
elif not isdef:
|
||||||
|
break
|
||||||
|
linenum += 1
|
||||||
|
lines.insert(linenum, f"{prefix}#define {added:30} // Added by config.ini\n")
|
||||||
|
fullpath.write_text(''.join(lines), encoding='utf-8')
|
||||||
|
|
||||||
|
# Fetch configuration files from GitHub given the path.
|
||||||
|
# Return True if any files were fetched.
|
||||||
|
def fetch_example(url):
|
||||||
|
if url.endswith("/"): url = url[:-1]
|
||||||
|
if not url.startswith('http'):
|
||||||
|
brch = "bugfix-2.1.x"
|
||||||
|
if '@' in url: url, brch = map(str.strip, url.split('@'))
|
||||||
|
if url == 'examples/default': url = 'default'
|
||||||
|
url = f"https://raw.githubusercontent.com/MarlinFirmware/Configurations/{brch}/config/{url}"
|
||||||
|
url = url.replace("%", "%25").replace(" ", "%20")
|
||||||
|
|
||||||
|
# Find a suitable fetch command
|
||||||
|
if shutil.which("curl") is not None:
|
||||||
|
fetch = "curl -L -s -S -f -o"
|
||||||
|
elif shutil.which("wget") is not None:
|
||||||
|
fetch = "wget -q -O"
|
||||||
|
else:
|
||||||
|
blab("Couldn't find curl or wget", -1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Reset configurations to default
|
||||||
|
os.system("git checkout HEAD Marlin/*.h")
|
||||||
|
|
||||||
|
# Try to fetch the remote files
|
||||||
|
gotfile = False
|
||||||
|
for fn in ("Configuration.h", "Configuration_adv.h", "_Bootscreen.h", "_Statusscreen.h"):
|
||||||
|
if os.system(f"{fetch} wgot {url}/{fn} >/dev/null 2>&1") == 0:
|
||||||
|
shutil.move('wgot', config_path(fn))
|
||||||
|
gotfile = True
|
||||||
|
|
||||||
|
if Path('wgot').exists(): shutil.rmtree('wgot')
|
||||||
|
|
||||||
|
return gotfile
|
||||||
|
|
||||||
|
def section_items(cp, sectkey):
|
||||||
|
return cp.items(sectkey) if sectkey in cp.sections() else []
|
||||||
|
|
||||||
|
# Apply all items from a config section
|
||||||
|
def apply_ini_by_name(cp, sect):
|
||||||
|
iniok = True
|
||||||
|
if sect in ('config:base', 'config:root'):
|
||||||
|
iniok = False
|
||||||
|
items = section_items(cp, 'config:base') + section_items(cp, 'config:root')
|
||||||
|
else:
|
||||||
|
items = section_items(cp, sect)
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
if iniok or not item[0].startswith('ini_'):
|
||||||
|
apply_opt(item[0], item[1])
|
||||||
|
|
||||||
|
# Apply all config sections from a parsed file
|
||||||
|
def apply_all_sections(cp):
|
||||||
|
for sect in cp.sections():
|
||||||
|
if sect.startswith('config:'):
|
||||||
|
apply_ini_by_name(cp, sect)
|
||||||
|
|
||||||
|
# Apply certain config sections from a parsed file
|
||||||
|
def apply_sections(cp, ckey='all'):
|
||||||
|
blab(f"Apply section key: {ckey}")
|
||||||
|
if ckey == 'all':
|
||||||
|
apply_all_sections(cp)
|
||||||
|
else:
|
||||||
|
# Apply the base/root config.ini settings after external files are done
|
||||||
|
if ckey in ('base', 'root'):
|
||||||
|
apply_ini_by_name(cp, 'config:base')
|
||||||
|
|
||||||
|
# Apply historically 'Configuration.h' settings everywhere
|
||||||
|
if ckey == 'basic':
|
||||||
|
apply_ini_by_name(cp, 'config:basic')
|
||||||
|
|
||||||
|
# Apply historically Configuration_adv.h settings everywhere
|
||||||
|
# (Some of which rely on defines in 'Conditionals_LCD.h')
|
||||||
|
elif ckey in ('adv', 'advanced'):
|
||||||
|
apply_ini_by_name(cp, 'config:advanced')
|
||||||
|
|
||||||
|
# Apply a specific config:<name> section directly
|
||||||
|
elif ckey.startswith('config:'):
|
||||||
|
apply_ini_by_name(cp, ckey)
|
||||||
|
|
||||||
|
# Apply settings from a top level config.ini
|
||||||
|
def apply_config_ini(cp):
|
||||||
|
blab("=" * 20 + " Gather 'config.ini' entries...")
|
||||||
|
|
||||||
|
# Pre-scan for ini_use_config to get config_keys
|
||||||
|
base_items = section_items(cp, 'config:base') + section_items(cp, 'config:root')
|
||||||
|
config_keys = ['base']
|
||||||
|
for ikey, ival in base_items:
|
||||||
|
if ikey == 'ini_use_config':
|
||||||
|
config_keys = map(str.strip, ival.split(','))
|
||||||
|
|
||||||
|
# For each ini_use_config item perform an action
|
||||||
|
for ckey in config_keys:
|
||||||
|
addbase = False
|
||||||
|
|
||||||
|
# For a key ending in .ini load and parse another .ini file
|
||||||
|
if ckey.endswith('.ini'):
|
||||||
|
sect = 'base'
|
||||||
|
if '@' in ckey: sect, ckey = map(str.strip, ckey.split('@'))
|
||||||
|
cp2 = configparser.ConfigParser()
|
||||||
|
cp2.read(config_path(ckey))
|
||||||
|
apply_sections(cp2, sect)
|
||||||
|
ckey = 'base';
|
||||||
|
|
||||||
|
# (Allow 'example/' as a shortcut for 'examples/')
|
||||||
|
elif ckey.startswith('example/'):
|
||||||
|
ckey = 'examples' + ckey[7:]
|
||||||
|
|
||||||
|
# For 'examples/<path>' fetch an example set from GitHub.
|
||||||
|
# For https?:// do a direct fetch of the URL.
|
||||||
|
if ckey.startswith('examples/') or ckey.startswith('http'):
|
||||||
|
fetch_example(ckey)
|
||||||
|
ckey = 'base'
|
||||||
|
|
||||||
|
if ckey == 'all':
|
||||||
|
apply_sections(cp)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Apply keyed sections after external files are done
|
||||||
|
apply_sections(cp, 'config:' + ckey)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#
|
||||||
|
# From command line use the given file name
|
||||||
|
#
|
||||||
|
import sys
|
||||||
|
args = sys.argv[1:]
|
||||||
|
if len(args) > 0:
|
||||||
|
if args[0].endswith('.ini'):
|
||||||
|
ini_file = args[0]
|
||||||
|
else:
|
||||||
|
print("Usage: %s <.ini file>" % sys.argv[0])
|
||||||
|
else:
|
||||||
|
ini_file = config_path('config.ini')
|
||||||
|
|
||||||
|
if ini_file:
|
||||||
|
user_ini = configparser.ConfigParser()
|
||||||
|
user_ini.read(ini_file)
|
||||||
|
apply_config_ini(user_ini)
|
||||||
|
|
||||||
|
else:
|
||||||
|
#
|
||||||
|
# From within PlatformIO use the loaded INI file
|
||||||
|
#
|
||||||
|
import pioutil
|
||||||
|
if pioutil.is_pio_build():
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
try:
|
||||||
|
verbose = int(env.GetProjectOption('custom_verbose'))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
from platformio.project.config import ProjectConfig
|
||||||
|
apply_config_ini(ProjectConfig())
|
@ -5,45 +5,49 @@
|
|||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
Import("env")
|
Import("env")
|
||||||
import os,requests,zipfile,tempfile,shutil
|
import requests,zipfile,tempfile,shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
url = "https://github.com/makerbase-mks/Mks-Robin-Nano-Marlin2.0-Firmware/archive/0263cdaccf.zip"
|
url = "https://github.com/makerbase-mks/Mks-Robin-Nano-Marlin2.0-Firmware/archive/0263cdaccf.zip"
|
||||||
deps_path = env.Dictionary("PROJECT_LIBDEPS_DIR")
|
deps_path = Path(env.Dictionary("PROJECT_LIBDEPS_DIR"))
|
||||||
zip_path = os.path.join(deps_path, "mks-assets.zip")
|
zip_path = deps_path / "mks-assets.zip"
|
||||||
assets_path = os.path.join(env.Dictionary("PROJECT_BUILD_DIR"), env.Dictionary("PIOENV"), "assets")
|
assets_path = Path(env.Dictionary("PROJECT_BUILD_DIR"), env.Dictionary("PIOENV"), "assets")
|
||||||
|
|
||||||
def download_mks_assets():
|
def download_mks_assets():
|
||||||
print("Downloading MKS Assets")
|
print("Downloading MKS Assets")
|
||||||
r = requests.get(url, stream=True)
|
r = requests.get(url, stream=True)
|
||||||
# the user may have a very clean workspace,
|
# the user may have a very clean workspace,
|
||||||
# so create the PROJECT_LIBDEPS_DIR directory if not exits
|
# so create the PROJECT_LIBDEPS_DIR directory if not exits
|
||||||
if os.path.exists(deps_path) == False:
|
if not deps_path.exists():
|
||||||
os.mkdir(deps_path)
|
deps_path.mkdir()
|
||||||
with open(zip_path, 'wb') as fd:
|
with zip_path.open('wb') as fd:
|
||||||
for chunk in r.iter_content(chunk_size=128):
|
for chunk in r.iter_content(chunk_size=128):
|
||||||
fd.write(chunk)
|
fd.write(chunk)
|
||||||
|
|
||||||
def copy_mks_assets():
|
def copy_mks_assets():
|
||||||
print("Copying MKS Assets")
|
print("Copying MKS Assets")
|
||||||
output_path = tempfile.mkdtemp()
|
output_path = Path(tempfile.mkdtemp())
|
||||||
zip_obj = zipfile.ZipFile(zip_path, 'r')
|
zip_obj = zipfile.ZipFile(zip_path, 'r')
|
||||||
zip_obj.extractall(output_path)
|
zip_obj.extractall(output_path)
|
||||||
zip_obj.close()
|
zip_obj.close()
|
||||||
if os.path.exists(assets_path) == True and os.path.isdir(assets_path) == False:
|
if assets_path.exists() and not assets_path.is_dir():
|
||||||
os.unlink(assets_path)
|
assets_path.unlink()
|
||||||
if os.path.exists(assets_path) == False:
|
if not assets_path.exists():
|
||||||
os.mkdir(assets_path)
|
assets_path.mkdir()
|
||||||
base_path = ''
|
base_path = ''
|
||||||
for filename in os.listdir(output_path):
|
for filename in output_path.iterdir():
|
||||||
base_path = filename
|
base_path = filename
|
||||||
for filename in os.listdir(os.path.join(output_path, base_path, 'Firmware', 'mks_font')):
|
fw_path = (output_path / base_path / 'Firmware')
|
||||||
shutil.copy(os.path.join(output_path, base_path, 'Firmware', 'mks_font', filename), assets_path)
|
font_path = fw_path / 'mks_font'
|
||||||
for filename in os.listdir(os.path.join(output_path, base_path, 'Firmware', 'mks_pic')):
|
for filename in font_path.iterdir():
|
||||||
shutil.copy(os.path.join(output_path, base_path, 'Firmware', 'mks_pic', filename), assets_path)
|
shutil.copy(font_path / filename, assets_path)
|
||||||
|
pic_path = fw_path / 'mks_pic'
|
||||||
|
for filename in pic_path.iterdir():
|
||||||
|
shutil.copy(pic_path / filename, assets_path)
|
||||||
shutil.rmtree(output_path, ignore_errors=True)
|
shutil.rmtree(output_path, ignore_errors=True)
|
||||||
|
|
||||||
if os.path.exists(zip_path) == False:
|
if not zip_path.exists():
|
||||||
download_mks_assets()
|
download_mks_assets()
|
||||||
|
|
||||||
if os.path.exists(assets_path) == False:
|
if not assets_path.exists():
|
||||||
copy_mks_assets()
|
copy_mks_assets()
|
||||||
|
@ -7,16 +7,14 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,shutil,marlin
|
import shutil,marlin
|
||||||
from SCons.Script import DefaultEnvironment
|
from pathlib import Path
|
||||||
from platformio import util
|
|
||||||
|
|
||||||
env = DefaultEnvironment()
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get the platform name from the 'platform_packages' option,
|
# Get the platform name from the 'platform_packages' option,
|
||||||
# or look it up by the platform.class.name.
|
# or look it up by the platform.class.name.
|
||||||
#
|
#
|
||||||
|
env = marlin.env
|
||||||
platform = env.PioPlatform()
|
platform = env.PioPlatform()
|
||||||
|
|
||||||
from platformio.package.meta import PackageSpec
|
from platformio.package.meta import PackageSpec
|
||||||
@ -37,8 +35,8 @@ if pioutil.is_pio_build():
|
|||||||
if platform_name in [ "usb-host-msc", "usb-host-msc-cdc-msc", "usb-host-msc-cdc-msc-2", "usb-host-msc-cdc-msc-3", "tool-stm32duino", "biqu-bx-workaround", "main" ]:
|
if platform_name in [ "usb-host-msc", "usb-host-msc-cdc-msc", "usb-host-msc-cdc-msc-2", "usb-host-msc-cdc-msc-3", "tool-stm32duino", "biqu-bx-workaround", "main" ]:
|
||||||
platform_name = "framework-arduinoststm32"
|
platform_name = "framework-arduinoststm32"
|
||||||
|
|
||||||
FRAMEWORK_DIR = platform.get_package_dir(platform_name)
|
FRAMEWORK_DIR = Path(platform.get_package_dir(platform_name))
|
||||||
assert os.path.isdir(FRAMEWORK_DIR)
|
assert FRAMEWORK_DIR.is_dir()
|
||||||
|
|
||||||
board = env.BoardConfig()
|
board = env.BoardConfig()
|
||||||
|
|
||||||
@ -47,14 +45,14 @@ if pioutil.is_pio_build():
|
|||||||
#series = mcu_type[:7].upper() + "xx"
|
#series = mcu_type[:7].upper() + "xx"
|
||||||
|
|
||||||
# Prepare a new empty folder at the destination
|
# Prepare a new empty folder at the destination
|
||||||
variant_dir = os.path.join(FRAMEWORK_DIR, "variants", variant)
|
variant_dir = FRAMEWORK_DIR / "variants" / variant
|
||||||
if os.path.isdir(variant_dir):
|
if variant_dir.is_dir():
|
||||||
shutil.rmtree(variant_dir)
|
shutil.rmtree(variant_dir)
|
||||||
if not os.path.isdir(variant_dir):
|
if not variant_dir.is_dir():
|
||||||
os.mkdir(variant_dir)
|
variant_dir.mkdir()
|
||||||
|
|
||||||
# Source dir is a local variant sub-folder
|
# Source dir is a local variant sub-folder
|
||||||
source_dir = os.path.join("buildroot/share/PlatformIO/variants", variant)
|
source_dir = Path("buildroot/share/PlatformIO/variants", variant)
|
||||||
assert os.path.isdir(source_dir)
|
assert source_dir.is_dir()
|
||||||
|
|
||||||
marlin.copytree(source_dir, variant_dir)
|
marlin.copytree(source_dir, variant_dir)
|
||||||
|
@ -4,37 +4,32 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,marlin
|
|
||||||
# Append ${PROGNAME}.bin firmware after bootloader and save it as 'jgaurora_firmware.bin'
|
# Append ${PROGNAME}.bin firmware after bootloader and save it as 'jgaurora_firmware.bin'
|
||||||
def addboot(source, target, env):
|
def addboot(source, target, env):
|
||||||
firmware = open(target[0].path, "rb")
|
from pathlib import Path
|
||||||
lengthfirmware = os.path.getsize(target[0].path)
|
|
||||||
bootloader_bin = "buildroot/share/PlatformIO/scripts/" + "jgaurora_bootloader.bin"
|
|
||||||
bootloader = open(bootloader_bin, "rb")
|
|
||||||
lengthbootloader = os.path.getsize(bootloader_bin)
|
|
||||||
|
|
||||||
firmware_with_boothloader_bin = target[0].dir.path + '/firmware_with_bootloader.bin'
|
fw_path = Path(target[0].path)
|
||||||
if os.path.exists(firmware_with_boothloader_bin):
|
fwb_path = fw_path.parent / 'firmware_with_bootloader.bin'
|
||||||
os.remove(firmware_with_boothloader_bin)
|
with fwb_path.open("wb") as fwb_file:
|
||||||
firmwareimage = open(firmware_with_boothloader_bin, "wb")
|
bl_path = Path("buildroot/share/PlatformIO/scripts/jgaurora_bootloader.bin")
|
||||||
position = 0
|
bl_file = bl_path.open("rb")
|
||||||
while position < lengthbootloader:
|
while True:
|
||||||
byte = bootloader.read(1)
|
b = bl_file.read(1)
|
||||||
firmwareimage.write(byte)
|
if b == b'': break
|
||||||
position += 1
|
else: fwb_file.write(b)
|
||||||
position = 0
|
|
||||||
while position < lengthfirmware:
|
|
||||||
byte = firmware.read(1)
|
|
||||||
firmwareimage.write(byte)
|
|
||||||
position += 1
|
|
||||||
bootloader.close()
|
|
||||||
firmware.close()
|
|
||||||
firmwareimage.close()
|
|
||||||
|
|
||||||
firmware_without_bootloader_bin = target[0].dir.path + '/firmware_for_sd_upload.bin'
|
with fw_path.open("rb") as fw_file:
|
||||||
if os.path.exists(firmware_without_bootloader_bin):
|
while True:
|
||||||
os.remove(firmware_without_bootloader_bin)
|
b = fw_file.read(1)
|
||||||
os.rename(target[0].path, firmware_without_bootloader_bin)
|
if b == b'': break
|
||||||
#os.rename(target[0].dir.path+'/firmware_with_bootloader.bin', target[0].dir.path+'/firmware.bin')
|
else: fwb_file.write(b)
|
||||||
|
|
||||||
|
fws_path = Path(target[0].dir.path, 'firmware_for_sd_upload.bin')
|
||||||
|
if fws_path.exists():
|
||||||
|
fws_path.unlink()
|
||||||
|
|
||||||
|
fw_path.rename(fws_path)
|
||||||
|
|
||||||
|
import marlin
|
||||||
marlin.add_post_action(addboot);
|
marlin.add_post_action(addboot);
|
||||||
|
@ -8,10 +8,8 @@
|
|||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,marlin
|
import os,marlin
|
||||||
Import("env")
|
|
||||||
|
|
||||||
from SCons.Script import DefaultEnvironment
|
board = marlin.env.BoardConfig()
|
||||||
board = DefaultEnvironment().BoardConfig()
|
|
||||||
|
|
||||||
def encryptByte(byte):
|
def encryptByte(byte):
|
||||||
byte = 0xFF & ((byte << 6) | (byte >> 2))
|
byte = 0xFF & ((byte << 6) | (byte >> 2))
|
||||||
|
@ -2,21 +2,18 @@
|
|||||||
# marlin.py
|
# marlin.py
|
||||||
# Helper module with some commonly-used functions
|
# Helper module with some commonly-used functions
|
||||||
#
|
#
|
||||||
import os,shutil
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from SCons.Script import DefaultEnvironment
|
from SCons.Script import DefaultEnvironment
|
||||||
env = DefaultEnvironment()
|
env = DefaultEnvironment()
|
||||||
|
|
||||||
from os.path import join
|
|
||||||
|
|
||||||
def copytree(src, dst, symlinks=False, ignore=None):
|
def copytree(src, dst, symlinks=False, ignore=None):
|
||||||
for item in os.listdir(src):
|
for item in src.iterdir():
|
||||||
s = join(src, item)
|
if item.is_dir():
|
||||||
d = join(dst, item)
|
shutil.copytree(item, dst / item.name, symlinks, ignore)
|
||||||
if os.path.isdir(s):
|
|
||||||
shutil.copytree(s, d, symlinks, ignore)
|
|
||||||
else:
|
else:
|
||||||
shutil.copy2(s, d)
|
shutil.copy2(item, dst / item.name)
|
||||||
|
|
||||||
def replace_define(field, value):
|
def replace_define(field, value):
|
||||||
for define in env['CPPDEFINES']:
|
for define in env['CPPDEFINES']:
|
||||||
@ -34,7 +31,7 @@ def relocate_vtab(address):
|
|||||||
|
|
||||||
# Replace the existing -Wl,-T with the given ldscript path
|
# Replace the existing -Wl,-T with the given ldscript path
|
||||||
def custom_ld_script(ldname):
|
def custom_ld_script(ldname):
|
||||||
apath = os.path.abspath("buildroot/share/PlatformIO/ldscripts/" + ldname)
|
apath = str(Path("buildroot/share/PlatformIO/ldscripts", ldname).resolve())
|
||||||
for i, flag in enumerate(env["LINKFLAGS"]):
|
for i, flag in enumerate(env["LINKFLAGS"]):
|
||||||
if "-Wl,-T" in flag:
|
if "-Wl,-T" in flag:
|
||||||
env["LINKFLAGS"][i] = "-Wl,-T" + apath
|
env["LINKFLAGS"][i] = "-Wl,-T" + apath
|
||||||
@ -52,15 +49,15 @@ def encrypt_mks(source, target, env, new_name):
|
|||||||
mf = env["MARLIN_FEATURES"]
|
mf = env["MARLIN_FEATURES"]
|
||||||
if "FIRMWARE_BIN" in mf: new_name = mf["FIRMWARE_BIN"]
|
if "FIRMWARE_BIN" in mf: new_name = mf["FIRMWARE_BIN"]
|
||||||
|
|
||||||
fwpath = target[0].path
|
fwpath = Path(target[0].path)
|
||||||
fwfile = open(fwpath, "rb")
|
fwfile = fwpath.open("rb")
|
||||||
enfile = open(target[0].dir.path + "/" + new_name, "wb")
|
enfile = Path(target[0].dir.path, new_name).open("wb")
|
||||||
length = os.path.getsize(fwpath)
|
length = fwpath.stat().st_size
|
||||||
position = 0
|
position = 0
|
||||||
try:
|
try:
|
||||||
while position < length:
|
while position < length:
|
||||||
byte = fwfile.read(1)
|
byte = fwfile.read(1)
|
||||||
if position >= 320 and position < 31040:
|
if 320 <= position < 31040:
|
||||||
byte = chr(ord(byte) ^ key[position & 31])
|
byte = chr(ord(byte) ^ key[position & 31])
|
||||||
if sys.version_info[0] > 2:
|
if sys.version_info[0] > 2:
|
||||||
byte = bytes(byte, 'latin1')
|
byte = bytes(byte, 'latin1')
|
||||||
@ -69,7 +66,7 @@ def encrypt_mks(source, target, env, new_name):
|
|||||||
finally:
|
finally:
|
||||||
fwfile.close()
|
fwfile.close()
|
||||||
enfile.close()
|
enfile.close()
|
||||||
os.remove(fwpath)
|
fwpath.unlink()
|
||||||
|
|
||||||
def add_post_action(action):
|
def add_post_action(action):
|
||||||
env.AddPostAction(join("$BUILD_DIR", "${PROGNAME}.bin"), action);
|
env.AddPostAction(str(Path("$BUILD_DIR", "${PROGNAME}.bin")), action);
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
import re
|
|
||||||
|
|
||||||
opt_output = '--opt' in sys.argv
|
opt_output = '--opt' in sys.argv
|
||||||
output_suffix = '.sh' if opt_output else '' if '--bare-output' in sys.argv else '.gen'
|
output_suffix = '.sh' if opt_output else '' if '--bare-output' in sys.argv else '.gen'
|
||||||
|
@ -10,12 +10,10 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,sys,marlin
|
import marlin
|
||||||
Import("env")
|
|
||||||
|
|
||||||
from SCons.Script import DefaultEnvironment
|
|
||||||
board = DefaultEnvironment().BoardConfig()
|
|
||||||
|
|
||||||
|
env = marlin.env
|
||||||
|
board = env.BoardConfig()
|
||||||
board_keys = board.get("build").keys()
|
board_keys = board.get("build").keys()
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -55,8 +53,13 @@ if pioutil.is_pio_build():
|
|||||||
#
|
#
|
||||||
if 'rename' in board_keys:
|
if 'rename' in board_keys:
|
||||||
|
|
||||||
|
# If FIRMWARE_BIN is defined by config, override all
|
||||||
|
mf = env["MARLIN_FEATURES"]
|
||||||
|
if "FIRMWARE_BIN" in mf: new_name = mf["FIRMWARE_BIN"]
|
||||||
|
else: new_name = board.get("build.rename")
|
||||||
|
|
||||||
def rename_target(source, target, env):
|
def rename_target(source, target, env):
|
||||||
firmware = os.path.join(target[0].dir.path, board.get("build.rename"))
|
from pathlib import Path
|
||||||
os.replace(target[0].path, firmware)
|
Path(target[0].path).replace(Path(target[0].dir.path, new_name))
|
||||||
|
|
||||||
marlin.add_post_action(rename_target)
|
marlin.add_post_action(rename_target)
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#
|
#
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
import os,sys
|
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
def is_pio_build():
|
def is_pio_build():
|
||||||
from SCons.Script import DefaultEnvironment
|
from SCons.Script import DefaultEnvironment
|
||||||
env = DefaultEnvironment()
|
env = DefaultEnvironment()
|
||||||
|
if "IsCleanTarget" in dir(env) and env.IsCleanTarget(): return False
|
||||||
return not env.IsIntegrationDump()
|
return not env.IsIntegrationDump()
|
||||||
|
|
||||||
def get_pio_version():
|
def get_pio_version():
|
||||||
|
@ -5,11 +5,13 @@
|
|||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
|
|
||||||
import os,re,sys
|
import re,sys
|
||||||
|
from pathlib import Path
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
def get_envs_for_board(board):
|
def get_envs_for_board(board):
|
||||||
with open(os.path.join("Marlin", "src", "pins", "pins.h"), "r") as file:
|
ppath = Path("Marlin/src/pins/pins.h")
|
||||||
|
with ppath.open() as file:
|
||||||
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
envregex = r"(?:env|win):"
|
envregex = r"(?:env|win):"
|
||||||
@ -52,11 +54,16 @@ if pioutil.is_pio_build():
|
|||||||
if 'PIOENV' not in env:
|
if 'PIOENV' not in env:
|
||||||
raise SystemExit("Error: PIOENV is not defined. This script is intended to be used with PlatformIO")
|
raise SystemExit("Error: PIOENV is not defined. This script is intended to be used with PlatformIO")
|
||||||
|
|
||||||
if 'MARLIN_FEATURES' not in env:
|
# Require PlatformIO 6.1.1 or later
|
||||||
raise SystemExit("Error: this script should be used after common Marlin scripts")
|
vers = pioutil.get_pio_version()
|
||||||
|
if vers < [6, 1, 1]:
|
||||||
|
raise SystemExit("Error: Marlin requires PlatformIO >= 6.1.1. Use 'pio upgrade' to get a newer version.")
|
||||||
|
|
||||||
if 'MOTHERBOARD' not in env['MARLIN_FEATURES']:
|
if 'MARLIN_FEATURES' not in env:
|
||||||
raise SystemExit("Error: MOTHERBOARD is not defined in Configuration.h")
|
raise SystemExit("Error: this script should be used after common Marlin scripts.")
|
||||||
|
|
||||||
|
if len(env['MARLIN_FEATURES']) == 0:
|
||||||
|
raise SystemExit("Error: Failed to parse Marlin features. See previous error messages.")
|
||||||
|
|
||||||
build_env = env['PIOENV']
|
build_env = env['PIOENV']
|
||||||
motherboard = env['MARLIN_FEATURES']['MOTHERBOARD']
|
motherboard = env['MARLIN_FEATURES']['MOTHERBOARD']
|
||||||
@ -72,9 +79,10 @@ if pioutil.is_pio_build():
|
|||||||
#
|
#
|
||||||
# Check for Config files in two common incorrect places
|
# Check for Config files in two common incorrect places
|
||||||
#
|
#
|
||||||
for p in [ env['PROJECT_DIR'], os.path.join(env['PROJECT_DIR'], "config") ]:
|
epath = Path(env['PROJECT_DIR'])
|
||||||
for f in [ "Configuration.h", "Configuration_adv.h" ]:
|
for p in [ epath, epath / "config" ]:
|
||||||
if os.path.isfile(os.path.join(p, f)):
|
for f in ("Configuration.h", "Configuration_adv.h"):
|
||||||
|
if (p / f).is_file():
|
||||||
err = "ERROR: Config files found in directory %s. Please move them into the Marlin subfolder." % p
|
err = "ERROR: Config files found in directory %s. Please move them into the Marlin subfolder." % p
|
||||||
raise SystemExit(err)
|
raise SystemExit(err)
|
||||||
|
|
||||||
@ -82,12 +90,12 @@ if pioutil.is_pio_build():
|
|||||||
# Find the name.cpp.o or name.o and remove it
|
# Find the name.cpp.o or name.o and remove it
|
||||||
#
|
#
|
||||||
def rm_ofile(subdir, name):
|
def rm_ofile(subdir, name):
|
||||||
build_dir = os.path.join(env['PROJECT_BUILD_DIR'], build_env);
|
build_dir = Path(env['PROJECT_BUILD_DIR'], build_env);
|
||||||
for outdir in [ build_dir, os.path.join(build_dir, "debug") ]:
|
for outdir in (build_dir, build_dir / "debug"):
|
||||||
for ext in [ ".cpp.o", ".o" ]:
|
for ext in (".cpp.o", ".o"):
|
||||||
fpath = os.path.join(outdir, "src", "src", subdir, name + ext)
|
fpath = outdir / "src/src" / subdir / (name + ext)
|
||||||
if os.path.exists(fpath):
|
if fpath.exists():
|
||||||
os.remove(fpath)
|
fpath.unlink()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Give warnings on every build
|
# Give warnings on every build
|
||||||
@ -104,16 +112,27 @@ if pioutil.is_pio_build():
|
|||||||
# Check for old files indicating an entangled Marlin (mixing old and new code)
|
# Check for old files indicating an entangled Marlin (mixing old and new code)
|
||||||
#
|
#
|
||||||
mixedin = []
|
mixedin = []
|
||||||
p = os.path.join(env['PROJECT_DIR'], "Marlin", "src", "lcd", "dogm")
|
p = Path(env['PROJECT_DIR'], "Marlin/src/lcd/dogm")
|
||||||
for f in [ "ultralcd_DOGM.cpp", "ultralcd_DOGM.h" ]:
|
for f in [ "ultralcd_DOGM.cpp", "ultralcd_DOGM.h" ]:
|
||||||
if os.path.isfile(os.path.join(p, f)):
|
if (p / f).is_file():
|
||||||
mixedin += [ f ]
|
mixedin += [ f ]
|
||||||
p = os.path.join(env['PROJECT_DIR'], "Marlin", "src", "feature", "bedlevel", "abl")
|
p = Path(env['PROJECT_DIR'], "Marlin/src/feature/bedlevel/abl")
|
||||||
for f in [ "abl.cpp", "abl.h" ]:
|
for f in [ "abl.cpp", "abl.h" ]:
|
||||||
if os.path.isfile(os.path.join(p, f)):
|
if (p / f).is_file():
|
||||||
mixedin += [ f ]
|
mixedin += [ f ]
|
||||||
if mixedin:
|
if mixedin:
|
||||||
err = "ERROR: Old files fell into your Marlin folder. Remove %s and try again" % ", ".join(mixedin)
|
err = "ERROR: Old files fell into your Marlin folder. Remove %s and try again" % ", ".join(mixedin)
|
||||||
raise SystemExit(err)
|
raise SystemExit(err)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check FILAMENT_RUNOUT_SCRIPT has a %c parammeter when required
|
||||||
|
#
|
||||||
|
if 'FILAMENT_RUNOUT_SENSOR' in env['MARLIN_FEATURES'] and 'NUM_RUNOUT_SENSORS' in env['MARLIN_FEATURES']:
|
||||||
|
if env['MARLIN_FEATURES']['NUM_RUNOUT_SENSORS'].isdigit() and int(env['MARLIN_FEATURES']['NUM_RUNOUT_SENSORS']) > 1:
|
||||||
|
if 'FILAMENT_RUNOUT_SCRIPT' in env['MARLIN_FEATURES']:
|
||||||
|
frs = env['MARLIN_FEATURES']['FILAMENT_RUNOUT_SCRIPT']
|
||||||
|
if "M600" in frs and "%c" not in frs:
|
||||||
|
err = "ERROR: FILAMENT_RUNOUT_SCRIPT needs a %c parameter (e.g., \"M600 T%c\") when NUM_RUNOUT_SENSORS is > 1"
|
||||||
|
raise SystemExit(err)
|
||||||
|
|
||||||
sanity_check_target()
|
sanity_check_target()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# preprocessor.py
|
# preprocessor.py
|
||||||
#
|
#
|
||||||
import subprocess,os,re
|
import subprocess
|
||||||
|
|
||||||
nocache = 1
|
nocache = 1
|
||||||
verbose = 0
|
verbose = 0
|
||||||
@ -54,51 +54,41 @@ def run_preprocessor(env, fn=None):
|
|||||||
#
|
#
|
||||||
def search_compiler(env):
|
def search_compiler(env):
|
||||||
|
|
||||||
ENV_BUILD_PATH = os.path.join(env['PROJECT_BUILD_DIR'], env['PIOENV'])
|
from pathlib import Path, PurePath
|
||||||
GCC_PATH_CACHE = os.path.join(ENV_BUILD_PATH, ".gcc_path")
|
|
||||||
|
ENV_BUILD_PATH = Path(env['PROJECT_BUILD_DIR'], env['PIOENV'])
|
||||||
|
GCC_PATH_CACHE = ENV_BUILD_PATH / ".gcc_path"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
filepath = env.GetProjectOption('custom_gcc')
|
gccpath = env.GetProjectOption('custom_gcc')
|
||||||
blab("Getting compiler from env")
|
blab("Getting compiler from env")
|
||||||
return filepath
|
return gccpath
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Warning: The cached .gcc_path will obscure a newly-installed toolkit
|
# Warning: The cached .gcc_path will obscure a newly-installed toolkit
|
||||||
if not nocache and os.path.exists(GCC_PATH_CACHE):
|
if not nocache and GCC_PATH_CACHE.exists():
|
||||||
blab("Getting g++ path from cache")
|
blab("Getting g++ path from cache")
|
||||||
with open(GCC_PATH_CACHE, 'r') as f:
|
return GCC_PATH_CACHE.read_text()
|
||||||
return f.read()
|
|
||||||
|
|
||||||
# Find the current platform compiler by searching the $PATH
|
# Use any item in $PATH corresponding to a platformio toolchain bin folder
|
||||||
# which will be in a platformio toolchain bin folder
|
path_separator = ':'
|
||||||
path_regex = re.escape(env['PROJECT_PACKAGES_DIR'])
|
gcc_exe = '*g++'
|
||||||
gcc = "g++"
|
|
||||||
if env['PLATFORM'] == 'win32':
|
if env['PLATFORM'] == 'win32':
|
||||||
path_separator = ';'
|
path_separator = ';'
|
||||||
path_regex += r'.*\\bin'
|
gcc_exe += ".exe"
|
||||||
gcc += ".exe"
|
|
||||||
else:
|
|
||||||
path_separator = ':'
|
|
||||||
path_regex += r'/.+/bin'
|
|
||||||
|
|
||||||
# Search for the compiler
|
# Search for the compiler in PATH
|
||||||
for pathdir in env['ENV']['PATH'].split(path_separator):
|
for ppath in map(Path, env['ENV']['PATH'].split(path_separator)):
|
||||||
if not re.search(path_regex, pathdir, re.IGNORECASE):
|
if ppath.match(env['PROJECT_PACKAGES_DIR'] + "/**/bin"):
|
||||||
continue
|
for gpath in ppath.glob(gcc_exe):
|
||||||
for filepath in os.listdir(pathdir):
|
gccpath = str(gpath.resolve())
|
||||||
if not filepath.endswith(gcc):
|
|
||||||
continue
|
|
||||||
# Use entire path to not rely on env PATH
|
|
||||||
filepath = os.path.sep.join([pathdir, filepath])
|
|
||||||
# Cache the g++ path to no search always
|
# Cache the g++ path to no search always
|
||||||
if not nocache and os.path.exists(ENV_BUILD_PATH):
|
if not nocache and ENV_BUILD_PATH.exists():
|
||||||
blab("Caching g++ for current env")
|
blab("Caching g++ for current env")
|
||||||
with open(GCC_PATH_CACHE, 'w+') as f:
|
GCC_PATH_CACHE.write_text(gccpath)
|
||||||
f.write(filepath)
|
return gccpath
|
||||||
|
|
||||||
return filepath
|
gccpath = env.get('CXX')
|
||||||
|
blab("Couldn't find a compiler! Fallback to %s" % gccpath)
|
||||||
filepath = env.get('CXX')
|
return gccpath
|
||||||
blab("Couldn't find a compiler! Fallback to %s" % filepath)
|
|
||||||
return filepath
|
|
||||||
|
421
buildroot/share/PlatformIO/scripts/schema.py
Normal file
421
buildroot/share/PlatformIO/scripts/schema.py
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# schema.py
|
||||||
|
#
|
||||||
|
# Used by signature.py via common-dependencies.py to generate a schema file during the PlatformIO build.
|
||||||
|
# This script can also be run standalone from within the Marlin repo to generate all schema files.
|
||||||
|
#
|
||||||
|
import re,json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def extend_dict(d:dict, k:tuple):
|
||||||
|
if len(k) >= 1 and k[0] not in d:
|
||||||
|
d[k[0]] = {}
|
||||||
|
if len(k) >= 2 and k[1] not in d[k[0]]:
|
||||||
|
d[k[0]][k[1]] = {}
|
||||||
|
if len(k) >= 3 and k[2] not in d[k[0]][k[1]]:
|
||||||
|
d[k[0]][k[1]][k[2]] = {}
|
||||||
|
|
||||||
|
grouping_patterns = [
|
||||||
|
re.compile(r'^([XYZIJKUVW]|[XYZ]2|Z[34]|E[0-7])$'),
|
||||||
|
re.compile(r'^AXIS\d$'),
|
||||||
|
re.compile(r'^(MIN|MAX)$'),
|
||||||
|
re.compile(r'^[0-8]$'),
|
||||||
|
re.compile(r'^HOTEND[0-7]$'),
|
||||||
|
re.compile(r'^(HOTENDS|BED|PROBE|COOLER)$'),
|
||||||
|
re.compile(r'^[XYZIJKUVW]M(IN|AX)$')
|
||||||
|
]
|
||||||
|
# If the indexed part of the option name matches a pattern
|
||||||
|
# then add it to the dictionary.
|
||||||
|
def find_grouping(gdict, filekey, sectkey, optkey, pindex):
|
||||||
|
optparts = optkey.split('_')
|
||||||
|
if 1 < len(optparts) > pindex:
|
||||||
|
for patt in grouping_patterns:
|
||||||
|
if patt.match(optparts[pindex]):
|
||||||
|
subkey = optparts[pindex]
|
||||||
|
modkey = '_'.join(optparts)
|
||||||
|
optparts[pindex] = '*'
|
||||||
|
wildkey = '_'.join(optparts)
|
||||||
|
kkey = f'{filekey}|{sectkey}|{wildkey}'
|
||||||
|
if kkey not in gdict: gdict[kkey] = []
|
||||||
|
gdict[kkey].append((subkey, modkey))
|
||||||
|
|
||||||
|
# Build a list of potential groups. Only those with multiple items will be grouped.
|
||||||
|
def group_options(schema):
|
||||||
|
for pindex in range(10, -1, -1):
|
||||||
|
found_groups = {}
|
||||||
|
for filekey, f in schema.items():
|
||||||
|
for sectkey, s in f.items():
|
||||||
|
for optkey in s:
|
||||||
|
find_grouping(found_groups, filekey, sectkey, optkey, pindex)
|
||||||
|
|
||||||
|
fkeys = [ k for k in found_groups.keys() ]
|
||||||
|
for kkey in fkeys:
|
||||||
|
items = found_groups[kkey]
|
||||||
|
if len(items) > 1:
|
||||||
|
f, s, w = kkey.split('|')
|
||||||
|
extend_dict(schema, (f, s, w)) # Add wildcard group to schema
|
||||||
|
for subkey, optkey in items: # Add all items to wildcard group
|
||||||
|
schema[f][s][w][subkey] = schema[f][s][optkey] # Move non-wildcard item to wildcard group
|
||||||
|
del schema[f][s][optkey]
|
||||||
|
del found_groups[kkey]
|
||||||
|
|
||||||
|
# Extract all board names from boards.h
|
||||||
|
def load_boards():
|
||||||
|
bpath = Path("Marlin/src/core/boards.h")
|
||||||
|
if bpath.is_file():
|
||||||
|
with bpath.open() as bfile:
|
||||||
|
boards = []
|
||||||
|
for line in bfile:
|
||||||
|
if line.startswith("#define BOARD_"):
|
||||||
|
bname = line.split()[1]
|
||||||
|
if bname != "BOARD_UNKNOWN": boards.append(bname)
|
||||||
|
return "['" + "','".join(boards) + "']"
|
||||||
|
return ''
|
||||||
|
|
||||||
|
#
|
||||||
|
# Extract a schema from the current configuration files
|
||||||
|
#
|
||||||
|
def extract():
|
||||||
|
# Load board names from boards.h
|
||||||
|
boards = load_boards()
|
||||||
|
|
||||||
|
# Parsing states
|
||||||
|
class Parse:
|
||||||
|
NORMAL = 0 # No condition yet
|
||||||
|
BLOCK_COMMENT = 1 # Looking for the end of the block comment
|
||||||
|
EOL_COMMENT = 2 # EOL comment started, maybe add the next comment?
|
||||||
|
GET_SENSORS = 3 # Gathering temperature sensor options
|
||||||
|
ERROR = 9 # Syntax error
|
||||||
|
|
||||||
|
# List of files to process, with shorthand
|
||||||
|
filekey = { 'Configuration.h':'basic', 'Configuration_adv.h':'advanced' }
|
||||||
|
# A JSON object to store the data
|
||||||
|
sch_out = { 'basic':{}, 'advanced':{} }
|
||||||
|
# Regex for #define NAME [VALUE] [COMMENT] with sanitized line
|
||||||
|
defgrep = re.compile(r'^(//)?\s*(#define)\s+([A-Za-z0-9_]+)\s*(.*?)\s*(//.+)?$')
|
||||||
|
# Defines to ignore
|
||||||
|
ignore = ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXAMPLES_DIR', 'CONFIG_EXPORT')
|
||||||
|
# Start with unknown state
|
||||||
|
state = Parse.NORMAL
|
||||||
|
# Serial ID
|
||||||
|
sid = 0
|
||||||
|
# Loop through files and parse them line by line
|
||||||
|
for fn, fk in filekey.items():
|
||||||
|
with Path("Marlin", fn).open() as fileobj:
|
||||||
|
section = 'none' # Current Settings section
|
||||||
|
line_number = 0 # Counter for the line number of the file
|
||||||
|
conditions = [] # Create a condition stack for the current file
|
||||||
|
comment_buff = [] # A temporary buffer for comments
|
||||||
|
options_json = '' # A buffer for the most recent options JSON found
|
||||||
|
eol_options = False # The options came from end of line, so only apply once
|
||||||
|
join_line = False # A flag that the line should be joined with the previous one
|
||||||
|
line = '' # A line buffer to handle \ continuation
|
||||||
|
last_added_ref = None # Reference to the last added item
|
||||||
|
# Loop through the lines in the file
|
||||||
|
for the_line in fileobj.readlines():
|
||||||
|
line_number += 1
|
||||||
|
|
||||||
|
# Clean the line for easier parsing
|
||||||
|
the_line = the_line.strip()
|
||||||
|
|
||||||
|
if join_line: # A previous line is being made longer
|
||||||
|
line += (' ' if line else '') + the_line
|
||||||
|
else: # Otherwise, start the line anew
|
||||||
|
line, line_start = the_line, line_number
|
||||||
|
|
||||||
|
# If the resulting line ends with a \, don't process now.
|
||||||
|
# Strip the end off. The next line will be joined with it.
|
||||||
|
join_line = line.endswith("\\")
|
||||||
|
if join_line:
|
||||||
|
line = line[:-1].strip()
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
line_end = line_number
|
||||||
|
|
||||||
|
defmatch = defgrep.match(line)
|
||||||
|
|
||||||
|
# Special handling for EOL comments after a #define.
|
||||||
|
# At this point the #define is already digested and inserted,
|
||||||
|
# so we have to extend it
|
||||||
|
if state == Parse.EOL_COMMENT:
|
||||||
|
# If the line is not a comment, we're done with the EOL comment
|
||||||
|
if not defmatch and the_line.startswith('//'):
|
||||||
|
comment_buff.append(the_line[2:].strip())
|
||||||
|
else:
|
||||||
|
last_added_ref['comment'] = ' '.join(comment_buff)
|
||||||
|
comment_buff = []
|
||||||
|
state = Parse.NORMAL
|
||||||
|
|
||||||
|
def use_comment(c, opt, sec, bufref):
|
||||||
|
if c.startswith(':'): # If the comment starts with : then it has magic JSON
|
||||||
|
d = c[1:].strip() # Strip the leading :
|
||||||
|
cbr = c.rindex('}') if d.startswith('{') else c.rindex(']') if d.startswith('[') else 0
|
||||||
|
if cbr:
|
||||||
|
opt, cmt = c[1:cbr+1].strip(), c[cbr+1:].strip()
|
||||||
|
if cmt != '': bufref.append(cmt)
|
||||||
|
else:
|
||||||
|
opt = c[1:].strip()
|
||||||
|
elif c.startswith('@section'): # Start a new section
|
||||||
|
sec = c[8:].strip()
|
||||||
|
elif not c.startswith('========'):
|
||||||
|
bufref.append(c)
|
||||||
|
return opt, sec
|
||||||
|
|
||||||
|
# In a block comment, capture lines up to the end of the comment.
|
||||||
|
# Assume nothing follows the comment closure.
|
||||||
|
if state in (Parse.BLOCK_COMMENT, Parse.GET_SENSORS):
|
||||||
|
endpos = line.find('*/')
|
||||||
|
if endpos < 0:
|
||||||
|
cline = line
|
||||||
|
else:
|
||||||
|
cline, line = line[:endpos].strip(), line[endpos+2:].strip()
|
||||||
|
|
||||||
|
# Temperature sensors are done
|
||||||
|
if state == Parse.GET_SENSORS:
|
||||||
|
options_json = f'[ {options_json[:-2]} ]'
|
||||||
|
|
||||||
|
state = Parse.NORMAL
|
||||||
|
|
||||||
|
# Strip the leading '*' from block comments
|
||||||
|
if cline.startswith('*'): cline = cline[1:].strip()
|
||||||
|
|
||||||
|
# Collect temperature sensors
|
||||||
|
if state == Parse.GET_SENSORS:
|
||||||
|
sens = re.match(r'^(-?\d+)\s*:\s*(.+)$', cline)
|
||||||
|
if sens:
|
||||||
|
s2 = sens[2].replace("'","''")
|
||||||
|
options_json += f"{sens[1]}:'{s2}', "
|
||||||
|
|
||||||
|
elif state == Parse.BLOCK_COMMENT:
|
||||||
|
|
||||||
|
# Look for temperature sensors
|
||||||
|
if cline == "Temperature sensors available:":
|
||||||
|
state, cline = Parse.GET_SENSORS, "Temperature Sensors"
|
||||||
|
|
||||||
|
options_json, section = use_comment(cline, options_json, section, comment_buff)
|
||||||
|
|
||||||
|
# For the normal state we're looking for any non-blank line
|
||||||
|
elif state == Parse.NORMAL:
|
||||||
|
# Skip a commented define when evaluating comment opening
|
||||||
|
st = 2 if re.match(r'^//\s*#define', line) else 0
|
||||||
|
cpos1 = line.find('/*') # Start a block comment on the line?
|
||||||
|
cpos2 = line.find('//', st) # Start an end of line comment on the line?
|
||||||
|
|
||||||
|
# Only the first comment starter gets evaluated
|
||||||
|
cpos = -1
|
||||||
|
if cpos1 != -1 and (cpos1 < cpos2 or cpos2 == -1):
|
||||||
|
cpos = cpos1
|
||||||
|
comment_buff = []
|
||||||
|
state = Parse.BLOCK_COMMENT
|
||||||
|
eol_options = False
|
||||||
|
|
||||||
|
elif cpos2 != -1 and (cpos2 < cpos1 or cpos1 == -1):
|
||||||
|
cpos = cpos2
|
||||||
|
|
||||||
|
# Comment after a define may be continued on the following lines
|
||||||
|
if defmatch != None and cpos > 10:
|
||||||
|
state = Parse.EOL_COMMENT
|
||||||
|
comment_buff = []
|
||||||
|
|
||||||
|
# Process the start of a new comment
|
||||||
|
if cpos != -1:
|
||||||
|
cline, line = line[cpos+2:].strip(), line[:cpos].strip()
|
||||||
|
|
||||||
|
if state == Parse.BLOCK_COMMENT:
|
||||||
|
# Strip leading '*' from block comments
|
||||||
|
if cline.startswith('*'): cline = cline[1:].strip()
|
||||||
|
else:
|
||||||
|
# Expire end-of-line options after first use
|
||||||
|
if cline.startswith(':'): eol_options = True
|
||||||
|
|
||||||
|
# Buffer a non-empty comment start
|
||||||
|
if cline != '':
|
||||||
|
options_json, section = use_comment(cline, options_json, section, comment_buff)
|
||||||
|
|
||||||
|
# If the line has nothing before the comment, go to the next line
|
||||||
|
if line == '':
|
||||||
|
options_json = ''
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parenthesize the given expression if needed
|
||||||
|
def atomize(s):
|
||||||
|
if s == '' \
|
||||||
|
or re.match(r'^[A-Za-z0-9_]*(\([^)]+\))?$', s) \
|
||||||
|
or re.match(r'^[A-Za-z0-9_]+ == \d+?$', s):
|
||||||
|
return s
|
||||||
|
return f'({s})'
|
||||||
|
|
||||||
|
#
|
||||||
|
# The conditions stack is an array containing condition-arrays.
|
||||||
|
# Each condition-array lists the conditions for the current block.
|
||||||
|
# IF/N/DEF adds a new condition-array to the stack.
|
||||||
|
# ELSE/ELIF/ENDIF pop the condition-array.
|
||||||
|
# ELSE/ELIF negate the last item in the popped condition-array.
|
||||||
|
# ELIF adds a new condition to the end of the array.
|
||||||
|
# ELSE/ELIF re-push the condition-array.
|
||||||
|
#
|
||||||
|
cparts = line.split()
|
||||||
|
iselif, iselse = cparts[0] == '#elif', cparts[0] == '#else'
|
||||||
|
if iselif or iselse or cparts[0] == '#endif':
|
||||||
|
if len(conditions) == 0:
|
||||||
|
raise Exception(f'no #if block at line {line_number}')
|
||||||
|
|
||||||
|
# Pop the last condition-array from the stack
|
||||||
|
prev = conditions.pop()
|
||||||
|
|
||||||
|
if iselif or iselse:
|
||||||
|
prev[-1] = '!' + prev[-1] # Invert the last condition
|
||||||
|
if iselif: prev.append(atomize(line[5:].strip()))
|
||||||
|
conditions.append(prev)
|
||||||
|
|
||||||
|
elif cparts[0] == '#if':
|
||||||
|
conditions.append([ atomize(line[3:].strip()) ])
|
||||||
|
elif cparts[0] == '#ifdef':
|
||||||
|
conditions.append([ f'defined({line[6:].strip()})' ])
|
||||||
|
elif cparts[0] == '#ifndef':
|
||||||
|
conditions.append([ f'!defined({line[7:].strip()})' ])
|
||||||
|
|
||||||
|
# Handle a complete #define line
|
||||||
|
elif defmatch != None:
|
||||||
|
|
||||||
|
# Get the match groups into vars
|
||||||
|
enabled, define_name, val = defmatch[1] == None, defmatch[3], defmatch[4]
|
||||||
|
|
||||||
|
# Increment the serial ID
|
||||||
|
sid += 1
|
||||||
|
|
||||||
|
# Create a new dictionary for the current #define
|
||||||
|
define_info = {
|
||||||
|
'section': section,
|
||||||
|
'name': define_name,
|
||||||
|
'enabled': enabled,
|
||||||
|
'line': line_start,
|
||||||
|
'sid': sid
|
||||||
|
}
|
||||||
|
|
||||||
|
# Type is based on the value
|
||||||
|
if val == '':
|
||||||
|
value_type = 'switch'
|
||||||
|
elif re.match(r'^(true|false)$', val):
|
||||||
|
value_type = 'bool'
|
||||||
|
val = val == 'true'
|
||||||
|
elif re.match(r'^[-+]?\s*\d+$', val):
|
||||||
|
value_type = 'int'
|
||||||
|
val = int(val)
|
||||||
|
elif re.match(r'[-+]?\s*(\d+\.|\d*\.\d+)([eE][-+]?\d+)?[fF]?', val):
|
||||||
|
value_type = 'float'
|
||||||
|
val = float(val.replace('f',''))
|
||||||
|
else:
|
||||||
|
value_type = 'string' if val[0] == '"' \
|
||||||
|
else 'char' if val[0] == "'" \
|
||||||
|
else 'state' if re.match(r'^(LOW|HIGH)$', val) \
|
||||||
|
else 'enum' if re.match(r'^[A-Za-z0-9_]{3,}$', val) \
|
||||||
|
else 'int[]' if re.match(r'^{(\s*[-+]?\s*\d+\s*(,\s*)?)+}$', val) \
|
||||||
|
else 'float[]' if re.match(r'^{(\s*[-+]?\s*(\d+\.|\d*\.\d+)([eE][-+]?\d+)?[fF]?\s*(,\s*)?)+}$', val) \
|
||||||
|
else 'array' if val[0] == '{' \
|
||||||
|
else ''
|
||||||
|
|
||||||
|
if val != '': define_info['value'] = val
|
||||||
|
if value_type != '': define_info['type'] = value_type
|
||||||
|
|
||||||
|
# Join up accumulated conditions with &&
|
||||||
|
if conditions: define_info['requires'] = ' && '.join(sum(conditions, []))
|
||||||
|
|
||||||
|
# If the comment_buff is not empty, add the comment to the info
|
||||||
|
if comment_buff:
|
||||||
|
full_comment = '\n'.join(comment_buff)
|
||||||
|
|
||||||
|
# An EOL comment will be added later
|
||||||
|
# The handling could go here instead of above
|
||||||
|
if state == Parse.EOL_COMMENT:
|
||||||
|
define_info['comment'] = ''
|
||||||
|
else:
|
||||||
|
define_info['comment'] = full_comment
|
||||||
|
comment_buff = []
|
||||||
|
|
||||||
|
# If the comment specifies units, add that to the info
|
||||||
|
units = re.match(r'^\(([^)]+)\)', full_comment)
|
||||||
|
if units:
|
||||||
|
units = units[1]
|
||||||
|
if units == 's' or units == 'sec': units = 'seconds'
|
||||||
|
define_info['units'] = units
|
||||||
|
|
||||||
|
# Set the options for the current #define
|
||||||
|
if define_name == "MOTHERBOARD" and boards != '':
|
||||||
|
define_info['options'] = boards
|
||||||
|
elif options_json != '':
|
||||||
|
define_info['options'] = options_json
|
||||||
|
if eol_options: options_json = ''
|
||||||
|
|
||||||
|
# Create section dict if it doesn't exist yet
|
||||||
|
if section not in sch_out[fk]: sch_out[fk][section] = {}
|
||||||
|
|
||||||
|
# If define has already been seen...
|
||||||
|
if define_name in sch_out[fk][section]:
|
||||||
|
info = sch_out[fk][section][define_name]
|
||||||
|
if isinstance(info, dict): info = [ info ] # Convert a single dict into a list
|
||||||
|
info.append(define_info) # Add to the list
|
||||||
|
else:
|
||||||
|
# Add the define dict with name as key
|
||||||
|
sch_out[fk][section][define_name] = define_info
|
||||||
|
|
||||||
|
if state == Parse.EOL_COMMENT:
|
||||||
|
last_added_ref = define_info
|
||||||
|
|
||||||
|
return sch_out
|
||||||
|
|
||||||
|
def dump_json(schema:dict, jpath:Path):
|
||||||
|
with jpath.open('w') as jfile:
|
||||||
|
json.dump(schema, jfile, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
def dump_yaml(schema:dict, ypath:Path):
|
||||||
|
import yaml
|
||||||
|
with ypath.open('w') as yfile:
|
||||||
|
yaml.dump(schema, yfile, default_flow_style=False, width=120, indent=2)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
schema = extract()
|
||||||
|
except Exception as exc:
|
||||||
|
print("Error: " + str(exc))
|
||||||
|
schema = None
|
||||||
|
|
||||||
|
if schema:
|
||||||
|
|
||||||
|
# Get the first command line argument
|
||||||
|
import sys
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
arg = sys.argv[1]
|
||||||
|
else:
|
||||||
|
arg = 'some'
|
||||||
|
|
||||||
|
# JSON schema
|
||||||
|
if arg in ['some', 'json', 'jsons']:
|
||||||
|
print("Generating JSON ...")
|
||||||
|
dump_json(schema, Path('schema.json'))
|
||||||
|
|
||||||
|
# JSON schema (wildcard names)
|
||||||
|
if arg in ['group', 'jsons']:
|
||||||
|
group_options(schema)
|
||||||
|
dump_json(schema, Path('schema_grouped.json'))
|
||||||
|
|
||||||
|
# YAML
|
||||||
|
if arg in ['some', 'yml', 'yaml']:
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError:
|
||||||
|
print("Installing YAML module ...")
|
||||||
|
import subprocess
|
||||||
|
try:
|
||||||
|
subprocess.run(['python3', '-m', 'pip', 'install', 'pyyaml'])
|
||||||
|
import yaml
|
||||||
|
except:
|
||||||
|
print("Failed to install YAML module")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Generating YML ...")
|
||||||
|
dump_yaml(schema, Path('schema.yml'))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -1,7 +1,11 @@
|
|||||||
#
|
#
|
||||||
# signature.py
|
# signature.py
|
||||||
#
|
#
|
||||||
import os,subprocess,re,json,hashlib
|
import schema
|
||||||
|
|
||||||
|
import subprocess,re,json,hashlib
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
#
|
#
|
||||||
# Return all macro names in a header as an array, so we can take
|
# Return all macro names in a header as an array, so we can take
|
||||||
@ -35,8 +39,8 @@ def get_file_sha256sum(filepath):
|
|||||||
# Compress a JSON file into a zip file
|
# Compress a JSON file into a zip file
|
||||||
#
|
#
|
||||||
import zipfile
|
import zipfile
|
||||||
def compress_file(filepath, outputbase):
|
def compress_file(filepath, outpath):
|
||||||
with zipfile.ZipFile(outputbase + '.zip', 'w', compression=zipfile.ZIP_BZIP2, compresslevel=9) as zipf:
|
with zipfile.ZipFile(outpath, 'w', compression=zipfile.ZIP_BZIP2, compresslevel=9) as zipf:
|
||||||
zipf.write(filepath, compress_type=zipfile.ZIP_BZIP2, compresslevel=9)
|
zipf.write(filepath, compress_type=zipfile.ZIP_BZIP2, compresslevel=9)
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -51,19 +55,19 @@ def compute_build_signature(env):
|
|||||||
# Definitions from these files will be kept
|
# Definitions from these files will be kept
|
||||||
files_to_keep = [ 'Marlin/Configuration.h', 'Marlin/Configuration_adv.h' ]
|
files_to_keep = [ 'Marlin/Configuration.h', 'Marlin/Configuration_adv.h' ]
|
||||||
|
|
||||||
build_dir = os.path.join(env['PROJECT_BUILD_DIR'], env['PIOENV'])
|
build_path = Path(env['PROJECT_BUILD_DIR'], env['PIOENV'])
|
||||||
|
|
||||||
# Check if we can skip processing
|
# Check if we can skip processing
|
||||||
hashes = ''
|
hashes = ''
|
||||||
for header in files_to_keep:
|
for header in files_to_keep:
|
||||||
hashes += get_file_sha256sum(header)[0:10]
|
hashes += get_file_sha256sum(header)[0:10]
|
||||||
|
|
||||||
marlin_json = os.path.join(build_dir, 'marlin_config.json')
|
marlin_json = build_path / 'marlin_config.json'
|
||||||
marlin_zip = os.path.join(build_dir, 'mc')
|
marlin_zip = build_path / 'mc.zip'
|
||||||
|
|
||||||
# Read existing config file
|
# Read existing config file
|
||||||
try:
|
try:
|
||||||
with open(marlin_json, 'r') as infile:
|
with marlin_json.open() as infile:
|
||||||
conf = json.load(infile)
|
conf = json.load(infile)
|
||||||
if conf['__INITIAL_HASH'] == hashes:
|
if conf['__INITIAL_HASH'] == hashes:
|
||||||
# Same configuration, skip recomputing the building signature
|
# Same configuration, skip recomputing the building signature
|
||||||
@ -109,7 +113,10 @@ def compute_build_signature(env):
|
|||||||
|
|
||||||
defines[key] = value if len(value) else ""
|
defines[key] = value if len(value) else ""
|
||||||
|
|
||||||
if not 'CONFIGURATION_EMBEDDING' in defines:
|
#
|
||||||
|
# Continue to gather data for CONFIGURATION_EMBEDDING or CONFIG_EXPORT
|
||||||
|
#
|
||||||
|
if not ('CONFIGURATION_EMBEDDING' in defines or 'CONFIG_EXPORT' in defines):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Second step is to filter useless macro
|
# Second step is to filter useless macro
|
||||||
@ -145,6 +152,85 @@ def compute_build_signature(env):
|
|||||||
if key in conf_defines[header]:
|
if key in conf_defines[header]:
|
||||||
data[header][key] = resolved_defines[key]
|
data[header][key] = resolved_defines[key]
|
||||||
|
|
||||||
|
# Every python needs this toy
|
||||||
|
def tryint(key):
|
||||||
|
try:
|
||||||
|
return int(defines[key])
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
config_dump = tryint('CONFIG_EXPORT')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Produce an INI file if CONFIG_EXPORT == 2
|
||||||
|
#
|
||||||
|
if config_dump == 2:
|
||||||
|
print("Generating config.ini ...")
|
||||||
|
config_ini = build_path / 'config.ini'
|
||||||
|
with config_ini.open('w') as outfile:
|
||||||
|
ignore = ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXPORT')
|
||||||
|
filegrp = { 'Configuration.h':'config:basic', 'Configuration_adv.h':'config:advanced' }
|
||||||
|
vers = defines["CONFIGURATION_H_VERSION"]
|
||||||
|
dt_string = datetime.now().strftime("%Y-%m-%d at %H:%M:%S")
|
||||||
|
ini_fmt = '{0:40}{1}\n'
|
||||||
|
outfile.write(
|
||||||
|
'#\n'
|
||||||
|
+ '# Marlin Firmware\n'
|
||||||
|
+ '# config.ini - Options to apply before the build\n'
|
||||||
|
+ '#\n'
|
||||||
|
+ f'# Generated by Marlin build on {dt_string}\n'
|
||||||
|
+ '#\n'
|
||||||
|
+ '\n'
|
||||||
|
+ '[config:base]\n'
|
||||||
|
+ ini_fmt.format('ini_use_config', ' = all')
|
||||||
|
+ ini_fmt.format('ini_config_vers', f' = {vers}')
|
||||||
|
)
|
||||||
|
# Loop through the data array of arrays
|
||||||
|
for header in data:
|
||||||
|
if header.startswith('__'):
|
||||||
|
continue
|
||||||
|
outfile.write('\n[' + filegrp[header] + ']\n')
|
||||||
|
for key in sorted(data[header]):
|
||||||
|
if key not in ignore:
|
||||||
|
val = 'on' if data[header][key] == '' else data[header][key]
|
||||||
|
outfile.write(ini_fmt.format(key.lower(), ' = ' + val))
|
||||||
|
|
||||||
|
#
|
||||||
|
# Produce a schema.json file if CONFIG_EXPORT == 3
|
||||||
|
#
|
||||||
|
if config_dump >= 3:
|
||||||
|
try:
|
||||||
|
conf_schema = schema.extract()
|
||||||
|
except Exception as exc:
|
||||||
|
print("Error: " + str(exc))
|
||||||
|
conf_schema = None
|
||||||
|
|
||||||
|
if conf_schema:
|
||||||
|
#
|
||||||
|
# Produce a schema.json file if CONFIG_EXPORT == 3
|
||||||
|
#
|
||||||
|
if config_dump in (3, 13):
|
||||||
|
print("Generating schema.json ...")
|
||||||
|
schema.dump_json(conf_schema, build_path / 'schema.json')
|
||||||
|
if config_dump == 13:
|
||||||
|
schema.group_options(conf_schema)
|
||||||
|
schema.dump_json(conf_schema, build_path / 'schema_grouped.json')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Produce a schema.yml file if CONFIG_EXPORT == 4
|
||||||
|
#
|
||||||
|
elif config_dump == 4:
|
||||||
|
print("Generating schema.yml ...")
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError:
|
||||||
|
env.Execute(env.VerboseAction(
|
||||||
|
'$PYTHONEXE -m pip install "pyyaml"',
|
||||||
|
"Installing YAML for schema.yml export",
|
||||||
|
))
|
||||||
|
import yaml
|
||||||
|
schema.dump_yaml(conf_schema, build_path / 'schema.yml')
|
||||||
|
|
||||||
# Append the source code version and date
|
# Append the source code version and date
|
||||||
data['VERSION'] = {}
|
data['VERSION'] = {}
|
||||||
data['VERSION']['DETAILED_BUILD_VERSION'] = resolved_defines['DETAILED_BUILD_VERSION']
|
data['VERSION']['DETAILED_BUILD_VERSION'] = resolved_defines['DETAILED_BUILD_VERSION']
|
||||||
@ -156,11 +242,18 @@ def compute_build_signature(env):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
#
|
#
|
||||||
# Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_DUMP > 0
|
# Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_EXPORT == 1
|
||||||
#
|
#
|
||||||
with open(marlin_json, 'w') as outfile:
|
if config_dump == 1 or 'CONFIGURATION_EMBEDDING' in defines:
|
||||||
|
with marlin_json.open('w') as outfile:
|
||||||
json.dump(data, outfile, separators=(',', ':'))
|
json.dump(data, outfile, separators=(',', ':'))
|
||||||
|
|
||||||
|
#
|
||||||
|
# The rest only applies to CONFIGURATION_EMBEDDING
|
||||||
|
#
|
||||||
|
if not 'CONFIGURATION_EMBEDDING' in defines:
|
||||||
|
return
|
||||||
|
|
||||||
# Compress the JSON file as much as we can
|
# Compress the JSON file as much as we can
|
||||||
compress_file(marlin_json, marlin_zip)
|
compress_file(marlin_json, marlin_zip)
|
||||||
|
|
||||||
@ -173,11 +266,11 @@ def compute_build_signature(env):
|
|||||||
+ b'const unsigned char mc_zip[] PROGMEM = {\n '
|
+ b'const unsigned char mc_zip[] PROGMEM = {\n '
|
||||||
)
|
)
|
||||||
count = 0
|
count = 0
|
||||||
for b in open(os.path.join(build_dir, 'mc.zip'), 'rb').read():
|
for b in (build_path / 'mc.zip').open('rb').read():
|
||||||
result_file.write(b' 0x%02X,' % b)
|
result_file.write(b' 0x%02X,' % b)
|
||||||
count += 1
|
count += 1
|
||||||
if (count % 16 == 0):
|
if count % 16 == 0:
|
||||||
result_file.write(b'\n ')
|
result_file.write(b'\n ')
|
||||||
if (count % 16):
|
if count % 16:
|
||||||
result_file.write(b'\n')
|
result_file.write(b'\n')
|
||||||
result_file.write(b'};\n')
|
result_file.write(b'};\n')
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# simulator.py
|
# simulator.py
|
||||||
# PlatformIO pre: script for simulator builds
|
# PlatformIO pre: script for simulator builds
|
||||||
#
|
#
|
||||||
|
|
||||||
import pioutil
|
import pioutil
|
||||||
if pioutil.is_pio_build():
|
if pioutil.is_pio_build():
|
||||||
# Get the environment thus far for the build
|
# Get the environment thus far for the build
|
||||||
|
@ -144,7 +144,7 @@ class DWIN_ICO_File():
|
|||||||
# process each file:
|
# process each file:
|
||||||
try:
|
try:
|
||||||
index = int(dirEntry.name[0:3])
|
index = int(dirEntry.name[0:3])
|
||||||
if (index < 0) or (index > 255):
|
if not (0 <= index <= 255):
|
||||||
print('...Ignoring invalid index on', dirEntry.path)
|
print('...Ignoring invalid index on', dirEntry.path)
|
||||||
continue
|
continue
|
||||||
#dirEntry.path is iconDir/name
|
#dirEntry.path is iconDir/name
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#----------------------------------------------------------------
|
#----------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import os.path
|
import os.path
|
||||||
import argparse
|
import argparse
|
||||||
import DWIN_ICO
|
import DWIN_ICO
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
#----------------------------------------------------------------
|
#----------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import os.path
|
import os.path
|
||||||
import argparse
|
import argparse
|
||||||
import DWIN_ICO
|
import DWIN_ICO
|
||||||
|
@ -50,7 +50,7 @@ class Thermistor:
|
|||||||
|
|
||||||
if c < 0:
|
if c < 0:
|
||||||
print("//////////////////////////////////////////////////////////////////////////////////////")
|
print("//////////////////////////////////////////////////////////////////////////////////////")
|
||||||
print("// WARNING: negative coefficient 'c'! Something may be wrong with the measurements! //")
|
print("// WARNING: Negative coefficient 'c'! Something may be wrong with the measurements! //")
|
||||||
print("//////////////////////////////////////////////////////////////////////////////////////")
|
print("//////////////////////////////////////////////////////////////////////////////////////")
|
||||||
c = -c
|
c = -c
|
||||||
self.c1 = a # Steinhart-Hart coefficients
|
self.c1 = a # Steinhart-Hart coefficients
|
||||||
@ -93,8 +93,8 @@ def main(argv):
|
|||||||
r2 = 1641.9 # resistance at middle temperature (1.6 KOhm)
|
r2 = 1641.9 # resistance at middle temperature (1.6 KOhm)
|
||||||
t3 = 250 # high temperature in Kelvin (250 degC)
|
t3 = 250 # high temperature in Kelvin (250 degC)
|
||||||
r3 = 226.15 # resistance at high temperature (226.15 Ohm)
|
r3 = 226.15 # resistance at high temperature (226.15 Ohm)
|
||||||
rp = 4700; # pull-up resistor (4.7 kOhm)
|
rp = 4700 # pull-up resistor (4.7 kOhm)
|
||||||
num_temps = 36; # number of entries for look-up table
|
num_temps = 36 # number of entries for look-up table
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(argv, "h", ["help", "rp=", "t1=", "t2=", "t3=", "num-temps="])
|
opts, args = getopt.getopt(argv, "h", ["help", "rp=", "t1=", "t2=", "t3=", "num-temps="])
|
||||||
@ -125,13 +125,13 @@ def main(argv):
|
|||||||
num_temps = int(arg)
|
num_temps = int(arg)
|
||||||
|
|
||||||
t = Thermistor(rp, t1, r1, t2, r2, t3, r3)
|
t = Thermistor(rp, t1, r1, t2, r2, t3, r3)
|
||||||
increment = int((ARES-1)/(num_temps-1));
|
increment = int((ARES - 1) / (num_temps - 1))
|
||||||
step = (TMIN-TMAX) / (num_temps-1)
|
step = int((TMIN - TMAX) / (num_temps - 1))
|
||||||
low_bound = t.temp(ARES-1);
|
low_bound = t.temp(ARES - 1)
|
||||||
up_bound = t.temp(1);
|
up_bound = t.temp(1)
|
||||||
min_temp = int(TMIN if TMIN > low_bound else low_bound)
|
min_temp = int(TMIN if TMIN > low_bound else low_bound)
|
||||||
max_temp = int(TMAX if TMAX < up_bound else up_bound)
|
max_temp = int(TMAX if TMAX < up_bound else up_bound)
|
||||||
temps = list(range(max_temp, TMIN+step, step));
|
temps = list(range(max_temp, TMIN + step, step))
|
||||||
|
|
||||||
print("// Thermistor lookup table for Marlin")
|
print("// Thermistor lookup table for Marlin")
|
||||||
print("// ./createTemperatureLookupMarlin.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps))
|
print("// ./createTemperatureLookupMarlin.py --rp=%s --t1=%s:%s --t2=%s:%s --t3=%s:%s --num-temps=%s" % (rp, t1, r1, t2, r2, t3, r3, num_temps))
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
# Generate Marlin TFT Images from bitmaps/PNG/JPG
|
# Generate Marlin TFT Images from bitmaps/PNG/JPG
|
||||||
|
|
||||||
import sys,re,struct
|
import sys,struct
|
||||||
from PIL import Image,ImageDraw
|
from PIL import Image
|
||||||
|
|
||||||
def image2bin(image, output_file):
|
def image2bin(image, output_file):
|
||||||
if output_file.endswith(('.c', '.cpp')):
|
if output_file.endswith(('.c', '.cpp')):
|
||||||
|
@ -189,9 +189,7 @@ def Upload(source, target, env):
|
|||||||
'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
||||||
'BOARD_CREALITY_V24S1']
|
'BOARD_CREALITY_V24S1']
|
||||||
# "upload_random_name": generate a random 8.3 firmware filename to upload
|
# "upload_random_name": generate a random 8.3 firmware filename to upload
|
||||||
upload_random_filename = marlin_motherboard in ['BOARD_CREALITY_V4', 'BOARD_CREALITY_V4210', 'BOARD_CREALITY_V422', 'BOARD_CREALITY_V423',
|
upload_random_filename = upload_delete_old_bins and not marlin_long_filename_host_support
|
||||||
'BOARD_CREALITY_V427', 'BOARD_CREALITY_V431', 'BOARD_CREALITY_V452', 'BOARD_CREALITY_V453',
|
|
||||||
'BOARD_CREALITY_V24S1'] and not marlin_long_filename_host_support
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ def resolve_path(path):
|
|||||||
while 0 <= path.find('../'):
|
while 0 <= path.find('../'):
|
||||||
end = path.find('../') - 1
|
end = path.find('../') - 1
|
||||||
start = path.find('/')
|
start = path.find('/')
|
||||||
while 0 <= path.find('/', start) and end > path.find('/', start):
|
while 0 <= path.find('/', start) < end:
|
||||||
start = path.find('/', start) + 1
|
start = path.find('/', start) + 1
|
||||||
path = path[0:start] + path[end + 4:]
|
path = path[0:start] + path[end + 4:]
|
||||||
|
|
||||||
@ -674,7 +674,7 @@ def line_print(line_input):
|
|||||||
if 0 == highlight[1]:
|
if 0 == highlight[1]:
|
||||||
found_1 = text.find(' ')
|
found_1 = text.find(' ')
|
||||||
found_tab = text.find('\t')
|
found_tab = text.find('\t')
|
||||||
if found_1 < 0 or found_1 > found_tab:
|
if not (0 <= found_1 <= found_tab):
|
||||||
found_1 = found_tab
|
found_1 = found_tab
|
||||||
write_to_screen_queue(text[:found_1 + 1])
|
write_to_screen_queue(text[:found_1 + 1])
|
||||||
for highlight_2 in highlights:
|
for highlight_2 in highlights:
|
||||||
@ -684,7 +684,7 @@ def line_print(line_input):
|
|||||||
if found >= 0:
|
if found >= 0:
|
||||||
found_space = text.find(' ', found_1 + 1)
|
found_space = text.find(' ', found_1 + 1)
|
||||||
found_tab = text.find('\t', found_1 + 1)
|
found_tab = text.find('\t', found_1 + 1)
|
||||||
if found_space < 0 or found_space > found_tab:
|
if not (0 <= found_space <= found_tab):
|
||||||
found_space = found_tab
|
found_space = found_tab
|
||||||
found_right = text.find(']', found + 1)
|
found_right = text.find(']', found + 1)
|
||||||
write_to_screen_queue(text[found_1 + 1:found_space + 1], highlight[2])
|
write_to_screen_queue(text[found_1 + 1:found_space + 1], highlight[2])
|
||||||
@ -701,7 +701,7 @@ def line_print(line_input):
|
|||||||
break
|
break
|
||||||
if did_something == False:
|
if did_something == False:
|
||||||
r_loc = text.find('\r') + 1
|
r_loc = text.find('\r') + 1
|
||||||
if r_loc > 0 and r_loc < len(text): # need to split this line
|
if 0 < r_loc < len(text): # need to split this line
|
||||||
text = text.split('\r')
|
text = text.split('\r')
|
||||||
for line in text:
|
for line in text:
|
||||||
if line != '':
|
if line != '':
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
import subprocess,os,sys,platform
|
import subprocess,os,platform
|
||||||
from SCons.Script import DefaultEnvironment
|
from SCons.Script import DefaultEnvironment
|
||||||
|
|
||||||
current_OS = platform.system()
|
current_OS = platform.system()
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
# Will continue on if a COM port isn't found so that the compilation can be done.
|
# Will continue on if a COM port isn't found so that the compilation can be done.
|
||||||
#
|
#
|
||||||
|
|
||||||
import os,sys
|
import os
|
||||||
from SCons.Script import DefaultEnvironment
|
from SCons.Script import DefaultEnvironment
|
||||||
import platform
|
import platform
|
||||||
current_OS = platform.system()
|
current_OS = platform.system()
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# Where have all the configurations gone?
|
# Where have all the configurations gone?
|
||||||
|
|
||||||
## https://github.com/MarlinFirmware/Configurations/archive/release-2.0.9.5.zip
|
## https://github.com/MarlinFirmware/Configurations/archive/release-2.0.9.6.zip
|
||||||
|
@ -20,6 +20,7 @@ build_src_filter = ${common.default_src_filter} +<src/HAL/ESP32>
|
|||||||
lib_ignore = NativeEthernet
|
lib_ignore = NativeEthernet
|
||||||
upload_speed = 500000
|
upload_speed = 500000
|
||||||
monitor_speed = 250000
|
monitor_speed = 250000
|
||||||
|
monitor_filters = colorize, time, send_on_enter, log2file, esp32_exception_decoder
|
||||||
#upload_port = marlinesp.local
|
#upload_port = marlinesp.local
|
||||||
#board_build.flash_mode = qio
|
#board_build.flash_mode = qio
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ boards_dir = buildroot/share/PlatformIO/boards
|
|||||||
default_envs = mega2560
|
default_envs = mega2560
|
||||||
include_dir = Marlin
|
include_dir = Marlin
|
||||||
extra_configs =
|
extra_configs =
|
||||||
|
Marlin/config.ini
|
||||||
ini/avr.ini
|
ini/avr.ini
|
||||||
ini/due.ini
|
ini/due.ini
|
||||||
ini/esp32.ini
|
ini/esp32.ini
|
||||||
@ -44,6 +45,7 @@ extra_configs =
|
|||||||
build_flags = -g3 -D__MARLIN_FIRMWARE__ -DNDEBUG
|
build_flags = -g3 -D__MARLIN_FIRMWARE__ -DNDEBUG
|
||||||
-fmax-errors=5
|
-fmax-errors=5
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
|
pre:buildroot/share/PlatformIO/scripts/configuration.py
|
||||||
pre:buildroot/share/PlatformIO/scripts/common-dependencies.py
|
pre:buildroot/share/PlatformIO/scripts/common-dependencies.py
|
||||||
pre:buildroot/share/PlatformIO/scripts/common-cxxflags.py
|
pre:buildroot/share/PlatformIO/scripts/common-cxxflags.py
|
||||||
pre:buildroot/share/PlatformIO/scripts/preflight-checks.py
|
pre:buildroot/share/PlatformIO/scripts/preflight-checks.py
|
||||||
@ -267,17 +269,10 @@ framework = arduino
|
|||||||
extra_scripts = ${common.extra_scripts}
|
extra_scripts = ${common.extra_scripts}
|
||||||
build_flags = ${common.build_flags}
|
build_flags = ${common.build_flags}
|
||||||
lib_deps = ${common.lib_deps}
|
lib_deps = ${common.lib_deps}
|
||||||
platform_packages = platformio/tool-dfuutil@^1.11.0
|
|
||||||
monitor_speed = 250000
|
monitor_speed = 250000
|
||||||
monitor_flags =
|
monitor_eol = LF
|
||||||
--quiet
|
monitor_echo = yes
|
||||||
--echo
|
monitor_filters = colorize, time, send_on_enter
|
||||||
--eol
|
|
||||||
LF
|
|
||||||
--filter
|
|
||||||
colorize
|
|
||||||
--filter
|
|
||||||
time
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Just print the dependency tree
|
# Just print the dependency tree
|
||||||
|
Loading…
Reference in New Issue
Block a user