Skip to content

Commit aac35ed

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

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
@@ -429,7 +429,7 @@ def GDB_NAME():
429429
"// SPI Constants",
430430
"// We are going to use SPI 0, and allocate it to the following GPIO pins",
431431
"// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
432-
'let SPI_PORT = "spi0"',
432+
"let SPI_PORT = get_spi0()",
433433
"let PIN_MISO: UInt32 = 16",
434434
"let PIN_CS: UInt32 = 17",
435435
"let PIN_SCK: UInt32 = 18",
@@ -444,8 +444,8 @@ def GDB_NAME():
444444
"gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI)",
445445
"",
446446
"// Chip select is active-low, so we'll initialise it to a driven-high state",
447-
"gpio_set_dir(PIN_CS, GPIO_OUT)",
448-
"gpio_put(PIN_CS, 1)",
447+
"PicoGPIO.setDirection(pin: PIN_CS, direction: .output) // Use swift wrapper",
448+
"gpio_put(PIN_CS, true)",
449449
"// For more examples of SPI use see https://github.com/raspberrypi/pico-examples/tree/master/spi",
450450
),
451451
],
@@ -454,7 +454,7 @@ def GDB_NAME():
454454
"// I2C defines",
455455
"// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.",
456456
"// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments",
457-
'let I2C_PORT = "i2c0"',
457+
"let I2C_PORT = get_i2c0()",
458458
"let I2C_SDA: UInt32 = 8",
459459
"let I2C_SCL: UInt32 = 9",
460460
),
@@ -477,24 +477,24 @@ def GDB_NAME():
477477
),
478478
(
479479
"// Get a free channel, panic() if there are none",
480-
"let chan = dma_claim_unused_channel(true)",
480+
"let chan = UInt32(dma_claim_unused_channel(true))",
481481
"",
482482
"// 8 bit transfers. Both read and write address increment after each",
483483
"// transfer (each pointing to a location in src or dst respectively).",
484484
"// No DREQ is selected, so the DMA transfers as fast as it can.",
485485
"",
486-
"let c = dma_channel_get_default_config(chan)",
486+
"var c = dma_channel_get_default_config(chan)",
487487
"channel_config_set_transfer_data_size(&c, DMA_SIZE_8)",
488488
"channel_config_set_read_increment(&c, true)",
489489
"channel_config_set_write_increment(&c, true)",
490490
"",
491491
"dma_channel_configure(",
492-
" chan, // Channel to be configured",
493-
" &c, // The configuration we just created",
494-
" dst, // The initial write address",
495-
" src, // The initial read address",
496-
" count_of(src), // Number of transfers; in this case each is 1 byte.",
497-
" true // Start immediately.",
492+
" chan, // Channel to be configured",
493+
" &c, // The configuration we just created",
494+
" &dst, // The initial write address",
495+
" src, // The initial read address",
496+
" UInt32(src.utf8.count), // Number of transfers; in this case each is 1 byte.",
497+
" true // Start immediately.",
498498
")",
499499
"",
500500
"// We could choose to go and do something else whilst the DMA is doing its",
@@ -538,7 +538,7 @@ def GDB_NAME():
538538
"guard let pio = get_pio0() else {",
539539
' fatalError("PIO0 not available")',
540540
"}",
541-
"let offset = pio_add_program(pio, &blink_program)",
541+
"let offset = pio_add_program(pio, [blink_program])",
542542
'print("Loaded program at \\(offset)")',
543543
"",
544544
"blink_pin_forever(pio, sm: 0, offset: UInt32(offset), pin: UInt32(PICO_DEFAULT_LED_PIN), freq: 3)",
@@ -586,7 +586,7 @@ def GDB_NAME():
586586
),
587587
(
588588
"// Timer example code - This example fires off the callback after 2000ms",
589-
"add_alarm_in_ms(2000, alarm_callback, NULL, false)",
589+
"add_alarm_in_ms(2000, alarm_callback, nil, false)",
590590
"// For more examples of timer use see https://github.com/raspberrypi/pico-examples/tree/master/timer",
591591
),
592592
],
@@ -951,6 +951,8 @@ def GenerateMain(folder, projectName, features, cpp, wantEntryProjName, swift):
951951
o = f'#include "{features_list[feat][H_FILE]}"\n'
952952
if swift and bridging_file:
953953
bridging_file.write(o)
954+
if feat == "pio":
955+
bridging_file.write('#include "blink.pio.h"')
954956
else:
955957
file.write(o)
956958
if feat in stdlib_examples_list:
@@ -997,7 +999,7 @@ def GenerateMain(folder, projectName, features, cpp, wantEntryProjName, swift):
997999
"struct Main {\n"
9981000
" \n"
9991001
" static func main() {\n"
1000-
" stdio_init_all();\n\n"
1002+
" stdio_init_all()\n\n"
10011003
)
10021004
else:
10031005
main = "\n\n" "int main()\n" "{\n" " stdio_init_all();\n\n"
@@ -1177,6 +1179,20 @@ def GenerateCMake(folder, params):
11771179

