diff --git a/OSC2MidiGateway.ino b/OSC2MidiGateway.ino index deb441e..34d3cfd 100644 --- a/OSC2MidiGateway.ino +++ b/OSC2MidiGateway.ino @@ -9,11 +9,34 @@ #endif */ +#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 AP_TRIGGER_PIN 15 #define AP_TIMEOUT 120 #define AP_NAME "OSC2MidiBridge" +#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 @@ -25,13 +48,60 @@ #include #include "OSC2Midi.h" #include +#include + +#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 +#define AP_DATA_RESET_PIN 15 +#define AP_MODE 23 + +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); + /* UART RX IO TX IO CTS RTS UART0 GPIO3 GPIO1 N/A N/A @@ -40,22 +110,194 @@ IPAddress clientIP; // store client IP for feedback */ HardwareSerial midi1(2); // RX: 16, TX: 17 -HardwareSerial midi2(1); // RX: 35, TX: 34 (changed in .../Arduino/hardware/espressif/esp32/cores/esp32/HardwareSerial.cpp!) +//HardwareSerial midi2(1); // RX: 35, TX: 34 (changed in .../Arduino/hardware/espressif/esp32/cores/esp32/HardwareSerial.cpp!) +#define D5 (18) +#define D6 (19) +SoftwareSerial midi2; MIDI_CREATE_INSTANCE(HardwareSerial, midi1, MIDI1); -MIDI_CREATE_INSTANCE(HardwareSerial, midi2, MIDI2); +MIDI_CREATE_INSTANCE(SoftwareSerial, midi2, MIDI2); void setup() { 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)); + + pinMode(AP_DATA_RESET_PIN, INPUT_PULLUP); + pinMode(AP_MODE, INPUT_PULLUP); + + if (digitalRead(AP_MODE) == LOW) + { + Serial.println("Mode: AP"); + } + else + { +#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 = "OSC2MIDI"; + AP_PASS = "osc2midi"; + + // 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."); + 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("osc2midi")) { + Serial.println("Error setting up MDNS responder!"); + while (1) { + delay(1000); + } + } + else + { + Serial.println("mDNS started."); + } + } + /* midi1.begin(31250, SERIAL_8N1, 16, 17); midi2.begin(31250, SERIAL_8N1, 35, 34); */ midi1.begin(31250); - midi2.begin(31250); - + midi2.begin(31250, SWSERIAL_8N1, D5, D6, false, 95, 11); + Serial.begin(115200); Serial.setDebugOutput(true); @@ -131,7 +373,7 @@ void loop() // Check if there are any CC messages from synth itself //MIDI1.read(); - if (MIDI1.read()) + if (MIDI1.read()) { Serial.print("MIDI-IN[1] Type: "); Serial.print(MIDI1.getType(), DEC); @@ -147,7 +389,7 @@ void loop() // MIDI-Merger from MIDI2 to MIDI1 if (MIDI2.read()) { - MIDI1.send(MIDI2.getType(), + MIDI1.send(MIDI2.getType(), MIDI2.getData1(), MIDI2.getData2(), MIDI2.getChannel()); @@ -162,6 +404,7 @@ void loop() Serial.println(" Channel: "); } } + check_status(); } void OSCToMidiCC(OSCMessage & msg, int offset) @@ -221,3 +464,148 @@ void MidiCCToOSC(uint8_t channel, uint8_t number, uint8_t val) 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; +}