Opacity meter with USB interface

Dependencies:   USBDevice mbed

Files at this revision

API Documentation at this revision

Comitter:
BPPearson
Date:
Tue Jan 05 16:44:57 2016 +0000
Commit message:
Opacity meter with USB interface

Changed in this revision

ByteOperations.cpp Show annotated file Show diff for this revision Revisions of this file
ByteOperations.h Show annotated file Show diff for this revision Revisions of this file
USBDevice.lib Show annotated file Show diff for this revision Revisions of this file
USBHIDProtocol.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ByteOperations.cpp	Tue Jan 05 16:44:57 2016 +0000
@@ -0,0 +1,37 @@
+#include "ByteOperations.h"
+#include <stdint.h>
+
+
+/* low index equals low nibble */
+/* Write 32 bit var to 4 bytes */
+void write_32_to_8(int *i, uint8_t dst[], uint32_t src){
+	dst[(*i)++] = (src >> 0)&0xFF ;
+	dst[(*i)++] = (src >> 8)&0xFF ;
+	dst[(*i)++] = (src >> 16)&0xFF;
+	dst[(*i)++] = (src >> 24)&0xFF;
+}
+
+/* Write 16 bit var to 2 bytes */
+void write_16_to_8(int *i, uint8_t dst[], uint16_t src){
+	dst[(*i)++] = (src >> 0)&0xFF ;
+	dst[(*i)++] = (src >> 8)&0xFF ;
+}
+
+/* Write 4 bytes to 32 bit var*/
+uint32_t read_8_to_32(int *i, uint8_t *src){
+	uint32_t data = 0;
+	data |= (src[(*i)++] << 0) ; 
+	data |= (src[(*i)++] << 8) ; 
+	data |= (src[(*i)++] << 16); 
+	data |= (src[(*i)++] << 24); 
+	return data;
+}
+
+/* Write 2 bytes to 16 bit var*/
+uint16_t read_8_to_16(int *i, uint8_t *src){
+	uint16_t data = 0;
+	data |= (src[(*i)++] << 0) ;
+	data |= (src[(*i)++] << 8) ;
+	return data;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ByteOperations.h	Tue Jan 05 16:44:57 2016 +0000
@@ -0,0 +1,278 @@
+#ifndef BYTEOPERATION_H_
+#define BYTEOPERATION_H_
+
+#include <stdint.h>
+
+/* low index equals low nibble */
+/* Write 32 bit var to 4 bytes */
+void write_32_to_8(int *i, uint8_t dst[], uint32_t src);
+
+/* Write 16 bit var to 2 bytes */
+void write_16_to_8(int *i, uint8_t dst[], uint16_t src);
+
+/* Write 4 bytes to 32 bit var*/
+uint32_t read_8_to_32(int *i, uint8_t *src);
+
+/* Write 2 bytes to 16 bit var*/
+uint16_t read_8_to_16(int *i, uint8_t *src);
+
+
+const uint8_t logaritmify[0xFF] = {
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+1  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+2  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+3  ,
+4  ,
+4  ,
+4  ,
+4  ,
+4  ,
+4  ,
+4  ,
+4  ,
+5  ,
+5  ,
+5  ,
+5  ,
+5  ,
+5  ,
+5  ,
+6  ,
+6  ,
+6  ,
+6  ,
+6  ,
+6  ,
+7  ,
+7  ,
+7  ,
+7  ,
+7  ,
+7  ,
+8  ,
+8  ,
+8  ,
+8  ,
+9  ,
+9  ,
+9  ,
+9  ,
+9  ,
+10 ,
+10 ,
+10 ,
+10 ,
+11 ,
+11 ,
+11 ,
+11 ,
+12 ,
+12 ,
+12 ,
+13 ,
+13 ,
+13 ,
+14 ,
+14 ,
+14 ,
+15 ,
+15 ,
+15 ,
+16 ,
+16 ,
+16 ,
+17 ,
+17 ,
+18 ,
+18 ,
+19 ,
+19 ,
+19 ,
+20 ,
+20 ,
+21 ,
+21 ,
+22 ,
+22 ,
+23 ,
+23 ,
+24 ,
+25 ,
+25 ,
+26 ,
+26 ,
+27 ,
+28 ,
+28 ,
+29 ,
+29 ,
+30 ,
+31 ,
+32 ,
+32 ,
+33 ,
+34 ,
+35 ,
+35 ,
+36 ,
+37 ,
+38 ,
+39 ,
+40 ,
+40 ,
+41 ,
+42 ,
+43 ,
+44 ,
+45 ,
+46 ,
+47 ,
+48 ,
+50 ,
+51 ,
+52 ,
+53 ,
+54 ,
+55 ,
+57 ,
+58 ,
+59 ,
+61 ,
+62 ,
+63 ,
+65 ,
+66 ,
+68 ,
+69 ,
+71 ,
+72 ,
+74 ,
+76 ,
+77 ,
+79 ,
+81 ,
+83 ,
+85 ,
+86 ,
+88 ,
+90 ,
+92 ,
+94 ,
+97 ,
+99 ,
+101,
+103,
+105,
+108,
+110,
+113,
+115,
+118,
+120,
+123,
+126,
+129,
+131,
+134,
+137,
+140,
+143,
+147,
+150,
+153,
+157,
+160,
+164,
+167,
+171,
+175,
+179,
+183,
+187,
+191,
+195,
+199,
+204,
+208,
+213,
+218,
+222,
+227,
+232,
+237,
+243,
+248};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice.lib	Tue Jan 05 16:44:57 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/USBDevice/#c7fd9d44ec8e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHIDProtocol.h	Tue Jan 05 16:44:57 2016 +0000
@@ -0,0 +1,18 @@
+#ifndef USBHIDPROTOCOL_H_
+#define USBHIDPROTOCOL_H_
+/* Command list */
+// Devices verifies with same CMD and optional data
+
+// System commands
+	#define CMD_SYS_CHECK				0x00	// Args: return version
+	#define CMD_SYS_RESET				0xFF	// Args: bool softreset
+
+	#define  CMD_GET_RAW_OPACITY		0x10
+	#define  CMD_GET_FILTERED_OPACITY 	0x11
+	#define  CMD_GET_CALIB_FACTOR 		0x12
+	#define  CMD_SET_CALIB_FACTOR 		0x13
+	#define  CMD_GET_FILTER_MODE 		0x14
+	#define  CMD_SET_FILTER_MODE 		0x15
+	
+#endif //USBHIDPROTOCOL_H_
+
--- /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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jan 05 16:44:57 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/cbbeb26dbd92
\ No newline at end of file