4 # Copyright (c) 2020-2023 Raspberry Pi (Trading) Ltd.
6 # SPDX-License-Identifier: BSD-3-Clause
12 from pyexpat import features
14 from pathlib import Path
23 from tkinter import messagebox as mb
24 from tkinter import filedialog as fd
25 from tkinter import simpledialog as sd
26 from tkinter import ttk
28 CMAKELIST_FILENAME = 'CMakeLists.txt'
29 CMAKECACHE_FILENAME = 'CMakeCache.txt'
31 COMPILER_NAME = 'arm-none-eabi-gcc'
33 VSCODE_LAUNCH_FILENAME = 'launch.json'
34 VSCODE_C_PROPERTIES_FILENAME = 'c_cpp_properties.json'
35 VSCODE_SETTINGS_FILENAME ='settings.json'
36 VSCODE_EXTENSIONS_FILENAME ='extensions.json'
37 VSCODE_FOLDER='.vscode'
39 CONFIG_UNSET="Not set"
41 # Standard libraries for all builds
42 # And any more to string below, space separator
43 STANDARD_LIBRARIES = 'pico_stdlib'
45 # Indexed on feature name, tuple contains the C file, the H file and the CMake project name for the feature.
46 # Some lists may contain an extra/ancillary file needed for that feature
54 'spi' : ("SPI", "spi.c", "hardware/spi.h", "hardware_spi"),
55 'i2c' : ("I2C interface", "i2c.c", "hardware/i2c.h", "hardware_i2c"),
56 'dma' : ("DMA support", "dma.c", "hardware/dma.h", "hardware_dma"),
57 'pio' : ("PIO interface", "pio.c", "hardware/pio.h", "hardware_pio"),
58 'interp' : ("HW interpolation", "interp.c", "hardware/interp.h", "hardware_interp"),
59 'timer' : ("HW timer", "timer.c", "hardware/timer.h", "hardware_timer"),
60 'watchdog' : ("HW watchdog", "watch.c", "hardware/watchdog.h", "hardware_watchdog"),
61 'clocks' : ("HW clocks", "clocks.c", "hardware/clocks.h", "hardware_clocks"),
64 picow_options_list = {
65 'picow_none' : ("None", "", "", "", ""),
66 'picow_led' : ("PicoW onboard LED", "", "pico/cyw43_arch.h", "pico_cyw43_arch_none", ""),
67 'picow_poll' : ("Polled lwIP", "", "pico/cyw43_arch.h", "pico_cyw43_arch_lwip_poll", "lwipopts.h"),
68 'picow_background' :("Background lwIP", "", "pico/cyw43_arch.h", "pico_cyw43_arch_lwip_threadsafe_background", "lwipopts.h"),
69 # 'picow_freertos' : ("Full lwIP (FreeRTOS)", "", "pico/cyw43_arch.h", "pico_cyw43_arch_lwip_sys_freertos", "lwipopts.h"),
72 stdlib_examples_list = {
73 'uart': ("UART", "uart.c", "hardware/uart.h", "hardware_uart"),
74 'gpio' : ("GPIO interface", "gpio.c", "hardware/gpio.h", "hardware_gpio"),
75 'div' : ("Low level HW Divider", "divider.c", "hardware/divider.h", "hardware_divider")
78 debugger_list = ["DebugProbe (CMSIS-DAP)", "SWD (Pi host)"]
79 debugger_config_list = ["cmsis-dap.cfg", "raspberrypi-swd.cfg"]
83 # Could add an extra item that shows how to use some of the available functions for the feature
86 # This also contains example code for the standard library (see stdlib_examples_list)
87 code_fragments_per_feature = {
90 "// By default the stdout UART is `uart0`, so we will use the second one",
91 "#define UART_ID uart1",
92 "#define BAUD_RATE 9600", "",
93 "// Use pins 4 and 5 for UART1",
94 "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
95 "#define UART_TX_PIN 4",
96 "#define UART_RX_PIN 5" ),
98 ( "// Set up our UART",
99 "uart_init(UART_ID, BAUD_RATE);",
100 "// Set the TX and RX pins by using the function select on the GPIO",
101 "// Set datasheet for more information on function select",
102 "gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);",
103 "gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);", "" )
107 "// We are going to use SPI 0, and allocate it to the following GPIO pins",
108 "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
109 "#define SPI_PORT spi0",
110 "#define PIN_MISO 16",
112 "#define PIN_SCK 18",
113 "#define PIN_MOSI 19" ),
115 ( "// SPI initialisation. This example will use SPI at 1MHz.",
116 "spi_init(SPI_PORT, 1000*1000);",
117 "gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);",
118 "gpio_set_function(PIN_CS, GPIO_FUNC_SIO);",
119 "gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);",
120 "gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);", "",
121 "// Chip select is active-low, so we'll initialise it to a driven-high state",
122 "gpio_set_dir(PIN_CS, GPIO_OUT);",
123 "gpio_put(PIN_CS, 1);", "")
128 "// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.",
129 "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
130 "#define I2C_PORT i2c0",
135 "// I2C Initialisation. Using it at 400Khz.",
136 "i2c_init(I2C_PORT, 400*1000);","",
137 "gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);",
138 "gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);",
139 "gpio_pull_up(I2C_SDA);",
140 "gpio_pull_up(I2C_SCL);"
146 "// Example uses GPIO 2",
150 "// GPIO initialisation.",
151 "// We will make this GPIO an input, and pull it up by default",
153 "gpio_set_dir(GPIO, GPIO_IN);",
154 "gpio_pull_up(GPIO);","",
160 "// Interpolator example code",
161 "interp_config cfg = interp_default_config();",
162 "// Now use the various interpolator library functions for your use case",
163 "// e.g. interp_config_clamp(&cfg, true);",
164 "// interp_config_shift(&cfg, 2);",
165 "// Then set the config ",
166 "interp_set_config(interp0, 0, &cfg);",
172 "int64_t alarm_callback(alarm_id_t id, void *user_data) {",
173 " // Put your timeout handler code in here",
178 "// Timer example code - This example fires off the callback after 2000ms",
179 "add_alarm_in_ms(2000, alarm_callback, NULL, false);"
185 "// Watchdog example code",
186 "if (watchdog_caused_reboot()) {",
187 " // Whatever action you may take if a watchdog caused a reboot",
189 "// Enable the watchdog, requiring the watchdog to be updated every 100ms or the chip will reboot",
190 "// second arg is pause on debug which means the watchdog will pause when stepping through code",
191 "watchdog_enable(100, 1);","",
192 "// You need to call this function at least more often than the 100ms in the enable call to prevent a reboot"
193 "watchdog_update();",
199 "// Example of using the HW divider. The pico_divider library provides a more user friendly set of APIs ",
200 "// over the divider (and support for 64 bit divides), and of course by default regular C language integer",
201 "// divisions are redirected thru that library, meaning you can just use C level `/` and `%` operators and",
202 "// gain the benefits of the fast hardware divider.",
203 "int32_t dividend = 123456;",
204 "int32_t divisor = -321;",
205 "// This is the recommended signed fast divider for general use.",
206 "divmod_result_t result = hw_divider_divmod_s32(dividend, divisor);",
207 "printf(\"%d/%d = %d remainder %d\\n\", dividend, divisor, to_quotient_s32(result), to_remainder_s32(result));",
208 "// This is the recommended unsigned fast divider for general use.",
209 "int32_t udividend = 123456;",
210 "int32_t udivisor = 321;",
211 "divmod_result_t uresult = hw_divider_divmod_u32(udividend, udivisor);",
212 "printf(\"%d/%d = %d remainder %d\\n\", udividend, udivisor, to_quotient_u32(uresult), to_remainder_u32(uresult));"
217 configuration_dictionary = list(dict())
221 compilerPath = Path("/usr/bin/arm-none-eabi-gcc")
226 def GetButtonBackground():
232 def GetButtonTextColour():
235 def RunGUI(sdkpath, args):
237 style = ttk.Style(root)
238 style.theme_use('default')
240 style.configure("TButton", padding=6, relief="groove", border=2, foreground=GetButtonTextColour(), background=GetButtonBackground())
241 style.configure("TLabel", foreground=GetTextColour(), background=GetBackground() )
242 style.configure("TCheckbutton", foreground=GetTextColour(), background=GetBackground())
243 style.configure("TRadiobutton", foreground=GetTextColour(), background=GetBackground() )
244 style.configure("TLabelframe", foreground=GetTextColour(), background=GetBackground() )
245 style.configure("TLabelframe.Label", foreground=GetTextColour(), background=GetBackground() )
246 style.configure("TCombobox", foreground=GetTextColour(), background=GetBackground() )
247 style.configure("TListbox", foreground=GetTextColour(), background=GetBackground() )
249 style.map("TCheckbutton", background = [('disabled', GetBackground())])
250 style.map("TRadiobutton", background = [('disabled', GetBackground())])
251 style.map("TButton", background = [('disabled', GetBackground())])
252 style.map("TLabel", background = [('background', GetBackground())])
253 style.map("TComboBox", background = [('readonly', GetBackground())])
255 app = ProjectWindow(root, sdkpath, args)
257 app.configure(background=GetBackground())
262 def RunWarning(message):
263 mb.showwarning('Raspberry Pi Pico Project Generator', message)
268 def thread_function(text, command, ok):
269 l = shlex.split(command)
270 proc = subprocess.Popen(l, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
271 for line in iter(proc.stdout.readline,''):
274 ok["state"] = tk.NORMAL
276 text.insert(tk.END, line)
279 # Function to run an OS command and display the output in a new modal window
280 class DisplayWindow(tk.Toplevel):
281 def __init__(self, parent, title):
282 tk.Toplevel.__init__(self, parent)
284 self.init_window(title)
286 def init_window(self, title):
289 frame = tk.Frame(self, borderwidth=5, relief=tk.RIDGE)
290 frame.pack(fill=tk.X, expand=True, side=tk.TOP)
292 scrollbar = tk.Scrollbar(frame)
293 self.text = tk.Text(frame, bg='gray14', fg='gray99')
294 scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
295 self.text.pack(side=tk.LEFT, fill=tk.Y)
296 scrollbar.config(command=self.text.yview)
297 self.text.config(yscrollcommand=scrollbar.set)
299 frame1 = tk.Frame(self, borderwidth=1)
300 frame1.pack(fill=tk.X, expand=True, side=tk.BOTTOM)
301 self.OKButton = ttk.Button(frame1, text="OK", command=self.OK)
302 self.OKButton["state"] = tk.DISABLED
306 self.transient(self.parent)
313 def RunCommandInWindow(parent, command):
314 w = DisplayWindow(parent, command)
315 x = threading.Thread(target=thread_function, args=(w.text, command, w.OKButton))
317 parent.wait_window(w)
319 class EditBoolWindow(sd.Dialog):
321 def __init__(self, parent, configitem, current):
323 self.config_item = configitem
324 self.current = current
325 sd.Dialog.__init__(self, parent, "Edit boolean configuration")
328 def body(self, master):
329 self.configure(background=GetBackground())
330 ttk.Label(self, text=self.config_item['name']).pack()
331 self.result = tk.StringVar()
332 self.result.set(self.current)
333 ttk.Radiobutton(master, text="True", variable=self.result, value="True").pack(anchor=tk.W)
334 ttk.Radiobutton(master, text="False", variable=self.result, value="False").pack(anchor=tk.W)
335 ttk.Radiobutton(master, text=CONFIG_UNSET, variable=self.result, value=CONFIG_UNSET).pack(anchor=tk.W)
338 return self.result.get()
340 class EditIntWindow(sd.Dialog):
342 def __init__(self, parent, configitem, current):
344 self.config_item = configitem
345 self.current = current
346 sd.Dialog.__init__(self, parent, "Edit integer configuration")
348 def body(self, master):
349 self.configure(background=GetBackground())
350 str = self.config_item['name'] + " Max = " + self.config_item['max'] + " Min = " + self.config_item['min']
351 ttk.Label(self, text=str).pack()
352 self.input = tk.Entry(self)
353 self.input.pack(pady=4)
354 self.input.insert(0, self.current)
355 ttk.Button(self, text=CONFIG_UNSET, command=self.unset).pack(pady=5)
358 self.result = self.input.get()
359 # Check for numeric entry
363 self.result = CONFIG_UNSET
369 class EditEnumWindow(sd.Dialog):
370 def __init__(self, parent, configitem, current):
372 self.config_item = configitem
373 self.current = current
374 sd.Dialog.__init__(self, parent, "Edit Enumeration configuration")
376 def body(self, master):
377 #self.configure(background=GetBackground())
378 values = self.config_item['enumvalues'].split('|')
379 values.insert(0,'Not set')
380 self.input = ttk.Combobox(self, values=values, state='readonly')
381 self.input.set(self.current)
382 self.input.pack(pady=12)
385 self.result = self.input.get()
392 class ConfigurationWindow(tk.Toplevel):
394 def __init__(self, parent, initial_config):
395 tk.Toplevel.__init__(self, parent)
397 self.results = initial_config
398 self.init_window(self)
400 def init_window(self, args):
401 self.configure(background=GetBackground())
402 self.title("Advanced Configuration")
403 ttk.Label(self, text="Select the advanced options you wish to enable or change. Note that you really should understand the implications of changing these items before using them!").grid(row=0, column=0, columnspan=5)
404 ttk.Label(self, text="Name").grid(row=1, column=0, sticky=tk.W)
405 ttk.Label(self, text="Type").grid(row=1, column=1, sticky=tk.W)
406 ttk.Label(self, text="Min").grid(row=1, column=2, sticky=tk.W)
407 ttk.Label(self, text="Max").grid(row=1, column=3, sticky=tk.W)
408 ttk.Label(self, text="Default").grid(row=1, column=4, sticky=tk.W)
409 ttk.Label(self, text="User").grid(row=1, column=5, sticky=tk.W)
411 okButton = ttk.Button(self, text="OK", command=self.ok)
412 cancelButton = ttk.Button(self, text="Cancel", command=self.cancel)
414 self.namelist = tk.Listbox(self, selectmode=tk.SINGLE)
415 self.typelist = tk.Listbox(self, selectmode=tk.SINGLE)
416 self.minlist = tk.Listbox(self, selectmode=tk.SINGLE)
417 self.maxlist = tk.Listbox(self, selectmode=tk.SINGLE)
418 self.defaultlist = tk.Listbox(self, selectmode=tk.SINGLE)
419 self.valuelist = tk.Listbox(self, selectmode=tk.SINGLE)
421 self.descriptionText = tk.Text(self, state=tk.DISABLED, height=2)
423 ## Make a list of our list boxes to make it all easier to handle
424 self.listlist = [self.namelist, self.typelist, self.minlist, self.maxlist, self.defaultlist, self.valuelist]
426 scroll = tk.Scrollbar(self, orient=tk.VERTICAL, command=self.yview)
428 for box in self.listlist:
430 box.config(yscrollcommand=scroll.set)
431 box.bind("<MouseWheel>", self.mousewheel)
432 box.bind("<Button-4>", self.mousewheel)
433 box.bind("<Button-5>", self.mousewheel)
434 box.bind("<<ListboxSelect>>", self.changeSelection)
435 box.bind("<Double-Button>", self.doubleClick)
436 box.config(exportselection=False)
437 box.bind("<Down>", self.OnEntryUpDown)
438 box.bind("<Up>", self.OnEntryUpDown)
440 scroll.grid(column=7, sticky=tk.N + tk.S)
443 for box in self.listlist:
444 box.grid(row=2, column=i, padx=0, sticky=tk.W + tk.E)
447 self.descriptionText.grid(row = 3, column=0, columnspan=4, sticky=tk.W + tk.E)
448 cancelButton.grid(column=5, row = 3, padx=5)
449 okButton.grid(column=4, row = 3, sticky=tk.E, padx=5)
451 # populate the list box with our config options
452 for conf in configuration_dictionary:
453 self.namelist.insert(tk.END, conf['name'])
457 self.typelist.insert(tk.END, s)
458 self.maxlist.insert(tk.END, conf['max'])
459 self.minlist.insert(tk.END, conf['min'])
460 self.defaultlist.insert(tk.END, conf['default'])
462 # see if this config has a setting, our results member has this predefined from init
463 val = self.results.get(conf['name'], CONFIG_UNSET)
464 self.valuelist.insert(tk.END, val)
465 if val != CONFIG_UNSET:
466 self.valuelist.itemconfig(self.valuelist.size() - 1, {'bg':'green'})
468 def yview(self, *args):
469 for box in self.listlist:
472 def mousewheel(self, event):
473 if (event.num == 4): # Linux encodes wheel as 'buttons' 4 and 5
475 elif (event.num == 5):
477 else: # Windows & OSX
480 for box in self.listlist:
481 box.yview("scroll", delta, "units")
484 def changeSelection(self, evt):
486 sellist = box.curselection()
489 index = int(sellist[0])
490 config = self.namelist.get(index)
491 # Now find the description for that config in the dictionary
492 for conf in configuration_dictionary:
493 if conf['name'] == config:
494 self.descriptionText.config(state=tk.NORMAL)
495 self.descriptionText.delete(1.0,tk.END)
496 str = config + "\n" + conf['description']
497 self.descriptionText.insert(1.0, str)
498 self.descriptionText.config(state=tk.DISABLED)
500 # Set all the other list boxes to the same index
501 for b in self.listlist:
503 b.selection_clear(0, tk.END)
504 b.selection_set(index)
506 def OnEntryUpDown(self, event):
508 selection = box.curselection()
511 index = int(selection[0])
512 if event.keysym == 'Up':
514 elif event.keysym == 'Down':
517 if 0 <= index < box.size():
518 for b in self.listlist:
519 b.selection_clear(0, tk.END)
520 b.selection_set(index)
523 def doubleClick(self, evt):
525 index = int(box.curselection()[0])
526 config = self.namelist.get(index)
527 # Get the associated dict entry from our list of configs
528 for conf in configuration_dictionary:
529 if conf['name'] == config:
530 if (conf['type'] == 'bool'):
531 result = EditBoolWindow(self, conf, self.valuelist.get(index)).get()
532 elif (conf['type'] == 'int' or conf['type'] == ""): # "" defaults to int
533 result = EditIntWindow(self, conf, self.valuelist.get(index)).get()
534 elif conf['type'] == 'enum':
535 result = EditEnumWindow(self, conf, self.valuelist.get(index)).get()
537 # Update the valuelist with our new item
538 self.valuelist.delete(index)
539 self.valuelist.insert(index, result)
540 if result != CONFIG_UNSET:
541 self.valuelist.itemconfig(index, {'bg':'green'})
545 # Get the selections, and create a list of them
546 for i, val in enumerate(self.valuelist.get(0, tk.END)):
547 if val != CONFIG_UNSET:
548 self.results[self.namelist.get(i)] = val
550 self.results.pop(self.namelist.get(i), None)
560 class WirelessSettingsWindow(sd.Dialog):
562 def __init__(self, parent):
563 sd.Dialog.__init__(self, parent, "Wireless settings")
566 def body(self, master):
567 self.configure(background=GetBackground())
568 master.configure(background=GetBackground())
569 self.ssid = tk.StringVar()
570 self.password = tk.StringVar()
572 a = ttk.Label(master, text='SSID :', background=GetBackground())
573 a.grid(row=0, column=0, sticky=tk.E)
574 a.configure(background=GetBackground())
575 ttk.Entry(master, textvariable=self.ssid).grid(row=0, column=1, sticky=tk.W+tk.E, padx=5)
577 ttk.Label(master, text='Password :').grid(row=1, column=0, sticky=tk.E)
578 ttk.Entry(master, textvariable=self.password).grid(row=1, column=1, sticky=tk.W+tk.E, padx=5)
580 self.transient(self.parent)
591 return (self.ssid.get(), self.password.get())
594 class ProjectWindow(tk.Frame):
596 def __init__(self, parent, sdkpath, args):
597 tk.Frame.__init__(self, parent)
599 self.sdkpath = sdkpath
600 self.init_window(args)
601 self.configs = dict()
603 self.password = str()
605 def setState(self, thing, state):
606 for child in thing.winfo_children():
607 child.configure(state=state)
609 def boardtype_change_callback(self, event):
610 boardtype = self.boardtype.get()
611 if boardtype == "pico_w":
612 self.setState(self.picowSubframe, "enabled")
614 self.setState(self.picowSubframe, "disabled")
616 def wirelessSettings(self):
617 result = WirelessSettingsWindow(self)
618 self.ssid, self.password = result.get()
620 def init_window(self, args):
621 self.master.title("Raspberry Pi Pico Project Generator")
622 self.master.configure(bg=GetBackground())
626 mainFrame = tk.Frame(self, bg=GetBackground()).grid(row=optionsRow, column=0, columnspan=6, rowspan=12)
628 # Need to keep a reference to the image or it will not appear.
629 self.logo = tk.PhotoImage(file=GetFilePath("logo_alpha.gif"))
630 logowidget = ttk.Label(mainFrame, image=self.logo, borderwidth=0, relief="solid").grid(row=0,column=0, columnspan=5, pady=10)
634 namelbl = ttk.Label(mainFrame, text='Project Name :').grid(row=optionsRow, column=0, sticky=tk.E)
635 self.projectName = tk.StringVar()
637 if args.name != None:
638 self.projectName.set(args.name)
640 self.projectName.set('ProjectName')
642 nameEntry = ttk.Entry(mainFrame, textvariable=self.projectName).grid(row=optionsRow, column=1, sticky=tk.W+tk.E, padx=5)
646 locationlbl = ttk.Label(mainFrame, text='Location :').grid(row=optionsRow, column=0, sticky=tk.E)
647 self.locationName = tk.StringVar()
648 self.locationName.set(os.getcwd())
649 locationEntry = ttk.Entry(mainFrame, textvariable=self.locationName).grid(row=optionsRow, column=1, columnspan=3, sticky=tk.W+tk.E, padx=5)
650 locationBrowse = ttk.Button(mainFrame, text='Browse', command=self.browse).grid(row=3, column=4)
654 ttk.Label(mainFrame, text = "Board Type :").grid(row=optionsRow, column=0, padx=4, sticky=tk.E)
655 self.boardtype = ttk.Combobox(mainFrame, values=boardtype_list, )
656 self.boardtype.grid(row=4, column=1, padx=4, sticky=tk.W+tk.E)
657 self.boardtype.set('pico')
658 self.boardtype.bind('<<ComboboxSelected>>',self.boardtype_change_callback)
662 featuresframe = ttk.LabelFrame(mainFrame, text="Library Options", relief=tk.RIDGE, borderwidth=2)
663 featuresframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=5, ipadx=5, padx=5, pady=5, sticky=tk.E+tk.W)
665 s = (len(features_list)/3)
667 self.feature_checkbox_vars = []
670 for i in features_list:
671 var = tk.StringVar(value='') # Off by default for the moment
672 c = features_list[i][GUI_TEXT]
673 cb = ttk.Checkbutton(featuresframe, text = c, var=var, onvalue=i, offvalue='')
674 cb.grid(row=row, column=col, padx=15, pady=2, ipadx=1, ipady=1, sticky=tk.E+tk.W)
675 self.feature_checkbox_vars.append(var)
683 # PicoW options section
684 self.picowSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Pico Wireless Options")
685 self.picowSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W)
686 self.pico_wireless = tk.StringVar()
690 for i in picow_options_list:
691 rb = ttk.Radiobutton(self.picowSubframe, text=picow_options_list[i][GUI_TEXT], variable=self.pico_wireless, val=i)
692 rb.grid(row=row, column=col, padx=15, pady=1, sticky=tk.E+tk.W)
698 # DOnt actually need any settings at the moment.
699 # ttk.Button(self.picowSubframe, text='Settings', command=self.wirelessSettings).grid(row=0, column=4, padx=5, pady=2, sticky=tk.E)
701 self.setState(self.picowSubframe, "disabled")
705 # output options section
706 ooptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Console Options")
707 ooptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W)
709 self.wantUART = tk.IntVar()
710 self.wantUART.set(args.uart)
711 ttk.Checkbutton(ooptionsSubframe, text="Console over UART", variable=self.wantUART).grid(row=0, column=0, padx=4, sticky=tk.W)
713 self.wantUSB = tk.IntVar()
714 self.wantUSB.set(args.usb)
715 ttk.Checkbutton(ooptionsSubframe, text="Console over USB (Disables other USB use)", variable=self.wantUSB).grid(row=0, column=1, padx=4, sticky=tk.W)
719 # Code options section
720 coptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Code Options")
721 coptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=3, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W)
723 self.wantExamples = tk.IntVar()
724 self.wantExamples.set(args.examples)
725 ttk.Checkbutton(coptionsSubframe, text="Add examples for Pico library", variable=self.wantExamples).grid(row=0, column=0, padx=4, sticky=tk.W)
727 self.wantRunFromRAM = tk.IntVar()
728 self.wantRunFromRAM.set(args.runFromRAM)
729 ttk.Checkbutton(coptionsSubframe, text="Run from RAM", variable=self.wantRunFromRAM).grid(row=0, column=1, padx=4, sticky=tk.W)
731 self.wantCPP = tk.IntVar()
732 self.wantCPP.set(args.cpp)
733 ttk.Checkbutton(coptionsSubframe, text="Generate C++", variable=self.wantCPP).grid(row=0, column=3, padx=4, sticky=tk.W)
735 ttk.Button(coptionsSubframe, text="Advanced...", command=self.config).grid(row=0, column=4, sticky=tk.E)
737 self.wantCPPExceptions = tk.IntVar()
738 self.wantCPPExceptions.set(args.cppexceptions)
739 ttk.Checkbutton(coptionsSubframe, text="Enable C++ exceptions", variable=self.wantCPPExceptions).grid(row=1, column=0, padx=4, sticky=tk.W)
741 self.wantCPPRTTI = tk.IntVar()
742 self.wantCPPRTTI.set(args.cpprtti)
743 ttk.Checkbutton(coptionsSubframe, text="Enable C++ RTTI", variable=self.wantCPPRTTI).grid(row=1, column=1, padx=4, sticky=tk.W)
747 # Build Options section
749 boptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="Build Options")
750 boptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W)
752 self.wantBuild = tk.IntVar()
753 self.wantBuild.set(args.build)
754 ttk.Checkbutton(boptionsSubframe, text="Run build after generation", variable=self.wantBuild).grid(row=0, column=0, padx=4, sticky=tk.W)
756 self.wantOverwrite = tk.IntVar()
757 self.wantOverwrite.set(args.overwrite)
758 ttk.Checkbutton(boptionsSubframe, text="Overwrite existing projects", variable=self.wantOverwrite).grid(row=0, column=1, padx=4, sticky=tk.W)
762 # IDE Options section
764 vscodeoptionsSubframe = ttk.LabelFrame(mainFrame, relief=tk.RIDGE, borderwidth=2, text="IDE Options")
765 vscodeoptionsSubframe.grid_columnconfigure(2, weight=1)
766 vscodeoptionsSubframe.grid(row=optionsRow, column=0, columnspan=5, rowspan=2, padx=5, pady=5, ipadx=5, ipady=3, sticky=tk.E+tk.W)
768 self.wantVSCode = tk.IntVar()
769 if args.project is None:
770 self.wantVSCode.set(False)
772 self.wantVSCode.set('vscode' in args.project)
773 ttk.Checkbutton(vscodeoptionsSubframe, text="Create VSCode project", variable=self.wantVSCode).grid(row=0, column=0, padx=4, sticky=tk.W)
775 ttk.Label(vscodeoptionsSubframe, text = " Debugger:").grid(row=0, column=1, padx=4, sticky=tk.W)
777 self.debugger = ttk.Combobox(vscodeoptionsSubframe, values=debugger_list, state="readonly")
778 self.debugger.grid(row=0, column=2, padx=4, sticky=tk.EW)
779 self.debugger.current(args.debugger)
783 # OK, Cancel, Help section
785 QuitButton = ttk.Button(mainFrame, text="Quit", command=self.quit).grid(row=optionsRow, column=4, stick=tk.E, padx=10, pady=5)
786 OKButton = ttk.Button(mainFrame, text="OK", command=self.OK).grid(row=optionsRow, column=3, padx=4, pady=5, sticky=tk.E)
788 # TODO help not implemented yet
789 # HelpButton = ttk.Button(mainFrame, text="Help", command=self.help).grid(row=optionsRow, column=0, pady=5)
791 # You can set a default path here, replace the string with whereever you want.
792 # self.locationName.set('/home/pi/pico_projects')
794 def GetFeatures(self):
798 for cb in self.feature_checkbox_vars:
803 picow_extra = self.pico_wireless.get()
805 if picow_extra != 'picow_none':
806 features.append(picow_extra)
811 # TODO Check if we want to exit here
815 # OK, grab all the settings from the page, then call the generators
816 projectPath = self.locationName.get()
817 features = self.GetFeatures()
819 if (self.wantVSCode.get()):
820 projects.append("vscode")
823 'sdkPath' : self.sdkpath,
824 'projectRoot' : Path(projectPath),
825 'projectName' : self.projectName.get(),
827 'wantOverwrite' : self.wantOverwrite.get(),
828 'wantBuild' : self.wantBuild.get(),
829 'boardtype' : self.boardtype.get(),
830 'features' : features,
831 'projects' : projects,
832 'configs' : self.configs,
833 'wantRunFromRAM': self.wantRunFromRAM.get(),
834 'wantExamples' : self.wantExamples.get(),
835 'wantUART' : self.wantUART.get(),
836 'wantUSB' : self.wantUSB.get(),
837 'wantCPP' : self.wantCPP.get(),
838 'debugger' : self.debugger.current(),
839 'exceptions' : self.wantCPPExceptions.get(),
840 'rtti' : self.wantCPPRTTI.get(),
842 'password' : self.password,
845 DoEverything(self, params)
848 name = fd.askdirectory()
849 self.locationName.set(name)
855 # Run the configuration window
856 self.configs = ConfigurationWindow(self, self.configs).get()
858 def CheckPrerequisites():
859 global isMac, isWindows
860 isMac = (platform.system() == 'Darwin')
861 isWindows = (platform.system() == 'Windows')
863 # Do we have a compiler?
864 return shutil.which(COMPILER_NAME)
867 def CheckSDKPath(gui):
868 sdkPath = os.getenv('PICO_SDK_PATH')
871 m = 'Unable to locate the Raspberry Pi Pico SDK, PICO_SDK_PATH is not set'
876 elif not os.path.isdir(sdkPath):
877 m = 'Unable to locate the Raspberry Pi Pico SDK, PICO_SDK_PATH does not point to a directory'
886 def GetFilePath(filename):
887 if os.path.islink(__file__):
888 script_file = os.readlink(__file__)
890 script_file = __file__
891 return os.path.join(os.path.dirname(script_file), filename)
893 def ParseCommandLine():
894 debugger_flags = ', '.join('{} = {}'.format(i, v) for i, v in enumerate(debugger_list))
895 parser = argparse.ArgumentParser(description='Pico Project generator')
896 parser.add_argument("name", nargs="?", help="Name of the project")
897 parser.add_argument("-t", "--tsv", help="Select an alternative pico_configs.tsv file", default=GetFilePath("pico_configs.tsv"))
898 parser.add_argument("-o", "--output", help="Set an alternative CMakeList.txt filename", default="CMakeLists.txt")
899 parser.add_argument("-x", "--examples", action='store_true', help="Add example code for the Pico standard library")
900 parser.add_argument("-l", "--list", action='store_true', help="List available features")
901 parser.add_argument("-c", "--configs", action='store_true', help="List available project configuration items")
902 parser.add_argument("-f", "--feature", action='append', help="Add feature to generated project")
903 parser.add_argument("-over", "--overwrite", action='store_true', help="Overwrite any existing project AND files")
904 parser.add_argument("-b", "--build", action='store_true', help="Build after project created")
905 parser.add_argument("-g", "--gui", action='store_true', help="Run a GUI version of the project generator")
906 parser.add_argument("-p", "--project", action='append', help="Generate projects files for IDE. Options are: vscode")
907 parser.add_argument("-r", "--runFromRAM", action='store_true', help="Run the program from RAM rather than flash")
908 parser.add_argument("-uart", "--uart", action='store_true', default=1, help="Console output to UART (default)")
909 parser.add_argument("-nouart", "--nouart", action='store_true', default=0, help="Disable console output to UART")
910 parser.add_argument("-usb", "--usb", action='store_true', help="Console output to USB (disables other USB functionality")
911 parser.add_argument("-cpp", "--cpp", action='store_true', default=0, help="Generate C++ code")
912 parser.add_argument("-cpprtti", "--cpprtti", action='store_true', default=0, help="Enable C++ RTTI (Uses more memory)")
913 parser.add_argument("-cppex", "--cppexceptions", action='store_true', default=0, help="Enable C++ exceptions (Uses more memory)")
914 parser.add_argument("-d", "--debugger", type=int, help="Select debugger ({})".format(debugger_flags), default=0)
915 parser.add_argument("-board", "--boardtype", action="store", default='pico', help="Select board type (see --boardlist for available boards)")
916 parser.add_argument("-bl", "--boardlist", action="store_true", help="List available board types")
917 parser.add_argument("-cp", "--cpath", help="Override default VSCode compiler path")
919 return parser.parse_args()
922 def GenerateMain(folder, projectName, features, cpp):
925 filename = Path(folder) / (projectName + '.cpp')
927 filename = Path(folder) / (projectName + '.c')
929 file = open(filename, 'w')
931 main = ('#include <stdio.h>\n'
932 '#include "pico/stdlib.h"\n'
939 for feat in features:
940 if (feat in features_list):
941 o = f'#include "{features_list[feat][H_FILE]}"\n'
943 if (feat in stdlib_examples_list):
944 o = f'#include "{stdlib_examples_list[feat][H_FILE]}"\n'
946 if (feat in picow_options_list):
947 o = f'#include "{picow_options_list[feat][H_FILE]}"\n'
953 for feat in features:
954 if (feat in code_fragments_per_feature):
955 for s in code_fragments_per_feature[feat][DEFINES]:
963 ' stdio_init_all();\n\n'
967 # Add any initialisers
969 for feat in features:
970 if (feat in code_fragments_per_feature):
971 for s in code_fragments_per_feature[feat][INITIALISERS]:
972 main += (" " * indent)
977 main += (' puts("Hello, world!");\n\n'
987 def GenerateCMake(folder, params):
989 filename = Path(folder) / CMAKELIST_FILENAME
990 projectName = params['projectName']
991 board_type = params['boardtype']
993 # OK, for the path, CMake will accept forward slashes on Windows, and thats
994 # seemingly a bit easier to handle than the backslashes
995 p = str(params['sdkPath']).replace('\\','/')
998 cmake_header1 = (f"# Generated Cmake Pico project file\n\n"
999 "cmake_minimum_required(VERSION 3.13)\n\n"
1000 "set(CMAKE_C_STANDARD 11)\n"
1001 "set(CMAKE_CXX_STANDARD 17)\n\n"
1002 "# Initialise pico_sdk from installed location\n"
1003 "# (note this can come from environment, CMake cache etc)\n"
1004 f"set(PICO_SDK_PATH {sdk_path})\n\n"
1005 f"set(PICO_BOARD {board_type} CACHE STRING \"Board type\")\n\n"
1006 "# Pull in Raspberry Pi Pico SDK (must be before project)\n"
1007 "include(pico_sdk_import.cmake)\n\n"
1008 "if (PICO_SDK_VERSION_STRING VERSION_LESS \"1.4.0\")\n"
1009 " message(FATAL_ERROR \"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}\")\n"
1011 f"project({projectName} C CXX ASM)\n"
1015 "\n# Initialise the Raspberry Pi Pico SDK\n"
1016 "pico_sdk_init()\n\n"
1017 "# Add executable. Default name is the project name, version 0.1\n\n"
1021 file = open(filename, 'w')
1023 file.write(cmake_header1)
1025 if params['exceptions']:
1026 file.write("\nset(PICO_CXX_ENABLE_EXCEPTIONS 1)\n")
1029 file.write("\nset(PICO_CXX_ENABLE_RTTI 1)\n")
1031 file.write(cmake_header3)
1033 # add the preprocessor defines for overall configuration
1034 if params['configs']:
1035 file.write('# Add any PICO_CONFIG entries specified in the Advanced settings\n')
1036 for c, v in params['configs'].items():
1041 file.write(f'add_compile_definitions({c} = {v})\n')
1044 # No GUI/command line to set a different executable name at this stage
1045 executableName = projectName
1047 if params['wantCPP']:
1048 file.write(f'add_executable({projectName} {projectName}.cpp )\n\n')
1050 file.write(f'add_executable({projectName} {projectName}.c )\n\n')
1052 file.write(f'pico_set_program_name({projectName} "{executableName}")\n')
1053 file.write(f'pico_set_program_version({projectName} "0.1")\n\n')
1055 if params['wantRunFromRAM']:
1056 file.write(f'# no_flash means the target is to run from RAM\n')
1057 file.write(f'pico_set_binary_type({projectName} no_flash)\n\n')
1059 # Console output destinations
1060 if params['wantUART']:
1061 file.write(f'pico_enable_stdio_uart({projectName} 1)\n')
1063 file.write(f'pico_enable_stdio_uart({projectName} 0)\n')
1065 if params['wantUSB']:
1066 file.write(f'pico_enable_stdio_usb({projectName} 1)\n\n')
1068 file.write(f'pico_enable_stdio_usb({projectName} 0)\n\n')
1070 # If we need wireless, check for SSID and password
1071 # removed for the moment as these settings are currently only needed for the pico-examples
1072 # but may be required in here at a later date.
1074 if 'ssid' in params or 'password' in params:
1075 file.write('# Add any wireless access point information\n')
1076 file.write(f'target_compile_definitions({projectName} PRIVATE\n')
1077 if 'ssid' in params:
1078 file.write(f'WIFI_SSID=\" {params["ssid"]} \"\n')
1080 file.write(f'WIFI_SSID=\"${WIFI_SSID}\"')
1082 if 'password' in params:
1083 file.write(f'WIFI_PASSWORD=\"{params["password"]}\"\n')
1085 file.write(f'WIFI_PASSWORD=\"${WIFI_PASSWORD}\"')
1088 # Standard libraries
1089 file.write('# Add the standard library to the build\n')
1090 file.write(f'target_link_libraries({projectName}\n')
1091 file.write(" " + STANDARD_LIBRARIES)
1094 # Standard include directories
1095 file.write('# Add the standard include files to the build\n')
1096 file.write(f'target_include_directories({projectName} PRIVATE\n')
1097 file.write(" ${CMAKE_CURRENT_LIST_DIR}\n")
1098 file.write(" ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required\n")
1101 # Selected libraries/features
1102 if (params['features']):
1103 file.write('# Add any user requested libraries\n')
1104 file.write(f'target_link_libraries({projectName} \n')
1105 for feat in params['features']:
1106 if (feat in features_list):
1107 file.write(" " + features_list[feat][LIB_NAME] + '\n')
1108 if (feat in picow_options_list):
1109 file.write(" " + picow_options_list[feat][LIB_NAME] + '\n')
1110 file.write(' )\n\n')
1112 file.write(f'pico_add_extra_outputs({projectName})\n\n')
1117 # Generates the requested project files, if any
1118 def generateProjectFiles(projectPath, projectName, sdkPath, projects, debugger):
1120 oldCWD = os.getcwd()
1122 os.chdir(projectPath)
1124 debugger = debugger_config_list[debugger]
1125 gdbPath = "arm-none-eabi-gdb" if isWindows else "gdb-multiarch"
1126 # Need to escape windows files paths backslashes
1127 cPath = str(compilerPath).replace('\\', '\\\\' )
1132 ' "version": "0.2.0",\n'
1133 ' "configurations": [\n'
1135 ' "name": "Pico Debug (Cortex-Debug)",\n'
1136 ' "cwd": "${workspaceRoot}",\n'
1137 ' "executable": "${command:cmake.launchTargetPath}",\n'
1138 ' "request": "launch",\n'
1139 ' "type": "cortex-debug",\n'
1140 ' "servertype": "openocd",\n'
1141 f' "gdbPath": "{gdbPath}",\n'
1142 ' "device": "RP2040",\n'
1143 ' "configFiles": [\n'
1144 f' "interface/{debugger}",\n'
1145 ' "target/rp2040.cfg"\n'
1147 ' "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",\n'
1148 ' "runToEntryPoint": "main",\n'
1149 ' // Give restart the same functionality as runToEntryPoint - main\n'
1150 ' "postRestartCommands": [\n'
1154 ' "openOCDLaunchCommands": [\n'
1155 ' "adapter speed 1000"\n'
1159 ' "name": "Pico Debug (Cortex-Debug with external OpenOCD)",\n'
1160 ' "cwd": "${workspaceRoot}",\n'
1161 ' "executable": "${command:cmake.launchTargetPath}",\n'
1162 ' "request": "launch",\n'
1163 ' "type": "cortex-debug",\n'
1164 ' "servertype": "external",\n'
1165 ' "gdbTarget": "localhost:3333",\n'
1166 f' "gdbPath": "{gdbPath}",\n'
1167 ' "device": "RP2040",\n'
1168 ' "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",\n'
1169 ' "runToEntryPoint": "main",\n'
1170 ' // Give restart the same functionality as runToEntryPoint - main\n'
1171 ' "postRestartCommands": [\n'
1177 ' "name": "Pico Debug (C++ Debugger)",\n'
1178 ' "type": "cppdbg",\n'
1179 ' "request": "launch",\n'
1180 ' "cwd": "${workspaceRoot}",\n'
1181 ' "program": "${command:cmake.launchTargetPath}",\n'
1182 ' "MIMode": "gdb",\n'
1183 ' "miDebuggerPath": "{gdbPath}",\n'
1184 ' "miDebuggerServerAddress": "localhost:3333",\n'
1185 ' "debugServerPath": "openocd",\n'
1186 ' "debugServerArgs": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \\"adapter speed 1000\\"",\n'
1187 ' "serverStarted": "Listening on port .* for gdb connections",\n'
1188 ' "filterStderr": true,\n'
1189 ' "stopAtEntry": true,\n'
1190 ' "hardwareBreakpoints": {\n'
1191 ' "require": true,\n'
1194 ' "preLaunchTask": "Flash",\n'
1195 ' "svdPath": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd"\n'
1201 ' "configurations": [\n'
1203 ' "name": "Pico",\n'
1204 ' "includePath": [\n'
1205 ' "${workspaceFolder}/**",\n'
1206 ' "${env:PICO_SDK_PATH}/**"\n'
1209 f' "compilerPath": "{cPath}",\n'
1210 ' "cStandard": "c17",\n'
1211 ' "cppStandard": "c++14",\n'
1212 ' "intelliSenseMode": "linux-gcc-arm",\n'
1213 ' "configurationProvider" : "ms-vscode.cmake-tools"\n'
1220 ' "cmake.statusbar.advanced": {\n'
1222 ' "visibility": "hidden"\n'
1225 ' "visibility": "hidden"\n'
1228 ' "visibility": "hidden"\n'
1230 ' "buildTarget" : {\n'
1231 ' "visibility": "hidden"\n'
1234 ' "cmake.buildBeforeRun": true,\n'
1235 ' "cmake.configureOnOpen": true,\n'
1236 ' "cmake.configureSettings": {\n'
1237 ' "CMAKE_MODULE_PATH": "${env:PICO_INSTALL_PATH}/pico-sdk-tools"\n'
1239 ' "cmake.generator": "Ninja",\n'
1240 ' "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools")\n'
1243 extensions = ( '{\n'
1244 ' "recommendations": [\n'
1245 ' "marus25.cortex-debug",\n'
1246 ' "ms-vscode.cmake-tools",\n'
1247 ' "ms-vscode.cpptools"\n'
1248 ' "ms-vscode.cpptools-extension-pack",\n'
1249 ' "ms-vscode.vscode-serial-monitor"\n'
1253 # Create a build folder, and run our cmake project build from it
1254 if not os.path.exists(VSCODE_FOLDER):
1255 os.mkdir(VSCODE_FOLDER)
1257 os.chdir(VSCODE_FOLDER)
1259 filename = VSCODE_LAUNCH_FILENAME
1260 file = open(filename, 'w')
1264 file = open(VSCODE_C_PROPERTIES_FILENAME, 'w')
1265 file.write(properties)
1268 file = open(VSCODE_SETTINGS_FILENAME, 'w')
1269 file.write(settings)
1272 file = open(VSCODE_EXTENSIONS_FILENAME, 'w')
1273 file.write(extensions)
1277 print('Unknown project type requested')
1282 def LoadConfigurations():
1284 with open(args.tsv) as tsvfile:
1285 reader = csv.DictReader(tsvfile, dialect='excel-tab')
1287 configuration_dictionary.append(row)
1289 print("No Pico configurations file found. Continuing without")
1291 def LoadBoardTypes(sdkPath):
1292 # Scan the boards folder for all header files, extract filenames, and make a list of the results
1293 # default folder is <PICO_SDK_PATH>/src/boards/include/boards/*
1294 # If the PICO_BOARD_HEADER_DIRS environment variable is set, use that as well
1296 loc = sdkPath / "src/boards/include/boards"
1298 for x in Path(loc).iterdir():
1299 if x.suffix == '.h':
1300 boards.append(x.stem)
1302 loc = os.getenv('PICO_BOARD_HEADER_DIRS')
1305 for x in Path(loc).iterdir():
1306 if x.suffix == '.h':
1307 boards.append(x.stem)
1311 def DoEverything(parent, params):
1313 if not os.path.exists(params['projectRoot']):
1314 if params['wantGUI']:
1315 mb.showerror('Raspberry Pi Pico Project Generator', 'Invalid project path. Select a valid path and try again')
1318 print('Invalid project path')
1321 oldCWD = os.getcwd()
1322 os.chdir(params['projectRoot'])
1324 # Create our project folder as subfolder
1325 os.makedirs(params['projectName'], exist_ok=True)
1327 os.chdir(params['projectName'])
1329 projectPath = params['projectRoot'] / params['projectName']
1331 # First check if there is already a project in the folder
1332 # If there is we abort unless the overwrite flag it set
1333 if os.path.exists(CMAKELIST_FILENAME):
1334 if not params['wantOverwrite'] :
1335 if params['wantGUI']:
1336 # We can ask the user if they want to overwrite
1337 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')
1341 print('There already appears to be a project in this folder. Use the --overwrite option to overwrite the existing project')
1344 # We should really confirm the user wants to overwrite
1345 #print('Are you sure you want to overwrite the existing project files? (y/N)')
1346 #c = input().split(" ")[0]
1347 #if c != 'y' and c != 'Y' :
1350 # Copy the SDK finder cmake file to our project folder
1351 # Can be found here <PICO_SDK_PATH>/external/pico_sdk_import.cmake
1352 shutil.copyfile(params['sdkPath'] / 'external' / 'pico_sdk_import.cmake', projectPath / 'pico_sdk_import.cmake' )
1354 if params['features']:
1355 features_and_examples = params['features'][:]
1357 features_and_examples= []
1359 if params['wantExamples']:
1360 features_and_examples = list(stdlib_examples_list.keys()) + features_and_examples
1362 GenerateMain('.', params['projectName'], features_and_examples, params['wantCPP'])
1364 GenerateCMake('.', params)
1366 # If we have any ancilliary files, copy them to our project folder
1367 # Currently only the picow with lwIP support needs an extra file, so just check that list
1368 for feat in features_and_examples:
1369 if feat in picow_options_list:
1370 if picow_options_list[feat][ANCILLARY_FILE] != "":
1371 shutil.copy(sourcefolder + "/" + picow_options_list[feat][ANCILLARY_FILE], projectPath / picow_options_list[feat][ANCILLARY_FILE])
1373 # Create a build folder, and run our cmake project build from it
1374 if not os.path.exists('build'):
1379 # If we are overwriting a previous project, we should probably clear the folder, but that might delete something the users thinks is important, so
1380 # for the moment, just delete the CMakeCache.txt file as certain changes may need that to be recreated.
1382 if os.path.exists(CMAKECACHE_FILENAME):
1383 os.remove(CMAKECACHE_FILENAME)
1385 cpus = os.cpu_count()
1390 # Had a special case report, when using MinGW, need to check if using nmake or mingw32-make.
1391 if shutil.which("mingw32-make"):
1392 # Assume MinGW environment
1393 cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug -G "MinGW Makefiles" ..'
1394 makeCmd = 'mingw32-make '
1395 elif shutil.which("ninja"):
1396 # When installing SDK version 1.5.0 on windows with installer pico-setup-windows-x64-standalone.exe, ninja is used
1397 cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug -G Ninja ..'
1400 # Everything else assume nmake
1401 cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug -G "NMake Makefiles" ..'
1404 # Ninja now works OK under Linux, so if installed use it by default. It's faster.
1405 if shutil.which("ninja"):
1406 cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug -G Ninja ..'
1409 cmakeCmd = 'cmake -DCMAKE_BUILD_TYPE=Debug ..'
1410 makeCmd = 'make -j' + str(cpus)
1412 if params['wantGUI']:
1413 RunCommandInWindow(parent, cmakeCmd)
1417 if params['projects']:
1418 generateProjectFiles(projectPath, params['projectName'], params['sdkPath'], params['projects'], params['debugger'])
1420 if params['wantBuild']:
1421 if params['wantGUI']:
1422 RunCommandInWindow(parent, makeCmd)
1425 print('\nIf the application has built correctly, you can now transfer it to the Raspberry Pi Pico board')
1430 ###################################################################################
1431 # main execution starteth here
1433 sourcefolder = os.path.dirname(os.path.abspath(__file__))
1435 args = ParseCommandLine()
1440 if args.debugger > len(debugger_list) - 1:
1443 # Check we have everything we need to compile etc
1444 c = CheckPrerequisites()
1446 ## TODO Do both warnings in the same error message so user does have to keep coming back to find still more to do
1449 m = f'Unable to find the `{COMPILER_NAME}` compiler\n'
1450 m +='You will need to install an appropriate compiler to build a Raspberry Pi Pico project\n'
1451 m += 'See the Raspberry Pi Pico documentation for how to do this on your particular platform\n'
1459 if args.name == None and not args.gui and not args.list and not args.configs and not args.boardlist:
1460 print("No project name specfied\n")
1463 # Check if we were provided a compiler path, and override the default if so
1465 compilerPath = Path(args.cpath)
1467 compilerPath = Path(c)
1469 # load/parse any configuration dictionary we may have
1470 LoadConfigurations()
1472 p = CheckSDKPath(args.gui)
1479 boardtype_list = LoadBoardTypes(sdkPath)
1480 boardtype_list.sort()
1483 RunGUI(sdkPath, args) # does not return, only exits
1485 projectRoot = Path(os.getcwd())
1487 if args.list or args.configs or args.boardlist:
1489 print("Available project features:\n")
1490 for feat in features_list:
1491 print(feat.ljust(6), '\t', features_list[feat][GUI_TEXT])
1495 print("Available project configuration items:\n")
1496 for conf in configuration_dictionary:
1497 print(conf['name'].ljust(40), '\t', conf['description'])
1501 print("Available board types:\n")
1502 for board in boardtype_list:
1509 'sdkPath' : sdkPath,
1510 'projectRoot' : projectRoot,
1511 'projectName' : args.name,
1513 'wantOverwrite' : args.overwrite,
1514 'boardtype' : args.boardtype,
1515 'wantBuild' : args.build,
1516 'features' : args.feature,
1517 'projects' : args.project,
1519 'wantRunFromRAM': args.runFromRAM,
1520 'wantExamples' : args.examples,
1521 'wantUART' : args.uart,
1522 'wantUSB' : args.usb,
1523 'wantCPP' : args.cpp,
1524 'debugger' : args.debugger,
1525 'exceptions' : args.cppexceptions,
1526 'rtti' : args.cpprtti,
1531 DoEverything(None, params)