Skip to content

Commit e1ace0b

Browse files
committed
Fix zephyr integration (part 5)
Signed-off-by: paulober <[email protected]>
1 parent f8d40e9 commit e1ace0b

File tree

5 files changed

+254
-132
lines changed

5 files changed

+254
-132
lines changed

src/extension.mts

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
type WebviewPanel,
66
commands,
77
ProgressLocation,
8+
Uri,
9+
FileSystemError,
810
} from "vscode";
911
import {
1012
extensionName,
@@ -101,9 +103,13 @@ import {
101103
import State from "./state.mjs";
102104
import { cmakeToolsForcePicoKit } from "./utils/cmakeToolsUtil.mjs";
103105
import { NewRustProjectPanel } from "./webview/newRustProjectPanel.mjs";
104-
import { OPENOCD_VERSION } from "./utils/sharedConstants.mjs";
106+
import {
107+
CMAKELISTS_ZEPHYR_HEADER,
108+
OPENOCD_VERSION,
109+
} from "./utils/sharedConstants.mjs";
105110
import VersionBundlesLoader from "./utils/versionBundles.mjs";
106111
import { setupZephyr } from "./utils/setupZephyr.mjs";
112+
import { unknownErrorToString } from "./utils/errorHelper.mjs";
107113

108114
export async function activate(context: ExtensionContext): Promise<void> {
109115
Logger.info(LoggerSource.extension, "Extension activation triggered");
@@ -268,10 +274,12 @@ export async function activate(context: ExtensionContext): Promise<void> {
268274
false
269275
);
270276

277+
const cmakeListsContents = new TextDecoder().decode(
278+
await workspace.fs.readFile(Uri.file(cmakeListsFilePath))
279+
);
280+
271281
// Check for pico_zephyr in CMakeLists.txt
272-
if (
273-
readFileSync(cmakeListsFilePath).toString("utf-8").includes("pico_zephyr")
274-
) {
282+
if (cmakeListsContents.startsWith(CMAKELISTS_ZEPHYR_HEADER)) {
275283
Logger.info(LoggerSource.extension, "Project is of type: Zephyr");
276284
await commands.executeCommand(
277285
"setContext",
@@ -307,13 +315,44 @@ export async function activate(context: ExtensionContext): Promise<void> {
307315
ui.updateBoard("Other");
308316
}
309317
}
318+
319+
// check if build dir is empty and recommend to run a build to
320+
// get the intellisense working
321+
// TODO: maybe run cmake configure automatically if build folder empty
322+
try {
323+
const buildDirContents = await workspace.fs.readDirectory(
324+
Uri.file(join(workspaceFolder.uri.fsPath, "build"))
325+
);
326+
327+
if (buildDirContents.length === 0) {
328+
void window.showWarningMessage(
329+
"To get full intellisense support please build the project once."
330+
);
331+
}
332+
} catch (error) {
333+
if (error instanceof FileSystemError && error.code === "FileNotFound") {
334+
void window.showWarningMessage(
335+
"To get full intellisense support please build the project once."
336+
);
337+
338+
Logger.debug(
339+
LoggerSource.extension,
340+
'No "build" folder found. Intellisense might not work ' +
341+
"properly until a build has been done."
342+
);
343+
} else {
344+
Logger.error(
345+
LoggerSource.extension,
346+
"Error when reading build folder:",
347+
unknownErrorToString(error)
348+
);
349+
}
350+
}
351+
352+
return;
310353
}
311354
// check for pico_sdk_init() in CMakeLists.txt
312-
else if (
313-
!readFileSync(cmakeListsFilePath)
314-
.toString("utf-8")
315-
.includes("pico_sdk_init()")
316-
) {
355+
else if (!cmakeListsContents.includes("pico_sdk_init()")) {
317356
Logger.warn(
318357
LoggerSource.extension,
319358
"No pico_sdk_init() in CMakeLists.txt found."

src/utils/projectGeneration/projectZephyr.mts

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
import { extensionName } from "../../commands/command.mjs";
1414
import { commands, Uri, window, workspace } from "vscode";
1515
import {
16-
CURRENT_7ZIP_VERSION,
1716
CURRENT_DTC_VERSION,
1817
CURRENT_GPERF_VERSION,
1918
CURRENT_WGET_VERSION,
@@ -35,6 +34,7 @@ import {
3534
WIFI_WIFI_C,
3635
WIFI_WIFI_H,
3736
} from "./zephyrFiles.mjs";
37+
import { homedir } from "os";
3838

3939
// Kconfig snippets
4040
const spiKconfig: string = "CONFIG_SPI=y";
@@ -165,7 +165,7 @@ async function generateVSCodeConfig(
165165
intelliSenseMode: "linux-gcc-arm",
166166
compilerPath:
167167
// TODO: maybe move into command (the part before the executable) / test if not .exe works on win32
168-
"${userHome}/.pico-sdk/zephyr_workspace/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc",
168+
"${userHome}/.pico-sdk/zephyr_workspace/zephyr-sdk/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc",
169169
includePath: [
170170
"${workspaceFolder}/**",
171171
"${workspaceFolder}/build/zephyr/include",
@@ -205,7 +205,7 @@ async function generateVSCodeConfig(
205205
toolchainPrefix: "arm-zephyr-eabi",
206206
armToolchainPath:
207207
// TODO: maybe just full get zephyr compiler path command
208-
"${command:${extensionName}.getZephyrWorkspacePath}/zephyr-sdk-0.17.1/arm-zephyr-eabi/bin",
208+
"${command:${extensionName}.getZephyrWorkspacePath}/zephyr-sdk/arm-zephyr-eabi/bin",
209209
// TODO: get chip dynamically maybe: chip: `\${command:${extensionName}.${GetChipCommand.id}}`,
210210
// meaning only one cfg required
211211
device: `\${command:${extensionName}.${GetChipUppercaseCommand.id}}`,
@@ -243,7 +243,7 @@ async function generateVSCodeConfig(
243243
"C_Cpp.debugShortcut": false,
244244
"terminal.integrated.env.windows": {
245245
// TODO: contitionally cmake: \${env:USERPROFILE}/.pico-sdk/cmake/${latestVb.cmake}/bin
246-
Path: `\${env:USERPROFILE}/.pico-sdk/dtc/${CURRENT_DTC_VERSION}/bin;\${env:USERPROFILE}/.pico-sdk/gperf/${CURRENT_GPERF_VERSION};\${env:USERPROFILE}/.pico-sdk/ninja/${latestVb[1].ninja};\${env:USERPROFILE}/.pico-sdk/wget/${CURRENT_WGET_VERSION};\${env:USERPROFILE}/.pico-sdk/7zip/${CURRENT_7ZIP_VERSION};\${env:PATH}`,
246+
Path: `\${env:USERPROFILE}/.pico-sdk/dtc/${CURRENT_DTC_VERSION}/bin;\${env:USERPROFILE}/.pico-sdk/gperf/${CURRENT_GPERF_VERSION};\${env:USERPROFILE}/.pico-sdk/ninja/${latestVb[1].ninja};\${env:USERPROFILE}/.pico-sdk/wget/${CURRENT_WGET_VERSION};\${env:USERPROFILE}/.pico-sdk/7zip;\${env:PATH}`,
247247
},
248248
"terminal.integrated.env.osx": {
249249
PATH: `\${env:HOME}/.pico-sdk/dtc/${CURRENT_DTC_VERSION}/bin:\${env:HOME}/.pico-sdk/gperf/${CURRENT_GPERF_VERSION}:\${env:HOME}/.pico-sdk/ninja/${latestVb[1].ninja}:\${env:HOME}/.pico-sdk/wget:\${env:PATH}`,
@@ -262,10 +262,20 @@ async function generateVSCodeConfig(
262262
};
263263

264264
if (cmakePath.length > 0) {
265-
const pathWindows = cmakePath.replace(HOME_VAR, "${env:USERPROFILE}");
266-
const pathPosix = cmakePath.replace(HOME_VAR, "${env:HOME}");
267-
settings["cmake.cmakePath"] = cmakePath;
268-
settings["raspberry-pi-pico.cmakePath"] = cmakePath;
265+
const pathWindows = cmakePath
266+
.replace(HOME_VAR, "${env:USERPROFILE}")
267+
.replace(homedir().replace("\\", "/"), "${env:USERPROFILE}");
268+
const pathPosix = cmakePath
269+
.replace(HOME_VAR, "${env:HOME}")
270+
.replace(homedir().replace("\\", "/"), "${env:HOME}");
271+
settings["cmake.cmakePath"] = cmakePath.replace(
272+
homedir().replace("\\", "/"),
273+
"${userHome}"
274+
);
275+
settings["raspberry-pi-pico.cmakePath"] = cmakePath.replace(
276+
homedir().replace("\\", "/"),
277+
HOME_VAR
278+
);
269279
// add to path
270280
settings[
271281
"terminal.integrated.env.windows"
@@ -292,23 +302,25 @@ async function generateVSCodeConfig(
292302
// TODO: check! ""
293303
'"${workspaceFolder}"/build',
294304
'"${workspaceFolder}"',
295-
"--",
296-
`-DOPENOCD=\${command:${extensionName}.${GetOpenOCDRootCommand.id}}/openocd`,
297-
`-DOPENOCD_DEFAULT_PATH=\${command:${extensionName}.${GetOpenOCDRootCommand.id}}/scripts`,
298305
];
299306

300307
// If console is USB, use the local snippet
301308
if (data.console === "USB") {
302-
westArgs.unshift("-S", "usb_serial_port");
309+
westArgs.push("-S", "usb_serial_port");
303310
}
304311

312+
westArgs.push(
313+
"--",
314+
`-DOPENOCD=\${command:${extensionName}.${GetOpenOCDRootCommand.id}}/openocd`,
315+
`-DOPENOCD_DEFAULT_PATH=\${command:${extensionName}.${GetOpenOCDRootCommand.id}}/scripts`
316+
);
317+
305318
const tasks = {
306319
version: "2.0.0",
307320
tasks: [
308321
{
309322
label: "Compile Project",
310323
type: "shell",
311-
isBuildCommand: true,
312324
command: `\${command:${extensionName}.${GetWestPathCommand.id}}`,
313325
args: westArgs,
314326
group: {
@@ -426,15 +438,15 @@ const char JSON_POST_PATH[] = "/posts";
426438
427439
int main(void)
428440
{
429-
printk("Starting wifi example on %s\n", CONFIG_BOARD_TARGET);
441+
printk("Starting wifi example on %s\\n", CONFIG_BOARD_TARGET);
430442
431443
wifi_connect(WIFI_SSID, WIFI_PSK);
432444
433445
// Ping Google DNS 4 times
434-
printk("Pinging 8.8.8.8 to demonstrate connection:\n");
446+
printk("Pinging 8.8.8.8 to demonstrate connection:\\n");
435447
ping("8.8.8.8", 4);
436448
437-
printk("Now performing http GET request to google.com...\n");
449+
printk("Now performing http GET request to google.com...\\n");
438450
http_get_example(HTTP_HOSTNAME, HTTP_PATH);
439451
k_sleep(K_SECONDS(1));
440452
@@ -445,11 +457,11 @@ int main(void)
445457
{
446458
LOG_ERR("Error in json_get_example");
447459
} else {
448-
printk("Got JSON result:\n");
449-
printk("Title: %s\n", get_post_result.title);
450-
printk("Body: %s\n", get_post_result.body);
451-
printk("User ID: %d\n", get_post_result.userId);
452-
printk("ID: %d\n", get_post_result.id);
460+
printk("Got JSON result:\\n");
461+
printk("Title: %s\\n", get_post_result.title);
462+
printk("Body: %s\\n", get_post_result.body);
463+
printk("User ID: %d\\n", get_post_result.userId);
464+
printk("ID: %d\\n", get_post_result.id);
453465
}
454466
k_sleep(K_SECONDS(1));
455467
@@ -465,11 +477,11 @@ int main(void)
465477
{
466478
LOG_ERR("Error in json_post_example");
467479
} else {
468-
printk("Got JSON result:\n");
469-
printk("Title: %s\n", new_post_result.title);
470-
printk("Body: %s\n", new_post_result.body);
471-
printk("User ID: %d\n", new_post_result.userId);
472-
printk("ID: %d\n", new_post_result.id);
480+
printk("Got JSON result:\\n");
481+
printk("Title: %s\\n", new_post_result.title);
482+
printk("Body: %s\\n", new_post_result.body);
483+
printk("User ID: %d\\n", new_post_result.userId);
484+
printk("ID: %d\\n", new_post_result.id);
473485
}
474486
k_sleep(K_SECONDS(1));
475487
@@ -529,7 +541,7 @@ async function generateMainC(
529541
);
530542
}
531543

532-
mainC = mainC.concat("void main(void) {\n");
544+
mainC = mainC.concat("int main(void) {\n");
533545

534546
if (isBlinky) {
535547
mainC = mainC.concat(' printk("Hello World! Blinky sample\\n");\n\n');
@@ -561,13 +573,13 @@ async function generateMainC(
561573
}
562574
563575
led_state = !led_state;
564-
printk("LED state: %s\n", led_state ? "ON" : "OFF");
576+
printk("LED state: %s\\n", led_state ? "ON" : "OFF");
565577
566578
`;
567579
mainC = mainC.concat(blinkyLoop);
568580
} else {
569581
mainC = mainC.concat(
570-
' printk("Running on %s...\n", CONFIG_BOARD);\n\n'
582+
' printk("Running on %s...\\n", CONFIG_BOARD);\n\n'
571583
);
572584
}
573585

@@ -869,12 +881,16 @@ async function generateCMakeList(
869881
): Promise<boolean> {
870882
// TODO: maybe dynamic check cmake minimum cmake version on cmake selection
871883
// TODO: license notice required anymore?
872-
let cmakeList = `#-------------------------------------------------------------------------------
884+
let cmakeList = `#pico-zephyr-project
885+
#-------------------------------------------------------------------------------
873886
# Zephyr Example Application
874887
#
875888
# Copyright (c) 2021 Nordic Semiconductor ASA
876889
# SPDX-License-Identifier: Apache-2.0
877890
#-------------------------------------------------------------------------------
891+
# NOTE: Please do not remove the #pico-zephyr-project header, it is used by
892+
# the Raspberry Pi Pico SDK extension to identify the project type.
893+
#-------------------------------------------------------------------------------
878894
879895
cmake_minimum_required(VERSION 3.20.0)
880896

src/utils/projectGeneration/zephyrFiles.mts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(http);
2121
2222
static K_SEM_DEFINE(json_response_complete, 0, 1);
2323
static K_SEM_DEFINE(http_response_complete, 0, 1);
24-
static const char * json_post_headers[] = { "Content-Type: application/json\r\n", NULL };
24+
static const char * json_post_headers[] = { "Content-Type: application/json\\r\\n", NULL };
2525
2626
// Holds the HTTP response
2727
static char response_buffer[2048];
@@ -79,7 +79,7 @@ static void http_response_cb(struct http_response *rsp,
7979
printk("HTTP Callback: %.*s", rsp->data_len, rsp->recv_buf);
8080
8181
if (HTTP_DATA_FINAL == final_data){
82-
printk("\n");
82+
printk("\\n");
8383
k_sem_give(&http_response_complete);
8484
}
8585
}
@@ -135,7 +135,7 @@ static void json_response_cb(struct http_response *rsp,
135135
if (rsp->body_found)
136136
{
137137
LOG_DBG("Body:");
138-
printk("%.*s\n", rsp->body_frag_len, rsp->body_frag_start);
138+
printk("%.*s\\n", rsp->body_frag_len, rsp->body_frag_start);
139139
140140
if (returned_placeholder_post != NULL)
141141
{
@@ -448,7 +448,7 @@ void wifi_connect(const char * ssid, const char * psk)
448448
connection_result = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface,
449449
&cnx_params, sizeof(struct wifi_connect_req_params));
450450
if (connection_result) {
451-
LOG_ERR("Connection request failed with error: %d\n", connection_result);
451+
LOG_ERR("Connection request failed with error: %d\\n", connection_result);
452452
}
453453
k_sleep(K_MSEC(1000));
454454
}

0 commit comments

Comments
 (0)