Local Build Argon using po-util with OpenThread

Intro

A shout out to the youngman @nrobinson2000 who designed po-util. I have taught computer programming for 30 years and I have only taught 2 students that are of similar capability.

Any tech company should start paying this University student now, in the hope that he helps you later when you need it, as some big company is going to grab him Nathan he graduates in a few years.

Why po-util

Short answer: Because nothing else works for me.

Long answer: It is really hard to install things at school and to get students to install things on their home computers. (Even on my teacher laptop I have to ask the tech department to install software and they might get to it sometime that term.)

Teaching how to use software like Eclipse or Visual Studio takes an entire term and then there isn’t much time left to teach the course.

I prefer Cloud solutions since the students can work the same at school as at home. I am having some issues installing po-util on a few of my computers, but it is working great on my pro-account for Cloud9 (My Profession Development account will not pay for computers but it will pay for my cloud yearly fees, about $200 :slight_smile: )

Why a local build (When I say local build I really mean full control of what you are putting on your purchased firmware.)

I want to be able to use and teach all the OpenThread abilities, not just the ones allowed by the Particle Cloud

my po-util install

curl -V
node -v
npm -v
git --version

If any of these command die, then install the software with the following po-util will try to install them but if the installation dies if does not necessarily tell you about the issue

This is my full installation and setup list:

For cloud9 Pro you would need to also do this


sudo rm -rf /.dockerenv
sudo rm -rf ~/.nvm

Normally on linux do not do the above 2 commands

For the normal ubuntu installation do the following.

Updated as of Jan 10th, 2019 version 0.6.6 or po-util

sudo apt install curl
bash <(curl -sL get.po-util.com)

po init argon myProjectName
cd myProjectName


## monolithic Build of Mesh Devices (full load of firmware to device)
po config mesh-develop

po setup-mesh

MODULAR=n po argon build



## normal building of Mesh Devices
## po config v0.8.0-rc.27 
## po argon build


particle cloud login
## enter your particle userName then password

## see if your Argon is flashing cyan and online
particle list

## flash your code to the Argon over the air
po argon ota myArgonName

## actually nowI am preferring to use DFU mode since it acknowledges success
## on cloud9 I download the .bin and then use particle-cli to do the command
## on a local machine just run this
## dfu mode flashing yellow hold mode button tap reset about 5 seconds past flashing purple safe mode.
particle flash --usb  myArgonName.firmware.bin

I need to test the above but that is what I remember

3 Likes

Where did you find:

ot_api.h

and does anyone know how to do a monolithic build with po-util?

The ot_api.h header in the firmware repository, but you need to have checked out the mesh-develop branch, be building monolithic, and be targeting a mesh device.

1 Like

Hey @rickkas7 you familiar with po-util? I am using it on cloud9 Pro and very impressed

I think doing the following before building should work:

export MODULAR=n

I just tried it with a xenon build and it works.

It does take a little bit longer to compile of course.

1 Like

Is that just a command line statement before

po argon build

how to set it back to regular build?

1 Like

Yes.

You can set it back to modular (non-monolithic builds) with:

export MODULAR=y
1 Like

Hey @nrobinson2000 I am trying to get this really cool bit of code running on po-util using a monolithic build and the mesh-develop branch. I will keep trying but do you have any ideas?

#include "ot_api.h"
extern "C" {
	int8_t otPlatRadioGetRssi(otInstance *aInstance);
};

… hold on, I think it is working

Instead of exporting the MODULAR variable, you can do it temporarily on a command-by-command basis by just setting it right before your normal build command, all in one statement:

MODULAR=n po argon build

This will let you do the monolithic build, without resetting your environment for future commands.

2 Likes

I just tried to monolithically build the following and it worked:

#include "Particle.h"
#include "ot_api.h"
extern "C" {
	int8_t otPlatRadioGetRssi(otInstance *aInstance);
};


void setup() // Put setup code here to run once
{

}

void loop() // Put code here to loop forever
{

}
1 Like

Going to make my own thread since we moved away from range testing.

2 Likes

Or @rickkas7 or one of the Elites could move some of the replies to a new thread…

I did as well. Now what to do with it? Looks like this is the 2nd part to get the RSSI

int8_t rssi = otPlatRadioGetRssi(0);
snprintf(buf, sizeof(buf), ">%d <%d", (int)rssi, lastRssi);

// where buf is an output string.

So this is working for me

#include "Particle.h"
// Easiest RSSI test program
// By Jeremy Ellis


#include "ot_api.h"
extern "C" {
	int8_t otPlatRadioGetRssi(otInstance *aInstance);
};


void setup() {
  
}

void loop() {

  int8_t rssi = otPlatRadioGetRssi(0);
  //snprintf(buf, sizeof(buf), “>%d <%d”, (int)rssi, lastRssi);
  
  Particle.publish("RSSI ", "#" + String(rssi), 60, PRIVATE);  //shows printing an integer variable
  Particle.publish("----------------","-------------", 60, PRIVATE);    // just to show a space between samples
  delay(10000); // wait about 10 seconds

}

Getting this published printout

This is on the Argon, Will now try flashing to a Xenon

Note: RSSI is a negative scale so -1 is a strong signal and -100 is a very weak signal
0 should be a very strong signal but I think I get a result of 0 when no other thread devices are connected.

I originally thought OTA was a really sstable flash. even in the school environment if it took about 15 minutes. I now have changed to flashing using DFU since the OTA does not give proof of success and just reverts to the old version of firmware if the OTA fails without giving you any idea if it worked or not.

A trick here is to change something in your publish statement even add a version to an output string so you can confirm if the upload was a success.

2 Likes

