/*
Zeus Commander Controller Series
This code is in the public domain.
*/
#include <Bounce.h>
#include <Encoder.h>
#include "GOLDELOX.h"
GOLDELOX oledDisplay(&Serial2);
// USBMidi
usbMIDI.setHandleSysEx(handleSysEx);
//global variables
#define mwIButtonPin 4
#define mwXTButtonPin 5
#define esqMButtonPin 6
#define genericModeButtonPin 7
int bounceTime=5;
Bounce modeButton[4]={Bounce(mwIButtonPin,bounceTime),
Bounce(mwXTButtonPin,bounceTime),
Bounce(esqMButtonPin,bounceTime),
Bounce(genericModeButtonPin,bounceTime),};
elapsedMicros sinceButtonCheck; // timer for button check
unsigned int buttonCheckInterval=2000; // interval in microseconds for checking buttons
enum buttonNames{mwI,mwXT,esqM,genericMode};
enum buttonIcons{allUp,mwIdownProgram,mwIdownMulti,mwXTdownProgram,mwXTdownMulti,esqMdown,genericModedown};
uint32_t buttonIconAddress[7]={0x00003c00,0x00005E00,0x00008000,0x0000A200,0x0000C400,0x0000E600,0x00003c00};
// program modes
enum programModes{mwIsound,mwImulti,mwXTsound,mwXTmulti,esqMsound,universal};
uint32_t deviceIconAddress[6]={0x00013C00,0x00013C00,0x00017000,0x00017000,0x0001A400,0x00010800};
int currentProgram[6]={0,0,0,0,0,0};
const int maxProgramNumber[6]={127,127,127,127,119,127}; // maximum program number, used for constraint.
int buttonIcon=allUp;
int programMode=universal;
int mwImode=mwIsound;
int mwXTmode=mwXTsound;
const byte mwIversionNumberRequest[7] = {0xF0,0x3E,0x00,0x00,0x00,0x00,0xF7};
const byte mwIprogramDumpRequest[7] = {0xF0,0x3E,0x00,0x00,0x02,0x00,0xF7};
const byte mwIprogramBankDumpRequest[7] = {0xF0,0x3E,0x00,0x00,0x10,0x00,0xF7};
Encoder encoder(14,15);
long currentEncoderValue=0;
int parameterValue=0;
elapsedMillis sinceDisplayUpdate; // timer for oledDisplay update
unsigned int displayUpdateInterval=50; //
boolean updateDisplay=false;
elapsedMillis sysexRequestTime; // timer for syex request timeout
unsigned int sysexTimeout=5000; // timeout for sysex requests
const char* programNumbersMWXT[256] = {"A 1 \n","A 2 \n","A 3 \n","A 4 \n","A 5 \n","A 6 \n","A 7 \n","A 8 \n","A 9 \n","A 10 \n","A 11 \n","A 12 \n","A 13 \n","A 14 \n","A 15 \n","A 16 \n",
"A 17 \n","A 18 \n","A 19 \n","A 20 \n","A 21 \n","A 22 \n","A 23 \n","A 24 \n","A 25 \n","A 26 \n","A 27 \n","A 28 \n","A 29 \n","A 30 \n","A 31 \n","A 32 \n",
"A 33 \n","A 34 \n","A 35 \n","A 36 \n","A 37 \n","A 38 \n","A 39 \n","A 40 \n","A 41 \n","A 42 \n","A 43 \n","A 44 \n","A 45 \n","A 46 \n","A 47 \n","A 48 \n",
"A 49 \n","A 50 \n","A 51 \n","A 52 \n","A 53 \n","A 54 \n","A 55 \n","A 56 \n","A 57 \n","A 58 \n","A 59 \n","A 60 \n","A 61 \n","A 62 \n","A 63 \n","A 64 \n",
"A 65 \n","A 66 \n","A 67 \n","A 68 \n","A 69 \n","A 70 \n","A 71 \n","A 72 \n","A 73 \n","A 74 \n","A 75 \n","A 76 \n","A 77 \n","A 78 \n","A 79 \n","A 80 \n",
"A 81 \n","A 82 \n","A 83 \n","A 84 \n","A 85 \n","A 86 \n","A 87 \n","A 88 \n","A 89 \n","A 90 \n","A 91 \n","A 92 \n","A 93 \n","A 94 \n","A 95 \n","A 96 \n",
"A 97 \n","A 98 \n","A 99 \n","A100 \n","A101 \n","A102 \n","A103 \n","A104 \n","A105 \n","A106 \n","A107 \n","A108 \n","A109 \n","A110 \n","A111 \n","A112 \n",
"A113 \n","A114 \n","A115 \n","A116 \n","A117 \n","A118 \n","A119 \n","A120 \n","A121 \n","A122 \n","A123 \n","A124 \n","A125 \n","A126 \n","A127 \n","A128 \n",
"B 1 \n","B 2 \n","B 3 \n","B 4 \n","B 5 \n","B 6 \n","B 7 \n","B 8 \n","B 9 \n","B 10 \n","B 11 \n","B 12 \n","B 13 \n","B 14 \n","B 15 \n","B 16 \n",
"B 17 \n","B 18 \n","B 19 \n","B 20 \n","B 21 \n","B 22 \n","B 23 \n","B 24 \n","B 25 \n","B 26 \n","B 27 \n","B 28 \n","B 29 \n","B 30 \n","B 31 \n","B 32 \n",
"B 33 \n","B 34 \n","B 35 \n","B 36 \n","B 37 \n","B 38 \n","B 39 \n","B 40 \n","B 41 \n","B 42 \n","B 43 \n","B 44 \n","B 45 \n","B 46 \n","B 47 \n","B 48 \n",
"B 49 \n","B 50 \n","B 51 \n","B 52 \n","B 53 \n","B 54 \n","B 55 \n","B 56 \n","B 57 \n","B 58 \n","B 59 \n","B 60 \n","B 61 \n","B 62 \n","B 63 \n","B 64 \n",
"B 65 \n","B 66 \n","B 67 \n","B 68 \n","B 69 \n","B 70 \n","B 71 \n","B 72 \n","B 73 \n","B 74 \n","B 75 \n","B 76 \n","B 77 \n","B 78 \n","B 79 \n","B 80 \n",
"B 81 \n","B 82 \n","B 83 \n","B 84 \n","B 85 \n","B 86 \n","B 87 \n","B 88 \n","B 89 \n","B 90 \n","B 91 \n","B 92 \n","B 93 \n","B 94 \n","B 95 \n","B 96 \n",
"B 97 \n","B 98 \n","B 99 \n","B100 \n","B101 \n","B102 \n","B103 \n","B104 \n","B105 \n","B106 \n","B107 \n","B108 \n","B109 \n","B110 \n","B111 \n","B112 \n",
"B113 \n","B114 \n","B115 \n","B116 \n","B117 \n","B118 \n","B119 \n","B120 \n","B121 \n","B122 \n","B123 \n","B124 \n","B125 \n","B126 \n","B127 \n","B128 \n"};
const char* programNumbersMWI[128] = {"A 1 \n","A 2 \n","A 3 \n","A 4 \n","A 5 \n","A 6 \n","A 7 \n","A 8 \n",
"A 9 \n","A 10 \n","A 11 \n","A 12 \n","A 13 \n","A 14 \n","A 15 \n","A 16 \n",
"A 17 \n","A 18 \n","A 19 \n","A 20 \n","A 21 \n","A 22 \n","A 23 \n","A 24 \n",
"A 25 \n","A 26 \n","A 27 \n","A 28 \n","A 29 \n","A 30 \n","A 31 \n","A 32 \n",
"B 1 \n","B 2 \n","B 3 \n","B 4 \n","B 5 \n","B 6 \n","B 7 \n","B 8 \n",
"B 9 \n","B 10 \n","B 11 \n","B 12 \n","B 13 \n","B 14 \n","B 15 \n","B 16 \n",
"B 17 \n","B 18 \n","B 19 \n","B 20 \n","B 21 \n","B 22 \n","B 23 \n","B 24 \n",
"B 25 \n","B 26 \n","B 27 \n","B 28 \n","B 29 \n","B 30 \n","B 31 \n","B 32 \n",
"C 1 \n","C 2 \n","C 3 \n","C 4 \n","C 5 \n","C 6 \n","C 7 \n","C 8 \n",
"C 9 \n","C 10 \n","C 11 \n","C 12 \n","C 13 \n","C 14 \n","C 15 \n","C 16 \n",
"C 17 \n","C 18 \n","C 19 \n","C 20 \n","C 21 \n","C 22 \n","C 23 \n","C 24 \n",
"C 25 \n","C 26 \n","C 27 \n","C 28 \n","C 29 \n","C 30 \n","C 31 \n","C 32 \n",
"D 1 \n","D 2 \n","D 3 \n","D 4 \n","D 5 \n","D 6 \n","D 7 \n","D 8 \n",
"D 9 \n","D 10 \n","D 11 \n","D 12 \n","D 13 \n","D 14 \n","D 15 \n","D 16 \n",
"D 17 \n","D 18 \n","D 19 \n","D 20 \n","D 21 \n","D 22 \n","D 23 \n","D 24 \n",
"D 25 \n","D 26 \n","D 27 \n","D 28 \n","D 29 \n","D 30 \n","D 31 \n","D 32 \n",};
// This routine will try to mount and initialize the uSD card. If successful,
// it returns a TRUE, otherwise FALSE.
int led = 13;
boolean fmediatests;
// handle incoming sysex messages
void handleSysEx(byte* sysExData,unsigned int sysExSize,bool complete)
{
Serial.print("The sysex length is ");
Serial.print(sysExSize);
Serial.print(" bytes\t");
Serial.println(" ");
}
void setup() {
uint16_t result;
// put your setup code here, to run once:
delay (2000); //let the display start up
Serial2.begin(115200);
// define pin modes for led pins:
pinMode(mwIButtonPin,INPUT_PULLUP);
pinMode(mwXTButtonPin,INPUT_PULLUP);
pinMode(esqMButtonPin,INPUT_PULLUP);
pinMode(genericModeButtonPin,INPUT_PULLUP);
//--------------------------------Optional reset routine-----------------------------------
//Reset the Display using D4 of the Arduino (if using the new 4D Arduino Adaptor - Rev 2)
//If using the old 4D Arduino Adaptor (Rev 1), change D4 to D2 below.
//If using jumper wires, reverse the logic states below.
//Refer to the accompanying application note for important information.
pinMode(2, OUTPUT); // Set D4 on Arduino to Output (4D Arduino Adaptor V2 - Display Reset)
digitalWrite(2,0); // Reset the Display via D2
delay(100);
digitalWrite(2,1); // unReset the Display via D4
//-----------------------------------------END---------------------------------------------
delay (4000); //let the display start up
oledDisplay.putString((char *)" \n");
oledDisplay.mediaInit(&result) ;
delay(100);
// CLEAR 40 pixels high
oledDisplay.setByteAddress(0x00010800);
oledDisplay.displayImageRaw(0, 0) ;
delay(100);
oledDisplay.setSectorAddress(0x0000);
oledDisplay.setFont(7);
oledDisplay.moveCursor(0,0);
oledDisplay.putString((char *)"Sound\n");
oledDisplay.moveCursor(8,0);
displayProgramNumber(currentProgram[programMode]);
// test buttons
// ALL UP
delay(100);
oledDisplay.setByteAddress(0x00003c00);
oledDisplay.displayImageRaw(0, 94) ;
}
void loop() {
//usbMIDI
usbMIDI.read();
// check elapsedMicros and millis timers
if (sinceButtonCheck >=buttonCheckInterval) {
sinceButtonCheck = sinceButtonCheck - buttonCheckInterval;
handleButtons();
handleEncoder();
}
if (sinceDisplayUpdate >=displayUpdateInterval) {
sinceDisplayUpdate = sinceDisplayUpdate - displayUpdateInterval;
handleDisplay();
}
}
// handle soft buttons
void handleButtons(){
// array for current button state
int buttonState[4];
// update buttons and variable
for (int i=0;i<4;i++){
modeButton[i].update();
buttonState[i]=modeButton[i].read();
}
// buttons: mwI, mwXT, esqM, genericMode
// program modes: mwIsound, mwImulti, mwXTsound, mwXTmulti, esqM, universal
// buttonIcons: allUp,mwIdownProgram, mwIdownMulti, mwXTdownProgram, mwXTdownMulti, esqMdown, genericModedown
// microwave I button pressed
if (buttonState[mwI]==LOW && buttonState[mwXT]==HIGH && buttonState[esqM]==HIGH && buttonState[genericMode]==HIGH){
if (mwImode==mwIsound){
if(buttonIcon!=mwIdownProgram){
//button mwIdown multi choice
setButtonState(mwIdownProgram);
}
} else if (mwImode==mwImulti){
if(buttonIcon!=mwIdownMulti){
//button mwIdown program choice
setButtonState(mwIdownMulti);
}
}
if (programMode==mwXTsound || programMode==mwXTmulti || programMode==esqMsound || programMode==universal){
switchProgramMode(mwImode);
}
if( modeButton[esqM].risingEdge()){
if (mwImode==mwIsound){
mwImode=mwImulti;
programMode=mwImulti;
oledDisplay.moveCursor(0,0);
oledDisplay.putString((char *)"Multi \n");
updateDisplay=true;
} else if (mwImode==mwImulti){
mwImode=mwIsound;
programMode=mwIsound;
oledDisplay.moveCursor(0,0);
oledDisplay.putString((char *)"Sound\n");
updateDisplay=true;
}
}
if( modeButton[genericMode].risingEdge()){
usbMIDI.sendSysEx(7,mwIversionNumberRequest);
}
}
// microwave XT button pressed
if (buttonState[mwI]==HIGH && buttonState[mwXT]==LOW && buttonState[esqM]==HIGH && buttonState[genericMode]==HIGH){
//show mwXT button pressed
if(mwXTmode==mwXTsound){
if(buttonIcon!=mwXTdownProgram){
//button mwXTdown multi choice
setButtonState(mwXTdownProgram);
}
}else if (mwXTmode==mwXTmulti){
if(buttonIcon!=mwXTdownMulti){
//button mwXTdown multi choice
setButtonState(mwXTdownMulti);
}
}
if (programMode==mwIsound || programMode == mwImulti || programMode==esqMsound || programMode==universal){
switchProgramMode(mwXTmode);
}
if( modeButton[esqM].risingEdge()){
if (mwXTmode==mwXTsound){
mwXTmode=mwXTmulti;
programMode=mwXTmulti;
oledDisplay.moveCursor(0,0);
oledDisplay.putString((char *)"Multi \n");
// updateDisplay=true;
} else if (mwXTmode==mwXTmulti){
mwXTmode=mwXTsound;
programMode=mwXTsound;
oledDisplay.moveCursor(0,0);
oledDisplay.putString((char *)"Sound\n");
// updateDisplay=true;
}
}
}
// esqM button pressed
if (buttonState[mwI]==HIGH && buttonState[mwXT]==HIGH && buttonState[esqM]==LOW && buttonState[genericMode]==HIGH){
//show esqM button pressed
if (buttonIcon!=esqMdown){
setButtonState(esqMdown);
}
if (programMode!=esqMsound){
switchProgramMode(esqMsound);
}
}
// generic mode button pressed
if (buttonState[mwI]==HIGH && buttonState[mwXT]==HIGH && buttonState[esqM]==HIGH && buttonState[genericMode]==LOW){
//show all buttons up
if (buttonIcon!=allUp){
setButtonState(allUp);
}
if (programMode!=universal){
switchProgramMode(universal);
}
}
// all buttons up
if (buttonState[mwI]==HIGH && buttonState[mwXT]==HIGH && buttonState[esqM]==HIGH && buttonState[genericMode]==HIGH){
//show all buttons up
if (buttonIcon!=allUp){
setButtonState(allUp);
}
}
}
// set button state and update button icon
void setButtonState(int state){
buttonIcon=state;
oledDisplay.setByteAddress(buttonIconAddress[buttonIcon]);
oledDisplay.displayImageRaw(0, 94) ;
}
// handle rotary encoder
void handleEncoder(){
// long for new encoder value
long newEncoderValue = 0;
newEncoderValue=encoder.read();
if (abs(newEncoderValue-currentEncoderValue)>3)
{
currentProgram[programMode]=constrain(currentProgram[programMode]+int((newEncoderValue-currentEncoderValue)/4),0,maxProgramNumber[programMode]);
currentEncoderValue=newEncoderValue;
usbMIDI.sendProgramChange(currentProgram[programMode],1);
updateDisplay=true;
}
}
// update number & name for selected device
void handleDisplay(){
if (updateDisplay){
oledDisplay.moveCursor(7,0);
switch (programMode){
case mwIsound:
oledDisplay.putString((char *)programNumbersMWI[currentProgram[programMode]]);
//usbMIDI.sendSysEx(7,mwIprogramDumpRequest);
break;
case mwImulti:
oledDisplay.putString((char *)programNumbersMWI[currentProgram[programMode]]);
break;
case mwXTsound:
oledDisplay.putString((char *)programNumbersMWXT[currentProgram[programMode]]);
break;
case mwXTmulti:
oledDisplay.putString((char *)programNumbersMWXT[currentProgram[programMode]]);
break;
case esqMsound:
//oledDisplay.putString((char *)programNumbersESQM[currentProgram[programMode]]);
displayProgramNumber(currentProgram[programMode]);
break;
case universal:
//oledDisplay.putString((char *)programNumbers[currentProgram[programMode]]);
displayProgramNumber(currentProgram[programMode]);
break;
}
updateDisplay=false;
}
}
void displayProgramNumber(int number){
char stringBuffer[5];
dtostrf(float(number), 5, 0, stringBuffer);
oledDisplay.putString((char *)stringBuffer);
}
// switch device, display appropriate icon
void switchProgramMode(int mode){
programMode=mode;
// show appropriate icon
oledDisplay.setByteAddress(deviceIconAddress[programMode]);
oledDisplay.displayImageRaw(0, 50) ;
updateDisplay=true;
}
void requestMidiDump(int device){
switch (device){
case mwI:
// MW I
break;
case mwXT:
// MW XT
break;
case esqM:
// ESQ-M
break;
default:
break;
}
}