11781180
file.write(cmake_header1)
11791181
file.write(cmake_header_us)
1182+
if params["useSwift"]:
1183+
cmake_if_apple = (
1184+
"if(APPLE)\n"
1185+
" execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1186+
" execute_process(COMMAND dirname ${SWIFTC} OUTPUT_VARIABLE SWIFTC_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1187+
"elseif(WIN32)\n"
1188+
" execute_process(COMMAND where.exe swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1189+
' string(REGEX REPLACE "(.*)\\\\\\\\[^\\\\\\\\]*$" "\\\\1" SWIFTC_DIR "${SWIFTC}")\n'
1190+
"else()\n"
1191+
" execute_process(COMMAND which swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1192+
" execute_process(COMMAND dirname ${SWIFTC} OUTPUT_VARIABLE SWIFTC_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1193+
"endif()\n"
1194+
)
1195+
file.write(cmake_if_apple)
11801196
file.write(cmake_header2)
11811197

11821198
if params["exceptions"]:
@@ -1188,13 +1204,6 @@ def GenerateCMake(folder, params):
11881204
file.write(cmake_header3)
11891205

11901206
if params["useSwift"]:
1191-
cmake_if_apple = (
1192-
"if(APPLE)\n"
1193-
" execute_process(COMMAND xcrun -f swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1194-
"else()\n"
1195-
" execute_process(COMMAND which swiftc OUTPUT_VARIABLE SWIFTC OUTPUT_STRIP_TRAILING_WHITESPACE)\n"
1196-
"endif()\n"
1197-
)
11981207
cmake_swift_target = (
11991208
'set(SWIFT_TARGET "armv6m-none-none-eabi") # RP2040\n\n'
12001209
'if(PICO_PLATFORM STREQUAL "rp2350-arm-s")\n'
@@ -1209,8 +1218,12 @@ def GenerateCMake(folder, params):
12091218
' set(SWIFT_TARGET "riscv32-none-none-eabi")\n'
12101219
' list(APPEND CLANG_ARCH_ABI_FLAGS "-Xcc" "-march=rv32imac_zicsr_zifencei_zba_zbb_zbs_zbkb" "-Xcc" "-mabi=ilp32")\n'
12111220
"endif()\n"
1221+
'set(SWIFT_EMBEDDED_UNICODE_LIB "${SWIFTC_DIR}/../lib/swift/embedded/${SWIFT_TARGET}/libswiftUnicodeDataTables.a")\n\n'
1222+
"# Link the Swift Unicode Data Tables library\n"
1223+
"if(NOT EXISTS ${SWIFT_EMBEDDED_UNICODE_LIB})\n"
1224+
' message(FATAL_ERROR "Required Swift library not found: ${SWIFT_EMBEDDED_LIB}")\n'
1225+
"endif()\n\n"
12121226
)
1213-
file.write(cmake_if_apple)
12141227
file.write(cmake_swift_target)
12151228

12161229
# add the preprocessor defines for overall configuration
@@ -1237,6 +1250,12 @@ def GenerateCMake(folder, params):
12371250
file.write("# Add the standard library to the build\n")
12381251
file.write(f"target_link_libraries({projectName}\n")
12391252
file.write(" " + STANDARD_LIBRARIES)
1253+
if params["features"]:
1254+
for feat in params["features"]:
1255+
if feat in features_list:
1256+
file.write(" " + features_list[feat][LIB_NAME] + "\n")
1257+
if feat in picow_options_list:
1258+
file.write(" " + picow_options_list[feat][LIB_NAME] + "\n")
12401259
file.write(")\n\n")
12411260