So I tried the program on the Xenon and nothing worked. So I put my Mesh Hello program back on the xenon and things worked again.

Probably because the program I was putting on the Xenon had no mesh.publish only a particle.publish

Anyway, things were kind of interesting. The strongest RSSI value I could get was -19 RSSI with both devices an inch apart. The first meter away from each other the RSSI values fell to about -60 and then they slowly fell more. The lowest reading I got was -93. I have not done any major range testing yet. Antennae testing that @rickkas7 was doing at Mesh range testing would be very interesting.

At one point, I reported that holding the devices vertically really increased the distance measurements. I am not seeing that confirmed with digital values at close range, but perhaps at longer ranges the orientation of the Mesh devices becomes important.

2 Likes

I'd advise recommending the method @dougal mentioned, so you can choose to build monolithically when building instead of exporting it.

## For a normal build
po argon build

## For a monolithic build
MODULAR=n po argon build
1 Like

Hey @rickkas7 or @will What is the strongest RSSI value (where -1 is strong and -100 is weak) that a Xenon will be allowed to connect to an Argon? I am seeing some weird data, where my Xenon is flashing cyan or even green but still registering that the mesh.publish is communicating, almost as if the Mesh will not allow a proper connection between a Xenon and an Argon unless it has a good RSSI value lets say of about -75.

The experiment:

So if I walk with my Xenon far enough away from my Argon, I lose connectivity, but my program shows the RSSI values using a mesh.publish, so as I walk back to the Argon I prove that Mesh.publish is working but my Xenon will not reconnect to the Argon until I get quiet a bit closer.

Data:

The Code:

I changed the code around a bit but loaded similar versions on both the Argon and the Xenon.


#include "Particle.h"
// Particle Mesh Devices RSSI distance testing 
// By Jeremy Ellis
// needs po-util

// po init argon myArgonProject
// cd myArgonProject

// po config mesh-develop 
// po setup-mesh

// MODULAR=n po argon build

// particle login
// particle list
// po argon ota myArgonName



#include "ot_api.h"
extern "C" {
	int8_t otPlatRadioGetRssi(otInstance *aInstance);
};




// Event listener for "mySendToAll" event from Xenons
void myHandler(const char *event, const char *data) {
    delay(5);  // sends the data so an RSSI value is registered
}




/////////////////////////// important globals here ///////////////////////////////

int  myCode = 1;  // Integer to identify this device
int  myCutoffInterest = 18;    // which positive version of RSSI should be fast flash. default 18
bool myXenonAntennaAttached = false;  
bool myArgonBothAntennaAttached = false;  
bool myPublishToConsole = true;        // set true for Argon or debugging

/////////////////////////////// end globals ////////////////////////////

void setup() {
   
   pinMode(D7, OUTPUT);
   Mesh.subscribe("mySendToAll", myHandler);
   if (myXenonAntennaAttached){
       #if (PLATFORM_ID == PLATFORM_XENON) 
	       digitalWrite(ANTSW1, 0);
	       digitalWrite(ANTSW2, 1);
       #endif  
   }
    if (myArgonBothAntennaAttached){
       #if (PLATFORM_ID == PLATFORM_ARGON) 
	       digitalWrite(ANTSW1, 1);
	       digitalWrite(ANTSW2, 0);
       #endif  
   }
     
}

void loop() {
    
     
    // here need to get the RSSI as myCode
    
    
    int8_t rssi = otPlatRadioGetRssi(0);   // activate on monolithic build

    Mesh.publish("mySendToAll", String(rssi));

    //int rssi = myCode;   // for testing 
    

    
    int myNumber;
 
     myNumber = ((int(rssi) * -1)  * 100) - (myCutoffInterest * 100);    // for testing, makes positive and larger
   
   
    if (int(rssi) == 0) {
        digitalWrite(D7, HIGH);  // D7 permanently on,  no connection
    }  else {
    
        if (myNumber <= 50){
            myNumber = 50;   // very fast flashing
        }   
 
        if (myNumber > 0){ 
            digitalWrite(D7, HIGH);
            delay(50);   // very quick flash
            digitalWrite(D7, LOW);
            delay(myNumber);   
        }  else {
       
            Particle.publish("Weird "+ String(myNumber), ", #" + String(rssi) , 60, PRIVATE);  //shows printing an integer variable
            delay(2000);
        }
    
    
    }
    
    if (myPublishToConsole){  // mainly for Argon gateway unless debugging
        Particle.publish("delay #" + String(myNumber), "Device #"+String(myCode) + ", RSSI #" + String(rssi), 60, PRIVATE);  //shows printing an integer variable
        delay(2000); // wait about 2 seconds
    }  
    

}
3 Likes

This may sound like a silly question, but where exactly is ot_api.h?

Good question, I thought it was on the OpenThread github but it is in the https://github.com/particle-iot/device-os/tree/mesh-develop github

Permanent link to ot_api.h here and the ot_api.cpp

Live link to the particle openthread mesh-develop folder https://github.com/particle-iot/device-os/tree/mesh-develop/hal/network/openthread

Lots of interesting stuff in that file and the accompanying .cpp file.

1 Like

Hey @rickkas7 or @dougal you guys got any more example main.cpp monolithic builds I can look at?

I am a javascript programmer lost in C++ :persevere:

This defines a property:

#include "ot_api.h"
extern "C" {
	int8_t otPlatRadioGetRssi(otInstance *aInstance);
};

which is then used by

int8_t rssi = otPlatRadioGetRssi(0);

I want to define lots of methods, as an easy example, how would I define and then use the following from cli.cpp

void Interpreter::ProcessFactoryReset(int argc, char *argv[])