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