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
main.cpp
- Committer:
- el13tjoc
- Date:
- 2015-05-11
- Revision:
- 1:802453187acf
- Parent:
- 0:39399720eaeb
File content as of revision 1:802453187acf:
/** @file main.cpp @brief Program implementation */ #include "main.h" int main() { ///Powerdown the Ethernet peripheral PHY_PowerDown(); ///Read parameter variables from VALS.csv readNumberValuesFromFile(); ///Resise the smoothing values vector smoothingValues.resize(numberValues[distanceSmoothing]+1); ///Set MCP4151 chip select high initially CS = 1; /// Set the MCP4151 SPI for 16 bit mode 3 MCP4151.format(16,3); /// Set MCP4151 clock frequency to 1000000 MCP4151.frequency(1000000); ///Initialise the screen and print splash screen lcd.init(); lcd.printString("EXPRESSIONATOR",0,1); lcd.printString("version 1.0",0,2); lcd.printString("Toby O'Connell",0,4); wait(3); ///Setup callback function for range finder ticker startRangingTicker.attach(&startRangingFlag, 0.1); ///Set the initial range finder distance SRF08.setRangeRegister((int)((numberValues[maxDistance]-43.0)/43.0)); ///Setup callback function for when MIDI messages are received midi.attach(receivedMIDI); ///Setup callbacks functions for button presses buttonA.attach_asserted(&aPressed); //Attach functions to button presses buttonB.attach_asserted(&bPressed); buttonC.attach_asserted(&cPressed); buttonD.attach_asserted(&dPressed); ///Set button press doubounce freqencies to the default of 20ms buttonA.setSampleFrequency(); buttonB.setSampleFrequency(); buttonC.setSampleFrequency(); buttonD.setSampleFrequency(); ///Open the buttons.bmp image in binary, skip the header and copy into a buffer before closing img = fopen("/local/BUTTONS.BMP", "rb"); fseek (img , 54 , SEEK_SET); fread(imgbuffer, (84*3*48), 1, img); fclose(img); ///Show initial menu showScreen(); ///Create infinite while loop to run program repeatedly while(1) { if(aButtonFlag){ if (menu[state].screenType == menuType || digitArrowPosition + 1 >= maxValLen) { ///screenSelect() if button A is pressed and the screen type is a menu or a page type that is confirmed screenSelect(); } else { ///incrementDigitArrowPos() if button A is pressed and the screen type is not a menu or a page type that is confirmed incrementDigitArrowPos(); } aButtonFlag = 0; } if(bButtonFlag){ if (menu[state].screenType == menuType || digitArrowPosition - 1 < 0) { ///screenBack() if button B is pressed and the screen type is a menu or a page type that is reverted screenBack(); } else { ///decrementDigitArrowPos() if button B is pressed and the screen type is not a menu or a page type that is confirmed decrementDigitArrowPos(); } bButtonFlag = 0; } if(cButtonFlag){ if (menu[state].screenType == menuType) { ///menuUp() if button C is pressed and the screen type is a menu menuUp(); } else { ///incrementValue() if button C is pressed and the screen type is not a menu incrementValue(); } cButtonFlag = 0; } if(dButtonFlag){ if (menu[state].screenType == menuType) { ///menuDown() if button D is pressed and the screen type is a menu menuDown(); } else { ///decrementValue() if button D is pressed and the screen type is not a menu decrementValue(); } dButtonFlag = 0; } if(rangingStartFlag) { ///Start ranging if the startRangingTicker has fired rangingStart(); rangingStartFlag = 0; } if(rangeGetFlag) { ///Start ranging if the getRangeTimeout has fired rangeGet(); rangeGetFlag = 0; } if(measuredDistanceFlag) { if(numberValues[MIDIOutputOn]) { ///writeMIDI() if the distance has just been measured and MIDI output is on writeMIDI(distanceFraction); } if(numberValues[resistanceSourceIndex] == sensorSource) { ///writeMCP4151() if the distance has just been measured and the resistance source is the ultrasonic sensor writeMCP4151(distanceFraction); } ///showScreen() if the distance has just been measured and the screen type is the display screen if(menu[state].screenType == displayType) showScreen(); measuredDistanceFlag = 0; } if(receivedMIDIFlag) { if(numberValues[resistanceSourceIndex] == MIDISource) { ///writeMCP4151() if a MIDI message has been received and the resistance source is the MIDI input writeMCP4151(receivedMIDIValue/127.0); } ///showScreen() if a MIDI message has been received and the screen type is the display screen if(menu[state].screenType == displayType) showScreen(); receivedMIDIFlag = 0; } } } void aPressed() { aButtonFlag = 1; } //raise button flags void bPressed() { bButtonFlag = 1; } void cPressed() { cButtonFlag = 1; } void dPressed() { dButtonFlag = 1; } void startRangingFlag() { rangingStartFlag = 1;} //raise ranging star flag void getRangeFlag() { rangeGetFlag = 1;} //raise range get flag void screenSelect() { if (menu[state].screenType == pageType) { ///If exiting a page type screen checkValidity() and do the immediateUpdates() checkValidity(); writeNumberValuesToFile(); immediateUpdates(); } ///Change to the next state based on the menu arrow position state = menu[state].nextState[menuArrowPosition]; //Set new menu state basted on arrow position if (menu[state].screenType == pageType) { ///if entering a page type screen save the associated value to oldValue for reverting back oldValue = numberValues[menu[state].associatedValueIndex]; } ///Reset menu and digit arrow posiitons menuArrowPosition = 0; digitArrowPosition = 0; ///Update the display showScreen(); } void screenBack() { if (menu[state].screenType == pageType) { ///If reverting back out of a page type screen set the assoicated value to its previous value numberValues[menu[state].associatedValueIndex] = oldValue; } ///Go to FSM parent state state = menu[state].previousState; ///Reset menu and digit arrow posiitons menuArrowPosition = 0; digitArrowPosition = 0; ///Update the display showScreen(); } void menuUp() { ///Decrement the menu arrow position menuArrowPosition = (menuArrowPosition + menu[state].listLength - 1) % menu[state].listLength; ///Update the display showScreen(); } void menuDown() { ///Increment the menu arrow position menuArrowPosition = (menuArrowPosition + 1) % menu[state].listLength; ///Update the display showScreen(); } void incrementDigitArrowPos() { ///Increment the digit arrow position digitArrowPosition += 1; ///Update the display showScreen(); } void decrementDigitArrowPos() { ///Increment the digit arrow position digitArrowPosition -= 1; ///Update the display showScreen(); } void incrementValue() { ///Set the increment to '1' increment = 1; ///amend the value amendValue(); } void decrementValue() { ///Set the increment to '-1' increment = -1; ///amend the value amendValue(); } int amendNumberValue(int value) { ///Get the digit at the current arrow position int currentDigit = (int)(value / pow(10.0,maxValLen-1-digitArrowPosition))%10; if((currentDigit == 9 && increment == + 1) || (currentDigit == 0 && increment == - 1)) { ///If the digit is will become greater than 9 or less then 0, wrap around value = value - increment * 9 * pow(10.0,maxValLen-1-digitArrowPosition); } else { ///If not, increment / decrement the value value = value + increment * pow(10.0,maxValLen-1-digitArrowPosition); } ///return the value return value; } void amendValue() { switch(menu[state].associatedValueType) { case INT: ///If the associated is an int style number amendNumberValue() numberValues[menu[state].associatedValueIndex] = amendNumberValue(numberValues[menu[state].associatedValueIndex]); break; case INDEX: ///If the associated is an index style number increment / decrement it numberValues[menu[state].associatedValueIndex] = (maxNumberValues[menu[state].associatedMaxValueIndex] + numberValues[menu[state].associatedValueIndex] + increment) % maxNumberValues[menu[state].associatedMaxValueIndex]; break; case BOOL: ///If the associated is a boolean style number invert it numberValues[menu[state].associatedValueIndex] = !numberValues[menu[state].associatedValueIndex]; break; } ///Update the display showScreen(); } void showScreen() { ///Clear the screen lcd.clear(); ///Show the title lcd.printString(menu[state].title,0,0); if(menu[state].screenType == menuType) { for (int i = 0;i <= 3; i++) { ///If the screen type is a menu, print the items in its list lcd.printString(menu[state].list[i],6,i+1); } if(menu[state].listLength > 0) { ///if the list has items in it, then show show the menu arrow pointer lcd.printString(">",0,menuArrowPosition+1); } } else if(menu[state].screenType == pageType) { switch (menu[state].associatedValueType) { case INT: ///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 displayNumber(numberValues[menu[state].associatedValueIndex],maxNumberValues[menu[state].associatedMaxValueIndex]); lcd.printString("^",digitArrowPosition*6+7,3); break; case INDEX: ///If the screen type is a parameter editing page and the associated value is an index type number, displayList() displayList(valueLists[menu[state].associatedValueList],numberValues[menu[state].associatedValueIndex]); break; case BOOL: ///If the screen type is a parameter editing page and the associated value is a boolean type number, displayBool() displayBool(numberValues[menu[state].associatedValueIndex]); break; } } else { ///If the screen type is the display screen, displayMeasured() displayMeasured(); } ///Draw the buttons.bmp image to the screen using drawBMP() drawBMP(); } void displayNumber(int value, int maxValue) { char buffer[14]; ///Find the maximum length the incoming value could be maxValLen = sprintf(buffer,"%d",maxValue); ///Find the actual length of the incoming value valLen = sprintf(buffer,"%d",value); ///Print the value to the screen, filling any unused digit spaces with zeros for(int i = 0; i <= maxValLen - valLen; i++) { lcd.printString("0",6*i+7,2); } lcd.printString(buffer,6*(maxValLen-valLen)+7,2); } void displayList(string list[], int listIndex) { char buffer[14]; maxValLen = 1; ///Display the list element at the list index valLen = sprintf(buffer,"%s",list[listIndex].c_str()); lcd.printString(buffer,7,2); } void displayBool(bool toggle) { char buffer[14]; maxValLen = 1; ///Print "On" if the boolean value is 1 and "Off" if the boolean value is 0 valLen = sprintf(buffer,"%s", toggle ? "On" : "Off"); lcd.printString(buffer,7,2); } void displayMeasured() { char buffer[14]; ///Print the distance measured by the SRF08 sprintf(buffer,"D: %d",measuredDistance); lcd.printString(buffer,7,1); ///If the MIDI output is on, print the MIDI output value, else print "OFF" if(numberValues[MIDIOutputOn] == 1) { sprintf(buffer,"MO: %d",(int)(distanceFraction*127)); } else { sprintf(buffer,"MO: OFF"); } lcd.printString(buffer,7,2); ///Print the input MIDI value sprintf(buffer,"MI: %d",receivedMIDIValue); lcd.printString(buffer,7,3); if(numberValues[resistanceSourceIndex] == sensorSource) { ///If the resistance source is the SRF08, print the resistance based on that distance sprintf(buffer,"R: %d",(int)(numberValues[minResistance]+distanceFraction*(numberValues[maxResistance]-numberValues[minResistance]))); } else if(numberValues[resistanceSourceIndex] == MIDISource) { ///If the resistance source is the the MIDI input, print the resistance based on the MIDI value sprintf(buffer,"R: %d",(int)(numberValues[minResistance]+(receivedMIDIValue/127.0)*(numberValues[maxResistance]-numberValues[minResistance]))); } else { ///If the resistance source is set to OFF, print "OFF" sprintf(buffer,"R: OFF"); } lcd.printString(buffer,7,4); } void rangingStart() { ///detach the getRangeTimeout getRangeTimeout.detach(); ///start the SRF08 ranging SRF08.startRanging(CM); ///reattach the getRangeTimeout getRangeTimeout.attach(&getRangeFlag,0.07); } void rangeGet() { ///Get the measured distance from the SRF08 measuredDistance = SRF08.getRange(); //Convert the measuredDistance to a float between 0 and 1 distanceFraction = (measuredDistance * 10 - numberValues[minDistance]) / (float)(numberValues[maxDistance]-numberValues[minDistance]); ///If the distanceFraction is > 1 or < 0, limit it to 1 or 0 if(distanceFraction > 1) distanceFraction = 1; if(distanceFraction < 0) distanceFraction = 0; ///smooth() the distance fraction distanceFraction = smooth(distanceFraction); measuredDistanceFlag = 1; } void receivedMIDI(MIDIMessage msg) { if(msg.type() == MIDIMessage::ControlChangeType && msg.controller() == numberValues[MIDIInputController] && msg.channel() == numberValues[MIDIInputChannel]) { ///If the MIDI message is the right controller change on the right channel, save the value receivedMIDIValue = msg.value(); receivedMIDIFlag = 1; } } float smooth(float value) { ///Erase the first element in the smoothing vector smoothingValues.erase(smoothingValues.begin()); ///Add the value to the end of the smoothing vector smoothingValues.push_back(value); ///Sum the values in the smoothing vector float sum = 0; for(int i = 0; i < smoothingValues.size(); i++) { sum += smoothingValues[i]; } ///Return the mean average of the smoothing vector contents return sum/(smoothingValues.size()); } void writeMCP4151(float value) { ///Scale the max and min resistances for 0 to 10000 down to 0 to 255. int scaledMax = (int)(numberValues[maxResistance]/(10000/255.0)); int scaledMin = (int)(numberValues[minResistance]/(10000/255.0)); ///Convert the 0 to 1 float value to a 0 to 255 int value for the MCP4151 SPI digital potentiometer int writeValue = (int)(1 + scaledMin + value * (scaledMax - scaledMin)); ///Chip enable CS = 0; ///Write the new value MCP4151.write(writeValue); ///Chip disable CS = 1; } void writeMIDI(float value) { ///Convert the 0 to 1 float valye to 0 to 127 int value for the MIDI message int writeValue = (int)(value * 127); ///Write the 0 to 255 value to the MIDI output midi.write(MIDIMessage::ControlChange(numberValues[MIDIOutputController],writeValue,numberValues[MIDIOutputChannel])); } void drawBMP() { ///Iterate through each pixel in the image buffer for (int i = 0; i < 84*48 ; i++) { if (imgbuffer[i*3] == 0) { ///If the pixel is not white, write it to the screen lcd.setPixel(i%84,47-(int)(i/84)); } } lcd.refresh(); } void readNumberValuesFromFile() { ///Open the VALS.csv file ifstream csvValuesRead("/local/VALS.csv"); for(int i = 0; i < 11; i++) { ///Copy each line of the csv file to a each element in the numberValues array string line; getline(csvValuesRead, line); stringstream convertor(line); convertor >> numberValues[i]; } ///Close the VALS.csv file csvValuesRead.close(); } void writeNumberValuesToFile() { ///Open the VALS.csv file FILE *csvValuesWrite = fopen("/local/VALS.csv","w"); for(int i = 0; i < 11; i++) { ///Write each element in the numberValues array to each line in the csv file fprintf(csvValuesWrite,"%d\n",numberValues[i]); } ///Close the VALS.csv file fclose(csvValuesWrite); } void checkValidity() { if(numberValues[menu[state].associatedValueIndex] > maxNumberValues[menu[state].associatedMaxValueIndex]) { ///If the associated value is greater than the associated max value after being altered, revert back to the original numberValues[menu[state].associatedValueIndex] = oldValue; } if(numberValues[minResistance] >= numberValues[maxResistance]) { if(menu[state].associatedValueIndex == minResistance) { ///If the min resistance is greater than the max resistance make it 1 less than the maximum numberValues[minResistance] = numberValues[maxResistance] - 1; } else { ///If the max resistance is less than the max resistance make it 1 more than the minimum numberValues[maxResistance] = numberValues[minResistance] + 1; } } if(numberValues[minDistance] >= numberValues[maxDistance]) { if(menu[state].associatedValueIndex == minDistance) { ///If the min distance is greater than the max distance make it 1 less than the maximum numberValues[minDistance] = numberValues[maxDistance] - 1; } else { ///If the max distance is less than the max distance make it 1 more than the minimum numberValues[maxDistance] = numberValues[minDistance] + 1; } } } void immediateUpdates() { if(menu[state].associatedValueIndex == maxDistance) { ///If the associated value is the max distance, set the range of the SRF08 SRF08.setRangeRegister((int)((numberValues[maxDistance]-43.0)/43.0)); } if(menu[state].associatedValueIndex == distanceSmoothing) { ///If the associated value is the distanceSmoothing value, resize the smoothingValues vector smoothingValues.resize(numberValues[distanceSmoothing]+1); } }