aggregator code initial version add plot menu to continuously print #sensor, V, I on uart

Dependencies:   mbed

kl25-aggregator-plot.cpp

Committer:
vincenxp
Date:
2019-03-26
Revision:
0:667d2b410f9a

File content as of revision 0:667d2b410f9a:

/*******************************************************************************
*
*  MIT License (https://spdx.org/licenses/MIT.html)
*  Copyright 2018 NXP
*
*  MBED code for FRDM-KL25Z aggregator. Configures and triggers "smart" sensors.
*  Aggregates data and sends up the line to a host computer over USB serial. 
*  Other FRDM boards (K64F or K66F) may be used for ethernet connection or for 
*  more local memory or faster processing speed.
*
*
*  !!! 3Dec18: This now appears to be fixed with current version of library..
*  !!! must use mbed-2 from 20 Mar 2018 or serial port won't work !!! 
*  !!! do not update mbed library... !!!
*
********************************************************************************/

#include "mbed.h"

// Custom setup
#define CUSTOM 1

char version_info[] = "3 Dec 2018"; // date info... 

Serial uart(USBTX, USBRX); // standard FRDM board USBx

// set up GPIO connections...
DigitalOut reset(PTB0);                    // PTA1 on smart sensor board
DigitalOut interrupt(PTB1);                // PTA0 on smart sensor board
const int sensors = 14;
DigitalOut select[sensors] =                     // PTA2 on smart sensor board
        { (PTD4), (PTA12), (PTA4), (PTA5), (PTC8), (PTC9), (PTA13), 
          (PTD5), (PTD0), (PTD2), (PTD3), (PTD1), (PTB3), (PTB2)};  
I2C i2c(PTE0, PTE1); 

int addr8bit = 0x48 << 1; // default start addr for communication with sensors

// multipliers of ten used for decompressing data...
// *note* this array fails when it's not a const. index 4 returns zero for some
// reason... maybe mbed, not sure...  seems to be mbed-2 related...
const float pow10[14] = {1.0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 
                 1.0e-7, 1.0e-8, 1.0e-9, 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13};


// some more variables...
int n, i, j, k, status, temp;
#if (CUSTOM == 1)
int delay=0;   // starting delay for measurement updates...
#else
int delay=500000;   // starting delay for measurement updates...
#endif
long int count=0;
char cmd[20];       // buffer for holding data sent to/from sensor boards
char params[sensors][10];// array to keep sensor parameter data...
bool deebug=false;  // flag to print extra stuff for debug...
float v1, v2, i1, i2;   // for holding full float vs. compressed 3-sigfig measurements
bool full = false;  // boolean to control whether full binary numbers sent
bool gui = true;    // flag to print data out in compressed format
bool plot = true;  // flag use to send data in a plot-able format 
bool barg = false;   // flag for bar graph...

// timer so we can time how long things take... 
Timer t;

// set up various arrays related to smart sensors...
bool present[sensors] = { false, false };     // whether or not a sensor is present
bool continuous = true; // flag for making continuous vs. triggered measurements...
// this array of addresses also needed to be made a const array or 
// some values would inexplicably change and cause I2C errors 
// (because the address in the array gets changed somehow)... const fixes...
// this seems to be mbed-2 related...
const short int address[sensors] =  // assigned address for each sensor
        { 0x50<<1, 0x51<<1, 0x52<<1, 0x53<<1, 0x54<<1, 
          0x55<<1, 0x56<<1, 0x57<<1, 0x58<<1, 0x59<<1, 
          0x5a<<1, 0x5b<<1, 0x5c<<1, 0x5d<<1 };

// this union allows easily converting float value to bare bytes and back again...
union u_tag {
     char b[4];
     float fval;
     int bobo;
   } volt[2], curr[2];   // voltage and current value from sensor



// function that sends measurement trigger pulse to all sensors, singalling
// them to take a measurement which will be subsequently and sequentially read...
void send_trigger(){          
    interrupt = 1;
    wait_us(50);
    interrupt = 0;
}



