Michael Hogan / Mbed 2 deprecated Hamamatsu_C12666MA

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
mikehogan62
Date:
Thu Dec 15 04:47:55 2016 +0000
Commit message:
Initial publication of code for Hamamatsu C12666MA sensor and Pure Engineering carrier module for ST Micro mbed modules. Licensed as Creative Commons, non-commercial, shara alike .. see https://creativecommons.org/licenses/by-nc-sa/2.0/ for details

Changed in this revision

C12666.cpp Show annotated file Show diff for this revision Revisions of this file
C12666.h Show annotated file Show diff for this revision Revisions of this file
CommandDispatch.cpp Show annotated file Show diff for this revision Revisions of this file
CommandDispatch.h Show annotated file Show diff for this revision Revisions of this file
CommandProcessor.cpp Show annotated file Show diff for this revision Revisions of this file
CommandProcessor.h Show annotated file Show diff for this revision Revisions of this file
TO_DO.txt 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
text_snippets.txt Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C12666.cpp	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,199 @@
+#include "mbed.h"
+#include "C12666.h"
+
+// These values need to be accessed by the are real-time control values
+// so they are not contained within the class
+volatile int specClockSig;
+volatile int specReady;
+volatile SpecState specState;
+volatile int specDataIndex;
+volatile unsigned int specBufferFilling;
+unsigned int lastspecBufferFilling;
+int video_bias = DEFAULT_VIDEO_BIAS; // approximate bias of video signal
+int video_max[] = {DEFAULT_VIDEO_AD_MAX_HI_GAIN, DEFAULT_VIDEO_AD_MAX_LO_GAIN}; // aproximate saturation value of video signal.  First value is for high gain, second is for low gain
+
+uint16_t rawSpectralSamples[2][SPEC_CHANNELS];
+double darkScan[SPEC_CHANNELS];
+double avgScan[SPEC_CHANNELS];
+
+extern DigitalOut specGain;
+extern DigitalOut specST;
+extern DigitalOut specClock;
+extern AnalogIn specVideo;
+extern DigitalOut whiteLED;
+extern DigitalOut laserLED;
+extern DigitalOut clippingLED;
+extern Ticker clockTicker;
+        
+extern int debugLevel;
+
+
+
+C12666_spectrometer::C12666_spectrometer()
+{
+
+    pszSerialNum[0] = 0;
+    A_0 = 0.0;
+    B_1 = 0.0;
+    B_2 = 0.0;
+    B_3 = 0.0;
+    B_4 = 0.0;
+    B_5 = 0.0;
+
+    specGain = 0;  // default to high gain
+    specST = 1;    // set ST signal high
+    specClock = 0; // arbitrarily start clock on low ...
+    whiteLED = 0;  // set while LED off
+    laserLED = 0;  // set laser LED off
+
+    specClockSig = 0;
+    specReady = 0;
+    specState = spec_idle;
+    specDataIndex = 0;
+    specBufferFilling = 0;
+    lastspecBufferFilling = 0;
+    clippingLED = 0;
+    clockPulse_us = DEFAULT_CLOCK_PULSE_US;
+    // clear out the spectral data array and
+    // Start the timer that drives the routine
+    memset(rawSpectralSamples, 0, sizeof(rawSpectralSamples));    
+    clockTicker.attach_us(&specClockFn, clockPulse_us);
+}
+
+// specClock is the event handler for the timer interrupt
+// it handes the spectrometer clock and also manages the clock
+void specClockFn()
+{
+
+    // bail if we are not running
+    if (specState != spec_idle) {
+
+        // toggle the spec clock bit ...
+        specClock = !specClock;
+
+        // if spec clock is on a rising edge, update the state machine
+        if( specClock ) {
+            switch(specState) {
+                case spec_start :
+                    specST = 0;
+                    specDataIndex = 0;
+                    specState = spec_sample_clock0;
+                    break;
+
+                case spec_sample_clock0 :
+                    specST = 1;
+                    specState = spec_sample_clock1;
+                    break;
+
+                case spec_sample_clock1 :
+
+                    // advance to the next state
+                    specState = spec_sample_clock2;
+
+                    break;
+
+                case spec_sample_clock2 :
+                    // sample data into the appropriate buffer
+                    rawSpectralSamples[specBufferFilling][specDataIndex] = specVideo.read_u16();
+                    clippingLED = rawSpectralSamples[specBufferFilling][specDataIndex] > video_max[specGain.read()]; // flash LED if we are clipping
+
+                    // advance the buffer
+                    specDataIndex++;
+                
+                    specState = spec_sample_clock3;
+                    break;
+
+                case spec_sample_clock3 :
+
+                    // if we have sampled all of the channels
+                    // then go the spec_start state
+                    if(specDataIndex == SPEC_CHANNELS) {
+                        specState = spec_start;
+                        
+                        // if we have set the ready flag and we are not mid-print, 
+                        // then move to the other buffer
+                        if(specReady) {
+                            specBufferFilling = (specBufferFilling == 0) ? 1 : 0;
+                        }
+
+                        // set specReady flag,
+                        // since arriving here means that we have read out at least one full sample
+                        // and that integration times will be consistent going forward
+                        specReady = 1;
+                    } else {
+                        specState = spec_sample_clock0;
+                    }
+                    break;
+            }
+        }
+    }
+}
+
+void C12666_spectrometer::Start(){
+    specClockSig = 0;
+    specReady = 0;
+    specState = spec_start;
+    specDataIndex = 0;
+    specBufferFilling = 0;
+    lastspecBufferFilling = 0;
+    clippingLED = 0;    
+    clockTicker.attach_us(&specClockFn, clockPulse_us);    
+}
+
+void C12666_spectrometer::Stop(){
+    specClockSig = 0;
+    specReady = 0;
+    specState = spec_idle;
+    specDataIndex = 0;
+    specBufferFilling = 0;
+    lastspecBufferFilling = 0;
+    clippingLED = 0;
+    clockTicker.detach();
+}
+
+void C12666_spectrometer::setWhiteLED(int onOrOff){
+    whiteLED  = (onOrOff != 0);    
+}
+
+void C12666_spectrometer::setUVLED(int onOrOff){
+    laserLED = (onOrOff != 0);
+}
+
+
+void C12666_spectrometer::setClockPeriod(long clockPeriod_usec){
+    clockPulse_us = clockPeriod_usec;
+    clockTicker.detach();
+    specClockSig = 0;
+    specReady = 0;
+    specState = (specState == spec_idle) ? spec_idle : spec_start;
+    specDataIndex = 0;
+    specBufferFilling = 0;
+    lastspecBufferFilling = 0;
+    clippingLED = 0;
+    clockTicker.attach_us(&specClockFn, clockPulse_us);
+}
+
+
+void C12666_spectrometer::getVolatileParams(int& specClockSig_, int& specReady_, SpecState& specState_, int& specDataIndex_, unsigned int& specBufferFilling_){
+    specClockSig_ = specClockSig;
+    specReady_ = specReady;
+    specState_ = specState;
+    specDataIndex_ = specDataIndex;
+    specBufferFilling_ = specBufferFilling;
+}
+
+// make a quick coppy of the last complete spectrum
+// into the buffer passd in the rawSpectrumBuffer argument
+void C12666_spectrometer::getRawSpectrum(uint16_t* rawSpectrumBuffer){
+    
+    // determine if thelast full raw spectrum is in 
+    // rawSpectralSamples[0] or rawSpectralSamples[1]
+    // if specBufferFilling = 0 then the last buffer = 1
+    // elseif specBufferFilling = 0 then the last buffer = 0
+    int lastBufferIndex = -specBufferFilling + 1;
+    
+    // copy the data to the buffer
+    memcpy(rawSpectrumBuffer, rawSpectralSamples[lastBufferIndex], sizeof(uint16_t) * SPEC_CHANNELS);
+}
+
+C12666_spectrometer::~C12666_spectrometer(){}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C12666.h	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,93 @@
+#ifndef C1266_H
+#define C1266_H
+#include "mbed.h"
+
+
+enum SpecState {spec_idle, spec_start, spec_sample_clock0, spec_sample_clock1, spec_sample_clock2, spec_sample_clock3};
+
+// number of different spectral bins
+#define SPEC_CHANNELS    256
+
+// default clock pulse width
+#define DEFAULT_CLOCK_PULSE_US 100
+
+// shortest clock pulse width we will permit
+#define MIN_CLOCK_PULSE_US     5
+
+// default gain limits for hi gain and low gain
+// If we exceed these levels, 
+#define DEFAULT_VIDEO_AD_MAX_HI_GAIN 40000
+#define DEFAULT_VIDEO_AD_MAX_LO_GAIN 32000
+
+#define DEFAULT_VIDEO_BIAS 0
+#define SPEC_SERIAL_NUM_LEN 32
+
+
+
+void specClockFn();
+
+class C12666_spectrometer 
+{
+    public:
+    C12666_spectrometer();
+    ~C12666_spectrometer();
+
+
+        // set the serial number and calibration coefficients for that serial number
+        void setCalibration(const char* psz_newSerialNum, double newA_0, double newB_1, double newB_2, double newB_3, double newB_4, double newB_5){
+            strncpy(pszSerialNum, psz_newSerialNum, SPEC_SERIAL_NUM_LEN-1);
+            A_0 = newA_0;
+            B_1 = newB_1;
+            B_2 = newB_2;
+            B_3 = newB_3;
+            B_4 = newB_4;
+            B_5 = newB_5;
+            
+        }
+        
+        // retrieve all of the calibration coefficients
+        void getCalibration(char* psz_getSerialNum, double& getA_0, double& getB_1, double& getB_2, double& getB_3, double& getB_4, double& getB_5){
+            strncpy(psz_getSerialNum, pszSerialNum, SPEC_SERIAL_NUM_LEN-1);
+            getA_0 = A_0;
+            getB_1 = B_1;
+            getB_2 = B_2;
+            getB_3 = B_3;
+            getB_4 = B_4;
+            getB_5 = B_5;        
+        }   
+        
+        void getVolatileParams(int& specClockSig_, int& specReady_, SpecState& specState_, int& specDataIndex_, unsigned int& specBufferFilling_);
+        void getRawSpectrum(uint16_t* rawSpectrumBuffer);
+        
+        void Start();
+        void Stop();
+        void setNumDarks();
+        
+        void setWhiteLED(int onOrOff);
+        void setUVLED(int onOrOff);
+        void setClockPeriod(long clockPeriod_usec);
+        inline long getClockPeriod(){ return clockPulse_us; }
+
+        
+    protected:
+        
+        
+        timestamp_t clockPulse_us;
+        
+
+        
+        
+
+
+        char pszSerialNum[SPEC_SERIAL_NUM_LEN];
+        double A_0;
+        double B_1;
+        double B_2;
+        double B_3;
+        double B_4;
+        double B_5;
+        
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandDispatch.cpp	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,542 @@
+#include "mbed.h"
+#include "CommandDispatch.h"
+#include "C12666.h"
+
+extern C12666_spectrometer spec;
+extern DigitalOut specGain;
+extern DigitalOut specST;
+extern DigitalOut specClock;
+extern AnalogIn specVideo;
+extern DigitalOut whiteLED;
+extern DigitalOut laserLED;
+extern DigitalOut clippingLED; //
+extern Ticker clockTicker;
+
+
+// external references to object that we need in this scope
+// the "serial" object and the debugLevel are mainly used helpful printf statements
+// that are used to debug etc.
+extern Serial serial;
+extern int debugLevel;
+
+/*
+volatile int specClockSig;
+volatile int specReady;
+volatile SpecState specState;
+volatile int specDataIndex;
+volatile unsigned int specBufferFilling;
+*/
+extern int lastspecBufferFillng;
+
+// Set default integration time to 100us
+extern timestamp_t clockPulse_us;
+
+extern C12666_spectrometer *pSpec;
+
+extern int video_bias;
+extern int video_max[];
+
+
+/*  
+
+  These commands are used to interact with an MBED enabled STMF303 Nucleo-32 board
+
+  
+  BEGIN_DISPATCH_DECLS
+    
+    :DEBUG(int debugLevel)
+      # sets a debug level flag for turning on various levels of logging
+    
+    :COEFFICIENTS(string SerialNum, double A0, double B1, double B2, double B3, double B4, double B5)
+      # Sets the coefficients that map the pixels in the spec to individual wavenumbers
+    
+    :WAVELENGTHS()
+      # Tells the system to emit the 256 wavelength values given by the coefficients that are set in the coefficients routine
+    
+    :SAVE()
+      # SAVE saves coefficient information to the SD storage for the system 
+
+    :DARKS(int num_darks)
+      # Sets number of dark scans to take  
+
+    :SCANS(int num_scans)
+      # Sets number of (non-dark) scans to take
+      
+    :WHITE(int onOrOff)
+      # Tells system to turn on Whie LED as a light source
+      
+    :UVLASER(int onOrOff)
+      # Tells system to turn on UV LED Laser as light source
+      
+    :RAW_SCAN()
+      # Tells system to take a single, raw scan_is
+      
+    :FILE()
+      # Tells system to write results to SD storage.  File names describe conditions for the scan etc.
+      
+    :SERIAL()
+      # Tells system to emit results over serial port
+      
+    :START()
+      # Start scanning
+-      
+    :STOP()
+      # Stop scanning
+      
+    :CLOCK_PERIOD(long clockPeriod_usec)
+      # set integration time in microseconds
+      
+    :GAIN(int high_or_low)
+      # set gain .. 0 sets low gain, non-0 sets high gain
+      
+    :VIDMAX(int lowGainMaxAD, int highGainMaxAD)
+      # sets max AD counts for low and high gain.  
+      
+    :SHOW()
+      # returns a JSON string that tells the current configuration of the system
+      
+    
+      
+  END_DISPATCH_DECLS
+*/
+
+
+
+
+// It is unwise to alter code in the following UNWISE TO ALTER block
+// *********************************************************
+// ************** BEGIN UNWISE TO ALTER BLOCK **************
+// *********************************************************
+  char *getNextField(char *pszString, char fieldDelimiter){
+    pszString = strchr(pszString, fieldDelimiter);
+    if(pszString) pszString += 1;
+    return pszString;
+  }
+
+  int get_longArg(char *&pszCommandArgs, long defaultVal){
+    
+    long retval = defaultVal; // initialize the retval to a default ...
+
+    // if the command string pointer is not null, 
+    // then attempt to convert it to a long
+    // and advance pszCommand to the next ' ' char
+    // in the arguments string.
+    if(pszCommandArgs){
+      // point to start of string
+      retval = atol(pszCommandArgs);      
+      
+      // get pointer to next field
+      pszCommandArgs = getNextField(pszCommandArgs, ' ');
+
+    }
+    return retval;
+  }
+
+  U8 get_byteArg(char *&pszCommandArgs, U8 defaultVal){
+    return ((U8) get_longArg(pszCommandArgs, (long) defaultVal)); 
+  }
+
+  int get_intArg(char *&pszCommandArgs, int defaultVal){
+    return ((int) get_longArg(pszCommandArgs, (long) defaultVal)); 
+  }
+  
+  float get_floatArg(char *&pszCommandArgs, float defaultVal){
+    
+    float retval = defaultVal; // initialize the retval to a default ...
+
+    // if the command string pointer is not null, 
+    // then attempt to convert it to a float
+    // and advance pszCommand to the next ' ' char
+    // in the arguments string.
+    if(pszCommandArgs){
+      retval = atof(pszCommandArgs);      
+      pszCommandArgs = getNextField(pszCommandArgs, ' ');
+    }
+    return retval;
+  }
+  
+  double get_doubleArg(char *&pszCommandArgs, double defaultVal){
+    
+    double retval = defaultVal; // initialize the retval to a default ...
+
+    // if the command string pointer is not null, 
+    // then attempt to convert it to a float
+    // and advance pszCommand to the next ' ' char
+    // in the arguments string.
+    if(pszCommandArgs){
+      retval = atof(pszCommandArgs);      
+      pszCommandArgs = getNextField(pszCommandArgs, ' ');
+    }
+    return retval;
+  }  
+  
+  char* get_stringArg(char *&pszCommandArgs){
+
+    char *retval = 0;
+    
+    // if the command string pointer is not null, 
+    // then attempt to convert it to a float
+    // and advance pszCommand to the next ' ' char
+    // in the arguments string.
+    if(pszCommandArgs){
+      
+      // get pointer to current field in command string
+      retval = pszCommandArgs;
+      
+      // get pointer ot next field (if any) 
+      pszCommandArgs = getNextField(pszCommandArgs, ' ');
+      
+      // insert a null character after the current field
+      // to form a null terminanated string
+      if (pszCommandArgs) *(pszCommandArgs-1) = 0;      
+    }
+    return retval;
+  }    
+  
+// *********************************************************
+// ************** END UNWISE TO ALTER BLOCK **************
+// *********************************************************
+
+/*
+ sets a debug level flag for turning on various levels of logging
+*/
+void handle_DEBUG(char *&pszCommandArgs){
+    debugLevel = get_intArg(pszCommandArgs);
+}
+
+/*
+ Sets the coefficients that map the pixels in the spec to individual wavenumbers
+*/
+void handle_COEFFICIENTS(char *&pszCommandArgs){
+    char *psz_newSerialNum = get_stringArg(pszCommandArgs); 
+    double A_0 = get_doubleArg(pszCommandArgs);
+    double B_1 = get_doubleArg(pszCommandArgs);
+    double B_2 = get_doubleArg(pszCommandArgs);
+    double B_3 = get_doubleArg(pszCommandArgs);
+    double B_4 = get_doubleArg(pszCommandArgs);
+    double B_5 = get_doubleArg(pszCommandArgs);
+    
+    if (debugLevel) serial.printf("handle_COEFFICIENTS(A0:=%f, B1:=%f, B2:=%f, B3:=%f, B4:=%f, B5:=%f)\n",A_0, B_1, B_2, B_3, B_4, B_5);      
+    
+    spec.setCalibration(psz_newSerialNum, A_0, B_1, B_2, B_3, B_4, B_5);
+}
+
+/*
+ Tells the system to emit the 256 wavelength values given by the coefficients that are set in the coefficients routine
+*/
+void handle_WAVELENGTHS(char *&pszCommandArgs){
+
+
+    if (debugLevel) serial.printf("handle_WAVELENGTHS()\n");      
+    
+    char pszSerialNum[SPEC_SERIAL_NUM_LEN];
+    double A_0;
+    double B_1;
+    double B_2;
+    double B_3;
+    double B_4;
+    double B_5;
+    
+
+    spec.getCalibration(pszSerialNum, A_0, B_1, B_2, B_3, B_4, B_5);
+    
+    // print the start of a json statement that describes the WAVELENGTHS structure
+    // include the 5th order polynomial coefficients
+    serial.printf("WAVELENGTHS={A0:%f,B1:%f,B2:%f,B3:%f,B4:%f,B5:%f",A_0, B_1, B_2, B_3, B_4, B_5);
+    
+    // print the wavelengths themselves as an array
+    serial.printf(",NM:[");
+    double i;
+    double coeff;
+    for(i = 0; i < SPEC_CHANNELS; i ++){
+        coeff = A_0 + B_1 * i + B_2 * pow(i,2) + B_3 * pow(i,3) + B_4 * pow(i,4) + B_5 * pow(i,5);
+        if (i) serial.printf(",");
+        serial.printf("%f", coeff);
+    }
+    // end the wavelength array
+    // end the json statement
+    // and do a newline
+    serial.printf("]}\n");
+}
+
+/*
+ SAVE saves coefficient information to the SD storage for the system
+*/
+void handle_SAVE(char *&pszCommandArgs){
+
+  if (debugLevel) serial.printf("handle_SAVE()\n");  
+  // TODO: Fill in code for SAVE
+}
+
+/*
+ Sets number of dark scans to take
+*/
+void handle_DARKS(char *&pszCommandArgs){
+  int num_darks = get_intArg(pszCommandArgs);
+  if (debugLevel) serial.printf("handle_SCANS(num_darks:=%d)\n", num_darks);  
+  // TODO: Fill in code for DARKS
+}
+
+/*
+ Sets number of (non-dark) scans to take
+*/
+void handle_SCANS(char *&pszCommandArgs){
+  int num_scans = get_intArg(pszCommandArgs);
+  if (debugLevel) serial.printf("handle_SCANS(num_scans:=%d)\n", num_scans);  
+  
+  // TODO: Fill in code for SCANS
+}
+
+/*
+ Tells system to turn on Whie LED as a light source
+*/
+void handle_WHITE(char *&pszCommandArgs){
+
+  int onOrOff = get_intArg(pszCommandArgs); 
+  if (debugLevel) serial.printf("handle_WHITE(onOrOff:=%d)\n", onOrOff);  
+  spec.setWhiteLED(onOrOff);
+
+}
+
+/*
+ Tells system to turn on UV LED Laser as light source
+*/
+void handle_UVLASER(char *&pszCommandArgs){
+  int onOrOff = get_intArg(pszCommandArgs);
+  if (debugLevel) serial.printf("handle_UVLASER(onOrOff:=%d)\n", onOrOff);    
+  spec.setUVLED(onOrOff);
+}
+
+/*
+ Tells system to take a single, raw scan_is
+*/
+void handle_RAW_SCAN(char *&pszCommandArgs){
+
+    if (debugLevel) serial.printf("handle_RAW_SCAN()\n");    
+    
+    // TO_DO --- make this a little more clever so that the number of spec channels is not hard-wired
+    uint16_t rawSpectrumBuffer[SPEC_CHANNELS];  
+        
+    spec.getRawSpectrum(rawSpectrumBuffer);
+    
+    serial.printf("RAW_SCAN=[");
+    for (int i = 0; i < SPEC_CHANNELS; i++){
+        if(i) serial.printf(",");
+        serial.printf("%d",rawSpectrumBuffer[i]);
+    }
+    serial.printf("]\n");
+}
+
+/*
+ Tells system to write results to SD storage.  File names describe conditions for the scan etc.
+*/
+void handle_FILE(char *&pszCommandArgs){
+
+  // TODO: Fill in code for FILE
+    if (debugLevel) serial.printf("handle_FILE()\n");   
+}
+
+/*
+ Tells system to emit results over serial port
+*/
+void handle_SERIAL(char *&pszCommandArgs){
+
+    // TODO: Fill in code for SERIAL
+    if (debugLevel) serial.printf("handle_FILE()\n");     
+}
+
+/*
+ Start scanning
+*/
+void handle_START(char *&pszCommandArgs){
+    if (debugLevel) serial.printf("handle_START()\n");     
+    spec.Start();        
+}
+
+/*
+ Stop scanning
+*/
+void handle_STOP(char *&pszCommandArgs){
+    if (debugLevel) serial.printf("handle_STOP()\n");         
+    spec.Stop();      
+}
+
+
+/*
+ set integration time in microseconds
+*/
+void handle_CLOCK_PERIOD(char *&pszCommandArgs){
+    long clockPeriod_usec = get_longArg(pszCommandArgs);
+    if (debugLevel) serial.printf("handle_CLOCK_PERIOD(clockPeriod_usec=%d)\n", clockPeriod_usec);         
+    spec.setClockPeriod(clockPeriod_usec);
+}
+
+
+/*
+ set gain .. 0 sets low gain, non-0 sets high gain
+*/
+void handle_GAIN(char *&pszCommandArgs){
+    int high_or_low = get_intArg(pszCommandArgs);
+    if (debugLevel) serial.printf("handle_GAIN(high_or_low:=%d)\n", high_or_low);         
+    specGain = (high_or_low == 0); // if argument is 0 (low gain), then assert the specFain pin (pin high means low gain)
+}
+
+/*
+ sets max AD counts for low and high gain.
+*/
+void handle_VIDMAX(char *&pszCommandArgs){
+  int lowGainMaxAD = get_intArg(pszCommandArgs);
+  int highGainMaxAD = get_intArg(pszCommandArgs);
+
+  // Put high gain in 0th element of video_max
+  // and low gain in 1th element of video_max
+  // that way, we can use the state of the gain pin to index the appropriate A/D limit 
+  video_max[1] = lowGainMaxAD;
+  video_max[0] = highGainMaxAD;
+}
+
+/*
+ returns a JSON string that tells the current configuration of the system
+*/
+void handle_SHOW(char *&pszCommandArgs){
+    // make special call to stash copy of volatile values
+    int specClockSig;
+    int specReady;
+    SpecState specState;
+    int specDataIndex;
+    unsigned int specBufferFilling;
+    
+    spec.getVolatileParams(specClockSig, specReady, specState, specDataIndex, specBufferFilling);
+    
+      
+    // grab various digital signals and indexed values (like video_max) 
+    // before emitting them as json
+    int specGain_ = specGain.read();
+    int video_max_ = video_max[specGain_];
+    int whiteLED_ = whiteLED.read();
+    int laserLED_ = laserLED.read();  
+    
+    // get values related to integration time
+    long clockPeriod = spec.getClockPeriod();
+    long integrationTime = 8*256*clockPeriod;
+    
+    // get local copy of calibration data
+    char pszSerialNum[SPEC_SERIAL_NUM_LEN];
+    double A_0;
+    double B_1;
+    double B_2;
+    double B_3;
+    double B_4;
+    double B_5;
+    spec.getCalibration(pszSerialNum, A_0, B_1, B_2, B_3, B_4, B_5);      
+    
+    serial.printf("SHOW={specState:%d, specReady:%d, specDataIndex:%d, specBufferFilling:%d, video_bias:%d, video_max:%d, ",specState, specReady, specDataIndex, specBufferFilling, video_bias, video_max_);
+    serial.printf("specGain:%d, whiteLED:%d, laserLED:%d, ",specGain_, whiteLED_, laserLED_);
+    serial.printf("clockPeriod:%d, integrationTime:%d, ",clockPeriod, integrationTime);
+    serial.printf("serialNum:\"%s\", A0:%f, B1:%f, B2:%f, B3:%f, B4:%f, B5:%f",pszSerialNum, A_0, B_1, B_2, B_3, B_4, B_5);
+    serial.printf("}\n");    
+}
+
+namespace CommandDispatch {
+  #define COEFFICIENTS_COMMAND 0
+  #define WAVELENGTHS_COMMAND 1
+  #define SAVE_COMMAND 2
+  #define DARKS_COMMAND 3
+  #define SCANS_COMMAND 4
+  #define WHITE_COMMAND 5
+  #define UVLASER_COMMAND 6
+  #define RAW_SCAN_COMMAND 7
+  #define FILE_COMMAND 8
+  #define SERIAL_COMMAND 9
+  #define START_COMMAND 10
+  #define STOP_COMMAND 11
+  #define CLOCK_PERIOD_COMMAND 12
+  #define GAIN_COMMAND 13
+  #define VIDMAX_COMMAND 14
+  #define SHOW_COMMAND 15
+
+
+  union command_data_lookup_t {
+     char string[4 * NUM_COMMANDS];
+    unsigned long command_val[NUM_COMMANDS];
+  };
+
+  command_data_lookup_t commands = {
+    'D','E','B','U',
+    'C','O','E','F',
+    'W','A','V','E',
+    'S','A','V','E',
+    'D','A','R','K',
+    'S','C','A','N',
+    'W','H','I','T',
+    'U','V','L','A',
+    'R','A','W','_',
+    'F','I','L','E',
+    'S','E','R','I',
+    'S','T','A','R',
+    'S','T','O','P',
+    'C','L','O','C',
+    'G','A','I','N',
+    'V','I','D','M',
+    'S','H','O','W'};
+
+
+  handler_fn_t command_handlers[NUM_COMMANDS] = {
+    handle_DEBUG,
+    handle_COEFFICIENTS,
+    handle_WAVELENGTHS,
+    handle_SAVE,
+    handle_DARKS,
+    handle_SCANS,
+    handle_WHITE,
+    handle_UVLASER,
+    handle_RAW_SCAN,
+    handle_FILE,
+    handle_SERIAL,
+    handle_START,
+    handle_STOP,
+    handle_CLOCK_PERIOD,
+    handle_GAIN,
+    handle_VIDMAX,
+    handle_SHOW};
+};
+
+
+int dispatchCommand(command_data_t& command_data){
+    int i;
+    for (i = 0; i < NUM_COMMANDS; i++){     
+    
+        // Attempt to match the first four characters of command_data.command_val
+        // against a value in the commands table.
+        // This logic effectively encodes the four-character field as a long,
+        // which makes the matching a little easier.
+        if (CommandDispatch::commands.command_val[i] == command_data.command_val){
+        
+            // Echo what we are processing.
+            if (debugLevel){
+                serial.printf("Processing: %s\n",command_data.string);        
+            }
+            
+            // We have a match, so use the value of "i"
+            // to retrieve the pointer for the command handler
+            handler_fn_t command_handler = CommandDispatch::command_handlers[i];
+            
+            // get pointer to tail of string (beyond command portion)
+            // and pass to the handler function
+            char *pszCommandArgs = getNextField(command_data.string, ' ');
+            if (debugLevel){
+                serial.printf("%s\n",pszCommandArgs);
+            }
+                            
+            command_handler(pszCommandArgs);
+            
+            // exit the loop
+            break;
+        }
+    }    
+    
+    // if we iterate over all commands without a metch
+    // thrn return a 0 to indicate failure
+    // otherwise return a 1
+    return( i != NUM_COMMANDS);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandDispatch.h	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,195 @@
+#ifndef COMMAND_DISPATCH_H
+#define COMMAND_DISPATCH_H
+
+
+/*  
+
+  These commands are used to interact with an MBED enabled STMF303 Nucleo-32 board
+
+  
+  BEGIN_DISPATCH_DECLS
+    
+    :DEBUG(int debugLevel)
+      # sets a debug level flag for turning on various levels of logging
+
+    
+    :COEFFICIENTS(string SerialNum, double A0, double B1, double B2, double B3, double B4, double B5)
+      # Sets the coefficients that map the pixels in the spec to individual wavenumbers
+    
+    :WAVELENGTHS()
+      # Tells the system to emit the 256 wavelength values given by the coefficients that are set in the coefficients routine
+    
+    :SAVE()
+      # SAVE saves coefficient information to the SD storage for the system 
+
+    :DARKS(int num_darks)
+      # Sets number of dark scans to take  
+
+    :SCANS(int num_scans)
+      # Sets number of (non-dark) scans to take
+      
+    :WHITE(int onOrOff)
+      # Tells system to turn on Whie LED as a light source
+      
+    :UVLASER(int onOrOff)
+      # Tells system to turn on UV LED Laser as light source
+      
+    :RAW_SCAN()
+      # Tells system to take a single, raw scan_is
+      
+    :FILE()
+      # Tells system to write results to SD storage.  File names describe conditions for the scan etc.
+      
+    :SERIAL()
+      # Tells system to emit results over serial port
+      
+    :START()
+      # Start scanning
+      
+    :STOP()
+      # Stop scanning
+      
+    :CLOCK_PERIOD(long clockPeriod_usec)
+      # set integration time in microseconds
+      
+    :GAIN(int high_or_low)
+      # set gain .. 0 sets low gain, non-0 sets high gain
+      
+    :VIDMAX(int lowGainMaxAD, int highGainMaxAD)
+      # sets max AD counts for low and high gain.  
+      
+    :SHOW()
+      # returns a JSON string that tells the current configuration of the system
+      
+    
+      
+  END_DISPATCH_DECLS
+*/
+
+  #define NUM_COMMANDS 17
+
+
+// It is unwise to alter code in the following UNWISE TO ALTER block
+// *********************************************************
+// ************** BEGIN UNWISE TO ALTER BLOCK **************
+// *********************************************************
+  typedef void (*handler_fn_t)(char *&pszCommandArgs);
+
+  char *getNextField(char *pszString, char fieldDelimiter);
+
+  int get_longArg(char *&pszCommandArgs, long defaultVal=0);
+
+#ifndef U8
+  #define U8 unsigned char
+#endif
+    U8 get_byteArg(char *&pszCommandArgs, U8 defaultVal=0);
+    
+    int get_intArg(char *&pszCommandArgs, int defaultVal=0);
+    
+    float get_floatArg(char *&pszCommandArgs, float defaultVal=0.0);
+    
+    double get_doubleArg(char *&pszCommandArgs, double defaultVal=0.0); 
+    
+    char* get_stringArg(char *&pszCommandArgs);
+
+// Create a buffer of 127 characters to hold command strings (plus one extra byte for null termination)
+// Also wrap the command data in a union, so that we can easily convert the first four characters of the
+// command into a long in order to speed up the logic that maps commands to function handlers.
+#define COMMAND_STRING_LENGTH 127
+union command_data_t {
+  char string[COMMAND_STRING_LENGTH];
+  unsigned long command_val;
+};
+ 
+    int dispatchCommand(command_data_t& command_data);
+  
+// *********************************************************
+// ************** END UNWISE TO ALTER BLOCK **************
+// *********************************************************
+
+/*
+ sets a debug level flag for turning on various levels of logging
+*/
+void handle_DEBUG(char *&pszCommandArgs);
+
+/*
+ Sets the coefficients that map the pixels in the spec to individual wavenumbers
+*/
+void handle_COEFFICIENTS(char *&pszCommandArgs);
+
+/*
+ Tells the system to emit the 256 wavelength values given by the coefficients that are set in the coefficients routine
+*/
+void handle_WAVELENGTHS(char *&pszCommandArgs);
+
+/*
+ SAVE saves coefficient information to the SD storage for the system
+*/
+void handle_SAVE(char *&pszCommandArgs);
+
+/*
+ Sets number of dark scans to take
+*/
+void handle_DARKS(char *&pszCommandArgs);
+
+/*
+ Sets number of (non-dark) scans to take
+*/
+void handle_SCANS(char *&pszCommandArgs);
+
+/*
+ Tells system to turn on Whie LED as a light source
+*/
+void handle_WHITE(char *&pszCommandArgs);
+
+/*
+ Tells system to turn on UV LED Laser as light source
+*/
+void handle_UVLASER(char *&pszCommandArgs);
+
+/*
+ Tells system to take a single, raw scan
+*/
+void handle_RAW_SCAN(char *&pszCommandArgs);
+
+/*
+ Tells system to write results to SD storage.  File names describe conditions for the scan etc.
+*/
+void handle_FILE(char *&pszCommandArgs);
+
+/*
+ Tells system to emit results over serial port
+*/
+void handle_SERIAL(char *&pszCommandArgs);
+
+/*
+ Start scanning
+*/
+void handle_START(char *&pszCommandArgs);
+
+/*
+ Stop scanning
+*/
+void handle_STOP(char *&pszCommandArgs);
+
+/*
+ set integration time in microseconds
+*/
+void handle_CLOCK_PERIOD(char *&pszCommandArgs);
+
+/*
+ set gain .. 0 sets low gain, non-0 sets high gain
+*/
+void handle_GAIN(char *&pszCommandArgs);
+
+/*
+ sets max AD counts for low and high gain.
+*/
+void handle_VIDMAX(char *&pszCommandArgs);
+
+/*
+ returns a JSON string that tells the current configuration of the system
+*/
+void handle_SHOW(char *&pszCommandArgs);
+
+#endif // #ifndef COMMAND_DISPATCH_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandProcessor.cpp	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,88 @@
+#include "mbed.h"
+#include "CommandProcessor.h"
+#include "CommandDispatch.h"
+
+// external references to object that we need in this scope
+// the "serial" object and the debugLevel are mainly used helpful printf statements
+// that are used to debug etc.
+extern Serial serial;
+extern int debugLevel;
+
+command_data_t command_data;
+
+// Define an index variable that is used to load serial characters into the command_data buffer
+int command_str_index;
+
+// define states for the command processor as an enum
+Command_State_t command_state;
+ 
+// initializeCommandProcessor just initializes
+// variabls for the command processing so that it will work properly after a re-start
+void initializeCommandProcessor(){
+    // initialize the command string,
+  // the command string index,
+  // and the command_state
+  command_data.string[0]=(char)0;
+  command_str_index = 0;
+  command_state = WAITING;  
+}
+
+// processSerialCommands is used to read the serial port
+// and convert the character stream to plausible commands
+// It essentially looks for an input string that starts with a
+// ":" character and that ends with a ";" character.
+// Then it grabs the first field from that string and matches 
+// the first four characters against candidates strings in the
+// commands array.  This is done by casting the entries to long values
+// so that the match cane 
+void processSerialCommands(){
+  // If there are serial characters present,
+  // then process them
+  while (serial.readable()){
+
+    // Retrieve the next character
+    char inChar = serial.getc();; 
+    
+    // If we see the start of a command string,
+    // Then
+    //    Set the command processing state machine to READING,
+    //    and reset the character buffer for the command string 
+    if (inChar == COMMAND_START){
+      command_str_index = 0;
+      command_state = READING;
+      command_data.string[0]=(char)0;
+    }
+    // If we are reading a command and see the COMMAND_END character
+    // Then 
+    //   switch to the PROCESSING command state,
+    //   and break out of the loop
+    else if ((command_state == READING) && (inChar == COMMAND_END)){
+      command_state = PROCESSING;
+      break;
+    }
+    // If there is any other character,
+    //   and we still have room in the buffer, 
+    // Then 
+    //   add the character to the buffer and advance the command string index
+    //   also, fill in the character following the last char with a null termination.
+    else if ((command_state == READING) && (command_str_index < COMMAND_STRING_LENGTH)){
+      command_data.string[command_str_index] = inChar;
+      command_str_index++;
+      command_data.string[command_str_index]=(char)0;
+    }
+  }
+  
+  // If we are in the PROCESSING state, 
+  // then attempt to dispatch to the appropriate function
+  if (command_state == PROCESSING){
+    
+    // if we were unable to dispatch to a command, then complain
+    if ( (dispatchCommand(command_data) ==  0) && debugLevel) {
+        serial.printf("No Match for: %s\n", command_data.string);
+    }
+        
+    // reset the command state to WAITING and exit the for loop
+    command_state = WAITING;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandProcessor.h	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,33 @@
+#ifndef COMMAND_PROCESSOR_H
+#define COMMAND_PROCESSOR_H
+
+
+
+
+// declare variables used for managing command processing states
+// and reading command strings.
+// Define command start character (':') and command end character ";"
+#define COMMAND_START ':'
+#define COMMAND_END ';'
+
+
+
+// define states for the command processor as an enum
+enum Command_State_t {WAITING, READING, PROCESSING};
+ 
+// initializeCommandProcessor just initializes
+// variabls for the command processing so that it will work properly after a re-start
+void initializeCommandProcessor();
+
+// processSerialCommands is used to read the serial port
+// and convert the character stream to plausible commands
+// It essentially looks for an input string that starts with a
+// ":" character and that ends with a ";" character.
+// Then it grabs the first field from that string and matches 
+// the first four characters against candidates strings in the
+// commands array.  This is done by casting the entries to long values
+// so that the match cane 
+void processSerialCommands();
+
+
+#endif // #ifndef COMMAND_PROCESSOR_H++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TO_DO.txt	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,3 @@
+Ensure START/STOP work as intended
+Get NUM_DARK etc working
+Integrate with R
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,55 @@
+#include "mbed.h"
+#include "CommandProcessor.h"
+#include "C12666.h"
+
+
+Serial serial(USBTX, USBRX);
+DigitalOut specGain(A0);
+DigitalOut specST(A1);
+DigitalOut specClock(A2);
+AnalogIn specVideo(A3);
+DigitalOut whiteLED(A4);
+DigitalOut laserLED(A5);
+DigitalOut clippingLED(LED3);
+Ticker clockTicker;
+C12666_spectrometer spec;
+
+// use debug level to turn on/off various printf logging stuff
+int debugLevel = 0;
+
+// Use setup and loop style logic a la Arduino
+// so that we can use the dispatch code from the various other modules in the suste
+void setup();
+void loop();
+
+int main()
+{
+    setup();
+    while(1) {
+      loop();
+    }
+}
+
+void setup(void)
+{
+    // Set up the serial port ...
+    serial.baud(115200);
+    serial.printf("Biorealize: PureEngineering C12666MA UV-VIS Spectrometer 03MAY2016\n");
+
+
+
+    
+    // initialize the variables that handle command dispatching
+    initializeCommandProcessor();
+
+
+
+}
+
+void loop(void)
+{
+    processSerialCommands();
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/c0f6e94411f5
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/text_snippets.txt	Thu Dec 15 04:47:55 2016 +0000
@@ -0,0 +1,3 @@
+:COEFFICIENTS 16a00055 318.7948193 2.386405907 -0.0007973593848 -0.000005712853029 0.000000003262240438 1.24E-11;
+:COEFFICIENTS 16a00055 318.7948193 2.386405907 -0.0007973593848 -0.000005712853029 0.000000003262240438 1.24E-11;
+:COEFFICIENTS 16a00049 312.7990824 2.38900469 -0.0007590948411 -0.000006698919144 0.00000001087748788 0.00000001087748788;