12421261
main_file_name = f"{entry_point_file_name}.swift"
@@ -1273,6 +1292,22 @@ def GenerateCMake(folder, params):
12731292
"endfunction()\n\n"
12741293
f"gather_compile_definitions_recursive({projectName})\n"
12751294
"get_property(COMPILE_DEFINITIONS GLOBAL PROPERTY compilerdefs_list)\n\n"
1295+
"# ==== BEGIN Generate compile definitions from linked libraries\n"
1296+
"# Gather libraries linked to project\n"
1297+
f"get_target_property({projectName}_LIBRARIES {projectName} INTERFACE_LINK_LIBRARIES)\n"
1298+
f"if(NOT {projectName}_LIBRARIES)\n"
1299+
f' set({projectName}_LIBRARIES "") # Default to an empty list if none found\n'
1300+
"endif()\n\n"
1301+
'set(SWIFTC_LIB_DEFINITIONS "")\n'
1302+
f"foreach(LIBRARY IN LISTS {projectName}_LIBRARIES)\n"
1303+
" # Convert it to uppercase\n"
1304+
" string(TOUPPER ${LIBRARY} LIB_NAME_UPPER)\n"
1305+
' list(APPEND SWIFTC_LIB_DEFINITIONS "-D" "${LIB_NAME_UPPER}")\n'
1306+
"endforeach()\n\n"
1307+
"# Convert the list to a string for the Swift command\n"
1308+
'string(REPLACE " " ";" SWIFTC_DEFINITIONS_STR "${SWIFTC_LIB_DEFINITIONS}")\n'
1309+
'message(STATUS "SWIFTC_LIB_DEFINITIONS: ${SWIFTC_DEFINITIONS_STR}")\n'
1310+
"# ==== END Generate compile definitions from linked libraries\n\n"
12761311
"# Parse compiler definitions into a format that swiftc can understand\n"
12771312
"list(REMOVE_DUPLICATES COMPILE_DEFINITIONS)\n"
12781313
'list(PREPEND COMPILE_DEFINITIONS "")\n'
@@ -1284,13 +1319,16 @@ def GenerateCMake(folder, params):
12841319
" ${SWIFTC}\n"
12851320
" -target ${SWIFT_TARGET} -Xcc -mfloat-abi=soft -Xcc -fshort-enums\n"
12861321
" -Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library\n"
1322+
" ${SWIFTC_DEFINITIONS_STR}\n"
12871323
f" $$\( echo '$<TARGET_PROPERTY:{projectName},INCLUDE_DIRECTORIES>' | tr '\;' '\\\\n' | sed -e 's/\\\\\(.*\\\\\)/-Xcc -I\\\\1/g' \)\n"
12881324
" $$\( echo '${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}' | tr ' ' '\\\\n' | sed -e 's/\\\\\(.*\\\\\)/-Xcc -I\\\\1/g' \)\n"
12891325
" -import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h\n"
1326+
" ${USERHOME}/.pico-sdk/sdk/PicoSDK.swift\n"
12901327
f" ${{CMAKE_CURRENT_LIST_DIR}}/{main_file_name}\n"
12911328
" -c -o ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o\n"
12921329
" DEPENDS\n"
12931330
" ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h\n"
1331+
" ${USERHOME}/.pico-sdk/sdk/PicoSDK.swift\n"
12941332
f" ${{CMAKE_CURRENT_LIST_DIR}}/{main_file_name}\n"
12951333
")\n"
12961334
)
@@ -1353,6 +1391,13 @@ def GenerateCMake(folder, params):
13531391
file.write(" " + STANDARD_LIBRARIES)
13541392
file.write(")\n\n")
13551393
else:
1394+
file.write("# Link Swift Unicode data tables to the build\n")
1395+
file.write(f"target_link_options({projectName} PRIVATE\n")
1396+
file.write(
1397+
" -Wl,--whole-archive ${SWIFT_EMBEDDED_UNICODE_LIB} -Wl,--no-whole-archive\n"
1398+
)
1399+
file.write(")\n\n")
1400+
13561401
file.write("# Add the swift artifact to the build\n")
13571402
file.write(f"target_link_libraries({projectName}\n")
13581403
file.write(" ${CMAKE_CURRENT_BINARY_DIR}/_swiftcode.o\n")
@@ -1372,7 +1417,7 @@ def GenerateCMake(folder, params):
13721417
file.write(f"add_dependencies({projectName} {projectName}-swiftcode)\n")
13731418

13741419
# Selected libraries/features
1375-
if params["features"]:
1420+
if params["features"] and not params["useSwift"]:
13761421
file.write("# Add any user requested libraries\n")
13771422
file.write(f"target_link_libraries({projectName} \n")
13781423
for feat in params["features"]:

src/utils/download.mts

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

486486
const targetDirectory = buildSDKPath(version);
487487

488+
// Copy swift wrapper
489+
const sdkRoot = dirname(targetDirectory);
490+
await mkdir(sdkRoot, { recursive: true });
491+
copyFileSync(
492+
joinPosix(getScriptsRoot(), "PicoSDK.swift"),
493+
joinPosix(sdkRoot, "PicoSDK.swift")
494+
);
495+
488496
// Check if the SDK is already installed
489497
if (
490498
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)