]> Git Repo - pico-vscode.git/blob - scripts/pico_project.py
Beta 13 (RC 2)
[pico-vscode.git] / scripts / pico_project.py
1 #!/usr/bin/env python3
2
3 #
4 # Copyright (c) 2020-2024 Raspberry Pi (Trading) Ltd.
5 #
6 # SPDX-License-Identifier: BSD-3-Clause
7 #
8
9 #
10 # Copyright (c) 2023-2024 paulober <github.com/paulober>
11 #
12 # SPDX-License-Identifier: MPL-2.0
13 #
14
15 import argparse
16 import os
17 import shutil
18 from pathlib import Path
19 import sys
20 import platform
21 import csv
22
23 CMAKELIST_FILENAME = 'CMakeLists.txt'
24 CMAKECACHE_FILENAME = 'CMakeCache.txt'
25
26 COMPILER_NAME = 'arm-none-eabi-gcc'
27
28 VSCODE_LAUNCH_FILENAME = 'launch.json'
29 VSCODE_C_PROPERTIES_FILENAME = 'c_cpp_properties.json'
30 VSCODE_CMAKE_KITS_FILENAME ='cmake-kits.json'
31 VSCODE_SETTINGS_FILENAME ='settings.json'
32 VSCODE_EXTENSIONS_FILENAME ='extensions.json'
33 VSCODE_TASKS_FILENAME ='tasks.json'
34 VSCODE_FOLDER='.vscode'
35
36 CONFIG_UNSET="Not set"
37
38 # Standard libraries for all builds
39 # And any more to string below, space separator
40 STANDARD_LIBRARIES = 'pico_stdlib'
41
42 # Indexed on feature name, tuple contains the C file, the H file and the CMake project name for the feature. 
43 # Some lists may contain an extra/ancillary file needed for that feature
44 GUI_TEXT = 0
45 C_FILE = 1
46 H_FILE = 2
47 LIB_NAME = 3
48 ANCILLARY_FILE = 4
49
50 features_list = {
51     'spi' :             ("SPI",             "spi.c",            "hardware/spi.h",       "hardware_spi",         ""),
52     'i2c' :             ("I2C interface",   "i2c.c",            "hardware/i2c.h",       "hardware_i2c",         ""),
53     'dma' :             ("DMA support",     "dma.c",            "hardware/dma.h",       "hardware_dma",         ""),
54     'pio' :             ("PIO interface",   "pio.c",            "hardware/pio.h",       "hardware_pio",         "blink.pio"),
55     'interp' :          ("HW interpolation", "interp.c",        "hardware/interp.h",    "hardware_interp",      ""),
56     'timer' :           ("HW timer",        "timer.c",          "hardware/timer.h",     "hardware_timer",       ""),
57     'watchdog' :        ("HW watchdog",     "watch.c",          "hardware/watchdog.h",  "hardware_watchdog",    ""),
58     'clocks' :          ("HW clocks",       "clocks.c",         "hardware/clocks.h",    "hardware_clocks",      ""),
59 }
60
61 picow_options_list = {
62     'picow_none' :      ("None", "",                            "",    "",                                                                  ""),
63     'picow_led' :       ("PicoW onboard LED", "",               "pico/cyw43_arch.h",    "pico_cyw43_arch_none",                             ""),
64     'picow_poll' :      ("Polled lwIP",     "",                 "pico/cyw43_arch.h",    "pico_cyw43_arch_lwip_poll",                        "lwipopts.h"),
65     'picow_background' :("Background lwIP", "",                 "pico/cyw43_arch.h",    "pico_cyw43_arch_lwip_threadsafe_background",       "lwipopts.h"),
66 #    'picow_freertos' :  ("Full lwIP (FreeRTOS)", "",            "pico/cyw43_arch.h",    "pico_cyw43_arch_lwip_sys_freertos",                "lwipopts.h"),
67 }
68
69 stdlib_examples_list = {
70     'uart':     ("UART",                    "uart.c",           "hardware/uart.h",      "hardware_uart"),
71     'gpio' :    ("GPIO interface",          "gpio.c",           "hardware/gpio.h",      "hardware_gpio"),
72     'div' :     ("Low level HW Divider",    "divider.c",        "hardware/divider.h",   "hardware_divider")
73 }
74
75 debugger_list = ["DebugProbe (CMSIS-DAP)", "SWD (Pi host)"]
76 debugger_config_list = ["interface/cmsis-dap.cfg", "raspberrypi-swd.cfg"]
77
78 DEFINES = 0
79 INITIALISERS = 1
80 # Could add an extra item that shows how to use some of the available functions for the feature
81 #EXAMPLE = 2
82
83 # This also contains example code for the standard library (see stdlib_examples_list)
84 code_fragments_per_feature = {
85     'uart' : [
86               (
87                 "// UART defines",
88                 "// By default the stdout UART is `uart0`, so we will use the second one",
89                 "#define UART_ID uart1",
90                 "#define BAUD_RATE 9600", "",
91                 "// Use pins 4 and 5 for UART1",
92                 "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
93                 "#define UART_TX_PIN 4",
94                 "#define UART_RX_PIN 5"
95               ),
96               (
97                 "// Set up our UART",
98                 "uart_init(UART_ID, BAUD_RATE);",
99                 "// Set the TX and RX pins by using the function select on the GPIO",
100                 "// Set datasheet for more information on function select",
101                 "gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);",
102                 "gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);",
103                 "// For more examples of UART use see https://github.com/raspberrypi/pico-examples/tree/master/uart"
104               )
105             ],
106     'spi' : [
107               (
108                 "// SPI Defines",
109                 "// We are going to use SPI 0, and allocate it to the following GPIO pins",
110                 "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
111                 "#define SPI_PORT spi0",
112                 "#define PIN_MISO 16",
113                 "#define PIN_CS   17",
114                 "#define PIN_SCK  18",
115                 "#define PIN_MOSI 19"
116               ),
117               (
118                 "// SPI initialisation. This example will use SPI at 1MHz.",
119                 "spi_init(SPI_PORT, 1000*1000);",
120                 "gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);",
121                 "gpio_set_function(PIN_CS,   GPIO_FUNC_SIO);",
122                 "gpio_set_function(PIN_SCK,  GPIO_FUNC_SPI);",
123                 "gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);", "",
124                 "// Chip select is active-low, so we'll initialise it to a driven-high state",
125                 "gpio_set_dir(PIN_CS, GPIO_OUT);",
126                 "gpio_put(PIN_CS, 1);",
127                 "// For more examples of SPI use see https://github.com/raspberrypi/pico-examples/tree/master/spi"
128               )
129             ],
130     'i2c' : [
131               (
132                 "// I2C defines",
133                 "// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.",
134                 "// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
135                 "#define I2C_PORT i2c0",
136                 "#define I2C_SDA 8",
137                 "#define I2C_SCL 9",
138               ),
139               (
140                 "// I2C Initialisation. Using it at 400Khz.",
141                 "i2c_init(I2C_PORT, 400*1000);","",
142                 "gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);",
143                 "gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);",
144                 "gpio_pull_up(I2C_SDA);",
145                 "gpio_pull_up(I2C_SCL);",
146                 "// For more examples of I2C use see https://github.com/raspberrypi/pico-examples/tree/master/i2c",
147               )
148             ],
149     "dma" : [
150               (
151                 '// Data will be copied from src to dst',
152                 'const char src[] = "Hello, world! (from DMA)";',
153                 'char dst[count_of(src)];',
154               ),
155               (
156                 '// Get a free channel, panic() if there are none',
157                 'int chan = dma_claim_unused_channel(true);',
158                 '',
159                 '// 8 bit transfers. Both read and write address increment after each',
160                 '// transfer (each pointing to a location in src or dst respectively).',
161                 '// No DREQ is selected, so the DMA transfers as fast as it can.',
162                 '',
163                 'dma_channel_config c = dma_channel_get_default_config(chan);',
164                 'channel_config_set_transfer_data_size(&c, DMA_SIZE_8);',
165                 'channel_config_set_read_increment(&c, true);',
166                 'channel_config_set_write_increment(&c, true);',
167                 '',
168                 'dma_channel_configure(',
169                 '    chan,          // Channel to be configured',
170                 '    &c,            // The configuration we just created',
171                 '    dst,           // The initial write address',
172                 '    src,           // The initial read address',
173                 '    count_of(src), // Number of transfers; in this case each is 1 byte.',
174                 '    true           // Start immediately.',
175                 ');',
176                 '',
177                 '// We could choose to go and do something else whilst the DMA is doing its',
178                 '// thing. In this case the processor has nothing else to do, so we just',
179                 '// wait for the DMA to finish.',
180                 'dma_channel_wait_for_finish_blocking(chan);',
181                 '',
182                 '// The DMA has now copied our text from the transmit buffer (src) to the',
183                 '// receive buffer (dst), so we can print it out from there.',
184                 'puts(dst);',
185               )
186             ],
187
188     "pio" : [
189               (
190                 '#include "blink.pio.h"','',
191                 'void blink_pin_forever(PIO pio, uint sm, uint offset, uint pin, uint freq) {',
192                 '    blink_program_init(pio, sm, offset, pin);',
193                 '    pio_sm_set_enabled(pio, sm, true);',
194                 '',
195                 '    printf("Blinking pin %d at %d Hz\\n", pin, freq);',
196                 '',
197                 '    // PIO counter program takes 3 more cycles in total than we pass as',
198                 '    // input (wait for n + 1; mov; jmp)',
199                 '    pio->txf[sm] = (125000000 / (2 * freq)) - 3;',
200                 '}',
201               ),
202               (
203                 '// PIO Blinking example',
204                 'PIO pio = pio0;',
205                 'uint offset = pio_add_program(pio, &blink_program);',
206                 'printf("Loaded program at %d\\n", offset);',
207                 '',
208                 '#ifdef PICO_DEFAULT_LED_PIN',
209                 'blink_pin_forever(pio, 0, offset, PICO_DEFAULT_LED_PIN, 3);',
210                 '#else',
211                 'blink_pin_forever(pio, 0, offset, 6, 3);',
212                 '#endif',
213                 '// For more pio examples see https://github.com/raspberrypi/pico-examples/tree/master/pio',
214               )
215             ],
216
217     "clocks" :  [
218                   (),
219                   (
220                     'printf("System Clock Frequency is %d Hz\\n", clock_get_hz(clk_sys));',
221                     'printf("USB Clock Frequency is %d Hz\\n", clock_get_hz(clk_usb));',
222                     '// For more examples of clocks use see https://github.com/raspberrypi/pico-examples/tree/master/clocks',
223                   )
224                 ],
225
226     "gpio" : [
227               (
228                 "// GPIO defines",
229                 "// Example uses GPIO 2",
230                 "#define GPIO 2"
231               ),
232               (
233                 "// GPIO initialisation.",
234                 "// We will make this GPIO an input, and pull it up by default",
235                 "gpio_init(GPIO);",
236                 "gpio_set_dir(GPIO, GPIO_IN);",
237                 "gpio_pull_up(GPIO);",
238                 "// See https://github.com/raspberrypi/pico-examples/tree/master/gpio for other gpio examples, including using interrupts",
239               )
240             ],
241     "interp" :[
242                (),
243                (
244                 "// Interpolator example code",
245                 "interp_config cfg = interp_default_config();",
246                 "// Now use the various interpolator library functions for your use case",
247                 "// e.g. interp_config_clamp(&cfg, true);",
248                 "//      interp_config_shift(&cfg, 2);",
249                 "// Then set the config ",
250                 "interp_set_config(interp0, 0, &cfg);",
251                 "// For examples of interpolator use see https://github.com/raspberrypi/pico-examples/tree/master/interp"
252                )
253               ],
254
255     "timer"  : [
256                 (
257                  "int64_t alarm_callback(alarm_id_t id, void *user_data) {",
258                  "    // Put your timeout handler code in here",
259                  "    return 0;",
260                  "}"
261                 ),
262                 (
263                  "// Timer example code - This example fires off the callback after 2000ms",
264                  "add_alarm_in_ms(2000, alarm_callback, NULL, false);",
265                  "// For more examples of timer use see https://github.com/raspberrypi/pico-examples/tree/master/timer"
266                 )
267               ],
268
269     "watchdog":[ (),
270                 (
271                     "// Watchdog example code",
272                     "if (watchdog_caused_reboot()) {",
273                     "    printf(\"Rebooted by Watchdog!\\n\");",
274                     "    // Whatever action you may take if a watchdog caused a reboot",
275                     "}","",
276                     "// Enable the watchdog, requiring the watchdog to be updated every 100ms or the chip will reboot",
277                     "// second arg is pause on debug which means the watchdog will pause when stepping through code",
278                     "watchdog_enable(100, 1);","",
279                     "// You need to call this function at least more often than the 100ms in the enable call to prevent a reboot",
280                     "watchdog_update();",
281                 )
282               ],
283
284     "div"    : [ (),
285                  (
286                     "// Example of using the HW divider. The pico_divider library provides a more user friendly set of APIs ",
287                     "// over the divider (and support for 64 bit divides), and of course by default regular C language integer",
288                     "// divisions are redirected thru that library, meaning you can just use C level `/` and `%` operators and",
289                     "// gain the benefits of the fast hardware divider.",
290                     "int32_t dividend = 123456;",
291                     "int32_t divisor = -321;",
292                     "// This is the recommended signed fast divider for general use.",
293                     "divmod_result_t result = hw_divider_divmod_s32(dividend, divisor);",
294                     "printf(\"%d/%d = %d remainder %d\\n\", dividend, divisor, to_quotient_s32(result), to_remainder_s32(result));",
295                     "// This is the recommended unsigned fast divider for general use.",
296                     "int32_t udividend = 123456;",
297                     "int32_t udivisor = 321;",
298                     "divmod_result_t uresult = hw_divider_divmod_u32(udividend, udivisor);",
299                     "printf(\"%d/%d = %d remainder %d\\n\", udividend, udivisor, to_quotient_u32(uresult), to_remainder_u32(uresult));",
300                     "// See https://github.com/raspberrypi/pico-examples/tree/master/divider for more complex use"
301                  )
302                 ],
303
304     "picow_led":[ (),
305                   (
306                     "// Example to turn on the Pico W LED",
307                     "cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);"
308                   )
309                 ],
310
311     "picow_wifi":[ (),
312                   (
313                     '// Enable wifi station',
314                     'cyw43_arch_enable_sta_mode();\n',
315                     'printf("Connecting to Wi-Fi...\\n");',
316                     'if (cyw43_arch_wifi_connect_timeout_ms("Your Wi-Fi SSID", "Your Wi-Fi Password", CYW43_AUTH_WPA2_AES_PSK, 30000)) {',
317                     '    printf("failed to connect.\\n");',
318                     '    return 1;',
319                     '} else {',
320                     '    printf("Connected.\\n");',
321                     '    // Read the ip address in a human readable way',
322                     '    uint8_t *ip_address = (uint8_t*)&(cyw43_state.netif[0].ip_addr.addr);',
323                     '    printf("IP address %d.%d.%d.%d\\n", ip_address[0], ip_address[1], ip_address[2], ip_address[3]);',
324                     '}',
325                   )
326                 ]
327 }
328
329 # Add wifi example for poll and background modes
330 code_fragments_per_feature["picow_poll"] = code_fragments_per_feature["picow_wifi"]
331 code_fragments_per_feature["picow_background"] = code_fragments_per_feature["picow_wifi"]
332
333 configuration_dictionary = list(dict())
334
335 isMac = False
336 isWindows = False
337 compilerPath = Path("/usr/bin/arm-none-eabi-gcc")
338
339 def relativeSDKPath(sdkVersion):
340     return f"/.pico-sdk/sdk/{sdkVersion}"
341
342 def relativeToolchainPath(toolchainVersion):
343     return f"/.pico-sdk/toolchain/{toolchainVersion}"
344
345 def relativeToolsPath(sdkVersion):
346     return f"/.pico-sdk/tools/{sdkVersion}"
347
348 def relativeOpenOCDPath(openocdVersion):
349     return f"/.pico-sdk/openocd/{openocdVersion}"
350
351 def cmakeSdkPath(sdkVersion):
352     return f"${{USERHOME}}{relativeSDKPath(sdkVersion)}"
353
354 def cmakeToolchainPath(toolchainVersion):
355     return f"${{USERHOME}}{relativeToolchainPath(toolchainVersion)}"
356
357 def cmakeToolsPath(sdkVersion):
358     return f"${{USERHOME}}{relativeToolsPath(sdkVersion)}"
359
360 def propertiesSdkPath(sdkVersion, force_windows=False, force_non_windows=False):
361     if (isWindows or force_windows) and not force_non_windows:
362         return f"${{env:USERPROFILE}}{relativeSDKPath(sdkVersion)}"
363     else:
364         return f"${{env:HOME}}{relativeSDKPath(sdkVersion)}"
365
366 def codeSdkPath(sdkVersion):
367     return f"${{userHome}}{relativeSDKPath(sdkVersion)}"
368
369 def codeOpenOCDPath(openocdVersion):
370     return f"${{userHome}}{relativeOpenOCDPath(openocdVersion)}"
371
372 def propertiesToolchainPath(toolchainVersion, force_windows=False, force_non_windows=False):
373     if (isWindows or force_windows) and not force_non_windows:
374         return f"${{env:USERPROFILE}}{relativeToolchainPath(toolchainVersion)}"
375     else:
376         return f"${{env:HOME}}{relativeToolchainPath(toolchainVersion)}"
377
378 def codeToolchainPath(toolchainVersion):
379     return f"${{userHome}}{relativeToolchainPath(toolchainVersion)}"
380
381 def CheckPrerequisites():
382     global isMac, isWindows
383     isMac = (platform.system() == 'Darwin')
384     isWindows = (platform.system() == 'Windows')
385
386     # Do we have a compiler?
387     return shutil.which(COMPILER_NAME, 1, os.environ["Path" if isWindows else "PATH"])
388
389
390 def CheckSDKPath(gui):
391     sdkPath = os.getenv('PICO_SDK_PATH')
392
393     if sdkPath == None:
394         m = 'Unable to locate the Raspberry Pi Pico SDK, PICO_SDK_PATH is not set'
395         print(m)
396     elif not os.path.isdir(sdkPath):
397         m = 'Unable to locate the Raspberry Pi Pico SDK, PICO_SDK_PATH does not point to a directory'
398         print(m)
399         sdkPath = None
400
401     return sdkPath
402
403 def GetFilePath(filename):
404     if os.path.islink(__file__):
405         script_file = os.readlink(__file__)
406     else:
407         script_file = __file__
408     return os.path.join(os.path.dirname(script_file), filename)
409
410 def ParseCommandLine():
411     debugger_flags = ', '.join('{} = {}'.format(i, v) for i, v in enumerate(debugger_list))
412     parser = argparse.ArgumentParser(description='Pico Project generator')
413     parser.add_argument("name", nargs="?", help="Name of the project")
414     parser.add_argument("-t", "--tsv", help="Select an alternative pico_configs.tsv file", default=GetFilePath("pico_configs.tsv"))
415     parser.add_argument("-o", "--output", help="Set an alternative CMakeList.txt filename", default="CMakeLists.txt")
416     parser.add_argument("-x", "--examples", action='store_true', help="Add example code for the Pico standard library")
417     parser.add_argument("-l", "--list", action='store_true', help="List available features")
418     parser.add_argument("-c", "--configs", action='store_true', help="List available project configuration items")
419     parser.add_argument("-f", "--feature", action='append', help="Add feature to generated project")
420     parser.add_argument("-over", "--overwrite", action='store_true', help="Overwrite any existing project AND files")
421     parser.add_argument("-conv", "--convert", action='store_true', help="Convert any existing project - risks data loss")
422     parser.add_argument("-exam", "--example", action='store_true', help="Convert an examples folder to standalone project")
423     parser.add_argument("-b", "--build", action='store_true', help="Build after project created")
424     parser.add_argument("-g", "--gui", action='store_true', help="Run a GUI version of the project generator")
425     parser.add_argument("-p", "--project", action='append', help="Generate projects files for IDE. Options are: vscode")
426     parser.add_argument("-r", "--runFromRAM", action='store_true', help="Run the program from RAM rather than flash")
427     parser.add_argument("-uart", "--uart", action='store_true', default=1, help="Console output to UART (default)")
428     parser.add_argument("-nouart", "--nouart", action='store_true', default=0, help="Disable console output to UART")
429     parser.add_argument("-usb", "--usb", action='store_true', help="Console output to USB (disables other USB functionality")
430     parser.add_argument("-cpp", "--cpp", action='store_true', default=0, help="Generate C++ code")
431     parser.add_argument("-cpprtti", "--cpprtti", action='store_true', default=0, help="Enable C++ RTTI (Uses more memory)")
432     parser.add_argument("-cppex", "--cppexceptions", action='store_true', default=0, help="Enable C++ exceptions (Uses more memory)")
433     parser.add_argument("-d", "--debugger", type=int, help="Select debugger ({})".format(debugger_flags), default=0)
434     parser.add_argument("-board", "--boardtype", action="store", default='pico', help="Select board type (see --boardlist for available boards)")
435     parser.add_argument("-bl", "--boardlist", action="store_true", help="List available board types")
436     parser.add_argument("-cp", "--cpath", help="Override default VSCode compiler path")
437     parser.add_argument("-root", "--projectRoot", help="Override default project root where the new project will be created")
438     parser.add_argument("-sdkVersion", "--sdkVersion", help="Pico SDK version to use (required)")
439     parser.add_argument("-tcVersion", "--toolchainVersion", help="ARM Embeded Toolchain version to use (required)")
440     parser.add_argument("-np", "--ninjaPath", help="Ninja path")
441     parser.add_argument("-cmp", "--cmakePath", help="CMake path")
442     parser.add_argument("-cupy", "--customPython", action='store_true', help="Custom python path used to execute the script.")
443     parser.add_argument("-openOCDVersion", "--openOCDVersion", help="OpenOCD version to use - defaults to 0", default=0)
444
445     return parser.parse_args()
446
447
448 def GenerateMain(folder, projectName, features, cpp):
449
450     if cpp:
451         filename = Path(folder) / (projectName + '.cpp')
452     else:
453         filename = Path(folder) / (projectName + '.c')
454
455     file = open(filename, 'w')
456
457     main = ('#include <stdio.h>\n'
458             '#include "pico/stdlib.h"\n'
459             )
460     file.write(main)
461
462     if (features):
463
464         # Add any includes
465         for feat in features:
466             if (feat in features_list):
467                 if len(features_list[feat][H_FILE]) == 0:
468                     continue
469                 o = f'#include "{features_list[feat][H_FILE]}"\n'
470                 file.write(o)
471             if (feat in stdlib_examples_list):
472                 if len(stdlib_examples_list[feat][H_FILE]) == 0:
473                     continue
474                 o = f'#include "{stdlib_examples_list[feat][H_FILE]}"\n'
475                 file.write(o)
476             if (feat in picow_options_list):
477                 if len(picow_options_list[feat][H_FILE]) == 0:
478                     continue
479                 o = f'#include "{picow_options_list[feat][H_FILE]}"\n'
480                 file.write(o)
481
482         file.write('\n')
483
484         # Add any defines
485         for feat in features:
486             if (feat in code_fragments_per_feature):
487                 for s in code_fragments_per_feature[feat][DEFINES]:
488                     file.write(s)
489                     file.write('\n')
490                 file.write('\n')
491
492     main = ('\n\n'
493             'int main()\n'
494             '{\n'
495             '    stdio_init_all();\n\n'
496             )
497
498     if any([feat in picow_options_list and feat != "picow_none" for feat in features]):
499         main += (
500             '    // Initialise the Wi-Fi chip\n'
501             '    if (cyw43_arch_init()) {\n'
502             '        printf("Wi-Fi init failed\\n");\n'
503             '        return -1;\n'
504             '    }\n\n')
505
506     if (features):
507         # Add any initialisers
508         indent = 4
509         for feat in features:
510             if (feat in code_fragments_per_feature):
511                 for s in code_fragments_per_feature[feat][INITIALISERS]:
512                     main += (" " * indent)
513                     main += s
514                     main += '\n'
515                 main += '\n'
516
517     main += ('    while (true) {\n'
518              '        printf("Hello, world!\\n");\n'
519              '        sleep_ms(1000);\n'
520              '    }\n'
521              '}\n'
522             )
523
524     file.write(main)
525
526     file.close()
527
528
529 def GenerateCMake(folder, params):
530    
531     filename = Path(folder) / CMAKELIST_FILENAME
532     projectName = params['projectName']
533     board_type = params['boardtype']
534
535     # OK, for the path, CMake will accept forward slashes on Windows, and thats
536     # seemingly a bit easier to handle than the backslashes
537     p = str(params['sdkPath']).replace('\\','/')
538
539     cmake_header1 = (f"# Generated Cmake Pico project file\n\n"
540                  "cmake_minimum_required(VERSION 3.13)\n\n"
541                  "set(CMAKE_C_STANDARD 11)\n"
542                  "set(CMAKE_CXX_STANDARD 17)\n"
543                  "set(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\n"
544                  "# Initialise pico_sdk from installed location\n"
545                  "# (note this can come from environment, CMake cache etc)\n\n"
546                 )
547     
548     # if you change the do never edit headline you need to change the check for it in extension.mts
549     cmake_header_us = (
550                 "# == DO NEVER EDIT THE NEXT LINES for Raspberry Pi Pico VS Code Extension to work ==\n"
551                 "if(WIN32)\n"
552                 "   set(USERHOME $ENV{USERPROFILE})\n"
553                 "else()\n"
554                 "    set(USERHOME $ENV{HOME})\n"
555                 "endif()\n"
556                 f"set(PICO_SDK_PATH {cmakeSdkPath(params['sdkVersion'])})\n"
557                 f"set(PICO_TOOLCHAIN_PATH {cmakeToolchainPath(params['toolchainVersion'])})\n"
558                 "if(WIN32)\n"
559                 f"    set(pico-sdk-tools_DIR {cmakeToolsPath(params['sdkVersion'])})\n"
560                 "    include(${pico-sdk-tools_DIR}/pico-sdk-tools-config.cmake)\n"
561                 "    include(${pico-sdk-tools_DIR}/pico-sdk-tools-config-version.cmake)\n"
562                 "endif()\n"
563                 "# ====================================================================================\n"
564                 )
565     
566     cmake_header2 = (
567                  f"set(PICO_BOARD {board_type} CACHE STRING \"Board type\")\n\n"
568                  "# Pull in Raspberry Pi Pico SDK (must be before project)\n"
569                  "include(pico_sdk_import.cmake)\n\n"
570                  "if (PICO_SDK_VERSION_STRING VERSION_LESS \"1.4.0\")\n"
571                  "  message(FATAL_ERROR \"Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}\")\n"
572                  "endif()\n\n"
573                  f"project({projectName} C CXX ASM)\n"
574                 )
575     
576     cmake_header3 = (
577                 "\n# Initialise the Raspberry Pi Pico SDK\n"
578                 "pico_sdk_init()\n\n"
579                 "# Add executable. Default name is the project name, version 0.1\n\n"
580                 )
581     
582
583     if params['wantConvert']:
584         with open(filename, 'r+') as file:
585             content = file.read()
586             file.seek(0)
587             lines = file.readlines()
588             file.seek(0)
589             if not params['wantExample']:
590                 # Prexisting CMake configuration - just adding cmake_header_us
591                 file.write(cmake_header_us)
592                 file.write(content)
593             else:
594                 if any(["pico_cyw43_arch_lwip_threadsafe_background" in line for line in lines]):
595                     print("Threadsafe Background")
596                     params["wantThreadsafeBackground"] = True
597                 if any(["pico_cyw43_arch_lwip_poll" in line for line in lines]):
598                     print("Poll")
599                     params["wantPoll"] = True
600                 # Get project name
601                 for line in lines:
602                     if "add_executable" in line:
603                         newProjectName = line.split('(')[1].split()[0].strip().strip("()")
604                         if params["wantThreadsafeBackground"] or params["wantPoll"]:
605                             newProjectName = newProjectName.replace("_background", "")
606                             newProjectName = newProjectName.replace("_poll", "")
607                         print("New project name", newProjectName)
608                         cmake_header2 = cmake_header2.replace(projectName, newProjectName)
609                 # Write all headers
610                 file.write(cmake_header1)
611                 file.write(cmake_header_us)
612                 file.write(cmake_header2)
613                 file.write(cmake_header3)
614                 file.flush()
615                 # Remove example_auto_set_url
616                 for i, line in enumerate(lines):
617                     if "example_auto_set_url" in line:
618                         lines[i] = ""
619                         print("Removed", line, lines[i])
620                 file.writelines(lines)
621         return
622
623
624     file = open(filename, 'w')
625
626     file.write(cmake_header1)
627     file.write(cmake_header_us)
628     file.write(cmake_header2)
629
630     if params['exceptions']:
631         file.write("\nset(PICO_CXX_ENABLE_EXCEPTIONS 1)\n")
632
633     if params['rtti']:
634         file.write("\nset(PICO_CXX_ENABLE_RTTI 1)\n")
635
636     file.write(cmake_header3)
637
638     # add the preprocessor defines for overall configuration
639     if params['configs']:
640         file.write('# Add any PICO_CONFIG entries specified in the Advanced settings\n')
641         for c, v in params['configs'].items():
642             if v == "True":
643                 v = "1"
644             elif v == "False":
645                 v = "0"
646             file.write(f'add_compile_definitions({c} = {v})\n')
647         file.write('\n')
648
649     # No GUI/command line to set a different executable name at this stage
650     executableName = projectName
651
652     if params['wantCPP']:
653         file.write(f'add_executable({projectName} {projectName}.cpp )\n\n')
654     else:
655         file.write(f'add_executable({projectName} {projectName}.c )\n\n')
656
657     file.write(f'pico_set_program_name({projectName} "{executableName}")\n')
658     file.write(f'pico_set_program_version({projectName} "0.1")\n\n')
659
660     if params['wantRunFromRAM']:
661         file.write(f'# no_flash means the target is to run from RAM\n')
662         file.write(f'pico_set_binary_type({projectName} no_flash)\n\n')
663
664     # Add pio output
665     if params['features'] and "pio" in params['features']:
666         file.write(f'# Generate PIO header\n')
667         file.write(f'pico_generate_pio_header({projectName} ${{CMAKE_CURRENT_LIST_DIR}}/blink.pio)\n\n')
668
669     # Console output destinations
670     file.write("# Modify the below lines to enable/disable output over UART/USB\n")
671     if params['wantUART']:
672         file.write(f'pico_enable_stdio_uart({projectName} 1)\n')
673     else:
674         file.write(f'pico_enable_stdio_uart({projectName} 0)\n')
675
676     if params['wantUSB']:
677         file.write(f'pico_enable_stdio_usb({projectName} 1)\n\n')
678     else:
679         file.write(f'pico_enable_stdio_usb({projectName} 0)\n\n')
680
681     # If we need wireless, check for SSID and password
682     # removed for the moment as these settings are currently only needed for the pico-examples
683     # but may be required in here at a later date.
684     if False:
685         if 'ssid' in params or 'password' in params:
686             file.write('# Add any wireless access point information\n')
687             file.write(f'target_compile_definitions({projectName} PRIVATE\n')
688             if 'ssid' in params:
689                 file.write(f'WIFI_SSID=\" {params["ssid"]} \"\n')
690             else:
691                 file.write(f'WIFI_SSID=\"${WIFI_SSID}\"')
692
693             if 'password' in params:
694                 file.write(f'WIFI_PASSWORD=\"{params["password"]}\"\n')
695             else:
696                 file.write(f'WIFI_PASSWORD=\"${WIFI_PASSWORD}\"')
697             file.write(')\n\n')
698
699     # Standard libraries
700     file.write('# Add the standard library to the build\n')
701     file.write(f'target_link_libraries({projectName}\n')
702     file.write("        " + STANDARD_LIBRARIES)
703     file.write(')\n\n')
704
705     # Standard include directories
706     file.write('# Add the standard include files to the build\n')
707     file.write(f'target_include_directories({projectName} PRIVATE\n')
708     file.write("  ${CMAKE_CURRENT_LIST_DIR}\n")
709     file.write("  ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required\n")
710     file.write(')\n\n')
711
712     # Selected libraries/features
713     if (params['features']):
714         file.write('# Add any user requested libraries\n')
715         file.write(f'target_link_libraries({projectName} \n')
716         for feat in params['features']:
717             if (feat in features_list):
718                 file.write("        " + features_list[feat][LIB_NAME] + '\n')
719             if (feat in picow_options_list):
720                 file.write("        " + picow_options_list[feat][LIB_NAME] + '\n')
721         file.write('        )\n\n')
722
723     file.write(f'pico_add_extra_outputs({projectName})\n\n')
724
725     file.close()
726
727
728 # Generates the requested project files, if any
729 def generateProjectFiles(projectPath, projectName, sdkPath, projects, debugger, sdkVersion, toolchainVersion, ninjaPath, cmakePath, customPython, openOCDVersion):
730
731     oldCWD = os.getcwd()
732
733     os.chdir(projectPath)
734
735     debugger = debugger_config_list[debugger]
736
737     if debugger == "raspberrypi-swd.cfg":
738         shutil.copyfile(sourcefolder + "/" +  "raspberrypi-swd.cfg", projectPath / "raspberrypi-swd.cfg")
739
740     gdbPath =  Path(codeToolchainPath(toolchainVersion)+"/bin/arm-none-eabi-gdb").as_posix() if isWindows or isMac else "gdb"
741     # Need to escape windows files paths backslashes
742     # TODO: env in currently not supported in compilerPath var
743     #cPath = f"${{env:PICO_TOOLCHAIN_PATH_{envSuffix}}}" + os.path.sep + os.path.basename(str(compilerPath).replace('\\', '\\\\' ))
744     cPath = compilerPath.as_posix() + (".exe" if isWindows else "")
745
746     # if this is a path in the .pico-sdk homedir tell the settings to use the homevar
747     user_home = os.path.expanduser("~").replace("\\", "/")
748     use_home_var = f"{user_home}/.pico-sdk" in ninjaPath
749
750     openocd_path = ""
751     server_path = "\n            \"serverpath\"" # Because no \ in f-strings
752     openocd_path_os = Path(user_home, relativeOpenOCDPath(openOCDVersion).replace("/", "", 1), "bin", "openocd.exe")
753     if os.path.exists(openocd_path_os):
754         openocd_path = f'{codeOpenOCDPath(openOCDVersion)}/bin/openocd.exe'
755
756     for p in projects :
757         if p == 'vscode':
758             launch = f'''{{
759     "version": "0.2.0",
760     "configurations": [
761         {{
762             "name": "Pico Debug (Cortex-Debug)",
763             "cwd": "{"${workspaceRoot}" if not isWindows else f"{codeOpenOCDPath(openOCDVersion)}/openocd/scripts"}",
764             "executable": "${{command:raspberry-pi-pico.launchTargetPath}}",
765             "request": "launch",
766             "type": "cortex-debug",
767             "servertype": "openocd",\
768 {f'{server_path}: "{openocd_path}",' if openocd_path else ""}
769             "gdbPath": "{gdbPath}",
770             "device": "RP2040",
771             "configFiles": [
772                 "{debugger}",
773                 "target/rp2040.cfg"
774             ],
775             "svdFile": "{codeSdkPath(sdkVersion)}/src/rp2040/hardware_regs/rp2040.svd",
776             "runToEntryPoint": "main",
777             // Give restart the same functionality as runToEntryPoint - main
778             "postRestartCommands": [
779                 "break main",
780                 "continue"
781             ],
782             "openOCDLaunchCommands": [
783                 "adapter speed 5000"
784             ]
785         }},
786         {{
787             "name": "Pico Debug (Cortex-Debug with external OpenOCD)",
788             "cwd": "${{workspaceRoot}}",
789             "executable": "${{command:raspberry-pi-pico.launchTargetPath}}",
790             "request": "launch",
791             "type": "cortex-debug",
792             "servertype": "external",
793             "gdbTarget": "localhost:3333",
794             "gdbPath": "{gdbPath}",
795             "device": "RP2040",
796             "svdFile": "{codeSdkPath(sdkVersion)}/src/rp2040/hardware_regs/rp2040.svd",
797             "runToEntryPoint": "main",
798             // Give restart the same functionality as runToEntryPoint - main
799             "postRestartCommands": [
800                 "break main",
801                 "continue"
802             ]
803         }},
804         {{
805             "name": "Pico Debug (C++ Debugger)",
806             "type": "cppdbg",
807             "request": "launch",
808             "cwd": "${{workspaceRoot}}",
809             "program": "${{command:raspberry-pi-pico.launchTargetPath}}",
810             "MIMode": "gdb",
811             "miDebuggerPath": "{gdbPath}",
812             "miDebuggerServerAddress": "localhost:3333",
813             "debugServerPath": "{openocd_path if openocd_path else "openocd"}",
814             "debugServerArgs": "-f {debugger} -f target/rp2040.cfg -c \\"adapter speed 5000\\"",
815             "serverStarted": "Listening on port .* for gdb connections",
816             "filterStderr": true,
817             "hardwareBreakpoints": {{
818                 "require": true,
819                 "limit": 4
820             }},
821             "preLaunchTask": "Flash",
822             "svdPath": "{codeSdkPath(sdkVersion)}/src/rp2040/hardware_regs/rp2040.svd"
823         }},
824     ]
825 }}
826 '''
827
828             properties = f'''{{
829     "configurations": [
830         {{
831             "name": "Pico",
832             "includePath": [
833                 "${{workspaceFolder}}/**",
834                 "{propertiesSdkPath(sdkVersion)}/**"
835             ],
836             "forcedInclude": [
837                 "{propertiesSdkPath(sdkVersion)}/src/common/pico_base/include/pico.h",
838                 "${{workspaceFolder}}/build/generated/pico_base/pico/config_autogen.h"
839             ],
840             "defines": [],
841             "compilerPath": "{cPath}",
842             "compileCommands": "${{workspaceFolder}}/build/compile_commands.json",
843             "cStandard": "c17",
844             "cppStandard": "c++14",
845             "intelliSenseMode": "linux-gcc-arm"
846         }}
847     ],
848     "version": 4
849 }}
850 '''
851
852             pythonExe = sys.executable.replace("\\", "/").replace(user_home, "${HOME}") if use_home_var else sys.executable
853
854             # kits
855             kits = f'''[
856     {{
857         "name": "Pico",
858         "compilers": {{
859             "C": "{cPath}",
860             "CXX": "{cPath}"
861         }},
862         "toolchainFile": "{propertiesSdkPath(sdkVersion)}/cmake/preload/toolchains/pico_arm_gcc.cmake",
863         "environmentVariables": {{
864             "PATH": "${{command:raspberry-pi-pico.getEnvPath}};${{env:PATH}}"
865         }},
866         "cmakeSettings": {{
867             "Python3_EXECUTABLE": "${{command:raspberry-pi-pico.getPythonPath}}"
868         }}
869     }}
870 ]'''
871
872             # settings
873             settings = f'''{{
874     "cmake.options.statusBarVisibility": "hidden",
875     "cmake.options.advanced": {{
876         "build": {{
877             "statusBarVisibility": "hidden"
878         }},
879         "launch": {{
880             "statusBarVisibility": "hidden"
881         }},
882         "debug": {{
883             "statusBarVisibility": "hidden"
884         }}
885     }},
886     "cmake.configureOnEdit": false,
887     "cmake.automaticReconfigure": false,
888     "cmake.configureOnOpen": false,
889     "cmake.generator": "Ninja",
890     "cmake.cmakePath": "{cmakePath.replace(user_home, "${userHome}") if use_home_var else cmakePath}",
891     "C_Cpp.debugShortcut": false,
892     "terminal.integrated.env.windows": {{
893         "PICO_SDK_PATH": "{propertiesSdkPath(sdkVersion, force_windows=True)}",
894         "PICO_TOOLCHAIN_PATH": "{propertiesToolchainPath(toolchainVersion, force_windows=True)}",
895         "Path": "{propertiesToolchainPath(toolchainVersion, force_windows=True)}/bin;{os.path.dirname(cmakePath.replace(user_home, "${env:USERPROFILE}") if use_home_var else cmakePath)};{os.path.dirname(ninjaPath.replace(user_home, "${env:USERPROFILE}") if use_home_var else ninjaPath)};${{env:PATH}}"
896     }},
897     "terminal.integrated.env.osx": {{
898         "PICO_SDK_PATH": "{propertiesSdkPath(sdkVersion, force_non_windows=True)}",
899         "PICO_TOOLCHAIN_PATH": "{propertiesToolchainPath(toolchainVersion, force_non_windows=True)}",
900         "PATH": "{propertiesToolchainPath(toolchainVersion, force_non_windows=True)}/bin:{os.path.dirname(cmakePath.replace(user_home, "${env:HOME}") if use_home_var else cmakePath)}:{os.path.dirname(ninjaPath.replace(user_home, "${env:HOME}") if use_home_var else ninjaPath)}:${{env:PATH}}"
901     }},
902     "terminal.integrated.env.linux": {{
903         "PICO_SDK_PATH": "{propertiesSdkPath(sdkVersion, force_non_windows=True)}",
904         "PICO_TOOLCHAIN_PATH": "{propertiesToolchainPath(toolchainVersion, force_non_windows=True)}",
905         "PATH": "{propertiesToolchainPath(toolchainVersion, force_non_windows=True)}/bin:{os.path.dirname(cmakePath.replace(user_home, "${env:HOME}") if use_home_var else cmakePath)}:{os.path.dirname(ninjaPath.replace(user_home, "${env:HOME}") if use_home_var else ninjaPath)}:${{env:PATH}}"
906     }},
907     "raspberry-pi-pico.cmakeAutoConfigure": true,
908     "raspberry-pi-pico.useCmakeTools": false,
909     "raspberry-pi-pico.cmakePath": "{cmakePath.replace(user_home, "${HOME}") if use_home_var else cmakePath}",
910     "raspberry-pi-pico.ninjaPath": "{ninjaPath.replace(user_home, "${HOME}") if use_home_var else ninjaPath}"'''
911
912             if customPython:
913                 settings += f''',
914     "raspberry-pi-pico.python3Path": "{pythonExe}"'''
915                 
916             settings += '\n}\n'
917
918             # extensions
919             extensions = f'''{{
920     "recommendations": [
921         "marus25.cortex-debug",
922         "ms-vscode.cpptools",
923         "ms-vscode.cpptools-extension-pack",
924         "ms-vscode.vscode-serial-monitor",
925         "raspberry-pi.raspberry-pi-pico",
926     ]
927 }}
928 '''
929             tasks = f'''{{
930     "version": "2.0.0",
931     "tasks": [
932         {{
933             "label": "Compile Project",
934             "type": "process",
935             "isBuildCommand": true,
936             "command": "{ninjaPath.replace(user_home, "${userHome}") if use_home_var else ninjaPath}",
937             "args": ["-C", "${{workspaceFolder}}/build"],
938             "group": "build",
939             "presentation": {{
940                 "reveal": "always",
941                 "panel": "dedicated"
942             }},
943             "problemMatcher": "$gcc",
944             "windows": {{
945                 "command": "{ninjaPath.replace(user_home, "${env:USERPROFILE}") if use_home_var else ninjaPath}.exe"
946             }}
947         }},
948         {{
949             "label": "Flash",
950             "type": "process",
951             "command": "{openocd_path if openocd_path else "openocd"}",
952             "args": [
953                 "-f",
954                 "{debugger}",
955                 "-f",
956                 "target/rp2040.cfg",
957                 "-c",
958                 "adapter speed 5000; program \\"${{command:raspberry-pi-pico.launchTargetPath}}\\" verify reset exit"
959             ],
960             "problemMatcher": [],
961             "windows": {{
962                 "command": "{openocd_path.replace("${userHome}", "${env:USERPROFILE}") if openocd_path else "openocd"}",
963             }}
964         }}
965     ]
966 }}
967 '''
968
969             # Create a build folder, and run our cmake project build from it
970             if not os.path.exists(VSCODE_FOLDER):
971                 os.mkdir(VSCODE_FOLDER)
972
973             os.chdir(VSCODE_FOLDER)
974
975             file = open(VSCODE_TASKS_FILENAME, 'w')
976             file.write(tasks)
977             file.close()
978
979             filename = VSCODE_LAUNCH_FILENAME
980             file = open(filename, 'w')
981             file.write(launch)
982             file.close()
983
984             file = open(VSCODE_C_PROPERTIES_FILENAME, 'w')
985             file.write(properties)
986             file.close()
987
988             file = open(VSCODE_CMAKE_KITS_FILENAME, 'w')
989             file.write(kits)
990             file.close()
991
992             file = open(VSCODE_SETTINGS_FILENAME, 'w')
993             file.write(settings)
994             file.close()
995
996             file = open(VSCODE_EXTENSIONS_FILENAME, 'w')
997             file.write(extensions)
998             file.close()
999
1000         else :
1001             print('Unknown project type requested')
1002
1003     os.chdir(oldCWD)
1004
1005
1006 def LoadConfigurations():
1007     try:
1008         with open(args.tsv) as tsvfile:
1009             reader = csv.DictReader(tsvfile, dialect='excel-tab')
1010             for row in reader:
1011                 configuration_dictionary.append(row)
1012     except:
1013         print("No Pico configurations file found. Continuing without")
1014
1015 def LoadBoardTypes(sdkPath):
1016     # Scan the boards folder for all header files, extract filenames, and make a list of the results
1017     # default folder is <PICO_SDK_PATH>/src/boards/include/boards/*
1018     # If the PICO_BOARD_HEADER_DIRS environment variable is set, use that as well
1019
1020     loc = sdkPath / "src/boards/include/boards"
1021     boards=[]
1022     for x in Path(loc).iterdir():
1023         if x.suffix == '.h':
1024             boards.append(x.stem)
1025
1026     loc = os.getenv('PICO_BOARD_HEADER_DIRS')
1027
1028     if loc != None:
1029         for x in Path(loc).iterdir():
1030             if x.suffix == '.h':
1031                 boards.append(x.stem)
1032
1033     return boards
1034
1035 def DoEverything(parent, params):
1036
1037     if not os.path.exists(params['projectRoot']):
1038         print('Invalid project path')
1039         sys.exit(-1)
1040
1041     oldCWD = os.getcwd()
1042     os.chdir(params['projectRoot'])
1043
1044     # Create our project folder as subfolder
1045     os.makedirs(params['projectName'], exist_ok=True)
1046
1047     os.chdir(params['projectName'])
1048
1049     projectPath = params['projectRoot'] / params['projectName']
1050
1051     # First check if there is already a project in the folder
1052     # If there is we abort unless the overwrite flag it set
1053     if os.path.exists(CMAKELIST_FILENAME):
1054         if not (params['wantOverwrite'] or params['wantConvert']):
1055             print('There already appears to be a project in this folder. Use the --overwrite option to overwrite the existing project')
1056             sys.exit(-1)
1057
1058         # We should really confirm the user wants to overwrite
1059         #print('Are you sure you want to overwrite the existing project files? (y/N)')
1060         #c = input().split(" ")[0]
1061         #if c != 'y' and c != 'Y' :
1062         #    sys.exit(0)
1063
1064     # Copy the SDK finder cmake file to our project folder
1065     # Can be found here <PICO_SDK_PATH>/external/pico_sdk_import.cmake
1066     shutil.copyfile(params['sdkPath'] / 'external' / 'pico_sdk_import.cmake', projectPath / 'pico_sdk_import.cmake' )
1067
1068     if params['features']:
1069         features_and_examples = params['features'][:]
1070     else:
1071         features_and_examples= []
1072
1073     if params['wantExamples']:
1074         features_and_examples = list(stdlib_examples_list.keys()) + features_and_examples
1075
1076     if not (params['wantConvert']):
1077         GenerateMain(projectPath, params['projectName'], features_and_examples, params['wantCPP'])
1078
1079         # If we have any ancilliary files, copy them to our project folder
1080         # Currently only the picow with lwIP support needs an extra file, so just check that list
1081         for feat in features_and_examples:
1082             if feat in features_list:
1083                 if features_list[feat][ANCILLARY_FILE] != "":
1084                     shutil.copy(sourcefolder + "/" + features_list[feat][ANCILLARY_FILE], projectPath / features_list[feat][ANCILLARY_FILE])
1085             if feat in picow_options_list:
1086                 if picow_options_list[feat][ANCILLARY_FILE] != "":
1087                     shutil.copy(sourcefolder + "/" + picow_options_list[feat][ANCILLARY_FILE], projectPath / picow_options_list[feat][ANCILLARY_FILE])
1088
1089     GenerateCMake(projectPath, params)
1090
1091     if params['wantExample']:
1092         if params['wantThreadsafeBackground'] or params['wantPoll']:
1093             # Write lwipopts for examples
1094             shutil.copy(sourcefolder + "/" + "lwipopts.h", projectPath / "lwipopts.h")
1095
1096     # Create a build folder, and run our cmake project build from it
1097     if not os.path.exists('build'):
1098         os.mkdir('build')
1099
1100     os.chdir('build')
1101
1102     # If we are overwriting a previous project, we should probably clear the folder, but that might delete something the users thinks is important, so
1103     # for the moment, just delete the CMakeCache.txt file as certain changes may need that to be recreated.
1104
1105     if os.path.exists(CMAKECACHE_FILENAME):
1106         os.remove(CMAKECACHE_FILENAME)
1107
1108     cpus = os.cpu_count()
1109     if cpus == None:
1110         cpus = 1
1111
1112     if isWindows:
1113         if shutil.which("ninja") or (params["ninjaPath"] != None and params["ninjaPath"] != ""):
1114             # When installing SDK version 1.5.0 on windows with installer pico-setup-windows-x64-standalone.exe, ninja is used 
1115             cmakeCmd = params['cmakePath'] + ' -DCMAKE_BUILD_TYPE=Debug -G Ninja ..'
1116             makeCmd = params['ninjaPath'] + ' '        
1117         else:
1118             # Everything else assume nmake
1119             cmakeCmd = params['cmakePath'] + ' -DCMAKE_BUILD_TYPE=Debug -G "NMake Makefiles" ..'
1120             makeCmd = 'nmake '
1121     else:
1122         # Ninja now works OK under Linux, so if installed use it by default. It's faster.
1123         if shutil.which("ninja") or (params["ninjaPath"] != None and params["ninjaPath"] != ""):
1124             cmakeCmd = params['cmakePath'] + ' -DCMAKE_BUILD_TYPE=Debug -G Ninja ..'
1125             makeCmd = params['ninjaPath'] + ' '
1126         else:
1127             cmakeCmd = params['cmakePath'] + ' -DCMAKE_BUILD_TYPE=Debug ..'
1128             makeCmd = 'make -j' + str(cpus)
1129
1130     os.system(cmakeCmd)
1131
1132     if params['projects']:
1133         generateProjectFiles(
1134             projectPath, 
1135             params['projectName'], 
1136             params['sdkPath'], 
1137             params['projects'], 
1138             params['debugger'], 
1139             params["sdkVersion"], 
1140             params["toolchainVersion"], 
1141             params["ninjaPath"], 
1142             params["cmakePath"],
1143             params["customPython"],
1144             params["openOCDVersion"])
1145
1146     if params['wantBuild']:
1147         os.system(makeCmd)
1148         print('\nIf the application has built correctly, you can now transfer it to the Raspberry Pi Pico board')
1149
1150     os.chdir(oldCWD)
1151
1152
1153 ###################################################################################
1154 # main execution starteth here
1155
1156 sourcefolder = os.path.dirname(os.path.abspath(__file__))
1157
1158 args = ParseCommandLine()
1159
1160 if args.nouart:
1161     args.uart = False
1162
1163 if args.debugger > len(debugger_list) - 1:
1164     args.debugger = 0
1165
1166 # Check we have everything we need to compile etc
1167 c = CheckPrerequisites()
1168
1169 ## TODO Do both warnings in the same error message so user does have to keep coming back to find still more to do
1170
1171 if c == None:
1172     m = f'Unable to find the `{COMPILER_NAME}` compiler\n'
1173     m +='You will need to install an appropriate compiler to build a Raspberry Pi Pico project\n'
1174     m += 'See the Raspberry Pi Pico documentation for how to do this on your particular platform\n'
1175
1176     print(m)
1177     sys.exit(-1)
1178
1179 if args.name == None and not args.gui and not args.list and not args.configs and not args.boardlist:
1180     print("No project name specfied\n")
1181     sys.exit(-1)
1182
1183 # Check if we were provided a compiler path, and override the default if so
1184 if args.cpath:
1185     compilerPath = Path(args.cpath)
1186 elif args.toolchainVersion:
1187     compilerPath = Path(propertiesToolchainPath(args.toolchainVersion)+"/bin/"+COMPILER_NAME)
1188 else:
1189     compilerPath = Path(c)
1190
1191 # load/parse any configuration dictionary we may have
1192 LoadConfigurations()
1193
1194 p = CheckSDKPath(args.gui)
1195
1196 if p == None:
1197     sys.exit(-1)
1198
1199 sdkPath = Path(p)
1200
1201 boardtype_list = LoadBoardTypes(sdkPath)
1202 boardtype_list.sort()
1203
1204 projectRoot = Path(os.getcwd()) if not args.projectRoot else Path(args.projectRoot)
1205
1206 if args.list or args.configs or args.boardlist:
1207     if args.list:
1208         print("Available project features:\n")
1209         for feat in features_list:
1210             print(feat.ljust(6), '\t', features_list[feat][GUI_TEXT])
1211         print('\n')
1212
1213     if args.configs:
1214         print("Available project configuration items:\n")
1215         for conf in configuration_dictionary:
1216             print(conf['name'].ljust(40), '\t', conf['description'])
1217         print('\n')
1218
1219     if args.boardlist:
1220         print("Available board types:\n")
1221         for board in boardtype_list:
1222             print(board)
1223         print('\n')
1224
1225     sys.exit(0)
1226 else :
1227     params={
1228         'sdkPath'       : sdkPath,
1229         'projectRoot'   : projectRoot,
1230         'projectName'   : args.name,
1231         'wantGUI'       : False,
1232         'wantOverwrite' : args.overwrite,
1233         'wantConvert'   : args.convert or args.example,
1234         'wantExample'   : args.example,
1235         'wantThreadsafeBackground'  : False,
1236         'wantPoll'                  : False,
1237         'boardtype'     : args.boardtype,
1238         'wantBuild'     : args.build,
1239         'features'      : args.feature,
1240         'projects'      : args.project,
1241         'configs'       : (),
1242         'wantRunFromRAM': args.runFromRAM,
1243         'wantExamples'  : args.examples,
1244         'wantUART'      : args.uart,
1245         'wantUSB'       : args.usb,
1246         'wantCPP'       : args.cpp,
1247         'debugger'      : args.debugger,
1248         'exceptions'    : args.cppexceptions,
1249         'rtti'          : args.cpprtti,
1250         'ssid'          : '',
1251         'password'      : '',
1252         'sdkVersion'    : args.sdkVersion,
1253         'toolchainVersion': args.toolchainVersion,
1254         'ninjaPath'     : args.ninjaPath,
1255         'cmakePath'     : args.cmakePath,
1256         'customPython'  : args.customPython,
1257         'openOCDVersion': args.openOCDVersion
1258         }
1259
1260     DoEverything(None, params)
1261     sys.exit(0)
This page took 0.101064 seconds and 4 git commands to generate.