Use Visual Studio Code for your Particle development needs


#16

still valid. I’ve been using it almost every day for the last 5 months.
if you include a library please flatten the directory structure so all lib files (.cpp and .h) are next to your .ino files.
Gustavo.


#17

Do I have to flatten all of the Particle headers also?

Before I even attempt to collect all of those things and put them in one place, does this IDE show you compilation errors before you compile like any other IDE made in the past 20 years?


#18

not sure what you meant. If those headers are included in the libs your proj is using then the answer is yes.

nope


#19

Are there any IDEs at all that do show compile errors before you build?

This is a basic thing I’m asking for. Just basic syntax validation and rudimentary type checking.

double radians(double deg);```

it's pointing at the 2nd ```double```, not the first.  that formatting is lost here.

I have dozens of compile errors like that.  This code compiles fine on the Web "IDE"

#20

Sorry that I sound super whiney, I’m having a bad day and am very frustrated with getting anything “off-road” working on this platform. The paved route is very well done, manicured, well-kept, etc. One step off that path and you are in the weeds.


#21

sorry to hear about your bad day. Continue to write if you want to commiserate together further, I wasn’t having a super good day either… just not with this platform :slight_smile:
I think what you are after is a on-the-fly parser of the code, that would kick in while you write, but no, I haven’t seen such a piece of plugin/software around. Maybe the arduino plugin in VS Code could evolve to such thing in the future, maybe the Particle DEV could as well. However one can argue that the build process is so quick that “instantaneous feedback” vs “three to five seconds away feedback” is fine for a lot of people.
hope things look better tomorrow for you!
Gustavo.


#22

Thanks.

If this were a language I had 1000 more hours of experience with, I would agree with you fully. As it stands, I fight syntax errors FAR more than anything else. The tooling should be able to assist me with that. I mean that’s what tools and computers are for.

My skills lie partially in C#, and C# is one way to write plugins for Visual Studio, which DOES understand C++ well enough to give me what I’m after.

So I think I’m going to write a Particle extension for Visual Studio.


#23

that would be extremely awesome!


#24

I have fully switched to VSCode for doing Particle development.
Having all the login and device selection in Atom was nice, but the error parser never worked and the lack of control+click for jump-to-definition forced the switch.

To get the error parser working for Particle cloud build in VSCode, I extended the script from the original source in this post. There was a pretty odd thing where “workspace” would be prepended to paths when errors were reported, and you’ll see it removed with the error parser regex.

Works on OSX. Untested on other platforms. Be sure to install the C/C++ extension. Error parsing isn’t always perfect, but it pretty much works and it is very nice to have. Use of a .ino file will not work, since it gets internally renamed to .cpp upon compile.

Here’s my tasks.json:

//tasks.json for Particle online build
{ 
"version": "0.1.0", 
"command": "particle", 
"isShellCommand": true, 
"args": [], 
"showOutput": "always", 
"echoCommand": true, 
"tasks": [ 
    { 
        "taskName": "compile", 
        "suppressTaskName": false, 
        "isBuildCommand": true,             
        "args": ["electron","${workspaceRoot}", "--saveTo", "${workspaceRoot}/firmware.bin"],
        // Use the standard less compilation problem matcher.
            "problemMatcher": {
                "owner": "cpp",
                "fileLocation": ["relative", "${workspaceRoot}"],
                "pattern": {
                    "regexp": "^(/workspace|/worksapce/)(.*?):(\\d+):(\\d+):\\s+(warning|error|fatal error):\\s+(.*)$",
                    "file": 2,
                    "line": 3,
                    "column": 4,
                    "severity": 5,
                    "message": 6
                },
                "severity":"error"
            }
    }, 
    { 
        "taskName": "flash",             
        "suppressTaskName": false, 
        "isTestCommand": true, 
        "args": ["--usb", "firmware.bin"] 
    }    
]     
}

#25

Hi Andrew,
I’d like to give this a shot, but I need to ask you few questions:

How is this supposed to work?
what does it do if you have an error in the code when you compile?
is it supposed to flag the line with the error in the source file itself?

If you have a screenshot with the outcome, I’d like to see it, please.

I tried it in Ubuntu to see if I could find out how and if it would work, but did not succeed at even understanding what it should do.
thanks!
Gustavo.


#26

Hrm, what I wrote above no longer seems to work. The thing I mentioned there, that the string “workspace” was oddly prepended to console lines, does not seem to happen anymore.

I am not sure if I changed something in my environment or shell, or maybe it was part of an update to VSCode or the particle-cli or backend build system since then.

So now, using the following tasks.json file, the warning & error parser should work:

{ 
"version": "0.1.0", 
"command": "particle", 
"isShellCommand": true, 
"args": [], 
"showOutput": "always", 
"echoCommand": true, 
"tasks": [ 
    { 
        "taskName": "compile", 
        "suppressTaskName": false, 
        "isBuildCommand": true,             
        "args": ["electron","${workspaceRoot}", "--saveTo", "${workspaceRoot}/firmware.bin"],
        // Use the standard less compilation problem matcher.
            "problemMatcher": {
                "owner": "cpp",
                "fileLocation": ["relative", "${workspaceRoot}"],
                "pattern": {
                    "regexp": "^(.*?):(\\d+):(\\d+):\\s+(warning|error|fatal error):\\s+(.*)$",
                    "file": 1,
                    "line": 2,
                    "column": 3,
                    "severity": 4,
                    "message": 5
                },
                "severity":"error"
            }
    }, 
    { 
        "taskName": "flash",             
        "suppressTaskName": false, 
        "isTestCommand": true, 
        "args": ["--usb", "firmware.bin"] 
    }    
]     
} 

This is almost exactly the same as this SO response for Makefiles, and the binding for F8 is also useful: https://stackoverflow.com/questions/30269449/how-do-i-set-up-vscode-to-compile-c-code

Here’s a screenshot of how the problems should be picked up by the problem matcher when running the build task:


Teaching Electron Programming
#27

oh wow, this is beautiful and extremely useful!
I can confirm it works in Ubuntu with VS Code 1.13.0.

You mentioned earlier that this would only work in cpp files, but I’m happy to see it works on ino files too :slight_smile:

Do you mind if I add this info to the hackster project?
thanks!
Gustavo.


#28

Sure, go for it.
It’s kind of nuts to think about how much time I spent and how much code I generated using Atom and the web IDE with little to no error parser. Now, I would not be able to live without it.


#29

Oh, I think the .ino/.cpp is another recent change in the Particle backend or particle-cli ; it used to report back error in Main.ino as Main.cpp, so the error parser went looking for a file that did not exist. But now ther eis name consistency, so it works.


#30

If you’re a Visual Studio user, I strongly recommend using Visual studio for your C++ work. You need to abstract the hardware stuff so you get to use all of Visual Studio features including the debugging etc. I’m guessing most of your time is spent in your logic rather than accessing the hardware (directly).

For anything more complicated than Blinky, this is what I do myself. It gives you a lot of opportunity to clean up your code and build good abstractions since you have a really good code editor with refactoring and debugger at your disposal. You can use include the GSL NuGet to get really good Code analysis and guidance as per the C++ Guidelines Support Library.

For example, here is my hardware abstraction interface (abstract class).

/*
Hal.h - Hardware Abstraction Layer for Arduino
Abstracting some basic functions of the Arduino Library
So as to make it possible to decouple Arduino "things"
from other classes, decoupling those classes from Arduino
Created by Shiv Kumar, 2014.
website: http://www.matlus.com
Released into the public domain.
*/
#pragma once

#ifndef Hal_h
#define Hal_h

class Hal {
protected:
public:
	Hal() {}
	virtual ~Hal() {}
	virtual void doPinMode(uint16_t pin, uint8_t mode) = 0;
	virtual void doDigitalWrite(uint16_t pin, uint8_t value) = 0;
	virtual void doAnalogWrite(uint16_t pin, int8_t value) = 0;
	virtual void attach(uint8_t pin) = 0;
	virtual void detach() = 0;
	virtual void write(int position) = 0;
	virtual int doConstrain(int numberToConstrain, int lowerBound, int upperBound) = 0;
	virtual int doMap(int value, int sourceMin, int sourceMax, int targetMin, int targetMax) = 0;
};

#endif

For my Visual Studio project and I have an implementation (descendant) of this class that uses the Console (std::cout). I have about 7 classes that I can design, develop and test to ensure my application works as expected. Then I simply move all these classes into the Wed IDE or Particle DEV. Of course I have an implementation of the Hal class called HalSpark that looks like this:

/*
  HalSpark.h - Implementation of the Hal abstract class
  where this implementation delegates to the Arduino
  library functions
  Created by Shiv Kumar, 2014.
  website: http://www.matlus.com
  Released into the public domain.
*/
#pragma once

#ifndef HalSpark_h
#define HalSpark_h
#include "Hal.h"
#include "spark_wiring.h"

class HalSpark : public Hal {
public:
  HalSpark();
  ~HalSpark();
  void doPinMode(uint16_t pin, uint8_t mode) override final;
  void doDigitalWrite(uint16_t pin, uint8_t value) override final;
  void doAnalogWrite(uint16_t pin, int8_t value) override final;
  void attach(uint8_t pin) override final;
  void detach() override final;
  void write(int position) override final;
  int doConstrain(int numberToConstrain, int lowerBound,
                  int upperBound) override final;
  int doMap(int value, int sourceMin, int sourceMax, int targetMin,
            int targetMax) override final;
};

#endif
#include "HalSpark.h"

HalSpark::HalSpark() {}

HalSpark::~HalSpark() {}

void HalSpark::doPinMode(uint16_t pin, uint8_t mode) {
  PinMode pMode = PinMode::OUTPUT;

  switch (mode) {
  case 0:
    pMode = PinMode::INPUT;
    break;
  case 1:
    pMode = PinMode::OUTPUT;
    break;
  case 2:
    pMode = PinMode::INPUT_PULLUP;
    break;
  }

  pinMode(pin, pMode);
}

void HalSpark::doDigitalWrite(uint16_t pin, uint8_t value) {
  digitalWrite(pin, value);
}

void HalSpark::doAnalogWrite(uint16_t pin, int8_t value) {
  analogWrite(pin, value);
}

void HalSpark::attach(uint8_t pin) {
  // No implementation for this yet.
  // Will need to include the Servo Library
}

void HalSpark::detach() {
  // No implementation for this yet.
  // Will need to include the Servo Library
}

void HalSpark::write(int position) {
  // No implementation for this yet.
  // Will need to include the Servo Library
}

int HalSpark::doConstrain(int numberToConstrain, int lowerBound,
                          int upperBound) {
  return constrain(numberToConstrain, lowerBound, upperBound);
}

int HalSpark::doMap(int value, int sourceMin, int sourceMax, int targetMin,
                    int targetMax) {
  return map(value, sourceMin, sourceMax, targetMin, targetMax);
}

I use a similar thing for sensors and the like.

If the VS Code solution here works, then that’s good/preferable I would think.


#31

I’ve gotten just about everything to work by using the tasks.json file that @gusgonnet posted here: https://www.hackster.io/gusgonnet/use-visual-studio-code-for-your-particle-development-needs-9e23bc

However, I do need to add #include “application.h” to the top of my main.cpp. I am still using the default c_cpp_properties.json and do not know what paths to include so that VScode will know where to look for application.h. Does anyone know how where I can go to find that or how I should set up my c_cpp_properties.json so that I don’t get the squiggly warnings?


#32

It’s possible but a super huge pain to get all of the paths correct. You’ll need both the system firmware headers and the headers from the gcc-arm toolchain.

This post shows how to do it with Visual Studio 2017 15.5 preview, which I don’t actually recommend that you try to switch to, however there are enough similarities to VS Code that you should be able to make the same sort of settings and get rid of all of the squiggly warnings in Code.


#33

Hey Alex, I do not know how to do that, so I ignore the warnings… not ideal I admit.
Good luck and let us know if you figured it out with the post above from Rick.
Gustavo.


#34

I think that I need to include the path where “application.h” is on my computer, but I don’t actually know where that is. I feel like that should be something easy, but I’m having a hard time figuring that out.


#35

It’s not just application.h. You need everything that’s included from application.h or Particle.h. Also several of the gcc-arm header files. Also some defines and compiler options. For a Photon using 0.7.0, it’s:

{
			"name":"Particle photon",
			"includePath":[
				"${workspaceRoot}\\..\\firmware\\communication\\src",
				"${workspaceRoot}\\..\\firmware\\dynalib\\inc",
				"${workspaceRoot}\\..\\firmware\\hal\\inc",
				"${workspaceRoot}\\..\\firmware\\hal\\shared",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\api",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\include",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\libraries\\crypto",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\WWD\\include\\",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\platform\\GCC\\",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\platform\\include\\",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\security\\BESL",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\security\\BESL\\crypto",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\security\\BESL\\host\\WICED\\",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\security\\BESL\\include",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\photon\\wiced\\security\\BESL\\supplicant\\",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\stm32",
				"${workspaceRoot}\\..\\firmware\\hal\\src\\stm32f2xx",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\CMSIS\\Device\\ST\\Include",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\CMSIS\\Include",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\SPARK_Firmware_Driver\\inc",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\STM32_StdPeriph_Driver\\inc",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\STM32_USB_Device_Driver\\inc",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\STM32_USB_Host_Driver\\inc",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\STM32F2xx\\STM32_USB_OTG_Driver\\inc",
				"${workspaceRoot}\\..\\firmware\\platform\\MCU\\shared\\STM32\\inc",
				"${workspaceRoot}\\..\\firmware\\platform\\shared\\inc",
				"${workspaceRoot}\\..\\firmware\\services\\inc",
				"${workspaceRoot}\\..\\firmware\\system\\inc",
				"${workspaceRoot}\\..\\firmware\\user\\inc",
				"${workspaceRoot}\\..\\firmware\\wiring\\inc",
				"${workspaceRoot}\\..\\gcc-arm\\arm-none-eabi\\include",
				"${workspaceRoot}\\..\\gcc-arm\\arm-none-eabi\\include\\c++\\5.3.1",
				"${workspaceRoot}\\..\\gcc-arm\\arm-none-eabi\\include\\c++\\5.3.1\\arm-none-eabi",
				"${workspaceRoot}\\..\\gcc-arm\\arm-none-eabi\\include\\c++\\5.3.1\\arm-none-eabi\thumb",
				"${workspaceRoot}\\..\\gcc-arm\\arm-none-eabi\\include\\c++\\5.3.1\\ext",
				"${workspaceRoot}\\..\\gcc-arm\\lib\\gcc\\arm-none-eabi\\5.3.1\\include",
				"${workspaceRoot}\\src"
			],
			"defines":[
				"BOOTLOADER_SDK_3_3_0_PARTICLE",
				"DFU_BUILD_ENABLE",
				"INCLUDE_PLATFORM=1",
				"LOG_INCLUDE_SOURCE_INFO=1",
				"LOG_MODULE_CATEGORY=\"\\\"app\\\"\"",
				"MODULAR_FIRMWARE=1",
				"MODULE_DEPENDENCY2=0,0,0",
				"MODULE_DEPENDENCY=4,2,207",
				"MODULE_FUNCTION=5",
				"MODULE_INDEX=1",
				"MODULE_VERSION=5",
				"PARTICLE=1",
				"PARTICLE_DCT_COMPATIBILITY",
				"PARTICLE_USER_MODULE",
				"PLATFORM_ID=6",
				"PLATFORM_NAME=photon",
				"PLATFORM_THREADING=1",
				"PRODUCT_FIRMWARE_VERSION=65535",
				"PRODUCT_ID=6",
				"RELEASE_BUILD",
				"SPARK=1",
				"SPARK_PLATFORM",
				"SPARK_PLATFORM_NET=BCM9WCDUSI09",
				"START_DFU_FLASHER_SERIAL_SPEED=14400",
				"START_YMODEM_FLASHER_SERIAL_SPEED=28800",
				"STM32F2XX",
				"STM32_DEVICE",
				"SYSTEM_VERSION_STRING=0.7.0",
				"USBD_PID_CDC=0xC006",
				"USBD_PID_DFU=0xD006",
				"USBD_VID_SPARK=0x2B04",
				"USER_FIRMWARE_IMAGE_LOCATION=0x80A0000",
				"USER_FIRMWARE_IMAGE_SIZE=0x20000",
				"USE_STDPERIPH_DRIVER",
				"_GNU_SOURCE",
				"_WINSOCK_H"
			],
			"compilerSwitches":"-Wall -Wno-error=deprecated-declarations -Wno-switch -Wundef -fcheck-new -fdata-sections -ffunction-sections -fmessage-length=0 -fno-builtin-free -fno-builtin-malloc -fno-builtin-realloc -fno-exceptions -fno-rtti -fno-strict-aliasing -mcpu=cortex-m3 -mthumb -std=gnu++11 ",
			"intelliSenseMode":"linux-gcc-arm"
		},