Opacity meter with USB interface

Dependencies:   USBDevice mbed

Revision:
0:8ce24e6c4de1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jan 05 16:44:57 2016 +0000
@@ -0,0 +1,524 @@
+#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);
+    }
+
+}