Transitioning from ESP8266 to Photon/Argon

Hello Particle Community,

I’ve been working with ESP8266 for some time now and just recently started using Particle devices. Coming from ESP8266 using NodeMCU & Lua I would really appreciate if someone could help clarify few architecture and programing framework(s) / language(s) questions when it comes to Particle devices.

Reading the documents I understand that programing the embedded Particle hardware is divided into two parts: (1) DeviceOS (firmware/low level code written by Core Particle Team in C++) that interacts with the actual hardware and provides basic functionality & abstraction for (2) Application Firmware (written by user in C++) to do whatever the project requires. However, I feel a bit confused (given limited C++) exposure when it comes to putting together the DeviceOS & Application Code, What libraries are already included in the DeviceOS? What functionality & high-level abstraction do these libraries actually provide?

Another source of confusion is the use .ino files for Application Firmware, why is the Application Firmware written using the Wiring/Arduino Framework(s) instead of C++? How do I write the Application Firmware in C++ and not use Wiring/Arduino Framework(s)? When using NodeMCU & Lua to program the ESP8266, the device always boots the init.lua script, what is the equivalent for Particle devices if programming in C++? I realize a lot of these questions are probably trivial but I would really appreciate if someone could help out, links to specific documentation addressing the questions is always appreciated!

Thanks a lot for taking the time :slight_smile:

1 Like

Virtually everything that's documented hardware supports (e.g. I2C, SPI, UART, ...). When it's document in the Reference Docs it's supported with merely adding #include <Particle.h> (for .ino files that statement is added by the preprocessor if it's missing).

For ease of use for beginners, but Wiring/Arduino is not alternative to C++ but only an "extension/convention" added ontop of C++ standards. The code is fully C++ but adds some constructs and functions to "shield" the user from some HW specifics.

4 Likes

Thank you so much for taking the time to explain! Its starting to make more sense now :slight_smile:

Would be awesome if you can also answer some followup questions: So I have a photon connected via USB, using the Particle CLI I created a new project, flashed DeviceOS and the following Application Firmware.

photon-wifi.cpp


/*
 * Project: photon-wifi
 * Description:
 * Author:
 * Date:
 */

#include <Particle.h>

int main(){
    Serial.begin(9600);
    for(int index = 0; index < 15; index = index + 1){
        Serial.println(index+" :hello from photon-wifi.cpp");
        delay(2500);
    }
    return 0;
}

void wifi();
void wifi(){
    Serial.println("about to turn of wifi module...");
    delay(1000);
    WiFi.off();
    Serial.println("wifi module has been turned off");
}

However, when I monitor the serial output using: particle serial monitor, I am not seeing any print statements nor the Indicating “flashing white” led confirming that the wifi module was turned off. Also, that is the init.lua equivalent for C++? What is the Application Firmware file that gets executed?

Thanks again!

The Wiring/Arduino framework uses two default functions (void setup(void) and void loop(void)) you are supposed to implement and these will be called like this from the framework main() function (which you don’t implement).

// the framework main() function looks something like this (for illustrational purposes only)
int main() {
 // do some one-time prep stuff
 setup();
 //do some more one-time stuff
 while(true) {
   // do some regular prep stuff
   loop();
   // do some more regular stuff
 }
}

Consequently your code could look like this

void setup() {
  Serial.begin(); // USB serial does not care about baudrate
  Serial.println("Done once");
}

void loop() {
  static int c = 0;
  Serial.printlnf("repetition %d", ++c);
  delay(1000);
}
2 Likes

Awesome, thanks for the clarification!

So basically, all that is required is to have those two functions:


.cpp
void setup(){
}

void loop(){
}


If I have multiple .cpp files that I compile into .bin as Application Firmware, which .cpp files gets executed first on bootup?

C++ doesn't work like Javascript. There is no such thing as executing a file. When the device first starts up some system code will run, then setup is called. Then when setup returns, some more system stuff is done, and then loop is called repeatedly. This occurs no matter in which file these two functions are defined. You can have as many files of source code as you want.

2 Likes

Ahh, I see.
So what is I have both setup() & loop() in multiple files? There’s still no sequence?

x.cpp
#include <y.h>
void setup(){
}
void loop(){
// call some function from y.cpp
}


y.cpp
void setup(){
}
void loop(){
}

Sorry again for all of the noob questions.

You code will not link. It will say there are multiple definitions of these two symbols, setup and loop.

Each file of source code is compiled independently and it (generally) doesn't matter which order they are compiled. That's why C and C++ generally have header files (.h by convention) that "declare" things. In .cpp and .ino files things like functions are "defined". Then there is a link stage, which takes all of the individual compile units, and joins them together into the final executable code which gets loaded on the device. This stage links up all usages of a symbol with the definition of the symbol. The linker will notice you have the same symbol defined twice, and throw the error.

Remember, there is only one instance of setup and loop declared in your entire project. If you want to call functions in other source files, then you create a declaration in the ".h" file, and the definition of the function in a ".cpp" file. Include the ".h" in the ".cpp" you want to call from, and then just call it. I think it might be best if you looked at a simple example. I'll find one in the libraries for you.

2 Likes

Grr, the libraries tend to have other complications. Here is a quick minimal one off the top of my head…

#include "add_two_numbers.h"

void setup() {
  Serial.begin(); // USB serial does not care about baudrate
  Serial.println("Done once");
}

void loop() {
  static int c = 0;
  int doubled = addTwoNumbers(c,c);
  Serial.printlnf("repetition %d doubled: %d", ++c, doubled);
  delay(1000);
}

Then the header “add_two_numbers.h”

// Declares the function
int addTwoNumbers(int a, int b);

Then the implementation “add_two_numbers.cpp”

// Defines the function
int addTwoNumbers(int a, int b)
{
  return a+b;
}

This is just a real quick example. There are complications that you’ll learn about like how not to include headers more than once, and other things. Start playing around and see how far you can get.

2 Likes