#if !(defined(ESP32) ) #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. #endif // Use from 0 to 4. Higher number, more debugging messages and memory usage. #define _WIFIMGR_LOGLEVEL_ 3 #define DEBUG 1 #define MDNS_NAME "osc2midi" #define AP_SSID_NAME "OSC2MIDI" #define AP_SSID_CONFIG_NAME "OSC2MIDI-Config" #define AP_PASSWORD "osc2midi" #define MDNS_NAME "osc2midi" #define SOFT_SERIAL_RX 18 #define SOFT_SERIAL_TX 19 #define AP_TIMEOUT 120 #define AP_TRIGGER_PIN 15 #define AP_DATA_RESET_PIN 15 #define AP_MODE 23 #define LCD_I2C_ADDR 0x27 #define LCD_COL 16 #define LCD_ROW 2 #define FileFS SPIFFS #define FS_Name "SPIFFS" #define MIN_AP_PASSWORD_SIZE 8 #define SSID_MAX_LEN 32 #define PASS_MAX_LEN 64 #define NUM_WIFI_CREDENTIALS 2 #define CONFIG_FILENAME F("/wifi_cred.dat") // You only need to format the filesystem once //#define FORMAT_FILESYSTEM //#define RESET_AP_DATA #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 100 #define WIFI_MULTI_CONNECT_WAITING_MS 200 #define WIFICHECK_INTERVAL 1000 #define HEARTBEAT_INTERVAL 10000 #include #include #include #include #include #include // Use false if you don't like to display Available Pages in Information Page of Config Portal // Comment out or use true to display Available Pages in Information Page of Config Portal // Must be placed before #include #define USE_AVAILABLE_PAGES false //#define USE_STATIC_IP_CONFIG_IN_CP false #define USE_ESP_WIFIMANAGER_NTP false #define USE_CLOUDFLARE_NTP false #define USING_CORS_FEATURE false #include #include "debug.h" #include //#include #include #include #include #include #include #include #include "OSC2Midi.h" #include #include #include typedef struct { char wifi_ssid[SSID_MAX_LEN]; char wifi_pw [PASS_MAX_LEN]; } WiFi_Credentials; typedef struct { String wifi_ssid; String wifi_pw; } WiFi_Credentials_String; typedef struct { WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS]; } WM_Config; void OSCToMidiCC(OSCMessage &msg, int offset); void MidiCCToOSC(uint8_t channel, uint8_t number, uint8_t value); uint8_t connectMultiWiFi(void); WiFiUDP udp; IPAddress clientIP; // store client IP for feedback WiFiMulti wifiMulti; FS* filesystem = &SPIFFS; String Router_SSID; String Router_Pass; WM_Config WM_config; bool initialConfig = false; String AP_SSID; String AP_PASS; IPAddress stationIP = IPAddress(0, 0, 0, 0); IPAddress gatewayIP = IPAddress(192, 168, 2, 1); IPAddress netMask = IPAddress(255, 255, 255, 0); LiquidCrystal_I2C lcd(LCD_I2C_ADDR, LCD_COL, LCD_ROW); /* UART RX IO TX IO CTS RTS UART0 GPIO3 GPIO1 N/A N/A UART1 GPIO9 GPIO10 GPIO6 GPIO11 UART2 GPIO16 GPIO17 GPIO8 GPIO7 */ HardwareSerial midi1(2); // RX: 16, TX: 17 #ifndef D5 #define D5 (SOFT_SERIAL_RX) #define D6 (SOFT_SERIAL_TX) //#define D7 (23) //#define D8 (5) //#define TX (1) #endif SoftwareSerial midi2; MIDI_CREATE_INSTANCE(HardwareSerial, midi1, MIDI1); void setup() { pinMode(AP_TRIGGER_PIN, INPUT_PULLUP); pinMode(AP_DATA_RESET_PIN, INPUT_PULLUP); pinMode(AP_MODE, INPUT_PULLUP); Serial.begin(115200); Serial.setDebugOutput(true); DEBUG_MSG("\nOSC2Midi\n"); lcd.init(); lcd.backlight(); lcd.clear(); lcd.noCursor(); lcd.setCursor(0, 0); lcd.print("OSC2MIDI"); WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP Serial.print("\nStarting AutoConnectWithFeedBack using " + String(FS_Name)); Serial.println(" on " + String(ARDUINO_BOARD)); if (digitalRead(AP_MODE) == LOW) { Serial.println("Mode AccessPoint"); WiFi.softAP(AP_SSID_NAME, AP_PASSWORD); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Mode AP"); } else { Serial.println("Mode: Client"); lcd.clear(); #if defined(FORMAT_FILESYSTEM) FileFS.format(); #endif // Format FileFS if not yet if (!FileFS.begin(true)) { Serial.print(FS_Name); Serial.println(F(" failed! AutoFormatting.")); } unsigned long startedAt = millis(); ESP_WiFiManager ESP_wifiManager("osc2midi"); if (digitalRead(AP_DATA_RESET_PIN) == LOW) { ESP_wifiManager.resetSettings(); Serial.println("Restting AP data"); delay(5000); ESP.restart(); } //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode ESP_wifiManager.setAPCallback(configModeCallback); ESP_wifiManager.setDebugOutput(true); //set custom ip for portal ESP_wifiManager.setAPStaticIPConfig(IPAddress(192, 168, 100, 1), IPAddress(192, 168, 100, 1), IPAddress(255, 255, 255, 0)); ESP_wifiManager.setMinimumSignalQuality(-1); ESP_wifiManager.setConfigPortalChannel(0); ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask); #if USING_CORS_FEATURE == true ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin"); #endif Router_SSID = ESP_wifiManager.WiFi_SSID(); Router_Pass = ESP_wifiManager.WiFi_Pass(); //Remove this line if you do not want to see WiFi password printed Serial.println("Stored: SSID = " + Router_SSID + ", Pass = " + Router_Pass); if (Router_SSID != "") { ESP_wifiManager.setConfigPortalTimeout(120); //If no access point name has been previously entered disable timeout. Serial.println("Got stored Credentials. Timeout 120s"); } else { Serial.println("No stored Credentials. No timeout"); } // SSID and PW for Config Portal AP_SSID = AP_SSID_CONFIG_NAME; AP_PASS = AP_PASSWORD; // From v1.1.0, Don't permit NULL password if ( (Router_SSID == "") || (Router_Pass == "") ) { Serial.println("We haven't got any access point credentials, so get them now"); initialConfig = true; // Starts an access point //if (!ESP_wifiManager.startConfigPortal((const char *) ssid.c_str(), password)) if ( !ESP_wifiManager.startConfigPortal(AP_SSID.c_str(), AP_PASS.c_str()) ) { Serial.println("Not connected to WiFi but continuing anyway."); lcd.setCursor(0, 0); lcd.print("Mode WiFi Cfg-AP"); lcd.setCursor(0, 1); lcd.print("192.168.100.1"); } else { Serial.println("WiFi connected...yeey :)"); } memset(&WM_config, 0, sizeof(WM_config)); for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { String tempSSID = ESP_wifiManager.getSSID(i); String tempPW = ESP_wifiManager.getPW(i); if (strlen(tempSSID.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1) strcpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str()); else strncpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1); if (strlen(tempPW.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1) strcpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str()); else strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1); // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) { LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); } } saveConfigData(); Serial.println("Restarting..."); ESP.restart(); } wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str()); startedAt = millis(); if (!initialConfig) { // Load stored data, the addAP ready for MultiWiFi reconnection loadConfigData(); for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) { LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); } } if ( WiFi.status() != WL_CONNECTED ) { Serial.println("ConnectMultiWiFi in setup"); connectMultiWiFi(); } } Serial.print("After waiting "); Serial.print((float) (millis() - startedAt) / 1000L); Serial.print(" secs more in setup(), connection result is "); if (WiFi.status() == WL_CONNECTED) { Serial.print("connected. Local IP: "); Serial.println(WiFi.localIP()); } else Serial.println(ESP_wifiManager.getStatus(WiFi.status())); if (!MDNS.begin(MDNS_NAME)) { Serial.println("Error setting up MDNS responder!"); while (1) { delay(1000); } } else { Serial.println("mDNS started."); } lcd.clear(); lcd.setCursor(0, 0); lcd.print("Mode WiFi client"); lcd.setCursor(0, 1); lcd.print(WiFi.localIP()); } /* midi1.begin(31250, SERIAL_8N1, 16, 17); midi2.begin(31250, SERIAL_8N1, 35, 34); */ midi1.begin(31250); midi2.begin(31250, SWSERIAL_8N1, D5, D6, false, 95, 11); midi2.enableIntTx(false); udp.begin(8000); MIDI1.begin(MIDI_CHANNEL_OMNI); MIDI1.setHandleControlChange(MidiCCToOSC); MIDI1.turnThruOff(); } void loop() { if (digitalRead(AP_MODE) != LOW) check_status(); // check if we need to configure a AP if (digitalRead(AP_TRIGGER_PIN) == LOW) { WiFiManager wm; //reset settings - for testing //wifiManager.resetSettings(); wm.setConfigPortalTimeout(AP_TIMEOUT); if (!wm.startConfigPortal(AP_SSID_NAME)) { DEBUG_MSG("Failed to connect and hit timeout - restarting!\n"); delay(3000); ESP.restart(); delay(5000); } DEBUG_MSG("\nAP IP address: %s\n", WiFi.softAPIP().toString().c_str()); } else { OSCMessage msg; uint8_t buffer[1024]; uint16_t outPort; // Check if there are any OSC packets to handle size_t size = udp.parsePacket(); if (size > 0 && size <= 1024) { udp.read(buffer, size); msg.fill(buffer, size); if (!msg.hasError()) { DEBUG_OSC_MESSAGE(msg); msg.route("/midi/cc", OSCToMidiCC); //msg.route("/midi/sysex", OSCToMidiSYSEX); //msg.route("/midi/note", OSCToMidiNote); } else { DEBUG_MSG("Error parsing OSC message: %d\n", msg.getError()); } // Keep track of the client IP address for "talking back" clientIP = udp.remoteIP(); udp.flush(); } // Check if there are any CC messages from synth itself //MIDI1.read(); if (MIDI1.read()) { DEBUG_MSG("MIDI-IN[1] Type: "); DEBUG_MSG("%3d", MIDI1.getType()); DEBUG_MSG(" Data1: "); DEBUG_MSG("%3d", MIDI1.getData1()); DEBUG_MSG(" Data2: "); DEBUG_MSG("%3d", MIDI1.getData2()); DEBUG_MSG(" Channel: "); DEBUG_MSG("%0d", MIDI1.getChannel()); DEBUG_MSG("\n"); } // MIDI-Merger from (Soft-)MIDI2 to MIDI1 if (midi2.available() > 0) { while (midi2.available() > 0) { Serial.print("->M:"); Serial.println(midi2.peek(), DEC); midi1.write(midi2.read()); } } } } void OSCToMidiCC(OSCMessage & msg, int offset) { char address[100] = { 0 }; uint8_t cc, value; uint8_t midichannel; msg.getAddress(address, offset, sizeof(address)); midichannel = getMIDIChannel(address); //midichannel--; if (msg.size() == 1 && msg.isFloat(0)) { // Single or multi control with sending one value cc = getCC(address); value = round(msg.getFloat(0)); value = value > 127 ? 127 : value; DEBUG_MSG("MSG: % s\tChannel: % u\t\tCC: % u\tValue: % u\n", address, midichannel, cc, value); MIDI1.sendControlChange(cc, value, midichannel); } else if (msg.size() == 2 && msg.isFloat(0) && msg.isFloat(1)) { // XY pad, two values cc = getVar(address, 1); value = round(msg.getFloat(0)); value = value > 127 ? 127 : value; DEBUG_MSG("MSG: % s\tChannel: % u\t\tCC: % u\tValue: % u\n", address, midichannel, cc, value); MIDI1.sendControlChange(cc, value, midichannel); cc = getVar(address, 2); value = round(msg.getFloat(1)); value = value > 127 ? 127 : value; DEBUG_MSG("MSG: % s\tChannel: % u\t\tCC: % u\tValue: % u\n", address, midichannel, cc, value); MIDI1.sendControlChange(cc, value, midichannel); } else { DEBUG_MSG("Cannot handle: % s\n", address); } } void MidiCCToOSC(uint8_t channel, uint8_t number, uint8_t val) { char buffer[1024]; snprintf(buffer, sizeof(buffer), " / midi / cc / % u / % u", channel, number); DEBUG_MSG("MidiCCToOsc: % s % f\n", buffer, val * 1.0); if (clientIP) { OSCMessage msg = OSCMessage(buffer); msg.add(val); udp.beginPacket(clientIP, 9000); msg.send(udp); udp.endPacket(); } } void heartBeatPrint(void) { static int num = 1; if (WiFi.status() == WL_CONNECTED) Serial.print("H"); // H means connected to WiFi else Serial.print("F"); // F means not connected to WiFi if (num == 80) { Serial.println(); num = 1; } else if (num++ % 10 == 0) { Serial.print(" "); } } void check_WiFi(void) { if ( (WiFi.status() != WL_CONNECTED) ) { Serial.println("\nWiFi lost. Call connectMultiWiFi in loop"); connectMultiWiFi(); } } void check_status(void) { static ulong checkstatus_timeout = 0; static ulong checkwifi_timeout = 0; static ulong current_millis; current_millis = millis(); // Check WiFi every WIFICHECK_INTERVAL (1) seconds. if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0)) { check_WiFi(); checkwifi_timeout = current_millis + WIFICHECK_INTERVAL; } // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) { heartBeatPrint(); checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; } } void configModeCallback (ESP_WiFiManager *myESP_WiFiManager) { Serial.print("Entered config mode with "); Serial.println("AP_SSID : " + myESP_WiFiManager->getConfigPortalSSID() + " and AP_PASS = " + myESP_WiFiManager->getConfigPortalPW()); } void loadConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "r"); LOGERROR(F("LoadWiFiCfgFile ")); if (file) { file.readBytes((char *) &WM_config, sizeof(WM_config)); file.close(); LOGERROR(F("OK")); } else { LOGERROR(F("failed")); } } void saveConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "w"); LOGERROR(F("SaveWiFiCfgFile ")); if (file) { file.write((uint8_t*) &WM_config, sizeof(WM_config)); file.close(); LOGERROR(F("OK")); } else { LOGERROR(F("failed")); } } uint8_t connectMultiWiFi(void) { uint8_t status; LOGERROR(F("ConnectMultiWiFi with : ")); if ( (Router_SSID != "") && (Router_Pass != "") ) { LOGERROR3(F("* Flash - stored Router_SSID = "), Router_SSID, F(", Router_Pass = "), Router_Pass ); } for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) { LOGERROR3(F("* Additional SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); } } LOGERROR(F("Connecting MultiWifi...")); WiFi.mode(WIFI_STA); WiFi.config(stationIP, gatewayIP, netMask); int i = 0; status = wifiMulti.run(); delay(WIFI_MULTI_1ST_CONNECT_WAITING_MS); while ( ( i++ < 10 ) && ( status != WL_CONNECTED ) ) { status = wifiMulti.run(); if ( status == WL_CONNECTED ) break; else delay(WIFI_MULTI_CONNECT_WAITING_MS); } if ( status == WL_CONNECTED ) { LOGERROR1(F("WiFi connected after time: "), i); LOGERROR3(F("SSID: "), WiFi.SSID(), F(", RSSI = "), WiFi.RSSI()); LOGERROR3(F("Channel: "), WiFi.channel(), F(", IP address: "), WiFi.localIP() ); } else LOGERROR(F("WiFi not connected")); return status; }