This project allows for the sending of MIDI messages, and setting of variable resistances, controlled by a distance sensor. MIDI input messages can also be used to set the variable resistance.

Dependencies:   N5110 PinDetect SRF08 USBDevice mbed PowerControl

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

Go to the documentation of this file.
00001 /**
00002 @file main.cpp
00003 
00004 @brief Program implementation
00005 
00006 */
00007 #include "main.h"
00008 
00009 int main () {
00010     
00011     ///Powerdown the Ethernet peripheral
00012     PHY_PowerDown();
00013     
00014     ///Read parameter variables from VALS.csv
00015     readNumberValuesFromFile();
00016     ///Resise the smoothing values vector
00017     smoothingValues .resize(numberValues [distanceSmoothing]+1);
00018     
00019     ///Set MCP4151 chip select high initially
00020     CS = 1; 
00021     /// Set the MCP4151 SPI for 16 bit mode 3
00022     MCP4151.format(16,3);
00023     /// Set MCP4151 clock frequency to 1000000
00024     MCP4151.frequency(1000000);
00025     
00026     ///Initialise the screen and print splash screen
00027     lcd.init(); 
00028     lcd.printString("EXPRESSIONATOR",0,1);
00029     lcd.printString("version 1.0",0,2);
00030     lcd.printString("Toby O'Connell",0,4);
00031     wait(3);
00032     
00033     ///Setup callback function for range finder ticker 
00034     startRangingTicker.attach(&startRangingFlag, 0.1);
00035 
00036     ///Set the initial range finder distance 
00037     SRF08.setRangeRegister((int)((numberValues [maxDistance]-43.0)/43.0));
00038     
00039     ///Setup callback function for when MIDI messages are received
00040     midi.attach(receivedMIDI);
00041     
00042     ///Setup callbacks functions for button presses
00043     buttonA.attach_asserted(&aPressed); //Attach functions to button presses
00044     buttonB.attach_asserted(&bPressed);
00045     buttonC.attach_asserted(&cPressed);
00046     buttonD.attach_asserted(&dPressed);
00047     
00048     ///Set button press doubounce freqencies to the default of 20ms
00049     buttonA.setSampleFrequency();
00050     buttonB.setSampleFrequency();
00051     buttonC.setSampleFrequency();
00052     buttonD.setSampleFrequency();
00053     
00054     ///Open the buttons.bmp image in binary, skip the header and copy into a buffer before closing
00055     img  = fopen("/local/BUTTONS.BMP", "rb"); 
00056     fseek (img  , 54 , SEEK_SET); 
00057     fread(imgbuffer , (84*3*48), 1, img );
00058     fclose(img );
00059     
00060     ///Show initial menu
00061     showScreen(); 
00062     ///Create infinite while loop to run program repeatedly
00063     while(1) {
00064         if(aButtonFlag ){
00065             if (menu [state ].screenType == menuType || digitArrowPosition  + 1 >= maxValLen ) {
00066                 ///screenSelect() if button A is pressed and the screen type is a menu or a page type that is confirmed
00067                 screenSelect();
00068             } else {
00069                 ///incrementDigitArrowPos() if button A is pressed and the screen type is not a menu or a page type that is confirmed 
00070                 incrementDigitArrowPos();
00071             }
00072             aButtonFlag  = 0;
00073         }
00074         if(bButtonFlag ){
00075             if (menu [state ].screenType == menuType || digitArrowPosition  - 1 < 0) {
00076                 ///screenBack() if button B is pressed and the screen type is a menu or a page type that is reverted
00077                 screenBack();
00078             } else {
00079                 ///decrementDigitArrowPos() if button B is pressed and the screen type is not a menu or a page type that is confirmed 
00080                 decrementDigitArrowPos();
00081             }
00082             bButtonFlag  = 0;
00083         }
00084         if(cButtonFlag ){
00085             if (menu [state ].screenType == menuType) {
00086                 ///menuUp() if button C is pressed and the screen type is a menu
00087                 menuUp();   
00088             } else {
00089                 ///incrementValue() if button C is pressed and the screen type is not a menu
00090                 incrementValue();
00091             }
00092             cButtonFlag  = 0;
00093         }
00094         if(dButtonFlag ){
00095             if (menu [state ].screenType == menuType) {
00096                 ///menuDown() if button D is pressed and the screen type is a menu
00097                 menuDown();   
00098             } else {
00099                 ///decrementValue() if button D is pressed and the screen type is not a menu
00100                 decrementValue();
00101             }
00102             dButtonFlag  = 0;
00103         }
00104         if(rangingStartFlag ) {
00105             ///Start ranging if the startRangingTicker has fired
00106             rangingStart();
00107             rangingStartFlag  = 0;
00108         }
00109         if(rangeGetFlag ) {
00110             ///Start ranging if the getRangeTimeout has fired
00111             rangeGet();
00112             rangeGetFlag  = 0;
00113         }
00114         if(measuredDistanceFlag ) {
00115             if(numberValues [MIDIOutputOn]) { 
00116                 ///writeMIDI() if the distance has just been measured and MIDI output is on
00117                 writeMIDI(distanceFraction );
00118             }
00119             if(numberValues [resistanceSourceIndex] == sensorSource) {
00120                 ///writeMCP4151() if the distance has just been measured and the resistance source is the ultrasonic sensor
00121                 writeMCP4151(distanceFraction );
00122             }
00123             ///showScreen() if the distance has just been measured and the screen type is the display screen
00124             if(menu [state ].screenType == displayType) showScreen();
00125             measuredDistanceFlag  = 0;
00126         }
00127         if(receivedMIDIFlag ) {
00128             if(numberValues [resistanceSourceIndex] == MIDISource) {
00129                  ///writeMCP4151() if a MIDI message has been received and the resistance source is the MIDI input
00130                 writeMCP4151(receivedMIDIValue /127.0);
00131             }
00132              ///showScreen() if a MIDI message has been received and the screen type is the display screen
00133             if(menu [state ].screenType == displayType) showScreen();
00134             receivedMIDIFlag  = 0;
00135         }
00136     }    
00137 }
00138 
00139 
00140 void aPressed() { aButtonFlag  = 1; } //raise button flags
00141 void bPressed() { bButtonFlag  = 1; }
00142 void cPressed() { cButtonFlag  = 1; }
00143 void dPressed() { dButtonFlag  = 1; }
00144 
00145 void startRangingFlag() { rangingStartFlag  = 1;} //raise ranging star flag
00146 void getRangeFlag() { rangeGetFlag  = 1;} //raise range get flag
00147 
00148 void screenSelect() {
00149     if (menu [state ].screenType == pageType) {
00150         ///If exiting a page type screen checkValidity() and do the immediateUpdates()
00151         checkValidity();
00152         writeNumberValuesToFile();
00153         immediateUpdates();
00154     }
00155     ///Change to the next state based on the menu arrow position
00156     state  = menu [state ].nextState [menuArrowPosition ]; //Set new menu state basted on arrow position
00157     if (menu [state ].screenType == pageType) {
00158         ///if entering a page type screen save the associated value to oldValue for reverting back
00159         oldValue  = numberValues [menu [state ].associatedValueIndex ];
00160     }
00161     ///Reset menu and digit arrow posiitons
00162     menuArrowPosition  = 0; 
00163     digitArrowPosition  = 0;
00164     ///Update the display
00165     showScreen();
00166 }
00167 void screenBack() {
00168     if (menu [state ].screenType == pageType) {
00169         ///If reverting back out of a page type screen set the assoicated value to its previous value
00170         numberValues [menu [state ].associatedValueIndex ] = oldValue ;
00171     }
00172     ///Go to FSM parent state
00173     state  = menu [state ].previousState ;
00174      ///Reset menu and digit arrow posiitons
00175     menuArrowPosition  = 0; 
00176     digitArrowPosition  = 0;
00177     ///Update the display
00178     showScreen();
00179 }
00180 void menuUp() {
00181     ///Decrement the menu arrow position
00182     menuArrowPosition  = (menuArrowPosition  + menu [state ].listLength  - 1) % menu [state ].listLength;
00183     ///Update the display
00184     showScreen(); 
00185 }
00186 void menuDown() {
00187     ///Increment the menu arrow position
00188     menuArrowPosition  = (menuArrowPosition  + 1) % menu [state ].listLength;
00189     ///Update the display
00190     showScreen(); 
00191 }
00192 
00193 void incrementDigitArrowPos() {
00194     ///Increment the digit arrow position
00195     digitArrowPosition  += 1;
00196     ///Update the display
00197     showScreen();
00198 }
00199 void decrementDigitArrowPos() {
00200     ///Increment the digit arrow position
00201     digitArrowPosition  -= 1;
00202     ///Update the display
00203     showScreen(); 
00204 }
00205 
00206 void incrementValue() {
00207     ///Set the increment to '1'
00208     increment  = 1;
00209     ///amend the value
00210     amendValue();
00211 }
00212 
00213 void decrementValue() {
00214     ///Set the increment to '-1'
00215     increment  = -1;
00216     ///amend the value
00217     amendValue();
00218 }
00219 
00220 int amendNumberValue(int value) {
00221     ///Get the digit at the current arrow position
00222     int currentDigit = (int)(value / pow(10.0,maxValLen -1-digitArrowPosition ))%10;
00223     
00224     if((currentDigit == 9 && increment  == + 1) || (currentDigit == 0 && increment  == - 1)) {
00225         ///If the digit is will become greater than 9 or less then 0, wrap around
00226         value = value - increment  * 9 * pow(10.0,maxValLen -1-digitArrowPosition );
00227     } else {
00228         ///If not, increment / decrement the value
00229         value = value + increment  * pow(10.0,maxValLen -1-digitArrowPosition );
00230     }
00231     
00232     ///return the value
00233     return value;
00234 }
00235 
00236 void amendValue() {
00237     
00238     switch(menu [state ].associatedValueType) {
00239         case INT:
00240             ///If the associated is an int style number amendNumberValue()
00241             numberValues [menu [state ].associatedValueIndex ] = amendNumberValue(numberValues [menu[state ].associatedValueIndex]);
00242             break;
00243         case INDEX:
00244             ///If the associated is an index style number increment / decrement it
00245             numberValues [menu[state ].associatedValueIndex] = (maxNumberValues [menu[state ].associatedMaxValueIndex] + numberValues [menu[state ].associatedValueIndex] + increment ) % maxNumberValues [menu[state ].associatedMaxValueIndex];
00246             break;
00247         case BOOL:
00248             ///If the associated is a boolean style number invert it
00249             numberValues [menu[state ].associatedValueIndex] = !numberValues [menu[state ].associatedValueIndex];
00250             break;
00251     }
00252     ///Update the display
00253     showScreen();
00254 }
00255 
00256 
00257 
00258 void showScreen() {
00259     ///Clear the screen
00260     lcd.clear();
00261     ///Show the title
00262     lcd.printString(menu [state ].title,0,0);
00263     if(menu [state ].screenType == menuType) {
00264         for (int i = 0;i <= 3; i++) { 
00265             ///If the screen type is a menu, print the items in its list
00266             lcd.printString(menu [state ].list[i],6,i+1);
00267         }
00268         if(menu [state ].listLength > 0) {
00269             ///if the list has items in it, then show show the menu arrow pointer
00270             lcd.printString(">",0,menuArrowPosition +1); 
00271         }
00272     } else if(menu [state ].screenType == pageType) {
00273         switch (menu [state ].associatedValueType) {
00274         case INT:
00275             ///If the screen type is a parameter editing page and the associated value is an int type number, displayNumber() and show the digit arrow pointer
00276             displayNumber(numberValues [menu [state ].associatedValueIndex],maxNumberValues [menu [state ].associatedMaxValueIndex]);
00277             lcd.printString("^",digitArrowPosition *6+7,3);
00278             break;
00279         case INDEX:
00280             ///If the screen type is a parameter editing page and the associated value is an index type number, displayList()    
00281             displayList(valueLists [menu [state ].associatedValueList],numberValues [menu [state ].associatedValueIndex]);
00282             break;
00283         case BOOL:
00284             ///If the screen type is a parameter editing page and the associated value is a boolean type number, displayBool()
00285             displayBool(numberValues [menu [state ].associatedValueIndex]);
00286             break;
00287         }
00288     } else {
00289         ///If the screen type is the display screen, displayMeasured()
00290         displayMeasured();
00291     }
00292     ///Draw the buttons.bmp image to the screen using drawBMP()
00293     drawBMP();     
00294 }
00295 
00296 void displayNumber(int value, int maxValue) {
00297     char buffer[14];
00298     ///Find the maximum length the incoming value could be
00299     maxValLen  = sprintf(buffer,"%d",maxValue);
00300     ///Find the actual length of the incoming value
00301     valLen  = sprintf(buffer,"%d",value);
00302     ///Print the value to the screen, filling any unused digit spaces with zeros
00303     for(int i = 0; i <= maxValLen  - valLen ; i++) {
00304         lcd.printString("0",6*i+7,2);
00305     }
00306     lcd.printString(buffer,6*(maxValLen -valLen)+7,2);
00307 }
00308 
00309 void displayList(string list[], int listIndex) {
00310     char buffer[14];
00311     maxValLen  = 1;
00312     ///Display the list element at the list index
00313     valLen  = sprintf(buffer,"%s",list[listIndex].c_str());
00314     lcd.printString(buffer,7,2);  
00315 }
00316 
00317 void displayBool(bool toggle) {
00318     char buffer[14];
00319     maxValLen  = 1;
00320     ///Print "On" if the boolean value is 1 and "Off" if the boolean value is 0
00321     valLen  = sprintf(buffer,"%s", toggle ? "On" : "Off");
00322     lcd.printString(buffer,7,2);
00323 }
00324 
00325 void displayMeasured() {
00326     char buffer[14];
00327     ///Print the distance measured by the SRF08
00328     sprintf(buffer,"D: %d",measuredDistance );
00329     lcd.printString(buffer,7,1);
00330     ///If the MIDI output is on, print the MIDI output value, else print "OFF"
00331     if(numberValues [MIDIOutputOn] == 1) {
00332         sprintf(buffer,"MO: %d",(int)(distanceFraction *127));
00333     } else {
00334         sprintf(buffer,"MO: OFF");
00335     }
00336     lcd.printString(buffer,7,2);
00337     ///Print the input MIDI value
00338     sprintf(buffer,"MI: %d",receivedMIDIValue );
00339     lcd.printString(buffer,7,3);
00340     if(numberValues [resistanceSourceIndex] == sensorSource) {
00341         ///If the resistance source is the SRF08, print the resistance based on that distance
00342         sprintf(buffer,"R: %d",(int)(numberValues [minResistance]+distanceFraction *(numberValues [maxResistance]-numberValues [minResistance])));
00343     } else if(numberValues [resistanceSourceIndex] == MIDISource) {
00344         ///If the resistance source is the the MIDI input, print the resistance based on the MIDI value
00345         sprintf(buffer,"R: %d",(int)(numberValues [minResistance]+(receivedMIDIValue /127.0)*(numberValues [maxResistance]-numberValues [minResistance])));
00346     } else {
00347         ///If the resistance source is set to OFF, print "OFF"
00348         sprintf(buffer,"R: OFF");
00349     }
00350     lcd.printString(buffer,7,4);
00351 }
00352 
00353 void rangingStart() {
00354     ///detach the getRangeTimeout
00355     getRangeTimeout.detach();
00356     ///start the SRF08 ranging
00357     SRF08.startRanging(CM);
00358     ///reattach the getRangeTimeout
00359     getRangeTimeout.attach(&getRangeFlag,0.07);
00360 }
00361 
00362 void rangeGet() { 
00363     ///Get the measured distance from the SRF08
00364     measuredDistance  = SRF08.getRange();
00365     //Convert the measuredDistance to a float between 0 and 1
00366     distanceFraction  = (measuredDistance  * 10 - numberValues [minDistance]) / (float)(numberValues [maxDistance]-numberValues [minDistance]);
00367     ///If the distanceFraction is > 1 or < 0, limit it to 1 or 0
00368     if(distanceFraction  > 1) distanceFraction  = 1;
00369     if(distanceFraction  < 0) distanceFraction  = 0;
00370     ///smooth() the distance fraction 
00371     distanceFraction  = smooth(distanceFraction );
00372     measuredDistanceFlag  = 1;
00373 } 
00374 
00375 void receivedMIDI(MIDIMessage msg) {
00376     if(msg.type() == MIDIMessage::ControlChangeType && msg.controller() == numberValues [MIDIInputController] && msg.channel() == numberValues [MIDIInputChannel]) {  
00377         ///If the MIDI message is the right controller change on the right channel, save the value
00378         receivedMIDIValue  = msg.value();
00379         receivedMIDIFlag  = 1;
00380     }
00381 }
00382 
00383 
00384 float smooth(float value) {
00385     ///Erase the first element in the smoothing vector
00386     smoothingValues .erase(smoothingValues .begin());
00387     ///Add the value to the end of the smoothing vector
00388     smoothingValues .push_back(value);
00389     ///Sum the values in the smoothing vector
00390     float sum = 0;
00391     for(int i = 0; i < smoothingValues .size(); i++) {
00392         sum += smoothingValues [i];
00393     }    
00394     ///Return the mean average of the smoothing vector contents
00395     return sum/(smoothingValues .size());
00396 }
00397 
00398 
00399 
00400 void writeMCP4151(float value) {
00401     ///Scale the max and min resistances for 0 to 10000 down to 0 to 255.
00402     int scaledMax = (int)(numberValues [maxResistance]/(10000/255.0));
00403     int scaledMin = (int)(numberValues [minResistance]/(10000/255.0));
00404     ///Convert the 0 to 1 float value to a 0 to 255 int value for the MCP4151 SPI digital potentiometer
00405     int writeValue = (int)(1 + scaledMin + value * (scaledMax - scaledMin));
00406     ///Chip enable
00407     CS = 0;
00408     ///Write the new value
00409     MCP4151.write(writeValue);
00410     ///Chip disable
00411     CS = 1;
00412 }
00413 
00414 void writeMIDI(float value) {
00415     ///Convert the 0 to 1 float valye to 0 to 127 int value for the MIDI message
00416     int writeValue = (int)(value * 127);
00417     ///Write the 0 to 255 value to the MIDI output
00418     midi.write(MIDIMessage::ControlChange(numberValues [MIDIOutputController],writeValue,numberValues [MIDIOutputChannel]));   
00419 }
00420 
00421 void drawBMP() {
00422     ///Iterate through each pixel in the image buffer
00423     for (int i = 0; i < 84*48 ; i++) {
00424         if (imgbuffer [i*3] == 0) { 
00425             ///If the pixel is not white, write it to the screen
00426             lcd.setPixel(i%84,47-(int)(i/84));
00427         }
00428     }
00429     lcd.refresh();
00430 }
00431 
00432 void readNumberValuesFromFile() {
00433     ///Open the VALS.csv file
00434     ifstream csvValuesRead("/local/VALS.csv");
00435     for(int i = 0; i < 11; i++) {
00436         ///Copy each line of the csv file to a each element in the numberValues array
00437         string line;
00438         getline(csvValuesRead, line);          
00439         stringstream convertor(line);
00440         convertor >> numberValues [i];
00441     }
00442     ///Close the VALS.csv file
00443     csvValuesRead.close();
00444 }
00445 
00446 void writeNumberValuesToFile() {
00447     ///Open the VALS.csv file
00448     FILE *csvValuesWrite = fopen("/local/VALS.csv","w");
00449     for(int i = 0; i < 11; i++) {
00450         ///Write each element in the numberValues array to each line in the csv file
00451         fprintf(csvValuesWrite,"%d\n",numberValues [i]);
00452     }
00453     ///Close the VALS.csv file
00454     fclose(csvValuesWrite);
00455 }
00456 
00457 void checkValidity() {
00458     if(numberValues [menu [state ].associatedValueIndex] > maxNumberValues [menu [state ].associatedMaxValueIndex]) {
00459         ///If the associated value is greater than the associated max value after being altered, revert back to the original
00460         numberValues [menu [state ].associatedValueIndex ] = oldValue ;
00461     }
00462     if(numberValues [minResistance] >= numberValues [maxResistance]) {
00463         if(menu [state ].associatedValueIndex == minResistance) {
00464             ///If the min resistance is greater than the max resistance make it 1 less than the maximum
00465             numberValues [minResistance] = numberValues [maxResistance] - 1;
00466         } else {
00467             ///If the max resistance is less than the max resistance make it 1 more than the minimum
00468             numberValues [maxResistance] = numberValues [minResistance] + 1;
00469         }
00470     }
00471     if(numberValues [minDistance] >= numberValues [maxDistance]) {
00472         if(menu [state ].associatedValueIndex == minDistance) {
00473             ///If the min distance is greater than the max distance make it 1 less than the maximum
00474             numberValues [minDistance] = numberValues [maxDistance] - 1;
00475         } else {
00476             ///If the max distance is less than the max distance make it 1 more than the minimum
00477             numberValues [maxDistance] = numberValues [minDistance] + 1;
00478         }
00479     }
00480 }
00481 
00482 void immediateUpdates() {
00483     if(menu [state ].associatedValueIndex == maxDistance) {
00484         ///If the associated value is the max distance, set the range of the SRF08
00485         SRF08.setRangeRegister((int)((numberValues [maxDistance]-43.0)/43.0));
00486     }
00487     if(menu [state ].associatedValueIndex == distanceSmoothing) {
00488         ///If the associated value is the distanceSmoothing value, resize the smoothingValues vector
00489         smoothingValues .resize(numberValues [distanceSmoothing]+1);
00490     }
00491 }