Opacity meter with USB interface

Dependencies:   USBDevice mbed

main.cpp

Committer:
BPPearson
Date:
2016-01-05
Revision:
0:8ce24e6c4de1

File content as of revision 0:8ce24e6c4de1:

#include "mbed.h"
#include "USBHID.h"
#include "ByteOperations.h"
#include "USBHIDProtocol.h"

#define COMMAND 0
#define DATA 1

#define AVERAGE       0
#define MEDIAN        1
#define BINAVERAGE    2
#define RATEOFCHANGE  3

#define VERSION 0x01

Serial pc(USBTX, USBRX);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
AnalogIn opacity(p20);
AnalogOut fOpacity(p18);
BusInOut databus(p8, p9, p10, p11, p12, p13, p14, p15);
DigitalOut registerSelect(p5);
DigitalOut readWriteClock(p7);
DigitalOut readWrite(p6);
//DigitalIn unlocked(p8);
Ticker updateLCD;
Ticker processOpacity;
LocalFileSystem local("local");

USBHID *hid;
HID_REPORT send_report __attribute__((aligned (4))); // Aligned for fast access
HID_REPORT recv_report __attribute__((aligned (4))); // Aligned for fast access

float instantOpacity;
float filteredOpacity = 0.0;
float Opacity = 0.0;
char *helloStr = "Hello";
int filterAlgorithm = AVERAGE;
float anIn1Sum;
float anIn1SumSqr;
float stdDevCount;
float standardDeviation;
float calibFactor = 1.0;
int showCalibFactor = 0;
float anInVals[100];
int anInIdx = 0;
float binVal[10];
int binCnt[10];
int maxCnt = 0;
int maxIdx = 0;


void readConfigFile()
{
    
    FILE *fp = fopen("/local/config.dat", "r");

    if (fp != NULL)
    {
        fscanf(fp, "%f", &calibFactor); 
        fscanf(fp, "%d", &filterAlgorithm); 
        fclose(fp);
    }
}



void writeConfigFile()
{
    FILE *fp = fopen("/local/config.dat", "w");

    if (fp != NULL)
    {
        fprintf(fp, "%5.3f\n", calibFactor);
        fprintf(fp, "%1d\n", filterAlgorithm);
        fclose(fp);
    }
}



void empty_report(HID_REPORT *data){
    register uint32_t *p = (uint32_t *)data->data;
    for( register int i=0; i<((sizeof(HID_REPORT)-1)/4); i++ ){
        *p = 0xFFFFFFFF;
        p++;
    }
}

void checkForUSBRequest()
{
    char *cptrR;
    char *cptrT;
    float fTmp;
    //bool updatePIDValues = false;

    //try to read a msg
    if(hid->readNB(&recv_report)){
        
        // set character pointer to start of the parameter for set commands
        cptrR = (char *)&recv_report.data[1];
        cptrT = (char *)&send_report.data[1];

        led2 = 1;
        
        // Data packet received, start parsing
        int irx=0;
        int itx=0;

        send_report.data[itx++] = recv_report.data[0];

        switch ( recv_report.data[irx++] ){
            case    CMD_SYS_CHECK       :
                send_report.data[itx++] =  VERSION;
                break;
            
            case    CMD_SYS_RESET       : 
                  // Soft reset
                    empty_report(&recv_report);
                break;

            case CMD_GET_RAW_OPACITY:
                // return the raw opacity value
                sprintf(cptrT, "%6.5f", instantOpacity * 100.0);
                pc.printf("instant opacity = %f\n", instantOpacity * 100.0);
                break;
            case CMD_GET_FILTERED_OPACITY:
                // return filtered opacity
                sprintf(cptrT, "%6.5f", Opacity);
                pc.printf("filtered opacity = %f\n", Opacity);
                break;
            case CMD_GET_CALIB_FACTOR:
                // return calibration factor
                sprintf(cptrT, "%6.5f", calibFactor);
                pc.printf("calibration factor = %f\n", calibFactor);
                break;
            case CMD_SET_CALIB_FACTOR:
                // set calibration factor to value in packet
                sscanf(cptrR, "%f", &calibFactor);
                writeConfigFile();
                pc.printf("Set calibFactor to %f\n", calibFactor);
                break;
            case CMD_GET_FILTER_MODE:
                // return filter algorithm value
                sprintf(cptrT, "%6.3f", (float)filterAlgorithm);
                pc.printf("filterAlgorithm = %d\n", filterAlgorithm);
                break;
            case CMD_SET_FILTER_MODE:
                // set filter alogirthm
                sscanf(cptrR, "%f", &fTmp);
                filterAlgorithm = (int)fTmp;
                writeConfigFile();
                pc.printf("Set filter algorithm to %d\n", filterAlgorithm);
                break;
            case 0xEE   : {
                hid->sendNB(&send_report);  
                //WatchDog_us bello(100);
                }
            break;

            default:
                send_report.data[0] =   0xFF;   //Failure
            break;
        } // Switch 

        // Return command + optional new args
        hid->send(&send_report);

        // 0xFF unused bytes
        empty_report(&recv_report);         
        empty_report(&send_report);
        
        led2 = 0;
    }       // if packet
}



