Skip to content

Commit 4ab880a

Browse files
committed
Better swift support + examples
Signed-off-by: paulober <[email protected]>
1 parent aa5dcfe commit 4ab880a

File tree

5 files changed

+151
-25
lines changed

5 files changed

+151
-25
lines changed

scripts/PicoSDK.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This file contains a swift wrapper for some Pico SDK C style stuff
2+
// Upercase library names can be used to only include helpers for available APIs
3+
4+
#if PICO_STDLIB
5+
public struct PicoGPIO {
6+
/// Enum for GPIO direction, mirroring the C enum
7+
public enum Direction: UInt8 {
8+
case input = 0
9+
case output = 1
10+
}
11+
12+
/// Swift-friendly wrapper for gpio_set_dir
13+
public static func setDirection(pin: UInt32, direction: Direction) {
14+
gpio_set_dir(pin, direction.rawValue != 0)
15+
}
16+
}
17+
#endif

scripts/bridge.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,57 @@
11
#pragma once
22

3+
#ifndef PICO_DEFAULT_LED_PIN
4+
#define PICO_DEFAULT_LED_PIN 6
5+
#endif
6+
7+
#ifdef _HARDWARE_STRUCTS_SPI_H
8+
#ifdef spi0
9+
spi_inst_t* get_spi0(void) {
10+
return spi0;
11+
}
12+
#endif
13+
14+
#ifdef spi1
15+
spi_inst_t* get_spi1(void) {
16+
return spi1;
17+
}
18+
#endif
19+
#endif
20+
21+
#ifdef _HARDWARE_STRUCTS_I2C_H
22+
#ifdef i2c0
23+
i2c_inst_t* get_i2c0(void) {
24+
return i2c0;
25+
}
26+
#endif
27+
28+
#ifdef i2c1
29+
i2c_inst_t* get_i2c1(void) {
30+
return i2c1;
31+
}
32+
#endif
33+
#endif
34+
35+
#ifdef _HARDWARE_STRUCTS_PIO_H
36+
#ifdef pio0
37+
pio_hw_t* get_pio0(void) {
38+
return pio0;
39+
}
40+
#endif
41+
42+
#ifdef pio1
43+
pio_hw_t* get_pio1(void) {
44+
return pio1;
45+
}
46+
#endif
47+
48+
#ifdef pio2
49+
pio_hw_t* get_pio2(void) {
50+
return pio2;
51+
}
52+
#endif
53+
#endif
54+
355
/**
456
* @file bridge.h
557
* @brief Simplifies the usage of specific SDK features in Swift by providing wrapper functions.
@@ -11,6 +63,7 @@
1163

1264
#ifdef _HARDWARE_STRUCTS_UART_H // Ensure that UART hardware structs are included before compiling
1365

66+
#ifdef uart0
1467
/**
1568
* @brief Retrieves the instance for UART0.
1669
*
@@ -22,7 +75,9 @@
2275
uart_inst_t* get_uart0(void) {
2376
return uart0;
2477
}
78+
#endif
2579

80+
#ifdef uart1
2681
/**
2782
* @brief Retrieves the instance for UART1.
2883
*
@@ -34,5 +89,6 @@ uart_inst_t* get_uart0(void) {
3489
uart_inst_t* get_uart1(void) {
3590
return uart1;
3691
}
92+
#endif
3793

3894
#endif

scripts/pico_project.py

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ def GDB_NAME():
431431
"// SPI Constants",
432432
"// We are going to use SPI 0, and allocate it to the following GPIO pins",
433433
"// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
434-
'let SPI_PORT = "spi0"',
434+
"let SPI_PORT = get_spi0()",
435435
"let PIN_MISO: UInt32 = 16",
436436
"let PIN_CS: UInt32 = 17",
437437
"let PIN_SCK: UInt32 = 18",
@@ -446,8 +446,8 @@ def GDB_NAME():
446446
"gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI)",
447447
"",
448448
"// Chip select is active-low, so we'll initialise it to a driven-high state",
449-
"gpio_set_dir(PIN_CS, GPIO_OUT)",
450-
"gpio_put(PIN_CS, 1)",
449+
"PicoGPIO.setDirection(pin: PIN_CS, direction: .output) // Use swift wrapper",
450+
"gpio_put(PIN_CS, true)",
451451
"// For more examples of SPI use see https://github.com/raspberrypi/pico-examples/tree/master/spi",
452452
),
453453
],
@@ -456,7 +456,7 @@ def GDB_NAME():
456456
"// I2C defines",
457457
"// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.",
458458
"// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
459-
'let I2C_PORT = "i2c0"',
459+
"let I2C_PORT = get_i2c0()",
460460
"let I2C_SDA: UInt32 = 8",
461461
"let I2C_SCL: UInt32 = 9",
462462
),
@@ -479,24 +479,24 @@ def GDB_NAME():
479479
),
480480
(
481481
"// Get a free channel, panic() if there are none",
482-
"let chan = dma_claim_unused_channel(true)",
482+
"let chan = UInt32(dma_claim_unused_channel(true))",
483483
"",
484484
"// 8 bit transfers. Both read and write address increment after each",
485485
"// transfer (each pointing to a location in src or dst respectively).",
486486
"// No DREQ is selected, so the DMA transfers as fast as it can.",
487487
"",
488-
"let c = dma_channel_get_default_config(chan)",
488+
"var c = dma_channel_get_default_config(chan)",
489489
"channel_config_set_transfer_data_size(&c, DMA_SIZE_8)",
490490
"channel_config_set_read_increment(&c, true)",
491491
"channel_config_set_write_increment(&c, true)",
492492
"",
493493
"dma_channel_configure(",
494-
" chan, // Channel to be configured",
495-
" &c, // The configuration we just created",
496-
" dst, // The initial write address",
497-
" src, // The initial read address",
498-
" count_of(src), // Number of transfers; in this case each is 1 byte.",
499-
" true // Start immediately.",
494+
" chan, // Channel to be configured",
495+
" &c, // The configuration we just created",
496+
" &dst, // The initial write address",
497+
" src, // The initial read address",
498+
" UInt32(src.utf8.count), // Number of transfers; in this case each is 1 byte.",
499+
" true // Start immediately.",
500500
")",
501501
"",
502502
"// We could choose to go and do something else whilst the DMA is doing its",
@@ -540,7 +540,7 @@ def GDB_NAME():
540540
"guard let pio = get_pio0() else {",
541541
' fatalError("PIO0 not available")',
542542
"}",
543-
"let offset = pio_add_program(pio, &blink_program)",
543+
"let offset = pio_add_program(pio, [blink_program])",
544544
'print("Loaded program at \\(offset)")',
545545
"",
546546
"blink_pin_forever(pio, sm: 0, offset: UInt32(offset), pin: UInt32(PICO_DEFAULT_LED_PIN), freq: 3)",
@@ -588,7 +588,7 @@ def GDB_NAME():
588588
),
589589
(
590590
"// Timer example code - This example fires off the callback after 2000ms",
591-
"add_alarm_in_ms(2000, alarm_callback, NULL, false)",
591+
"add_alarm_in_ms(2000, alarm_callback, nil, false)",
592592
"// For more examples of timer use see https://github.com/raspberrypi/pico-examples/tree/master/timer",
593593
),
594594
],
@@ -999,6 +999,8 @@ def GenerateMain(folder, projectName, features, cpp, wantEntryProjName, swift):
999999
o = f'#include "{features_list[feat][H_FILE]}"\n'
10001000
if swift and bridging_file:
10011001
bridging_file.write(o)
1002+
if feat == "pio":
1003+
bridging_file.write('#include "blink.pio.h"')
10021004
else:
10031005
file.write(o)
10041006
if feat in stdlib_examples_list:
@@ -1045,7 +1047,7 @@ def GenerateMain(folder, projectName, features, cpp, wantEntryProjName, swift):
10451047
"struct Main {\n"
10461048
" \n"
10471049
" static func main() {\n"
1048-
" stdio_init_all();\n\n"
1050+
" stdio_init_all()\n\n"
10491051
)
10501052
else:
10511053
main = "\n\n" "int main()\n" "{\n" " stdio_init_all();\n\n"
@@ -1225,6 +1227,20 @@ def GenerateCMake(folder, params):
12251227

12261228
file.write(cmake_header1)
12271229
file.write(cmake_header_us)
1230+
if params["useSwift"]:
1231+
cmake_if_apple = (
1232+
"if(APPLE)\n"
1233+
" execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1234+
" execute_process(COMMAND dirname ${SWIFTC} OUTPUT_VARIABLE SWIFTC_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1235+
"elseif(WIN32)\n"
1236+
" execute_process(COMMAND where.exe swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1237+
' string(REGEX REPLACE "(.*)\\\\\\\\[^\\\\\\\\]*$" "\\\\1" SWIFTC_DIR "${SWIFTC}")\n'
1238+
"else()\n"
1239+
" execute_process(COMMAND which swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1240+
" execute_process(COMMAND dirname ${SWIFTC} OUTPUT_VARIABLE SWIFTC_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1241+
"endif()\n"
1242+
)
1243+
file.write(cmake_if_apple)
12281244
file.write(cmake_header2)
12291245

12301246
if params["exceptions"]:
@@ -1236,13 +1252,6 @@ def GenerateCMake(folder, params):
12361252
file.write(cmake_header3)
12371253

12381254
if params["useSwift"]:
1239-
cmake_if_apple = (
1240-
"if(APPLE)\n"
1241-
" execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1242-
"else()\n"
1243-
" execute_process(COMMAND which swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1244-
"endif()\n"
1245-
)
12461255
cmake_swift_target = (
12471256
'set(SWIFT_TARGET "armv6m-none-none-eabi") # RP2040\n\n'
12481257
'if(PICO_PLATFORM STREQUAL "rp2350-arm-s")\n'
@@ -1257,8 +1266,12 @@ def GenerateCMake(folder, params):
12571266
' set(SWIFT_TARGET "riscv32-none-none-eabi")\n'
12581267
' list(APPEND CLANG_ARCH_ABI_FLAGS "-Xcc" "-march=rv32imac_zicsr_zifencei_zba_zbb_zbs_zbkb" "-Xcc" "-mabi=ilp32")\n'
12591268
"endif()\n"
1269+
'set(SWIFT_EMBEDDED_UNICODE_LIB "${SWIFTC_DIR}/../lib/swift/embedded/${SWIFT_TARGET}/libswiftUnicodeDataTables.a")\n\n'
1270+
"# Link the Swift Unicode Data Tables library\n"
1271+
"if(NOT EXISTS ${SWIFT_EMBEDDED_UNICODE_LIB})\n"
1272+
' message(FATAL_ERROR "Required Swift library not found: ${SWIFT_EMBEDDED_LIB}")\n'
1273+
"endif()\n\n"
12601274
)
1261-
file.write(cmake_if_apple)
12621275
file.write(cmake_swift_target)
12631276

12641277
# add the preprocessor defines for overall configuration
@@ -1285,6 +1298,12 @@ def GenerateCMake(folder, params):
12851298
file.write("# Add the standard library to the build\n")
12861299
file.write(f"target_link_libraries({projectName}\n")
12871300
file.write(" " + STANDARD_LIBRARIES)
1301+
if params["features"]:
1302+
for feat in params["features"]:
1303+
if feat in features_list:
1304+
file.write(" " + features_list[feat][LIB_NAME] + "\n")
1305+
if feat in picow_options_list:
1306+
file.write(" " + picow_options_list[feat][LIB_NAME] + "\n")
12881307
file.write(")\n\n")
12891308

12901309
main_file_name = f"{entry_point_file_name}.swift"
@@ -1321,6 +1340,22 @@ def GenerateCMake(folder, params):
13211340
"endfunction()\n\n"
13221341
f"gather_compile_definitions_recursive({projectName})\n"
13231342
"get_property(COMPILE_DEFINITIONS GLOBAL PROPERTY compilerdefs_list)\n\n"
1343+
"# ==== BEGIN Generate compile definitions from linked libraries\n"
1344+
"# Gather libraries linked to project\n"
1345+
f"get_target_property({projectName}_LIBRARIES {projectName} INTERFACE_LINK_LIBRARIES)\n"
1346+
f"if(NOT {projectName}_LIBRARIES)\n"
1347+
f' set({projectName}_LIBRARIES "") # Default to an empty list if none found\n'
1348+
"endif()\n\n"
1349+
'set(SWIFTC_LIB_DEFINITIONS "")\n'
1350+
f"foreach(LIBRARY IN LISTS {projectName}_LIBRARIES)\n"
1351+
" # Convert it to uppercase\n"
1352+
" string(TOUPPER ${LIBRARY} LIB_NAME_UPPER)\n"
1353+
' list(APPEND SWIFTC_LIB_DEFINITIONS "-D" "${LIB_NAME_UPPER}")\n'
1354+
"endforeach()\n\n"
1355+
"# Convert the list to a string for the Swift command\n"
1356+
'string(REPLACE " " ";" SWIFTC_DEFINITIONS_STR "${SWIFTC_LIB_DEFINITIONS}")\n'
1357+
'message(STATUS "SWIFTC_LIB_DEFINITIONS: ${SWIFTC_DEFINITIONS_STR}")\n'
1358+
"# ==== END Generate compile definitions from linked libraries\n\n"
13241359
"# Parse compiler definitions into a format that swiftc can understand\n"
13251360
"list(REMOVE_DUPLICATES COMPILE_DEFINITIONS)\n"
13261361
'list(PREPEND COMPILE_DEFINITIONS "")\n'
@@ -1332,13 +1367,16 @@ def GenerateCMake(folder, params):
13321367
" ${SWIFTC}\n"
13331368
" -target ${SWIFT_TARGET} -Xcc -mfloat-abi=soft -Xcc -fshort-enums\n"
13341369
" -Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library\n"
1370+
" ${SWIFTC_DEFINITIONS_STR}\n"
13351371
f" $$\( echo '$<TARGET_PROPERTY:{projectName},INCLUDE_DIRECTORIES>' | tr '\;' '\\\\n' | sed -e 's/\\\\\(.*\\\\\)/-Xcc -I\\\\1/g' \)\n"
13361372
" $$\( echo '${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}' | tr ' ' '\\\\n' | sed -e 's/\\\\\(.*\\\\\)/-Xcc -I\\\\1/g' \)\n"
13371373
" -import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h\n"
1374+
" ${USERHOME}/.pico-sdk/sdk/PicoSDK.swift\n"
13381375
f" ${{CMAKE_CURRENT_LIST_DIR}}/{main_file_name}\n"
13391376
" -c -o ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o\n"
13401377
" DEPENDS\n"
13411378
" ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h\n"
1379+
" ${USERHOME}/.pico-sdk/sdk/PicoSDK.swift\n"
13421380
f" ${{CMAKE_CURRENT_LIST_DIR}}/{main_file_name}\n"
13431381
")\n"
13441382
)
@@ -1401,6 +1439,13 @@ def GenerateCMake(folder, params):
14011439
file.write(" " + STANDARD_LIBRARIES)
14021440
file.write(")\n\n")
14031441
else:
1442+
file.write("# Link Swift Unicode data tables to the build\n")
1443+
file.write(f"target_link_options({projectName} PRIVATE\n")
1444+
file.write(
1445+
" -Wl,--whole-archive ${SWIFT_EMBEDDED_UNICODE_LIB} -Wl,--no-whole-archive\n"
1446+
)
1447+
file.write(")\n\n")
1448+
14041449
file.write("# Add the swift artifact to the build\n")
14051450
file.write(f"target_link_libraries({projectName}\n")
14061451
file.write(" ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o\n")
@@ -1420,7 +1465,7 @@ def GenerateCMake(folder, params):
14201465
file.write(f"add_dependencies({projectName} {projectName}-swiftcode)\n")
14211466

14221467
# Selected libraries/features
1423-
if params["features"]:
1468+
if params["features"] and not params["useSwift"]:
14241469
file.write("# Add any user requested libraries\n")
14251470
file.write(f"target_link_libraries({projectName} \n")
14261471
for feat in params["features"]:

src/utils/download.mts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,14 @@ export async function downloadAndInstallSDK(
484484

485485
const targetDirectory = buildSDKPath(version);
486486

487+
// Copy swift wrapper
488+
const sdkRoot = dirname(targetDirectory);
489+
await mkdir(sdkRoot, { recursive: true });
490+
copyFileSync(
491+
joinPosix(getScriptsRoot(), "PicoSDK.swift"),
492+
joinPosix(sdkRoot, "PicoSDK.swift")
493+
);
494+
487495
// Check if the SDK is already installed
488496
if (
489497
existsSync(targetDirectory) &&

src/webview/newProjectPanel.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ export class NewProjectPanel {
18111811
</div>
18121812
</div>`
18131813
: `<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
1814-
Warning: Project Import Wizard may not work for all projects, and will often require manual correction after the import
1814+
Warning: Project Import Wizard may not work for all projects, and will often require manual correction after the import. Swift Projects aren't supported at the moment.
18151815
</h3>`
18161816
}
18171817
<div class="mt-6 mb-4">

0 commit comments

Comments
 (0)