// main code starts here...
int main() {
    
    // set things up...
    reset = 0;                          // place sensors in reset 
    interrupt = 0;                      // place trigger line low
    for (k=0; k<sensors; k++) select[k] = 1;  // set each sensor's select line high
    
    i2c.frequency(400000);              // set I2C frequency
    uart.baud(115200);                  // set UART baud rate
    uart.printf("\r\n\r\n\e[2J%s\r\nI'm here...\r\n ", version_info);   // signal that we're off and running...
                                        // where \e[2J clears the screen...
    
    // loop forever (although, as code has evolved, this loop never completes...)
    while(1) {
        reset = 0;      // issue a global reset
        wait(0.01);     // wait a bit
        reset = 1;      // release reset
        count++;        // overall iteration count
        uart.printf("\r\n\r\nReleased reset...  %d\r\n", count);
    
        wait(0.0005);    // wait a little bit...
        
        // iterate to identify and configure each connected sensor...
        for (k=0; k<sensors; k++){    // loop over all sensors
           present[k] = false;  // set presence to false before looking for sensor...

           select[k] = 0;       // smake sensor select line low to start address reassignment 
           uart.printf("Asserted select[%X] line low... \r\n", k);
    
           wait(0.001);         // wait a bit...

           // write the new address to sensor and then read it back to verify...
           cmd[0] = address[k];
           n = i2c.write( addr8bit, cmd, 1);
           uart.printf("Wrote: %x    error %d \r\n", cmd[0], n);
           if (n==0) present[k] = true; // a sensor IS connected on this select line, since it ACKed
           if (present[k]){
               cmd[0] = 0; // clear cmd... 
               wait(0.0001);
               n = i2c.read( addr8bit, cmd, 1);
               uart.printf("  ===> Read back: %x    error %d\r\n", cmd[0], n);
               // here we're reading it back but we're not actually checking the value... 
               // just assuming that since we were able to write, we'll read the same 
               // value back...
           } else i2c.stop(); // not present, error condition...

           wait(0.0001);
           select[k] = 1;   // set sensor's select line high, telling it to change its I2C addr
           uart.printf("Sending select[%X] back high to change address... \r\n", k);

           if (present[k]) {
               // now check that the address change was successful...  
               // write to the new address, there is currently no error out 
               // if sensor does not respond...  
               wait(0.0001);   
               cmd[0]=0xff;  
               n = i2c.write( address[k], cmd, 1);
               if (n==0) { uart.printf("\r\nSensor %X configured... now to test... \r\n\r\n", k); }
               else present[k]=false;
           } // endif
           
           if (present[k]) {
                 // read parameters from sensor
                 // Need to do this sequence without a trigger, since that'll cause an interrupt 
                 //      and clobber any pre-loaded paramter data...
                 cmd[0] = 99; // make a dummy write in order to pre-load parameter buffer...
                 n = i2c.write( address[k], cmd, 2 );
                 wait(0.001);
                 // here's where we actually read the parameters:
                 n = i2c.read( address[k], params[k], 9 ); // select is already high from above, so we don't need to do it again...
                 uart.printf("\r\n   params %d %d %d %d %d %d \r\n", params[k][0], params[k][1]*8, params[k][2]*8, params[k][3]*8, params[k][4]*8, params[k][5]);
                 
                 #if (CUSTOM == 0)
                 // now add one to each parameter to make sure we can write them all... 
                 // will see below if it worked... (we'll see it down below)
                 for (i=0; i<6; i++){
                     cmd[0] = i;
                     cmd[1] = params[k][i]+1;
                     uart.printf("     %d, %d, %d %d \r\n", k, i, cmd[0], cmd[1]);
                     n = i2c.write( address[k], cmd, 2 );
                     wait(0.01);
                 }
                 #endif

           }
           
        } // for k

        wait(0.0005);
    
        // ******************************************************************
        // read data from all connected sensors...    
        // ******************************************************************
        while (1) {
           //if (!gui) uart.printf("\r\nTriggering measurement... \r\n");
           //else uart.printf("\e[2J\r\n"); //  #     (A)     (V)\r\n"); 
           t.start();
           send_trigger(); // trigger tells all connected sensors to make the measurements 
           #if (CUSTOM == 0)
           wait_ms(8.75);  // need to give enough time to make them...
           #endif
           for (k=0; k<sensors; k++){ // iterate over all sensors
              if (present[k]){  // if a sensor is present, read its data
              
                if (full){
                 // full floating point data tranfer...
                 n = i2c.read( address[k], cmd, 9 );
                 if (deebug && !gui) uart.printf("    I2C adddr: 0x%X   %X\r\n", address[k], k);
                 // unstuff the bytes back into floating point values...
                 for (j=0; j<4; j++) curr[k].b[j] = cmd[j]; 
                 for (j=0; j<4; j++) volt[k].b[j] = cmd[j+4]; 
                 v1 = volt[k].fval; i1 = curr[k].fval;
                 if (!gui) uart.printf(" Sensor %X:  ===> %4.2e %4.2e 0x%x   err %d\r\n", k, volt[k].fval, curr[k].fval, cmd[8], n);   
                } // if (full)
                 
                 // compressed data transfer with status nibble: 2 float values of 3 sig figs each + status nibble: 
                 // where each value is 3 digits, single digit exponent, and two status bits packed into 2 bytes
                 // four bytes in total...
                 select[k] = 0; // indicate that we want to read compressed data from sensor...
                 n = i2c.read( address[k], cmd, 4 );
                 select[k] = 1;
                 // pull out status bits from the four received bytes...
                 status = (cmd[0]&(1<<7))>>4 | (cmd[1]&(1<<7))>>5 | (cmd[2]&(1<<7))>>6 | (cmd[3]&(1<<7))>>7 ;
                 if (deebug && !gui) uart.printf("  %02d %02d %02d %02d %8.6f %d %8.6f %d\r\n", cmd[0]&0x7f, cmd[1]&0x7f, cmd[2]&0x7f, cmd[3]&0x7f, 
                            pow10[(int)(((cmd[1]&(0x7f)) % 10)+2)], (int) (((cmd[1]&(0x7f)) % 10)+2), 
                            pow10[(int)(((cmd[3]&(0x7f)) % 10)+2)], (int) (((cmd[3]&(0x7f)) % 10)+2));
                 // now reconstruct the two float values...
                 curr[k].fval = (float) ( (cmd[0]&(0x7f))*10 + (cmd[1]&(0x7f))/10 ) * pow10[((cmd[1]&(0x7f)) % 10)+2];
                 volt[k].fval = (float) ( (cmd[2]&(0x7f))*10 + (cmd[3]&(0x7f))/10 ) * pow10[((cmd[3]&(0x7f)) % 10)+2];
                 v2 = volt[k].fval; i2 = curr[k].fval;
                 if (!gui) uart.printf("  compd %X:  ===> %4.2e V   %4.2e A    %d  err %d\r\n", k, volt[k].fval, curr[k].fval, status, n); 
                 if (deebug && !gui) printf("     volt? %s    current? %s \r\n", 
                                (abs(v1-v2)/v1 <0.05) ? "true" : "false", 
                                (abs(i1-i2)/i1 <0.05) ? "true" : "false");
                 
                 // if we're in gui mode, this is the only line that'll print out for each attached sensor...
                 if (gui && full) uart.printf("  %X  %4.2e %4.2e %4.2e %4.2e  \r\n", k, v1, v2, i1, i2);
                 else {
                     if (plot) uart.printf("%X  %5.3f   %8.6f\r\n", k , v2, i2);
                     //uart.printf(" #%X  %4.2e V   %4.2e A  ", k , v2, i2);
                     if (barg) for (j=0; j<40*i2; j++) uart.printf("*");
                     uart.printf("\r");
                 } // else
                 
                 // parameter readback from sensor
                 // !! Smart Sensor's selelct line needs to be high while doing this !!
                 // Need to do this sequence without a trigger, since that'll cause an interrupt 
                 // and clobber any pre-loaded paramter data...
                 if (deebug && !gui) {
                    cmd[0] = 99; // dummy write to pre-load parameter buffer...
                    n = i2c.write( address[k], cmd, 2 );
                    n = i2c.read( address[k], params[k], 9 ); // select is already high from above, so we don't need to do it again...
                    uart.printf("  params %d %d %d %d %d %d \r\n", params[k][0], params[k][1]*8, params[k][2]*8, params[k][3]*8, params[k][4]*8, params[k][5]);
                 }
              }
              else{
                 //uart.printf("  !!! device %d missing... \r\n", k);
              } //endif
           } // for k   
           //  wait_ms(250);
           while (t.read_us()<delay){
               // wait until delay worth of time has elapsed...
               }    
           t.stop();
           t.reset();
            
           if (!continuous) while (!uart.readable()); // wait here until we get text, if in triggered mode...
           while (uart.readable()){
                temp = uart.getc();
                if (deebug) printf ("%d\r\n", temp);
                if (temp==(int) '+') {
                    delay += 100000;
                    if (delay > 2000000) delay = 2000000;
                    }
                if (temp==(int) '-') {
                    delay -=100000;
                    #if (CUSTOM == 0)
                    if (delay < 14300) delay = 14300;
                    #else
                    if (delay < 0) delay = 0;
                    #endif
                    }
                if (temp==(int) 't') {
                    uart.printf ("\r\nDelay value = %d\r\n", delay);
                    }
                if (temp==(int) '_') {
                    delay = 500000;
                    }
                if (temp==(int) 'c') {
                    continuous = !continuous;
                    }
                if (temp==(int) 'd') {
                    deebug = !deebug;
                    }
                if (temp==(int) 'g') {
                    gui = false;
                    }
                if (temp==(int) 'G') {
                    gui = true;
                    }
                if (temp==(int) 'p') {
                    plot = true;
                    }
                if (temp==(int) 'b') {
                    barg = !barg;
                    }

                if (temp==(int) 'h') {
                    uart.printf("\r\n\r\n");
                    uart.printf("+/- add/remove update time\r\n");
                    uart.printf("_   half second update rate\r\n");
                    uart.printf("b   toggle bar graph in gui mode\r\n");
                    uart.printf("c   toggle continuous/single trigger\r\n");
                    uart.printf("t   trigger and print current delay value\r\n");
                    uart.printf("d   toggle debug flag\r\n");
                    uart.printf("g   turn off gui mode\r\n");
                    uart.printf("G   turn on gui mode\r\n");
                    uart.printf("p   plot data\r\n");
                    uart.printf("h   print this help\r\n");
                    uart.printf("\r\n");
                    wait(5);
                    }

                    
           } // while uart.readable...
                    
         } // while read from sensors...
         // *****************************************************************
         // end data read
         // *****************************************************************
    } // while main, should never actually fall out to here...
    
} // main