void writeToLCD(bool rs, char data){

    // set register select pin 
    registerSelect = rs;
    
    // set read/write pin to write
    readWrite = 0;
    
    // set bus as output
    databus.output();
    
    // put data onto bus
    databus = data;
    
    // pulse read/write clock
    readWriteClock = 1;
    
    wait_us(1);
    
    readWriteClock = 0;

    wait_us(1);
    
    // clear data bus
    databus = 0;
    
    //pc.printf("%02x\n", data);
    
}


char readFromLCD(bool rs){

    char data;
    
    // set register select pin 
    registerSelect = rs;
    
    // set read/write pin to read
    readWrite = 1;
    
    // set bus as output
    databus.input();
    
    // put data onto bus
    data = databus;
    
    // pulse read/write clock
    readWriteClock = 1;
    
    wait_us(10);
    
    readWriteClock = 0;
    
    return data;
}


void resetLCD(){
}


void initLCD(){
    
    // wait 15 ms to allow LCD to initialise
    wait_ms(15);
    
    // set interface for 8 bit mode
    writeToLCD(COMMAND, 0x30);

    // give it time    
    wait_ms(5);

    // set interface for 8 bit mode again
    writeToLCD(COMMAND, 0x30);

    // give it time    
    wait_us(100);

    // set interface for 8 bit mode again, last one before we can configure the display
    writeToLCD(COMMAND, 0x30);

    // give it time    
    wait_us(500);
    
    // set interface for 8 bit mode, 2 display lines and 5 x 8 character font
    writeToLCD(COMMAND, 0x38);

    // give it time    
    wait_us(100);
    
    // display off
    writeToLCD(COMMAND, 0x08);

    // give it time    
    wait_us(100);
    
    // clear the screen
    writeToLCD(COMMAND, 0x01);

    // give it time to finish    
    wait_ms(2);

    // set entry mode to increment cursor position cursor on write
    writeToLCD(COMMAND, 0x03);
    
    // give it time to finish    
    wait_us(100);

    // position cursor at home
    writeToLCD(COMMAND, 0x02);
    
    // give it time to finish    
    wait_ms(2);

    // display on
    writeToLCD(COMMAND, 0x0F);
}




void positionCursor(uint8_t x, uint8_t y){

    if (x > 7) x = 0;
    
    if (y == 1)
        writeToLCD(COMMAND, 0x80 + 0x40 + x);
    else
        writeToLCD(COMMAND, 0x80 + 0x00 + x);
        
    wait_us(50);
}


void displayString(int x, int y, char *str){
    
    // position cursor
    positionCursor(x, y);    
    
    // write string to screen
    for (int i=0; i<strlen(str); i++){
        writeToLCD(DATA, str[i]);
        
        wait_us(50);
    }
}


