diff --git a/pico_project.py b/pico_project.py index 3ace1b6..4e70dd9 100755 --- a/pico_project.py +++ b/pico_project.py @@ -7,32 +7,32 @@ # import argparse +import csv import os -import shutil -from pathlib import Path -import sys -import subprocess -from time import sleep import platform import shlex -import csv +import shutil +import subprocess +import sys +import threading +from pathlib import Path import tkinter as tk -from tkinter import messagebox as mb from tkinter import filedialog as fd +from tkinter import messagebox as mb from tkinter import simpledialog as sd from tkinter import ttk -CMAKELIST_FILENAME='CMakeLists.txt' -COMPILER_NAME='arm-none-eabi-gcc' +CMAKELIST_FILENAME = 'CMakeLists.txt' +COMPILER_NAME = 'arm-none-eabi-gcc' VSCODE_LAUNCH_FILENAME = 'launch.json' VSCODE_C_PROPERTIES_FILENAME = 'c_cpp_properties.json' -VSCODE_SETTINGS_FILENAME ='settings.json' -VSCODE_EXTENSIONS_FILENAME ='extensions.json' -VSCODE_FOLDER='.vscode' +VSCODE_SETTINGS_FILENAME = 'settings.json' +VSCODE_EXTENSIONS_FILENAME = 'extensions.json' +VSCODE_FOLDER = '.vscode' -CONFIG_UNSET="Not set" +CONFIG_UNSET = "Not set" # Standard libraries for all builds # And any more to string below, space separator @@ -45,20 +45,20 @@ LIB_NAME = 3 features_list = { - 'spi' : ("SPI", "spi.c", "hardware/spi.h", "hardware_spi"), - 'i2c' : ("I2C interface", "i2c.c", "hardware/i2c.h", "hardware_i2c"), - 'dma' : ("DMA support", "dma.c", "hardware/dma.h", "hardware_dma"), - 'pio' : ("PIO interface", "pio.c", "hardware/pio.h", "hardware_pio"), - 'interp' : ("HW interpolation", "interp.c", "hardware/interp.h", "hardware_interp"), - 'timer' : ("HW timer", "timer.c", "hardware/timer.h", "hardware_timer"), - 'watch' : ("HW watchdog", "watch.c", "hardware/watchdog.h", "hardware_watchdog"), - 'clocks' : ("HW clocks", "clocks.c", "hardware/clocks.h", "hardware_clocks"), + 'spi': ("SPI", "spi.c", "hardware/spi.h", "hardware_spi"), + 'i2c': ("I2C interface", "i2c.c", "hardware/i2c.h", "hardware_i2c"), + 'dma': ("DMA support", "dma.c", "hardware/dma.h", "hardware_dma"), + 'pio': ("PIO interface", "pio.c", "hardware/pio.h", "hardware_pio"), + 'interp': ("HW interpolation", "interp.c", "hardware/interp.h", "hardware_interp"), + 'timer': ("HW timer", "timer.c", "hardware/timer.h", "hardware_timer"), + 'watch': ("HW watchdog", "watch.c", "hardware/watchdog.h", "hardware_watchdog"), + 'clocks': ("HW clocks", "clocks.c", "hardware/clocks.h", "hardware_clocks"), } stdlib_examples_list = { - 'uart': ("UART", "uart.c", "hardware/uart.h", "hardware_uart"), - 'gpio' : ("GPIO interface", "gpio.c", "hardware/gpio.h", "hardware_gpio"), - 'div' : ("Low level HW Divider", "divider.c", "hardware/divider.h", "hardware_divider") + 'uart': ("UART", "uart.c", "hardware/uart.h", "hardware_uart"), + 'gpio': ("GPIO interface", "gpio.c", "hardware/gpio.h", "hardware_gpio"), + 'div': ("Low level HW Divider", "divider.c", "hardware/divider.h", "hardware_divider") } debugger_list = ["SWD", "PicoProbe"] @@ -67,137 +67,137 @@ DEFINES = 0 INITIALISERS = 1 # Could add an extra item that shows how to use some of the available functions for the feature -#EXAMPLE = 2 +# EXAMPLE = 2 # This also contains example code for the standard library (see stdlib_examples_list) code_fragments_per_feature = { - 'uart' : [ - ("// UART defines", - "// By default the stdout UART is `uart0`, so we will use the second one", - "#define UART_ID uart1", - "#define BAUD_RATE 9600", "", - "// Use pins 4 and 5 for UART1", - "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments", - "#define UART_TX_PIN 4", - "#define UART_RX_PIN 5" ), - - ( "// Set up our UART", - "uart_init(UART_ID, BAUD_RATE);", - "// Set the TX and RX pins by using the function select on the GPIO", - "// Set datasheet for more information on function select", - "gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);", - "gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);", "" ) - ], - 'spi' : [ - ( "// SPI Defines", - "// We are going to use SPI 0, and allocate it to the following GPIO pins", - "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments", - "#define SPI_PORT spi0", - "#define PIN_MISO 16", - "#define PIN_CS 17", - "#define PIN_SCK 18", - "#define PIN_MOSI 19" ), - - ( "// SPI initialisation. This example will use SPI at 1MHz.", - "spi_init(SPI_PORT, 1000*1000);", - "gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);", - "gpio_set_function(PIN_CS, GPIO_FUNC_SIO);", - "gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);", - "gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);", "", - "// Chip select is active-low, so we'll initialise it to a driven-high state", - "gpio_set_dir(PIN_CS, GPIO_OUT);", - "gpio_put(PIN_CS, 1);", "") - ], - 'i2c' : [ - ( - "// I2C defines", - "// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.", - "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments", - "#define I2C_PORT i2c0", - "#define I2C_SDA 8", - "#define I2C_SCL 9", - ), - ( - "// I2C Initialisation. Using it at 400Khz.", - "i2c_init(I2C_PORT, 400*1000);","", - "gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);", - "gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);", - "gpio_pull_up(I2C_SDA);", - "gpio_pull_up(I2C_SCL);" - ) - ], - "gpio" : [ - ( - "// GPIO defines", - "// Example uses GPIO 2", - "#define GPIO 2" - ), - ( - "// GPIO initialisation.", - "// We will make this GPIO an input, and pull it up by default", - "gpio_init(GPIO);", - "gpio_set_dir(GPIO, GPIO_IN);", - "gpio_pull_up(GPIO);","", - ) - ], - "interp" :[ - (), - ( - "// Interpolator example code", - "interp_config cfg = interp_default_config();", - "// Now use the various interpolator library functions for your use case", - "// e.g. interp_config_clamp(&cfg, true);", - "// interp_config_shift(&cfg, 2);", - "// Then set the config ", - "interp_set_config(interp0, 0, &cfg);", - ) - ], - - "timer" : [ - ( - "int64_t alarm_callback(alarm_id_t id, void *user_data) {", - " // Put your timeout handler code in here", - " return 0;", - "}" - ), - ( - "// Timer example code - This example fires off the callback after 2000ms", - "add_alarm_in_ms(2000, alarm_callback, NULL, false);" - ) - ], - - "watchdog":[ (), - ( - "// Watchdog example code", - "if (watchdog_caused_reboot()) {", - " // Whatever action you may take if a watchdog caused a reboot", - "}","", - "// Enable the watchdog, requiring the watchdog to be updated every 100ms or the chip will reboot", - "// second arg is pause on debug which means the watchdog will pause when stepping through code", - "watchdog_enable(100, 1);","", - "// You need to call this function at least more often than the 100ms in the enable call to prevent a reboot" - "watchdog_update();", - ) - ], - - "div" : [ (), + 'uart': [ + ("// UART defines", + "// By default the stdout UART is `uart0`, so we will use the second one", + "#define UART_ID uart1", + "#define BAUD_RATE 9600", "", + "// Use pins 4 and 5 for UART1", + "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments", + "#define UART_TX_PIN 4", + "#define UART_RX_PIN 5"), + + ("// Set up our UART", + "uart_init(UART_ID, BAUD_RATE);", + "// Set the TX and RX pins by using the function select on the GPIO", + "// Set datasheet for more information on function select", + "gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);", + "gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);", "") + ], + 'spi': [ + ("// SPI Defines", + "// We are going to use SPI 0, and allocate it to the following GPIO pins", + "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments", + "#define SPI_PORT spi0", + "#define PIN_MISO 16", + "#define PIN_CS 17", + "#define PIN_SCK 18", + "#define PIN_MOSI 19"), + + ("// SPI initialisation. This example will use SPI at 1MHz.", + "spi_init(SPI_PORT, 1000*1000);", + "gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);", + "gpio_set_function(PIN_CS, GPIO_FUNC_SIO);", + "gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);", + "gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);", "", + "// Chip select is active-low, so we'll initialise it to a driven-high state", + "gpio_set_dir(PIN_CS, GPIO_OUT);", + "gpio_put(PIN_CS, 1);", "") + ], + 'i2c': [ + ( + "// I2C defines", + "// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.", + "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments", + "#define I2C_PORT i2c0", + "#define I2C_SDA 8", + "#define I2C_SCL 9", + ), + ( + "// I2C Initialisation. Using it at 400Khz.", + "i2c_init(I2C_PORT, 400*1000);", "", + "gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);", + "gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);", + "gpio_pull_up(I2C_SDA);", + "gpio_pull_up(I2C_SCL);" + ) + ], + "gpio": [ + ( + "// GPIO defines", + "// Example uses GPIO 2", + "#define GPIO 2" + ), + ( + "// GPIO initialisation.", + "// We will make this GPIO an input, and pull it up by default", + "gpio_init(GPIO);", + "gpio_set_dir(GPIO, GPIO_IN);", + "gpio_pull_up(GPIO);", "", + ) + ], + "interp": [ + (), + ( + "// Interpolator example code", + "interp_config cfg = interp_default_config();", + "// Now use the various interpolator library functions for your use case", + "// e.g. interp_config_clamp(&cfg, true);", + "// interp_config_shift(&cfg, 2);", + "// Then set the config ", + "interp_set_config(interp0, 0, &cfg);", + ) + ], + + "timer": [ + ( + "int64_t alarm_callback(alarm_id_t id, void *user_data) {", + " // Put your timeout handler code in here", + " return 0;", + "}" + ), + ( + "// Timer example code - This example fires off the callback after 2000ms", + "add_alarm_in_ms(2000, alarm_callback, NULL, false);" + ) + ], + + "watchdog": [(), ( - "// Example of using the HW divider. The pico_divider library provides a more user friendly set of APIs ", - "// over the divider (and support for 64 bit divides), and of course by default regular C language integer", - "// divisions are redirected thru that library, meaning you can just use C level `/` and `%` operators and", - "// gain the benefits of the fast hardware divider.", - "int32_t dividend = 123456;", - "int32_t divisor = -321;", - "// This is the recommended signed fast divider for general use.", - "divmod_result_t result = hw_divider_divmod_s32(dividend, divisor);", - "printf(\"%d/%d = %d remainder %d\\n\", dividend, divisor, to_quotient_s32(result), to_remainder_s32(result));", - "// This is the recommended unsigned fast divider for general use.", - "int32_t udividend = 123456;", - "int32_t udivisor = 321;", - "divmod_result_t uresult = hw_divider_divmod_u32(udividend, udivisor);", - "printf(\"%d/%d = %d remainder %d\\n\", udividend, udivisor, to_quotient_u32(uresult), to_remainder_u32(uresult));" + "// Watchdog example code", + "if (watchdog_caused_reboot()) {", + " // Whatever action you may take if a watchdog caused a reboot", + "}", "", + "// Enable the watchdog, requiring the watchdog to be updated every 100ms or the chip will reboot", + "// second arg is pause on debug which means the watchdog will pause when stepping through code", + "watchdog_enable(100, 1);", "", + "// You need to call this function at least more often than the 100ms in the enable call to prevent a reboot" + "watchdog_update();", ) - ] + ], + + "div": [(), + ( + "// Example of using the HW divider. The pico_divider library provides a more user friendly set of APIs ", + "// over the divider (and support for 64 bit divides), and of course by default regular C language integer", + "// divisions are redirected thru that library, meaning you can just use C level `/` and `%` operators and", + "// gain the benefits of the fast hardware divider.", + "int32_t dividend = 123456;", + "int32_t divisor = -321;", + "// This is the recommended signed fast divider for general use.", + "divmod_result_t result = hw_divider_divmod_s32(dividend, divisor);", + "printf(\"%d/%d = %d remainder %d\\n\", dividend, divisor, to_quotient_s32(result), to_remainder_s32(result));", + "// This is the recommended unsigned fast divider for general use.", + "int32_t udividend = 123456;", + "int32_t udivisor = 321;", + "divmod_result_t uresult = hw_divider_divmod_u32(udividend, udivisor);", + "printf(\"%d/%d = %d remainder %d\\n\", udividend, udivisor, to_quotient_u32(uresult), to_remainder_u32(uresult));" + ) + ] } configuration_dictionary = list(dict()) @@ -205,7 +205,8 @@ isMac = False isWindows = False -class Parameters(): + +class Parameters: def __init__(self, sdkPath, projectRoot, projectName, gui, overwrite, build, features, projects, configs, runFromRAM, examples, uart, usb, cpp, debugger, exceptions, rtti): self.sdkPath = sdkPath @@ -226,31 +227,36 @@ def __init__(self, sdkPath, projectRoot, projectName, gui, overwrite, build, fea self.exceptions = exceptions self.rtti = rtti + def GetBackground(): return 'white' + def GetButtonBackground(): return 'white' + def GetTextColour(): return 'black' + def GetButtonTextColour(): return '#c51a4a' + def RunGUI(sdkpath, args): root = tk.Tk() style = ttk.Style(root) style.theme_use('default') ttk.Style().configure("TButton", padding=6, relief="groove", border=2, foreground=GetButtonTextColour(), background=GetButtonBackground()) - ttk.Style().configure("TLabel", foreground=GetTextColour(), background=GetBackground() ) - ttk.Style().configure("TCheckbutton", foreground=GetTextColour(), background=GetBackground() ) - ttk.Style().configure("TRadiobutton", foreground=GetTextColour(), background=GetBackground() ) - ttk.Style().configure("TLabelframe", foreground=GetTextColour(), background=GetBackground() ) - ttk.Style().configure("TLabelframe.Label", foreground=GetTextColour(), background=GetBackground() ) - ttk.Style().configure("TCombobox", foreground=GetTextColour(), background=GetBackground() ) - ttk.Style().configure("TListbox", foreground=GetTextColour(), background=GetBackground() ) + ttk.Style().configure("TLabel", foreground=GetTextColour(), background=GetBackground()) + ttk.Style().configure("TCheckbutton", foreground=GetTextColour(), background=GetBackground()) + ttk.Style().configure("TRadiobutton", foreground=GetTextColour(), background=GetBackground()) + ttk.Style().configure("TLabelframe", foreground=GetTextColour(), background=GetBackground()) + ttk.Style().configure("TLabelframe.Label", foreground=GetTextColour(), background=GetBackground()) + ttk.Style().configure("TCombobox", foreground=GetTextColour(), background=GetBackground()) + ttk.Style().configure("TListbox", foreground=GetTextColour(), background=GetBackground()) app = ProjectWindow(root, sdkpath, args) @@ -259,6 +265,7 @@ def RunGUI(sdkpath, args): root.mainloop() sys.exit(0) + def RunWarning(message): mb.showwarning('Raspberry Pi Pico Project Generator', message) sys.exit(0) @@ -273,28 +280,28 @@ def __init__(self, parent, entries): # This var will be automatically updated by the checkbox # The checkbox fills the var with the "onvalue" and "offvalue" as # it is clicked on and off - var = tk.StringVar(value='') # Off by default for the moment + var = tk.StringVar(value='') # Off by default for the moment self.vars.append(var) cb = ttk.Checkbutton(self, var=var, text=c, - onvalue=c, offvalue="", - width=20) + onvalue=c, offvalue="", + width=20) cb.pack(side="top", fill="x", anchor="w") def getCheckedItems(self): values = [] for var in self.vars: - value = var.get() + value = var.get() if value: values.append(value) return values -import threading + def thread_function(text, command, ok): l = shlex.split(command) proc = subprocess.Popen(l, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - for line in iter(proc.stdout.readline,''): + for line in iter(proc.stdout.readline, ''): if not line: if ok: ok["state"] = tk.NORMAL @@ -302,6 +309,7 @@ def thread_function(text, command, ok): text.insert(tk.END, line) text.see(tk.END) + # Function to run an OS command and display the output in a new modal window class DisplayWindow(tk.Toplevel): def __init__(self, parent, title): @@ -335,12 +343,14 @@ def init_window(self, title): def OK(self): self.destroy() + def RunCommandInWindow(parent, command): w = DisplayWindow(parent, command) x = threading.Thread(target=thread_function, args=(w.text, command, w.OKButton)) x.start() parent.wait_window(w) + class EditBoolWindow(sd.Dialog): def __init__(self, parent, configitem, current): @@ -349,7 +359,6 @@ def __init__(self, parent, configitem, current): self.current = current sd.Dialog.__init__(self, parent, "Edit boolean configuration") - def body(self, master): self.configure(background=GetBackground()) ttk.Label(self, text=self.config_item['name']).pack() @@ -362,6 +371,7 @@ def body(self, master): def get(self): return self.result.get() + class EditIntWindow(sd.Dialog): def __init__(self, parent, configitem, current): @@ -374,7 +384,7 @@ def body(self, master): self.configure(background=GetBackground()) str = self.config_item['name'] + " Max = " + self.config_item['max'] + " Min = " + self.config_item['min'] ttk.Label(self, text=str).pack() - self.input = tk.Entry(self) + self.input = tk.Entry(self) self.input.pack(pady=4) self.input.insert(0, self.current) ttk.Button(self, text=CONFIG_UNSET, command=self.unset).pack(pady=5) @@ -391,6 +401,7 @@ def unset(self): def get(self): return self.result + class EditEnumWindow(sd.Dialog): def __init__(self, parent, configitem, current): self.parent = parent @@ -399,10 +410,10 @@ def __init__(self, parent, configitem, current): sd.Dialog.__init__(self, parent, "Edit Enumeration configuration") def body(self, master): - #self.configure(background=GetBackground()) + # self.configure(background=GetBackground()) values = self.config_item['enumvalues'].split('|') - values.insert(0,'Not set') - self.input = ttk.Combobox(self, values=values, state='readonly') + values.insert(0, 'Not set') + self.input = ttk.Combobox(self, values=values, state='readonly') self.input.set(self.current) self.input.pack(pady=12) @@ -467,11 +478,11 @@ def init_window(self, args): i = 0 for box in self.listlist: box.grid(row=2, column=i, padx=0, sticky=tk.W + tk.E) - i+=1 + i += 1 - self.descriptionText.grid(row = 3, column=0, columnspan=4, sticky=tk.W + tk.E) - cancelButton.grid(column=4, row = 3, sticky=tk.E, padx=5) - okButton.grid(column=5, row = 3, padx=5) + self.descriptionText.grid(row=3, column=0, columnspan=4, sticky=tk.W + tk.E) + cancelButton.grid(column=4, row=3, sticky=tk.E, padx=5) + okButton.grid(column=5, row=3, padx=5) # populate the list box with our config options for conf in configuration_dictionary: @@ -488,18 +499,18 @@ def init_window(self, args): val = self.results.get(conf['name'], CONFIG_UNSET) self.valuelist.insert(tk.END, val) if val != CONFIG_UNSET: - self.valuelist.itemconfig(self.valuelist.size() - 1, {'bg':'green'}) + self.valuelist.itemconfig(self.valuelist.size() - 1, {'bg': 'green'}) def yview(self, *args): for box in self.listlist: box.yview(*args) def mousewheel(self, event): - if (event.num == 4): # Linux encodes wheel as 'buttons' 4 and 5 + if event.num == 4: # Linux encodes wheel as 'buttons' 4 and 5 delta = -1 - elif (event.num == 5): + elif event.num == 5: delta = 1 - else: # Windows & OSX + else: # Windows & OSX delta = event.delta for box in self.listlist: @@ -517,7 +528,7 @@ def changeSelection(self, evt): for conf in configuration_dictionary: if conf['name'] == config: self.descriptionText.config(state=tk.NORMAL) - self.descriptionText.delete(1.0,tk.END) + self.descriptionText.delete(1.0, tk.END) str = config + "\n" + conf['description'] self.descriptionText.insert(1.0, str) self.descriptionText.config(state=tk.DISABLED) @@ -541,9 +552,9 @@ def OnEntryUpDown(self, event): if 0 <= index < box.size(): for b in self.listlist: - b.selection_clear(0, tk.END) - b.selection_set(index) - b.see(index) + b.selection_clear(0, tk.END) + b.selection_set(index) + b.see(index) def doubleClick(self, evt): box = evt.widget @@ -552,9 +563,9 @@ def doubleClick(self, evt): # Get the associated dict entry from our list of configs for conf in configuration_dictionary: if conf['name'] == config: - if (conf['type'] == 'bool'): + if conf['type'] == 'bool': result = EditBoolWindow(self, conf, self.valuelist.get(index)).get() - elif (conf['type'] == 'int' or conf['type'] == ""): # "" defaults to int + elif conf['type'] == 'int' or conf['type'] == "": # "" defaults to int result = EditIntWindow(self, conf, self.valuelist.get(index)).get() elif conf['type'] == 'enum': result = EditEnumWindow(self, conf, self.valuelist.get(index)).get() @@ -563,7 +574,7 @@ def doubleClick(self, evt): self.valuelist.delete(index) self.valuelist.insert(index, result) if result != CONFIG_UNSET: - self.valuelist.itemconfig(index, {'bg':'green'}) + self.valuelist.itemconfig(index, {'bg': 'green'}) break def ok(self): @@ -601,7 +612,7 @@ def init_window(self, args): # Need to keep a reference to the image or it will not appear. self.logo = tk.PhotoImage(file=self._get_filepath("logo_alpha.gif")) - logowidget = ttk.Label(mainFrame, image=self.logo, borderwidth=0, relief="solid").grid(row=0,column=0, columnspan=5, pady=10) + logowidget = ttk.Label(mainFrame, image=self.logo, borderwidth=0, relief="solid").grid(row=0, column=0, columnspan=5, pady=10) namelbl = ttk.Label(mainFrame, text='Project Name :').grid(row=2, column=0, sticky=tk.E) self.projectName = tk.StringVar() @@ -611,37 +622,37 @@ def init_window(self, args): else: self.projectName.set('ProjectName') - nameEntry = ttk.Entry(mainFrame, textvariable=self.projectName).grid(row=2, column=1, sticky=tk.W+tk.E, padx=5) + nameEntry = ttk.Entry(mainFrame, textvariable=self.projectName).grid(row=2, column=1, sticky=tk.W + tk.E, padx=5) locationlbl = ttk.Label(mainFrame, text='Location :').grid(row=3, column=0, sticky=tk.E) self.locationName = tk.StringVar() self.locationName.set(os.getcwd()) - locationEntry = ttk.Entry(mainFrame, textvariable=self.locationName).grid(row=3, column=1, columnspan=3, sticky=tk.W+tk.E, padx=5) + locationEntry = ttk.Entry(mainFrame, textvariable=self.locationName).grid(row=3, column=1, columnspan=3, sticky=tk.W + tk.E, padx=5) locationBrowse = ttk.Button(mainFrame, text='Browse', command=self.browse).grid(row=3, column=4) # Features section featuresframe = ttk.LabelFrame(mainFrame, text="Library Options", relief=tk.RIDGE, borderwidth=2) - featuresframe.grid(row=4, column=0, columnspan=5, rowspan=5, ipadx=5, padx=5, sticky=tk.E+tk.W) + featuresframe.grid(row=4, column=0, columnspan=5, rowspan=5, ipadx=5, padx=5, sticky=tk.E + tk.W) # Add features to the list v = [] for i in features_list: v.append(features_list[i][GUI_TEXT]) - s = (len(v)//3) + 1 + s = (len(v) // 3) + 1 self.featuresEntry0 = ChecklistBox(featuresframe, v[:s]) self.featuresEntry0.grid(row=5, column=1, padx=4) - self.featuresEntry1 = ChecklistBox(featuresframe, v[s:s+s]) + self.featuresEntry1 = ChecklistBox(featuresframe, v[s:s + s]) self.featuresEntry1.grid(row=5, column=2, padx=4) - self.featuresEntry2 = ChecklistBox(featuresframe, v[s+s:]) + self.featuresEntry2 = ChecklistBox(featuresframe, v[s + s:]) self.featuresEntry2.grid(row=5, column=3, padx=4) optionsRow = 9 # output options section ooptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Console Options") - ooptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W) + ooptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E + tk.W) self.wantUART = tk.IntVar() self.wantUART.set(args.uart) @@ -655,7 +666,7 @@ def init_window(self, args): # Code options section coptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Code Options") - coptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=3, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W) + coptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=3, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E + tk.W) self.wantExamples = tk.IntVar() self.wantExamples.set(args.examples) @@ -684,7 +695,7 @@ def init_window(self, args): # Build Options section boptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Build Options") - boptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W) + boptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E + tk.W) self.wantBuild = tk.IntVar() self.wantBuild.set(args.build) @@ -697,12 +708,12 @@ def init_window(self, args): optionsRow += 2 vscodeoptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="IDE Options") - vscodeoptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W) + vscodeoptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E + tk.W) self.wantVSCode = tk.IntVar() ttk.Checkbutton(vscodeoptionsSubframe, text="Create VSCode project", variable=self.wantVSCode).grid(row=0, column=0, padx=4, sticky=tk.W) - ttk.Label(vscodeoptionsSubframe, text = " Debugger:").grid(row=0, column=1, padx=4, sticky=tk.W) + ttk.Label(vscodeoptionsSubframe, text=" Debugger:").grid(row=0, column=1, padx=4, sticky=tk.W) self.debugger = ttk.Combobox(vscodeoptionsSubframe, values=debugger_list, state="readonly") self.debugger.grid(row=0, column=2, padx=4, sticky=tk.W) @@ -728,7 +739,7 @@ def GetFeatures(self): f += self.featuresEntry2.getCheckedItems() for feat in features_list: - if features_list[feat][GUI_TEXT] in f : + if features_list[feat][GUI_TEXT] in f: features.append(feat) return features @@ -742,7 +753,7 @@ def OK(self): projectPath = self.locationName.get() features = self.GetFeatures() projects = list() - if (self.wantVSCode.get()): + if self.wantVSCode.get(): projects.append("vscode") p = Parameters(sdkPath=self.sdkpath, projectRoot=Path(projectPath), projectName=self.projectName.get(), @@ -767,6 +778,7 @@ def config(self): def _get_filepath(self, filename): return os.path.join(os.path.dirname(__file__), filename) + def CheckPrerequisites(): global isMac, isWindows isMac = (platform.system() == 'Darwin') @@ -781,13 +793,13 @@ def CheckSDKPath(gui): if sdkPath == None: m = 'Unable to locate the Raspberry Pi Pico SDK, PICO_SDK_PATH is not set' - if (gui): + if gui: RunWarning(m) else: print(m) elif not os.path.isdir(sdkPath): m = 'Unable to locate the Raspberry Pi Pico SDK, PICO_SDK_PATH does not point to a directory' - if (gui): + if gui: RunWarning(m) else: print(m) @@ -822,179 +834,170 @@ def ParseCommandLine(): def GenerateMain(folder, projectName, features, cpp): - if cpp: filename = Path(folder) / (projectName + '.cpp') else: filename = Path(folder) / (projectName + '.c') - file = open(filename, 'w') + with open(filename, 'w') as file: - main = ('#include \n' - '#include "pico/stdlib.h"\n' - ) - file.write(main) - - if (features): - - # Add any includes - for feat in features: - if (feat in features_list): - o = '#include "' + features_list[feat][H_FILE] + '"\n' - file.write(o) - if (feat in stdlib_examples_list): - o = '#include "' + stdlib_examples_list[feat][H_FILE] + '"\n' - file.write(o) - - file.write('\n') - - # Add any defines - for feat in features: - if (feat in code_fragments_per_feature): - for s in code_fragments_per_feature[feat][DEFINES]: - file.write(s) + main = ('#include \n' + '#include "pico/stdlib.h"\n' + ) + file.write(main) + + if features: + + # Add any includes + for feat in features: + if feat in features_list: + o = '#include "' + features_list[feat][H_FILE] + '"\n' + file.write(o) + if feat in stdlib_examples_list: + o = '#include "' + stdlib_examples_list[feat][H_FILE] + '"\n' + file.write(o) + + file.write('\n') + + # Add any defines + for feat in features: + if feat in code_fragments_per_feature: + for s in code_fragments_per_feature[feat][DEFINES]: + file.write(s) + file.write('\n') file.write('\n') - file.write('\n') - - main = ('\n\n' - 'int main()\n' - '{\n' - ' stdio_init_all();\n\n' - ) - if (features): - # Add any initialisers - indent = 4 - for feat in features: - if (feat in code_fragments_per_feature): - for s in code_fragments_per_feature[feat][INITIALISERS]: - main += (" " * indent) - main += s - main += '\n' - main += '\n' - - main += (' puts("Hello, world!");\n\n' - ' return 0;\n' - '}\n' - ) + main = ('\n\n' + 'int main()\n' + '{\n' + ' stdio_init_all();\n\n' + ) - file.write(main) + if features: + # Add any initialisers + indent = 4 + for feat in features: + if feat in code_fragments_per_feature: + for s in code_fragments_per_feature[feat][INITIALISERS]: + main += (" " * indent) + main += s + main += '\n' + main += '\n' + + main += (' puts("Hello, world!");\n\n' + ' return 0;\n' + '}\n' + ) - file.close() + file.write(main) def GenerateCMake(folder, params): - cmake_header1 = ("# Generated Cmake Pico project file\n\n" - "cmake_minimum_required(VERSION 3.13)\n\n" - "set(CMAKE_C_STANDARD 11)\n" - "set(CMAKE_CXX_STANDARD 17)\n\n" - "# initalize pico_sdk from installed location\n" - "# (note this can come from environment, CMake cache etc)\n" - ) + "cmake_minimum_required(VERSION 3.13)\n\n" + "set(CMAKE_C_STANDARD 11)\n" + "set(CMAKE_CXX_STANDARD 17)\n\n" + "# initalize pico_sdk from installed location\n" + "# (note this can come from environment, CMake cache etc)\n" + ) cmake_header2 = ("# Pull in Raspberry Pi Pico SDK (must be before project)\n" - "include(pico_sdk_import.cmake)\n\n" - ) + "include(pico_sdk_import.cmake)\n\n" + ) cmake_header3 = ( - "\n# Initialise the Raspberry Pi Pico SDK\n" - "pico_sdk_init()\n\n" - "# Add executable. Default name is the project name, version 0.1\n\n" - ) - + "\n# Initialise the Raspberry Pi Pico SDK\n" + "pico_sdk_init()\n\n" + "# Add executable. Default name is the project name, version 0.1\n\n" + ) filename = Path(folder) / CMAKELIST_FILENAME - file = open(filename, 'w') - - file.write(cmake_header1) + with open(filename, 'w') as file: - # OK, for the path, CMake will accept forward slashes on Windows, and thats - # seemingly a bit easier to handle than the backslashes + file.write(cmake_header1) - p = str(params.sdkPath).replace('\\','/') - p = '\"' + p + '\"' + # OK, for the path, CMake will accept forward slashes on Windows, and thats + # seemingly a bit easier to handle than the backslashes - file.write('set(PICO_SDK_PATH ' + p + ')\n\n') - file.write(cmake_header2) - file.write('project(' + params.projectName + ' C CXX ASM)\n') + p = str(params.sdkPath).replace('\\', '/') + p = '\"' + p + '\"' - if params.exceptions: - file.write("\nset(PICO_CXX_ENABLE_EXCEPTIONS 1)\n") + file.write('set(PICO_SDK_PATH ' + p + ')\n\n') + file.write(cmake_header2) + file.write('project(' + params.projectName + ' C CXX ASM)\n') - if params.rtti: - file.write("\nset(PICO_CXX_ENABLE_RTTI 1)\n") + if params.exceptions: + file.write("\nset(PICO_CXX_ENABLE_EXCEPTIONS 1)\n") - file.write(cmake_header3) + if params.rtti: + file.write("\nset(PICO_CXX_ENABLE_RTTI 1)\n") - # add the preprocessor defines for overall configuration - if params.configs: - file.write('# Add any PICO_CONFIG entries specified in the Advanced settings\n') - for c, v in params.configs.items(): - if v == "True": - v = "1" - elif v == "False": - v = "0" - file.write('add_compile_definitions(' + c + '=' + v + ')\n') - file.write('\n') + file.write(cmake_header3) - # No GUI/command line to set a different executable name at this stage - executableName = params.projectName + # add the preprocessor defines for overall configuration + if params.configs: + file.write('# Add any PICO_CONFIG entries specified in the Advanced settings\n') + for c, v in params.configs.items(): + if v == "True": + v = "1" + elif v == "False": + v = "0" + file.write('add_compile_definitions(' + c + '=' + v + ')\n') + file.write('\n') - if params.wantCPP: - file.write('add_executable(' + params.projectName + ' ' + params.projectName + '.cpp )\n\n') - else: - file.write('add_executable(' + params.projectName + ' ' + params.projectName + '.c )\n\n') - - file.write('pico_set_program_name(' + params.projectName + ' "' + executableName + '")\n') - file.write('pico_set_program_version(' + params.projectName + ' "0.1")\n\n') + # No GUI/command line to set a different executable name at this stage + executableName = params.projectName - if params.wantRunFromRAM: - file.write('# no_flash means the target is to run from RAM\n') - file.write('pico_set_binary_type(' + params.projectName + ' no_flash)\n\n') + if params.wantCPP: + file.write('add_executable(' + params.projectName + ' ' + params.projectName + '.cpp )\n\n') + else: + file.write('add_executable(' + params.projectName + ' ' + params.projectName + '.c )\n\n') - # Console output destinations - if params.wantUART: - file.write('pico_enable_stdio_uart(' + params.projectName + ' 1)\n') - else: - file.write('pico_enable_stdio_uart(' + params.projectName + ' 0)\n') + file.write('pico_set_program_name(' + params.projectName + ' "' + executableName + '")\n') + file.write('pico_set_program_version(' + params.projectName + ' "0.1")\n\n') - if params.wantUSB: - file.write('pico_enable_stdio_usb(' + params.projectName + ' 1)\n\n') - else: - file.write('pico_enable_stdio_usb(' + params.projectName + ' 0)\n\n') + if params.wantRunFromRAM: + file.write('# no_flash means the target is to run from RAM\n') + file.write('pico_set_binary_type(' + params.projectName + ' no_flash)\n\n') - # Standard libraries - file.write('# Add the standard library to the build\n') - file.write('target_link_libraries(' + params.projectName + ' ' + STANDARD_LIBRARIES + ')\n\n') + # Console output destinations + if params.wantUART: + file.write('pico_enable_stdio_uart(' + params.projectName + ' 1)\n') + else: + file.write('pico_enable_stdio_uart(' + params.projectName + ' 0)\n') + if params.wantUSB: + file.write('pico_enable_stdio_usb(' + params.projectName + ' 1)\n\n') + else: + file.write('pico_enable_stdio_usb(' + params.projectName + ' 0)\n\n') - # Selected libraries/features - if (params.features): - file.write('# Add any user requested libraries\n') - file.write('target_link_libraries(' + params.projectName + '\n') - for feat in params.features: - if (feat in features_list): - file.write(" " + features_list[feat][LIB_NAME] + '\n') - file.write(' )\n\n') + # Standard libraries + file.write('# Add the standard library to the build\n') + file.write('target_link_libraries(' + params.projectName + ' ' + STANDARD_LIBRARIES + ')\n\n') - file.write('pico_add_extra_outputs(' + params.projectName + ')\n\n') + # Selected libraries/features + if params.features: + file.write('# Add any user requested libraries\n') + file.write('target_link_libraries(' + params.projectName + '\n') + for feat in params.features: + if feat in features_list: + file.write(" " + features_list[feat][LIB_NAME] + '\n') + file.write(' )\n\n') - file.close() + file.write('pico_add_extra_outputs(' + params.projectName + ')\n\n') # Generates the requested project files, if any def generateProjectFiles(projectPath, projectName, sdkPath, projects, debugger): - oldCWD = os.getcwd() os.chdir(projectPath) deb = debugger_config_list[debugger] - # if debugger==0 else 'picoprobe.cfg - for p in projects : + # if debugger==0 else 'picoprobe.cfg + for p in projects: if p == 'vscode': v1 = ('{\n' ' // Use IntelliSense to learn about possible attributes.\n' @@ -1011,10 +1014,10 @@ def generateProjectFiles(projectPath, projectName, sdkPath, projects, debugger): ' "servertype": "openocd",\n' ' "gdbPath": "gdb-multiarch",\n' ' "device": "RP2040",\n' - ' "configFiles": [\n' + \ - ' "interface/' + deb + '",\n' + \ - ' "target/rp2040.cfg"\n' + \ - ' ],\n' + \ + ' "configFiles": [\n' + + ' "interface/' + deb + '",\n' + + ' "target/rp2040.cfg"\n' + + ' ],\n' + ' "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",\n' ' "runToMain": true,\n' ' // Give restart the same functionality as runToMain\n' @@ -1045,31 +1048,31 @@ def generateProjectFiles(projectPath, projectName, sdkPath, projects, debugger): ' "version": 4\n' '}\n') - s1 = ( '{\n' - ' "cmake.configureOnOpen": false,\n' - ' "cmake.statusbar.advanced": {\n' - ' "debug" : {\n' - ' "visibility": "hidden"\n' - ' },' - ' "launch" : {\n' - ' "visibility": "hidden"\n' - ' },\n' - ' "build" : {\n' - ' "visibility": "hidden"\n' - ' },\n' - ' "buildTarget" : {\n' - ' "visibility": "hidden"\n' - ' },\n' - ' },\n' - '}\n') - - e1 = ( '{\n' - ' "recommendations": [\n' - ' "marus25.cortex-debug",\n' - ' "ms-vscode.cmake-tools",\n' - ' "ms-vscode.cpptools"\n' - ' ]\n' - '}\n') + s1 = ('{\n' + ' "cmake.configureOnOpen": false,\n' + ' "cmake.statusbar.advanced": {\n' + ' "debug" : {\n' + ' "visibility": "hidden"\n' + ' },' + ' "launch" : {\n' + ' "visibility": "hidden"\n' + ' },\n' + ' "build" : {\n' + ' "visibility": "hidden"\n' + ' },\n' + ' "buildTarget" : {\n' + ' "visibility": "hidden"\n' + ' },\n' + ' },\n' + '}\n') + + e1 = ('{\n' + ' "recommendations": [\n' + ' "marus25.cortex-debug",\n' + ' "ms-vscode.cmake-tools",\n' + ' "ms-vscode.cpptools"\n' + ' ]\n' + '}\n') # Create a build folder, and run our cmake project build from it if not os.path.exists(VSCODE_FOLDER): @@ -1078,23 +1081,19 @@ def generateProjectFiles(projectPath, projectName, sdkPath, projects, debugger): os.chdir(VSCODE_FOLDER) filename = VSCODE_LAUNCH_FILENAME - file = open(filename, 'w') - file.write(v1) - file.close() + with open(filename, 'w') as file: + file.write(v1) - file = open(VSCODE_C_PROPERTIES_FILENAME, 'w') - file.write(c1) - file.close() + with open(VSCODE_C_PROPERTIES_FILENAME, 'w') as file: + file.write(c1) - file = open(VSCODE_SETTINGS_FILENAME, 'w') - file.write(s1) - file.close() + with open(VSCODE_SETTINGS_FILENAME, 'w') as file: + file.write(s1) - file = open(VSCODE_EXTENSIONS_FILENAME, 'w') - file.write(e1) - file.close() + with open(VSCODE_EXTENSIONS_FILENAME, 'w') as file: + file.write(e1) - else : + else: print('Unknown project type requested') os.chdir(oldCWD) @@ -1109,8 +1108,8 @@ def LoadConfigurations(): except: print("No Pico configurations file found. Continuing without") -def DoEverything(parent, params): +def DoEverything(parent, params): if not os.path.exists(params.projectRoot): if params.wantGUI: mb.showerror('Raspberry Pi Pico Project Generator', 'Invalid project path. Select a valid path and try again') @@ -1132,7 +1131,7 @@ def DoEverything(parent, params): # First check if there is already a project in the folder # If there is we abort unless the overwrite flag it set if os.path.exists(CMAKELIST_FILENAME): - if not params.wantOverwrite : + if not params.wantOverwrite: if params.wantGUI: # We can ask the user if they want to overwrite y = mb.askquestion('Raspberry Pi Pico Project Generator', 'There already appears to be a project in this folder. \nPress Yes to overwrite project files, or Cancel to chose another folder') @@ -1143,19 +1142,19 @@ def DoEverything(parent, params): sys.exit(-1) # We should really confirm the user wants to overwrite - #print('Are you sure you want to overwrite the existing project files? (y/N)') - #c = input().split(" ")[0] - #if c != 'y' and c != 'Y' : + # print('Are you sure you want to overwrite the existing project files? (y/N)') + # c = input().split(" ")[0] + # if c != 'y' and c != 'Y' : # sys.exit(0) # Copy the SDK finder cmake file to our project folder # Can be found here /external/pico_sdk_import.cmake - shutil.copyfile(params.sdkPath / 'external' / 'pico_sdk_import.cmake', projectPath / 'pico_sdk_import.cmake' ) + shutil.copyfile(params.sdkPath / 'external' / 'pico_sdk_import.cmake', projectPath / 'pico_sdk_import.cmake') if params.features: features_and_examples = params.features[:] else: - features_and_examples= [] + features_and_examples = [] if params.wantExamples: features_and_examples = list(stdlib_examples_list.keys()) + features_and_examples @@ -1214,14 +1213,14 @@ def DoEverything(parent, params): # Check we have everything we need to compile etc c = CheckPrerequisites() -## TODO Do both warnings in the same error message so user does have to keep coming back to find still more to do +# TODO Do both warnings in the same error message so user does have to keep coming back to find still more to do if c == None: m = 'Unable to find the `' + COMPILER_NAME + '` compiler\n' - m +='You will need to install an appropriate compiler to build a Raspberry Pi Pico project\n' + m += 'You will need to install an appropriate compiler to build a Raspberry Pi Pico project\n' m += 'See the Raspberry Pi Pico documentation for how to do this on your particular platform\n' - if (args.gui): + if args.gui: RunWarning(m) else: print(m) @@ -1242,7 +1241,7 @@ def DoEverything(parent, params): sdkPath = Path(p) if args.gui: - RunGUI(sdkPath, args) # does not return, only exits + RunGUI(sdkPath, args) # does not return, only exits projectRoot = Path(os.getcwd()) @@ -1260,11 +1259,10 @@ def DoEverything(parent, params): print('\n') sys.exit(0) -else : +else: p = Parameters(sdkPath=sdkPath, projectRoot=projectRoot, projectName=args.name, gui=False, overwrite=args.overwrite, build=args.build, features=args.feature, projects=args.project, configs=(), runFromRAM=args.runFromRAM, examples=args.examples, uart=args.uart, usb=args.usb, cpp=args.cpp, debugger=args.debugger, exceptions=args.cppexceptions, rtti=args.cpprtti) DoEverything(None, p) -