void standardDeviationCalc(float opacity)
{
    // add to standard deviation accumulators
    anIn1Sum += opacity;
    anIn1SumSqr += (opacity * opacity);
    
    // increment standard deviation counter
    stdDevCount++;
    
    // if enough readings for the standard deviation calculation
    if (stdDevCount >= 100)
    {
        // calculate the standard deviation
        // std dev = sqrt( (n * sum(x2) - sum(x)2)) / (n * (n - 1)))
        standardDeviation = ((stdDevCount * anIn1SumSqr) - (anIn1Sum * anIn1Sum)) / (stdDevCount * (stdDevCount - 1));
        if (standardDeviation > 0.0)
            standardDeviation = sqrt(standardDeviation);
        else
            standardDeviation = sqrt(-standardDeviation);
        
        // clear standard deviation accumulators for next set of readings
        anIn1Sum = 0.0;
        anIn1SumSqr = 0.0;
        stdDevCount = 0;
    }
 }
 
 
 void updateDisplay(){
    char str[20];
    
    sprintf( str, "o %5.1f", Opacity);

    displayString(0, 0, str);
    
    //if (showCalibFactor == 0){
        //sprintf( str, "s %5.2f", standardDeviation);

        //displayString(0, 1, str);
    //}
    //else{
        //sprintf( str, "m %5.2f", calibFactor);

        //displayString(0, 1, str);

        //showCalibFactor--;
    //}
}
 
 
 void updateOpacity()
{

   // read next analog input value into circular buffer, adjust reading for max value is 3.1 on 3.3V input
    anInVals[anInIdx] = opacity.read() * 1.0674;
    
    // increment anInIdx and check for wrap 
    anInIdx++;
    if (anInIdx >= 100)
        anInIdx = 0;
    
    // filter analog inputs with required algorithm
    switch (filterAlgorithm)
    {
        case AVERAGE:
            float accumulator = 0.0;
            for (int i=0; i<100; i++)
            {
                accumulator += anInVals[i];
            }
            instantOpacity = accumulator / 100;
            break;
        case MEDIAN:
            float tempF;
            for (int j=1; j<100; j++)
            {
                for (int i=1; i<100; i++)
                {
                    if (anInVals[i] < anInVals[i-1])
                    {
                        // swap places
                        tempF = anInVals[i-1] ;
                        anInVals[i-1] = anInVals[i];
                        anInVals[i] = tempF;
                    }
                }
            }
            instantOpacity = anInVals[49];
            break;
        case BINAVERAGE:
            // initialise bins to zero
            for (int i=0; i<10; i++)
            {
                binVal[i] = 0.0;
                binCnt[i] = 0;
            }
            
            // sort analog input values into one of ten bins
            for (int i=0; i<100; i++)
            {
                int binIdx = anInVals[i] * 10.0;
                if (binIdx > 9) 
                    binIdx = 9;
                binVal[binIdx] += anInVals[i];
                binCnt[binIdx]++;
            }

            maxCnt = 0;
            maxIdx = 0;
            // find the bin with most values added
            for (int i=0; i<10; i++)
            {
                if (binCnt[i] > maxCnt)
                {
                    maxCnt = binCnt[i];
                    maxIdx = i;
                }
            }
            
            instantOpacity = binVal[maxIdx] / binCnt[maxIdx];
            break;
        case RATEOFCHANGE:
            break;
        default:
            break;
    }

    // do standard deviation on the smoothed opacity value
    standardDeviationCalc(instantOpacity);

    // apply a filter to the instant reading to get the filtered reading
    filteredOpacity = (instantOpacity * 0.05) + (filteredOpacity * 0.95);

    // calculate opacity reading as 0..100%
    Opacity = filteredOpacity * calibFactor * 100.0;
    
    // write opacity value to analog output as 0..1.0 value
    fOpacity.write(Opacity / 100.0);
}
    
 
int main() {
    
    printf("initLCD()\n");
    
    initLCD();
    
    filterAlgorithm = BINAVERAGE;
    
    //calibUp.mode(PullUp);
    //calibDown.mode(PullUp);
    //unlocked.mode(PullUp);
    //calibUp.attach_deasserted(&incCalibFactor);
    //calibUp.attach_deasserted_held(&incCalibFactor);
    //calibDown.attach_deasserted(&decCalibFactor);
    //calibDown.attach_deasserted_held(&decCalibFactor);
    
    //calibUp.setSampleFrequency();
    //calibDown.setSampleFrequency();

    printf("readConfigFile()\n");

    readConfigFile();

    printf("start updateLCD ticker\n");

    updateLCD.attach(&updateDisplay, 0.5);

    printf("read opacity 10 times\n");

    // initialise analog input values
    for (int i=0; i<100; i++)
        anInVals[i] = opacity.read();
        
    printf("start processOpacity ticker\n");

    // start ticker to read and filter the opacity input
    processOpacity.attach(&updateOpacity, 0.1);
        
    printf("initialise USB\n");

    // USB Initialize   
    static USBHID hid_object(64, 64);
    hid = &hid_object;
    send_report.length = 64;

    while(1){

        // check for any commands from host computer
        checkForUSBRequest();
        
        wait_ms(10);
    }

}