From df5dcdc8495561e0c1bdc661677d549d83f2a932 Mon Sep 17 00:00:00 2001 From: Christoph Kuhr Date: Wed, 12 May 2021 19:31:04 +0200 Subject: [PATCH 01/20] added support for ESP32 POE ISO manufactured by Olimex. --- PlatformIO/platformio.ini | 4 +- PlatformIO/src/General.hpp | 10 ++- PlatformIO/src/Satellite.cpp | 8 +++ PlatformIO/src/StateMachine.hpp | 53 ++++++++++++++ PlatformIO/src/devices/Inmp441Max98357a.hpp | 77 ++++++++++++--------- PlatformIO/src/esp_types.h | 7 ++ 6 files changed, 124 insertions(+), 35 deletions(-) create mode 100644 PlatformIO/src/esp_types.h diff --git a/PlatformIO/platformio.ini b/PlatformIO/platformio.ini index 538be3a..1f30045 100644 --- a/PlatformIO/platformio.ini +++ b/PlatformIO/platformio.ini @@ -17,7 +17,9 @@ build_flags = extra_scripts = pre:load_settings.py platform = espressif32 upload_speed = 115200 -board = esp32dev +upload_port = /dev/ttyUSB5 +;board = esp32dev +board = esp32-poe-iso framework = arduino board_build.partitions = ../OTABuilder/partitions_two_ota.csv build_flags = ${common.build_flags} diff --git a/PlatformIO/src/General.hpp b/PlatformIO/src/General.hpp index 51c9385..8fc9055 100644 --- a/PlatformIO/src/General.hpp +++ b/PlatformIO/src/General.hpp @@ -1,6 +1,14 @@ #include #include + +#include "esp_types.h" + +#if ESP_TYPE == ESP32_POE_ISO +#include +#else #include +#endif + #include #include #include "RingBuf.h" @@ -411,4 +419,4 @@ void saveConfiguration(const char *filename, Config &config) { file.close(); Serial.println("Configuration saved! Rebooting"); ESP.restart(); -} \ No newline at end of file +} diff --git a/PlatformIO/src/Satellite.cpp b/PlatformIO/src/Satellite.cpp index 13fa487..7dee514 100644 --- a/PlatformIO/src/Satellite.cpp +++ b/PlatformIO/src/Satellite.cpp @@ -95,7 +95,15 @@ #include #include + +#include "esp_types.h" + +#if ESP_TYPE == ESP32_POE_ISO +#include +#else #include +#endif + #include "device.h" #define M5ATOMECHO 0 diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index 3174ba8..04443fa 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -185,7 +185,11 @@ class WifiConnected : public StateMachine { void entry(void) override { Serial.println("Enter WifiConnected"); +#if ESP_TYPE == ESP32_POE_ISO + Serial.printf("Connected to LAN with IP: %s, \n", ETH.localIP().toString().c_str()); +#else Serial.printf("Connected to Wifi with IP: %s, SSID: %s, BSSID: %s, RSSI: %d\n", WiFi.localIP().toString().c_str(), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), WiFi.RSSI()); +#endif xEventGroupClearBits(audioGroup, PLAY); xEventGroupClearBits(audioGroup, STREAM); device->updateBrightness(config.brightness); @@ -219,6 +223,15 @@ class WifiDisconnected : public StateMachine Serial.println("Enter WifiDisconnected"); Serial.printf("Total heap: %d\r\n", ESP.getHeapSize()); Serial.printf("Free heap: %d\r\n", ESP.getFreeHeap()); + + +#if ESP_TYPE == ESP32_POE_ISO + + WiFi.onEvent(WiFiEvent); + ETH.begin(); + +#else + device->updateBrightness(config.brightness); device->updateColors(COLORS_WIFI_DISCONNECTED); @@ -292,6 +305,8 @@ class WifiDisconnected : public StateMachine Serial.println("Connection Failed! Retry..."); } } +#endif + } void react(WifiConnectEvent const &) override { @@ -634,6 +649,43 @@ void initHeader(int readSize, int width, int rate) { void WiFiEvent(WiFiEvent_t event) { switch (event) { + +#if ESP_TYPE == ESP32_POE_ISO + case SYSTEM_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname(HOSTNAME); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + Serial.print("ETH MAC: "); + Serial.print(ETH.macAddress()); + Serial.print(", IPv4: "); + Serial.print(ETH.localIP()); + if (ETH.fullDuplex()) { + Serial.print(", FULL_DUPLEX"); + } + Serial.print(", "); + Serial.print(ETH.linkSpeed()); + Serial.println("Mbps"); + send_event(WifiConnectEvent()); + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + send_event(WifiDisconnectEvent()); + break; + case SYSTEM_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + send_event(WifiDisconnectEvent()); + break; + default: + Serial.println("ETH Event"); + break; + +#else + case SYSTEM_EVENT_STA_START: WiFi.setHostname(HOSTNAME); break; @@ -645,5 +697,6 @@ void WiFiEvent(WiFiEvent_t event) { break; default: break; +#endif } } diff --git a/PlatformIO/src/devices/Inmp441Max98357a.hpp b/PlatformIO/src/devices/Inmp441Max98357a.hpp index 61ecf46..8934c39 100644 --- a/PlatformIO/src/devices/Inmp441Max98357a.hpp +++ b/PlatformIO/src/devices/Inmp441Max98357a.hpp @@ -1,6 +1,6 @@ #include #include "IndicatorLight.h" - +#include "../esp_types.h" // I2S pins on ESp32cam MIC // GPIO2 <--> WS @@ -17,17 +17,28 @@ // GPIO12 <--> DIN #define I2S_LRC 16 #define I2S_BCLK 13 + +#if ESP_TYPE == ESP32_POE_ISO +#define I2S_DIN 3 +#else #define I2S_DIN 12 +#endif + #define I2S_PORT_TX I2S_NUM_1 #define I2S_SAMPLE_RATE (16000) #define I2S_SAMPLE_BITS (16) #define I2S_READ_LEN 512 +#if ESP_TYPE != ESP32_POE_ISO +// LEDs +#define LED_FLASH 4 +#define LED 5 +#else // LEDs #define LED_FLASH 4 #define LED 33 - +#endif class Inmp441Max98357a : public Device { @@ -51,36 +62,36 @@ void Inmp441Max98357a::init() { Serial.printf("Connect to Inmp441... \n"); // Speakers - i2s_config_t i2sConfig_tx = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), - .sample_rate = I2S_SAMPLE_RATE, - .bits_per_sample = i2s_bits_per_sample_t(I2S_SAMPLE_BITS), - .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, - .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, - .dma_buf_count = 2, - .dma_buf_len = 512, - }; - - i2s_pin_config_t pin_config_tx = { - .bck_io_num = I2S_BCLK, - .ws_io_num = I2S_LRC, - .data_out_num = I2S_DIN, - .data_in_num = -1 - }; - - err += i2s_driver_install(I2S_PORT_TX, &i2sConfig_tx, 0, NULL); - if (err != ESP_OK) { - Serial.printf("Failed installing headphone driver: %d\n", err); - while (true); - } - - err += i2s_set_pin(I2S_PORT_TX, &pin_config_tx); - if (err != ESP_OK) { - Serial.printf("Failed setting headphone pin: %d\n", err); - while (true); - } - Serial.println("I2S headphone driver installed.\n"); + i2s_config_t i2sConfig_tx = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), + .sample_rate = I2S_SAMPLE_RATE, + .bits_per_sample = i2s_bits_per_sample_t(I2S_SAMPLE_BITS), + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 2, + .dma_buf_len = 512, + }; + + i2s_pin_config_t pin_config_tx = { + .bck_io_num = I2S_BCLK, + .ws_io_num = I2S_LRC, + .data_out_num = I2S_DIN, + .data_in_num = -1 + }; + + err += i2s_driver_install(I2S_PORT_TX, &i2sConfig_tx, 0, NULL); + if (err != ESP_OK) { + Serial.printf("Failed installing headphone driver: %d\n", err); + while (true); + } + + err += i2s_set_pin(I2S_PORT_TX, &pin_config_tx); + if (err != ESP_OK) { + Serial.printf("Failed setting headphone pin: %d\n", err); + while (true); + } + Serial.println("I2S headphone driver installed.\n"); i2s_config_t i2s_config = { @@ -158,7 +169,7 @@ bool Inmp441Max98357a::readAudio(uint8_t *data, size_t size) { uint32_t j = 0; uint32_t dac_value = 0; for (int i = 0; i < size; i += 2) { - dac_value = ((((uint16_t) (i2s_read_buff[i + 1] & 0xf) << 8) | ((i2s_read_buff[i + 0])))); + dac_value = ((((uint16_t) (i2s_read_buff[i + 1] & 0xff) << 8) | ((i2s_read_buff[i + 0])))); data[j++] = 0; data[j++] = dac_value * 256 / 2048; } diff --git a/PlatformIO/src/esp_types.h b/PlatformIO/src/esp_types.h new file mode 100644 index 0000000..07b156b --- /dev/null +++ b/PlatformIO/src/esp_types.h @@ -0,0 +1,7 @@ + + +#define ESP_OTHER 0 +#define ESP32_POE_ISO 1 + + +#define ESP_TYPE ESP32_POE_ISO \ No newline at end of file From 7baa105b33dc69551e6e1496cd8a134a09a3b44b Mon Sep 17 00:00:00 2001 From: Christoph Kuhr Date: Wed, 12 May 2021 22:49:49 +0200 Subject: [PATCH 02/20] removed esp_types.h and added ESP_TYPES to Satellite.cpp, load_settings.py and settings.ini.example --- PlatformIO/load_settings.py | 3 ++- PlatformIO/platformio.ini | 6 +++--- PlatformIO/settings.ini.example | 4 ++++ PlatformIO/src/General.hpp | 2 -- PlatformIO/src/Satellite.cpp | 3 ++- PlatformIO/src/devices/Inmp441Max98357a.hpp | 3 +-- PlatformIO/src/esp_types.h | 7 ------- 7 files changed, 12 insertions(+), 16 deletions(-) delete mode 100644 PlatformIO/src/esp_types.h diff --git a/PlatformIO/load_settings.py b/PlatformIO/load_settings.py index 133d9bc..80c4788 100644 --- a/PlatformIO/load_settings.py +++ b/PlatformIO/load_settings.py @@ -28,7 +28,8 @@ ("MQTT_PASS", "\\\"" + config[sectionMqtt]["password"] + "\\\""), ("MQTT_MAX_PACKET_SIZE", 2000), ("CONFIG_ASYNC_TCP_RUNNING_CORE", 1), - ("DEVICE_TYPE", config[sectionGeneral]["device_type"]) + ("DEVICE_TYPE", config[sectionGeneral]["device_type"]), + ("ESP_TYPE", config[sectionGeneral]["esp_type"]) ] # MQTT "ip" was replaced with "hostname" that can now be an IP or a DNS hostname of the MQTT server diff --git a/PlatformIO/platformio.ini b/PlatformIO/platformio.ini index 1f30045..7cc1d16 100644 --- a/PlatformIO/platformio.ini +++ b/PlatformIO/platformio.ini @@ -17,9 +17,9 @@ build_flags = extra_scripts = pre:load_settings.py platform = espressif32 upload_speed = 115200 -upload_port = /dev/ttyUSB5 -;board = esp32dev -board = esp32-poe-iso +;upload_port = /dev/ttyUSB5 +board = esp32dev +;board = esp32-poe-iso framework = arduino board_build.partitions = ../OTABuilder/partitions_two_ota.csv build_flags = ${common.build_flags} diff --git a/PlatformIO/settings.ini.example b/PlatformIO/settings.ini.example index c3afb14..44ad734 100644 --- a/PlatformIO/settings.ini.example +++ b/PlatformIO/settings.ini.example @@ -4,6 +4,10 @@ deployhost=192.168.43.24 siteId=satellite ;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4 device_type=4 +; supported: ESP_OTHER=0, ESP32_POE_ISO=1 +; note: ESP32_POE_ISO is only tested with device_type INMP441MAX98357A=4 +; GPIO 12 is not accessible, GPIO 3 is used instead. +esp_type=0 [Wifi] ssid=SSID diff --git a/PlatformIO/src/General.hpp b/PlatformIO/src/General.hpp index 8fc9055..1d2e6f7 100644 --- a/PlatformIO/src/General.hpp +++ b/PlatformIO/src/General.hpp @@ -1,8 +1,6 @@ #include #include -#include "esp_types.h" - #if ESP_TYPE == ESP32_POE_ISO #include #else diff --git a/PlatformIO/src/Satellite.cpp b/PlatformIO/src/Satellite.cpp index 7dee514..82ac17d 100644 --- a/PlatformIO/src/Satellite.cpp +++ b/PlatformIO/src/Satellite.cpp @@ -96,7 +96,8 @@ #include #include -#include "esp_types.h" +#define ESP_OTHER 0 +#define ESP32_POE_ISO 1 #if ESP_TYPE == ESP32_POE_ISO #include diff --git a/PlatformIO/src/devices/Inmp441Max98357a.hpp b/PlatformIO/src/devices/Inmp441Max98357a.hpp index 8934c39..f40b0b0 100644 --- a/PlatformIO/src/devices/Inmp441Max98357a.hpp +++ b/PlatformIO/src/devices/Inmp441Max98357a.hpp @@ -1,6 +1,5 @@ #include #include "IndicatorLight.h" -#include "../esp_types.h" // I2S pins on ESp32cam MIC // GPIO2 <--> WS @@ -30,7 +29,7 @@ #define I2S_SAMPLE_BITS (16) #define I2S_READ_LEN 512 -#if ESP_TYPE != ESP32_POE_ISO +#if ESP_TYPE == ESP32_POE_ISO // LEDs #define LED_FLASH 4 #define LED 5 diff --git a/PlatformIO/src/esp_types.h b/PlatformIO/src/esp_types.h deleted file mode 100644 index 07b156b..0000000 --- a/PlatformIO/src/esp_types.h +++ /dev/null @@ -1,7 +0,0 @@ - - -#define ESP_OTHER 0 -#define ESP32_POE_ISO 1 - - -#define ESP_TYPE ESP32_POE_ISO \ No newline at end of file From 39d0acea9c6fe75fccf02b5071e6b28de7418907 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Mon, 17 May 2021 21:45:05 +0200 Subject: [PATCH 03/20] Add Esp32-poe-iso as device and support ETH --- PlatformIO/load_settings.py | 2 +- PlatformIO/settings.ini.example | 10 +- PlatformIO/src/General.hpp | 6 +- PlatformIO/src/Satellite.cpp | 15 +- PlatformIO/src/StateMachine.hpp | 158 ++++++++++---------- PlatformIO/src/devices/Esp32_poe_iso.hpp | 136 +++++++++++++++++ PlatformIO/src/devices/Inmp441Max98357a.hpp | 12 -- 7 files changed, 229 insertions(+), 110 deletions(-) create mode 100644 PlatformIO/src/devices/Esp32_poe_iso.hpp diff --git a/PlatformIO/load_settings.py b/PlatformIO/load_settings.py index 80c4788..1861a9b 100644 --- a/PlatformIO/load_settings.py +++ b/PlatformIO/load_settings.py @@ -29,7 +29,7 @@ ("MQTT_MAX_PACKET_SIZE", 2000), ("CONFIG_ASYNC_TCP_RUNNING_CORE", 1), ("DEVICE_TYPE", config[sectionGeneral]["device_type"]), - ("ESP_TYPE", config[sectionGeneral]["esp_type"]) + ("NETWORK_TYPE", config[sectionGeneral]["network_type"]) ] # MQTT "ip" was replaced with "hostname" that can now be an IP or a DNS hostname of the MQTT server diff --git a/PlatformIO/settings.ini.example b/PlatformIO/settings.ini.example index 44ad734..986e31c 100644 --- a/PlatformIO/settings.ini.example +++ b/PlatformIO/settings.ini.example @@ -2,12 +2,10 @@ hostname=192.168.43.140 deployhost=192.168.43.24 siteId=satellite -;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4 -device_type=4 -; supported: ESP_OTHER=0, ESP32_POE_ISO=1 -; note: ESP32_POE_ISO is only tested with device_type INMP441MAX98357A=4 -; GPIO 12 is not accessible, GPIO 3 is used instead. -esp_type=0 +;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4, ESP32_POE_ISO=5 +device_type=5 +;network_type: 0: WiFi, 1: Ethernet +network_type=0 [Wifi] ssid=SSID diff --git a/PlatformIO/src/General.hpp b/PlatformIO/src/General.hpp index 1d2e6f7..55374cc 100644 --- a/PlatformIO/src/General.hpp +++ b/PlatformIO/src/General.hpp @@ -1,10 +1,10 @@ #include #include -#if ESP_TYPE == ESP32_POE_ISO -#include +#if NETWORK_TYPE == NETWORK_ETHERNET + #include #else -#include + #include #endif #include diff --git a/PlatformIO/src/Satellite.cpp b/PlatformIO/src/Satellite.cpp index 82ac17d..84f479e 100644 --- a/PlatformIO/src/Satellite.cpp +++ b/PlatformIO/src/Satellite.cpp @@ -95,14 +95,13 @@ #include #include +#define NETWORK_WIFI 0 +#define NETWORK_ETHERNET 1 -#define ESP_OTHER 0 -#define ESP32_POE_ISO 1 - -#if ESP_TYPE == ESP32_POE_ISO -#include +#if NETWORK_TYPE == NETWORK_ETHERNET + #include #else -#include + #include #endif #include "device.h" @@ -112,6 +111,7 @@ #define AUDIOKIT 2 #define INMP441 3 #define INMP441MAX98357A 4 +#define ESP32_POE_ISO 5 // This is where you can include your device, make sure to create a *device @@ -131,6 +131,9 @@ #elif DEVICE_TYPE == INMP441MAX98357A #include "devices/Inmp441Max98357a.hpp" Inmp441Max98357a *device = new Inmp441Max98357a(); +#elif DEVICE_TYPE == ESP32_POE_ISO + #include "devices/Esp32_poe_iso.hpp" + Esp32_poe_iso *device = new Esp32_poe_iso(); #endif #include diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index 04443fa..f9e2994 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -185,11 +185,11 @@ class WifiConnected : public StateMachine { void entry(void) override { Serial.println("Enter WifiConnected"); -#if ESP_TYPE == ESP32_POE_ISO - Serial.printf("Connected to LAN with IP: %s, \n", ETH.localIP().toString().c_str()); -#else - Serial.printf("Connected to Wifi with IP: %s, SSID: %s, BSSID: %s, RSSI: %d\n", WiFi.localIP().toString().c_str(), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), WiFi.RSSI()); -#endif + #if NETWORK_TYPE == NETWORK_ETHERNET + Serial.printf("Connected to LAN with IP: %s, \n", ETH.localIP().toString().c_str()); + #else + Serial.printf("Connected to Wifi with IP: %s, SSID: %s, BSSID: %s, RSSI: %d\n", WiFi.localIP().toString().c_str(), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), WiFi.RSSI()); + #endif xEventGroupClearBits(audioGroup, PLAY); xEventGroupClearBits(audioGroup, STREAM); device->updateBrightness(config.brightness); @@ -224,89 +224,85 @@ class WifiDisconnected : public StateMachine Serial.printf("Total heap: %d\r\n", ESP.getHeapSize()); Serial.printf("Free heap: %d\r\n", ESP.getFreeHeap()); - -#if ESP_TYPE == ESP32_POE_ISO - - WiFi.onEvent(WiFiEvent); - ETH.begin(); - -#else - - device->updateBrightness(config.brightness); - device->updateColors(COLORS_WIFI_DISCONNECTED); - - // Set static ip address - #if defined(HOST_IP) && defined(HOST_GATEWAY) && defined(HOST_SUBNET) && defined(HOST_DNS1) - IPAddress ip; - IPAddress gateway; - IPAddress subnet; - IPAddress dns1; - IPAddress dns2; - - ip.fromString(HOST_IP); - gateway.fromString(HOST_GATEWAY); - subnet.fromString(HOST_SUBNET); - dns1.fromString(HOST_DNS1); - - #ifdef HOST_DNS2 - dns2.fromString(HOST_DNS2); + #if NETWORK_TYPE == NETWORK_ETHERNET + WiFi.onEvent(WiFiEvent); + ETH.begin(); + #else + device->updateBrightness(config.brightness); + device->updateColors(COLORS_WIFI_DISCONNECTED); + + // Set static ip address + #if defined(HOST_IP) && defined(HOST_GATEWAY) && defined(HOST_SUBNET) && defined(HOST_DNS1) + IPAddress ip; + IPAddress gateway; + IPAddress subnet; + IPAddress dns1; + IPAddress dns2; + + ip.fromString(HOST_IP); + gateway.fromString(HOST_GATEWAY); + subnet.fromString(HOST_SUBNET); + dns1.fromString(HOST_DNS1); + + #ifdef HOST_DNS2 + dns2.fromString(HOST_DNS2); + #endif + + Serial.printf("Set static ip: %s, gateway: %s, subnet: %s, dns1: %s, dns2: %s\r\n", ip.toString().c_str(), gateway.toString().c_str(), subnet.toString().c_str(), dns1.toString().c_str(), dns2.toString().c_str()); + WiFi.config(ip, gateway, subnet, dns1, dns2); #endif - Serial.printf("Set static ip: %s, gateway: %s, subnet: %s, dns1: %s, dns2: %s\r\n", ip.toString().c_str(), gateway.toString().c_str(), subnet.toString().c_str(), dns1.toString().c_str(), dns2.toString().c_str()); - WiFi.config(ip, gateway, subnet, dns1, dns2); - #endif + WiFi.onEvent(WiFiEvent); + WiFi.mode(WIFI_STA); - WiFi.onEvent(WiFiEvent); - WiFi.mode(WIFI_STA); + // find best AP (BSSID) if there are several AP for a given SSID + // https://github.com/arendst/Tasmota/blob/db615c5b0ba0053c3991cf40dd47b0d484ac77ae/tasmota/support_wifi.ino#L261 + // https://esp32.com/viewtopic.php?t=18979 + #if defined(SCAN_STRONGEST_AP) + Serial.println("WiFi scan start"); + int n = WiFi.scanNetworks(); // WiFi.scanNetworks will return the number of networks found + // or WIFI_SCAN_RUNNING (-1), WIFI_SCAN_FAILED (-2) - // find best AP (BSSID) if there are several AP for a given SSID - // https://github.com/arendst/Tasmota/blob/db615c5b0ba0053c3991cf40dd47b0d484ac77ae/tasmota/support_wifi.ino#L261 - // https://esp32.com/viewtopic.php?t=18979 - #if defined(SCAN_STRONGEST_AP) - Serial.println("WiFi scan start"); - int n = WiFi.scanNetworks(); // WiFi.scanNetworks will return the number of networks found - // or WIFI_SCAN_RUNNING (-1), WIFI_SCAN_FAILED (-2) + Serial.printf("WiFi scan done, result %d\n", n); + if (n <= 0) { + Serial.println("error or no networks found"); + } else { + for (int i = 0; i < n; ++i) { + // Print metrics for each network found + Serial.printf("%d: BSSID: %s %ddBm, %d%% %s, %s (%d)\n", i + 1, WiFi.BSSIDstr(i).c_str(), WiFi.RSSI(i), constrain(2 * (WiFi.RSSI(i) + 100), 0, 100), + (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? "open " : "encrypted", WiFi.SSID(i).c_str(), WiFi.channel(i)); + } + } + Serial.println(); - Serial.printf("WiFi scan done, result %d\n", n); - if (n <= 0) { - Serial.println("error or no networks found"); - } else { - for (int i = 0; i < n; ++i) { - // Print metrics for each network found - Serial.printf("%d: BSSID: %s %ddBm, %d%% %s, %s (%d)\n", i + 1, WiFi.BSSIDstr(i).c_str(), WiFi.RSSI(i), constrain(2 * (WiFi.RSSI(i) + 100), 0, 100), - (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? "open " : "encrypted", WiFi.SSID(i).c_str(), WiFi.channel(i)); + // find first that matches SSID. Expect results to be sorted by signal strength. + int i = 0; + while ( String(WIFI_SSID) != String(WiFi.SSID(i)) && (i < n)) { + i++; } - } - Serial.println(); - // find first that matches SSID. Expect results to be sorted by signal strength. - int i = 0; - while ( String(WIFI_SSID) != String(WiFi.SSID(i)) && (i < n)) { - i++; - } + if (i == n || n < 0) { + Serial.println("No network with SSID " WIFI_SSID " found!"); + WiFi.begin(WIFI_SSID, WIFI_PASS); // try basic method anyway + } else { + Serial.printf("SSID match found at index: %d\n", i + 1); + WiFi.begin(WIFI_SSID, WIFI_PASS, 0, WiFi.BSSID(i)); // pass selected BSSID + } + #else + WiFi.begin(WIFI_SSID, WIFI_PASS); + #endif - if (i == n || n < 0) { - Serial.println("No network with SSID " WIFI_SSID " found!"); - WiFi.begin(WIFI_SSID, WIFI_PASS); // try basic method anyway - } else { - Serial.printf("SSID match found at index: %d\n", i + 1); - WiFi.begin(WIFI_SSID, WIFI_PASS, 0, WiFi.BSSID(i)); // pass selected BSSID + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + retryCount++; + if (retryCount > 2) { + Serial.println("Connection Failed! Rebooting..."); + ESP.restart(); + } else { + Serial.println("Connection Failed! Retry..."); + } } - #else - WiFi.begin(WIFI_SSID, WIFI_PASS); #endif - while (WiFi.waitForConnectResult() != WL_CONNECTED) { - retryCount++; - if (retryCount > 2) { - Serial.println("Connection Failed! Rebooting..."); - ESP.restart(); - } else { - Serial.println("Connection Failed! Retry..."); - } - } -#endif - } void react(WifiConnectEvent const &) override { @@ -650,7 +646,7 @@ void initHeader(int readSize, int width, int rate) { void WiFiEvent(WiFiEvent_t event) { switch (event) { -#if ESP_TYPE == ESP32_POE_ISO + #if NETWORK_TYPE == NETWORK_ETHERNET case SYSTEM_EVENT_ETH_START: Serial.println("ETH Started"); //set eth hostname here @@ -683,9 +679,7 @@ void WiFiEvent(WiFiEvent_t event) { default: Serial.println("ETH Event"); break; - -#else - + #else case SYSTEM_EVENT_STA_START: WiFi.setHostname(HOSTNAME); break; @@ -697,6 +691,6 @@ void WiFiEvent(WiFiEvent_t event) { break; default: break; -#endif + #endif } } diff --git a/PlatformIO/src/devices/Esp32_poe_iso.hpp b/PlatformIO/src/devices/Esp32_poe_iso.hpp new file mode 100644 index 0000000..9e765da --- /dev/null +++ b/PlatformIO/src/devices/Esp32_poe_iso.hpp @@ -0,0 +1,136 @@ +#include +// I2S pins on ESp32cam MIC +// GPIO2 <--> WS +// GPIO14 <--> SCK +// GPIO15 <--> SD +#define I2S_SCK 14 +#define I2S_WS 2 +#define I2S_SD 15 +#define I2S_PORT I2S_NUM_0 + +// I2S pins on ESp32Cam Speakers +// GPIO16 <--> LRC +// GPIO13 <--> BCLK +// GPIO12 <--> DIN +#define I2S_LRC 16 +#define I2S_BCLK 13 +#define I2S_DIN 3 +#define I2S_PORT_TX I2S_NUM_1 + +#define I2S_SAMPLE_RATE (16000) +#define I2S_SAMPLE_BITS (16) +#define I2S_READ_LEN 512 + +class Esp32_poe_iso : public Device +{ + public: + Esp32_poe_iso(); + void init(); + void updateColors(int colors); + bool readAudio(uint8_t *data, size_t size); + void setWriteMode(int sampleRate, int bitDepth, int numChannels); + void writeAudio(uint8_t *data, size_t size, size_t *bytes_written); + private: + char* i2s_read_buff = (char*) calloc(I2S_READ_LEN, sizeof(char)); +}; + +Esp32_poe_iso::Esp32_poe_iso() {}; + +void Esp32_poe_iso::init() { + + esp_err_t err = ESP_OK; + Serial.printf("Connect to Inmp441... \n"); + + // Speakers + i2s_config_t i2sConfig_tx = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), + .sample_rate = I2S_SAMPLE_RATE, + .bits_per_sample = i2s_bits_per_sample_t(I2S_SAMPLE_BITS), + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 2, + .dma_buf_len = 512, + }; + + i2s_pin_config_t pin_config_tx = { + .bck_io_num = I2S_BCLK, + .ws_io_num = I2S_LRC, + .data_out_num = I2S_DIN, + .data_in_num = -1 + }; + + err += i2s_driver_install(I2S_PORT_TX, &i2sConfig_tx, 0, NULL); + if (err != ESP_OK) { + Serial.printf("Failed installing headphone driver: %d\n", err); + while (true); + } + + err += i2s_set_pin(I2S_PORT_TX, &pin_config_tx); + if (err != ESP_OK) { + Serial.printf("Failed setting headphone pin: %d\n", err); + while (true); + } + Serial.println("I2S headphone driver installed.\n"); + + + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER|I2S_MODE_RX), + .sample_rate = I2S_SAMPLE_RATE, + .bits_per_sample = i2s_bits_per_sample_t(I2S_SAMPLE_BITS), + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = 0, + .dma_buf_count = 2, + .dma_buf_len = 512, + .use_apll = 1 + }; + + i2s_pin_config_t pin_config = { + .bck_io_num = I2S_SCK, + .ws_io_num = I2S_WS, + .data_out_num = -1, + .data_in_num = I2S_SD + }; + + err += i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); + if (err != ESP_OK) { + Serial.printf("Failed installing mic driver: %d\n", err); + while (true); + } + + err += i2s_set_pin(I2S_PORT, &pin_config); + if (err != ESP_OK) { + Serial.printf("Failed setting mic pin: %d\n", err); + while (true); + } + Serial.println("I2S driver mic installed."); + + return; +} + +void Esp32_poe_iso::setWriteMode(int sampleRate, int bitDepth, int numChannels) +{ + if (sampleRate > 0) + { + i2s_set_clk(I2S_PORT_TX, sampleRate, static_cast(bitDepth), static_cast(numChannels)); + } +} + +void Esp32_poe_iso::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { + i2s_write(I2S_PORT_TX, data, size, bytes_written, portMAX_DELAY); +} + + +bool Esp32_poe_iso::readAudio(uint8_t *data, size_t size) { + size_t bytes_read; + i2s_read(I2S_PORT, (void*) i2s_read_buff, size, &bytes_read, portMAX_DELAY); + uint32_t j = 0; + uint32_t dac_value = 0; + for (int i = 0; i < size; i += 2) { + dac_value = ((((uint16_t) (i2s_read_buff[i + 1] & 0xff) << 8) | ((i2s_read_buff[i + 0])))); + data[j++] = 0; + data[j++] = dac_value * 256 / 2048; + } + return true; +} diff --git a/PlatformIO/src/devices/Inmp441Max98357a.hpp b/PlatformIO/src/devices/Inmp441Max98357a.hpp index f40b0b0..6cf7088 100644 --- a/PlatformIO/src/devices/Inmp441Max98357a.hpp +++ b/PlatformIO/src/devices/Inmp441Max98357a.hpp @@ -16,28 +16,16 @@ // GPIO12 <--> DIN #define I2S_LRC 16 #define I2S_BCLK 13 - -#if ESP_TYPE == ESP32_POE_ISO -#define I2S_DIN 3 -#else #define I2S_DIN 12 -#endif #define I2S_PORT_TX I2S_NUM_1 #define I2S_SAMPLE_RATE (16000) #define I2S_SAMPLE_BITS (16) #define I2S_READ_LEN 512 - -#if ESP_TYPE == ESP32_POE_ISO -// LEDs -#define LED_FLASH 4 -#define LED 5 -#else // LEDs #define LED_FLASH 4 #define LED 33 -#endif class Inmp441Max98357a : public Device { From 14c0a093d7918b5ef36c8352b05b0c310e68a118 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Mon, 17 May 2021 21:53:40 +0200 Subject: [PATCH 04/20] Add readme files --- Esp32-poe-iso.md | 5 +++++ README.md | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 Esp32-poe-iso.md diff --git a/Esp32-poe-iso.md b/Esp32-poe-iso.md new file mode 100644 index 0000000..2245364 --- /dev/null +++ b/Esp32-poe-iso.md @@ -0,0 +1,5 @@ +## Get Started for ESP32 POE ISO +- Set the device_type to 5 in the settings.ini +- Connect the device to your computer via USB, like a regular esp32 +- First flash, set "upload" as method under the OTA section in the settings.ini. After that you can set it to "ota" as well +- Build and flash the project with PlatformIO, for example run `pio run --target upload` from the commandline diff --git a/README.md b/README.md index 4e15777..2f0ac63 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,12 @@ Support for Snips is dropped. [Audio Kit](audiokit.md) +[INMP441](inmp441.md) + +[INMP441MAX98357A](inmp441max98357a.md) + +[ESP32-POE-ISO](Esp32-poe-iso.md) + ## MQTT commands The ESP32 Satellite is subscribed to various topics. From 0d6dc96a31cbdfebbaffbeabcd676810763b1d7d Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Mon, 17 May 2021 21:56:24 +0200 Subject: [PATCH 05/20] Remove updateColors --- PlatformIO/src/devices/Esp32_poe_iso.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/PlatformIO/src/devices/Esp32_poe_iso.hpp b/PlatformIO/src/devices/Esp32_poe_iso.hpp index 9e765da..791e06f 100644 --- a/PlatformIO/src/devices/Esp32_poe_iso.hpp +++ b/PlatformIO/src/devices/Esp32_poe_iso.hpp @@ -26,7 +26,6 @@ class Esp32_poe_iso : public Device public: Esp32_poe_iso(); void init(); - void updateColors(int colors); bool readAudio(uint8_t *data, size_t size); void setWriteMode(int sampleRate, int bitDepth, int numChannels); void writeAudio(uint8_t *data, size_t size, size_t *bytes_written); From 9324b70927131402e47fe5d6c6afb36cccab0aa6 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Tue, 6 Jul 2021 23:46:33 +0200 Subject: [PATCH 06/20] 16000 mono&stereo working --- PlatformIO/src/devices/MatrixVoice.hpp | 187 ++++++++++++++++++------- 1 file changed, 138 insertions(+), 49 deletions(-) diff --git a/PlatformIO/src/devices/MatrixVoice.hpp b/PlatformIO/src/devices/MatrixVoice.hpp index f3e9845..1c5785b 100644 --- a/PlatformIO/src/devices/MatrixVoice.hpp +++ b/PlatformIO/src/devices/MatrixVoice.hpp @@ -37,7 +37,7 @@ const uint8_t PROGMEM gamma8[] = { 255}; int err; -SpeexResamplerState *resampler = speex_resampler_init(1, 44100, 44100, 0, &err); +SpeexResamplerState *resampler = speex_resampler_init(1, 16000, 16000, 0, &err); class MatrixVoice : public Device { @@ -64,6 +64,10 @@ class MatrixVoice : public Device matrix_hal::EverloopImage image1d; void playBytes(int16_t* input, uint32_t length); void interleave(const int16_t * in_L, const int16_t * in_R, int16_t * out, const size_t num_samples); + bool FIFOFlush(); + uint16_t GetFIFOStatus(); + uint32_t PCM_sampling_frequency = 16000; + int fifoSize = 4096; int sampleRate, bitDepth, numChannels; int brightness = 15; }; @@ -82,6 +86,8 @@ void MatrixVoice::init() mics->SetSamplingRate(rate); matrix_hal::MicrophoneCore mic_core(*mics); mic_core.Setup(&wb); + uint16_t PCM_constant = 492; + wb.SpiWrite(matrix_hal::kConfBaseAddress + 9, (const uint8_t *)(&PCM_constant), sizeof(uint16_t)); }; void MatrixVoice::updateBrightness(int brightness) { @@ -161,8 +167,19 @@ void MatrixVoice::setWriteMode(int sampleRate, int bitDepth, int numChannels) { MatrixVoice::sampleRate = sampleRate; MatrixVoice::bitDepth = bitDepth; MatrixVoice::numChannels = numChannels; - speex_resampler_set_rate(resampler,sampleRate,44100); - speex_resampler_skip_zeros(resampler); + FIFOFlush(); + if (sampleRate != 16000) { + speex_resampler_set_rate(resampler,sampleRate,16000); + speex_resampler_skip_zeros(resampler); + } + if (numChannels == 1) { + writeSize = 512; + } else { + writeSize = 1024; + } + if (sampleRate == 44100) { + // writeSize = 1410; + } }; bool MatrixVoice::readAudio(uint8_t *data, size_t size) { @@ -177,54 +194,74 @@ bool MatrixVoice::readAudio(uint8_t *data, size_t size) { void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { *bytes_written = size; - float sleep = 4000; - if (MatrixVoice::sampleRate == 44100) { - if (MatrixVoice::numChannels == 2) { - //Nothing to do, write to wishbone bus - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, sizeof(data)); - std::this_thread::sleep_for(std::chrono::microseconds((int)sleep)); - } else { - int16_t mono[size / sizeof(int16_t)]; - int16_t stereo[size]; - //Convert 8 bit to 16 bit - for (int i = 0; i < size; i += 2) { + float sample_time = 1.0 / sampleRate; + uint16_t fifo_status = GetFIFOStatus(); + + if (numChannels == 1) { + int16_t stereo[size]; + int16_t mono[size / sizeof(int16_t)]; + for (int i = 0; i < size; i += 2) { mono[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); - } - MatrixVoice::interleave(mono, mono, stereo, size / sizeof(int16_t)); - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)stereo, sizeof(stereo)); - std::this_thread::sleep_for(std::chrono::microseconds((int)sleep) * 2); } - } else { - uint32_t in_len; - uint32_t out_len; - in_len = size / sizeof(int16_t); - out_len = size * (float)(44100 / MatrixVoice::sampleRate); - int16_t output[out_len]; - int16_t input[in_len]; - //Convert 8 bit to 16 bit - for (int i = 0; i < size; i += 2) { - input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + interleave(mono, mono, stereo, size / sizeof(int16_t)); + if (fifo_status > fifoSize * 3 / 4) { + int sleep = int(size * sizeof(int16_t) * sample_time * 1000); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); } + wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)stereo, size * sizeof(int16_t)); + } else { + // uint32_t in_len; + // uint32_t out_len; + // in_len = size; + // out_len = 512; + // int16_t output[out_len]; + // int16_t input[in_len]; + // //Convert 8 bit to 16 bit + // for (int i = 0; i < size; i += 2) { + // input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + // } + // speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); - if (MatrixVoice::numChannels == 2) { - speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); - - //play it! - playBytes(output, out_len); - } else { - speex_resampler_process_int(resampler, 0, input, &in_len, output, &out_len); - int16_t stereo[out_len * sizeof(int16_t)]; - int16_t mono[out_len]; - for (int i = 0; i < out_len; i++) { - mono[i] = output[i]; - } - MatrixVoice::interleave(mono, mono, stereo, out_len); - - //play it! - MatrixVoice::playBytes(stereo, out_len * sizeof(int16_t)); - } + if (fifo_status > fifoSize * 3 / 4) { + int sleep = int(size * sample_time * 1000); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + } + wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); } -}; +} + +// void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { +// *bytes_written = size; +// uint32_t in_len; +// uint32_t out_len; +// in_len = size / sizeof(int16_t); +// out_len = size * (float)(16000 / sampleRate); +// int16_t output[out_len]; +// int16_t input[in_len]; +// //Convert 8 bit to 16 bit +// for (int i = 0; i < size; i += 2) { +// input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); +// } + +// if (MatrixVoice::numChannels == 2) { +// speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); + +// //play it! +// playBytes(output, out_len); +// } else { +// speex_resampler_process_int(resampler, 0, input, &in_len, output, &out_len); +// int16_t stereo[out_len * sizeof(int16_t)]; +// int16_t mono[out_len]; + +// for (int i = 0; i < out_len; i++) { +// mono[i] = output[i]; +// } +// MatrixVoice::interleave(mono, mono, stereo, out_len); + +// //play it! +// MatrixVoice::playBytes(stereo, out_len * sizeof(int16_t)); +// } +// }; void MatrixVoice::interleave(const int16_t * in_L, const int16_t * in_R, int16_t * out, const size_t num_samples) { @@ -236,9 +273,11 @@ void MatrixVoice::interleave(const int16_t * in_L, const int16_t * in_R, int16_t } void MatrixVoice::playBytes(int16_t* input, uint32_t length) { - float sleep = 4000; + //float sleep = 4000; + float sample_time = 1.0 / PCM_sampling_frequency; int total = length * sizeof(int16_t); int index = 0; + uint16_t fifo_status = GetFIFOStatus(); while ( total - (index * sizeof(int16_t)) > MatrixVoice::writeSize) { uint16_t dataT[MatrixVoice::writeSize / sizeof(int16_t)]; @@ -246,8 +285,11 @@ void MatrixVoice::playBytes(int16_t* input, uint32_t length) { dataT[i] = input[i+index]; } + if (fifo_status > fifoSize * 3 / 4) { + int sleep = int(length * sample_time * 1000); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + } wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)dataT, MatrixVoice::writeSize); - std::this_thread::sleep_for(std::chrono::microseconds((int)sleep)); index = index + (MatrixVoice::writeSize / sizeof(int16_t)); } @@ -261,4 +303,51 @@ void MatrixVoice::playBytes(int16_t* input, uint32_t length) { wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)dataL, size * sizeof(uint16_t)); std::this_thread::sleep_for(std::chrono::microseconds((int)sleep) * (rest/MatrixVoice::writeSize)); } -} \ No newline at end of file +} + +bool MatrixVoice::FIFOFlush() { + int16_t value = 1; + wb.SpiWrite(matrix_hal::kConfBaseAddress + 12,(const uint8_t *)(&value), sizeof(uint16_t)); + value = 0; + wb.SpiWrite(matrix_hal::kConfBaseAddress + 12,(const uint8_t *)(&value), sizeof(uint16_t)); + return true; +} + +uint16_t MatrixVoice::GetFIFOStatus() { + uint16_t write_pointer; + uint16_t read_pointer; + wb.SpiRead(matrix_hal::kDACBaseAddress + 2050, (uint8_t *)(&read_pointer), sizeof(uint16_t)); + wb.SpiRead(matrix_hal::kDACBaseAddress + 2051, (uint8_t *)(&write_pointer), sizeof(uint16_t)); + + if (write_pointer > read_pointer) + return write_pointer - read_pointer; + else + return fifoSize - read_pointer + write_pointer; +} + +// bool MatrixVoice::GetPCMSamplingFrequency() { +// uint16_t PCM_constant; +// wb.SpiRead(matrix_hal::kConfBaseAddress + 9,(uint8_t *)(&PCM_constant), sizeof(uint16_t)); + +// for (int i = 0;; i++) { +// if (PCM_constant == PCM_sampling_frequencies[i][1]) { +// PCM_sampling_frequency = PCM_sampling_frequencies[i][0]; +// break; +// } +// } +// return true; +// } + +// bool MatrixVoice::SetPCMSamplingFrequency(uint32_t PCM_sampling_frequency) { +// uint16_t PCM_constant; +// for (int i = 0;; i++) { +// if (PCM_sampling_frequencies[i][0] == 0) return false; +// if (PCM_sampling_frequency == PCM_sampling_frequencies[i][0]) { +// PCM_sampling_frequency = PCM_sampling_frequencies[i][0]; +// PCM_constant = PCM_sampling_frequencies[i][1]; +// break; +// } +// } +// wb.SpiWrite(matrix_hal::kConfBaseAddress + 9, (const uint8_t *)(&PCM_constant), sizeof(uint16_t)); +// return true; +// } \ No newline at end of file From 61e1112e2b3e5d9210de1bdf5e29dcb82be81752 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sun, 11 Jul 2021 13:06:21 +0200 Subject: [PATCH 07/20] trying to fix all samplerates --- PlatformIO/src/devices/MatrixVoice.hpp | 153 +++++++++---------------- 1 file changed, 55 insertions(+), 98 deletions(-) diff --git a/PlatformIO/src/devices/MatrixVoice.hpp b/PlatformIO/src/devices/MatrixVoice.hpp index 1c5785b..df82e33 100644 --- a/PlatformIO/src/devices/MatrixVoice.hpp +++ b/PlatformIO/src/devices/MatrixVoice.hpp @@ -168,17 +168,21 @@ void MatrixVoice::setWriteMode(int sampleRate, int bitDepth, int numChannels) { MatrixVoice::bitDepth = bitDepth; MatrixVoice::numChannels = numChannels; FIFOFlush(); - if (sampleRate != 16000) { - speex_resampler_set_rate(resampler,sampleRate,16000); - speex_resampler_skip_zeros(resampler); - } + speex_resampler_set_rate(resampler,sampleRate,16000); + speex_resampler_skip_zeros(resampler); if (numChannels == 1) { writeSize = 512; } else { writeSize = 1024; } + if (sampleRate == 16000) { + writeSize = 1024; + } if (sampleRate == 44100) { - // writeSize = 1410; + writeSize = 2822; + } + if (sampleRate == 22050) { + writeSize = 1411; } }; @@ -194,40 +198,53 @@ bool MatrixVoice::readAudio(uint8_t *data, size_t size) { void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { *bytes_written = size; - float sample_time = 1.0 / sampleRate; - uint16_t fifo_status = GetFIFOStatus(); - - if (numChannels == 1) { - int16_t stereo[size]; - int16_t mono[size / sizeof(int16_t)]; - for (int i = 0; i < size; i += 2) { - mono[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); - } - interleave(mono, mono, stereo, size / sizeof(int16_t)); - if (fifo_status > fifoSize * 3 / 4) { - int sleep = int(size * sizeof(int16_t) * sample_time * 1000); - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)stereo, size * sizeof(int16_t)); - } else { - // uint32_t in_len; - // uint32_t out_len; - // in_len = size; - // out_len = 512; - // int16_t output[out_len]; - // int16_t input[in_len]; - // //Convert 8 bit to 16 bit - // for (int i = 0; i < size; i += 2) { - // input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); - // } - // speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); + float sample_time = 1.0 / 16000; + // std::valarray output; + // output.resize(size / sizeof(int16_t)); + uint32_t in_len = size / sizeof(int16_t); + uint32_t out_len; + int16_t input[in_len]; + int16_t output[512]; + int sleep = int(out_len * sizeof(int16_t) * sample_time * 1000); + for (int i = 0; i < size; i += 2) { + input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + } + //if (sampleRate != 16000) { + speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); + //} + + + // if (numChannels == 1) { + // // int16_t mono[size / sizeof(int16_t)]; + // // for (int i = 0; i < size; i += 2) { + // // mono[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + // // } + // // interleave(mono, mono, output, size / sizeof(int16_t)); + // } else { + // // uint32_t in_len; + // // uint32_t out_len; + // // in_len = size; + // // out_len = 512; + // // int16_t output[out_len]; + // // int16_t input[in_len]; + // // //Convert 8 bit to 16 bit + // // for (int i = 0; i < size; i += 2) { + // // input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + // // } + // // speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); + + // // if (fifo_status > fifoSize * 3 / 4) { + // // int sleep = int(size * sample_time * 1000); + // // std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + // // } + // // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); + // } - if (fifo_status > fifoSize * 3 / 4) { - int sleep = int(size * sample_time * 1000); - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); + uint16_t fifo_status = GetFIFOStatus(); + if (fifo_status > fifoSize * 3 / 4) { + std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); } + wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)output, out_len * sizeof(int16_t)); } // void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { @@ -272,39 +289,6 @@ void MatrixVoice::interleave(const int16_t * in_L, const int16_t * in_R, int16_t } } -void MatrixVoice::playBytes(int16_t* input, uint32_t length) { - //float sleep = 4000; - float sample_time = 1.0 / PCM_sampling_frequency; - int total = length * sizeof(int16_t); - int index = 0; - uint16_t fifo_status = GetFIFOStatus(); - - while ( total - (index * sizeof(int16_t)) > MatrixVoice::writeSize) { - uint16_t dataT[MatrixVoice::writeSize / sizeof(int16_t)]; - for (int i = 0; i < (MatrixVoice::writeSize / sizeof(int16_t)); i++) { - dataT[i] = input[i+index]; - } - - if (fifo_status > fifoSize * 3 / 4) { - int sleep = int(length * sample_time * 1000); - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)dataT, MatrixVoice::writeSize); - - index = index + (MatrixVoice::writeSize / sizeof(int16_t)); - } - int rest = total - (index * sizeof(int16_t)); - if (rest > 0) { - int size = rest / sizeof(int16_t); - uint16_t dataL[size]; - for (int i = 0; i < size; i++) { - dataL[i] = input[i+index]; - } - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)dataL, size * sizeof(uint16_t)); - std::this_thread::sleep_for(std::chrono::microseconds((int)sleep) * (rest/MatrixVoice::writeSize)); - } -} - bool MatrixVoice::FIFOFlush() { int16_t value = 1; wb.SpiWrite(matrix_hal::kConfBaseAddress + 12,(const uint8_t *)(&value), sizeof(uint16_t)); @@ -323,31 +307,4 @@ uint16_t MatrixVoice::GetFIFOStatus() { return write_pointer - read_pointer; else return fifoSize - read_pointer + write_pointer; -} - -// bool MatrixVoice::GetPCMSamplingFrequency() { -// uint16_t PCM_constant; -// wb.SpiRead(matrix_hal::kConfBaseAddress + 9,(uint8_t *)(&PCM_constant), sizeof(uint16_t)); - -// for (int i = 0;; i++) { -// if (PCM_constant == PCM_sampling_frequencies[i][1]) { -// PCM_sampling_frequency = PCM_sampling_frequencies[i][0]; -// break; -// } -// } -// return true; -// } - -// bool MatrixVoice::SetPCMSamplingFrequency(uint32_t PCM_sampling_frequency) { -// uint16_t PCM_constant; -// for (int i = 0;; i++) { -// if (PCM_sampling_frequencies[i][0] == 0) return false; -// if (PCM_sampling_frequency == PCM_sampling_frequencies[i][0]) { -// PCM_sampling_frequency = PCM_sampling_frequencies[i][0]; -// PCM_constant = PCM_sampling_frequencies[i][1]; -// break; -// } -// } -// wb.SpiWrite(matrix_hal::kConfBaseAddress + 9, (const uint8_t *)(&PCM_constant), sizeof(uint16_t)); -// return true; -// } \ No newline at end of file +} \ No newline at end of file From cbdb1fd6941c896dbac9aea206730f158023ad91 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Thu, 19 Aug 2021 11:32:07 +0200 Subject: [PATCH 08/20] audio --- PlatformIO/src/StateMachine.hpp | 12 +- PlatformIO/src/devices/MatrixVoice.hpp | 200 +++++++++++++++++++------ 2 files changed, 157 insertions(+), 55 deletions(-) diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index cca1b64..f685aaf 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -188,7 +188,7 @@ class WifiConnected : public StateMachine #if NETWORK_TYPE == NETWORK_ETHERNET Serial.printf("Connected to LAN with IP: %s, \n", ETH.localIP().toString().c_str()); #else - Serial.printf("Connected to Wifi with IP: %s, SSID: %s, BSSID: %s, RSSI: %d\n", WiFi.localIP().toString().c_str(), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), WiFi.RSSI()); + Serial.printf("Connected to Wifi with IP: %s, SSID: %s, BSSID: %s, RSSI: %d\r\n", WiFi.localIP().toString().c_str(), WiFi.SSID().c_str(), WiFi.BSSIDstr().c_str(), WiFi.RSSI()); #endif xEventGroupClearBits(audioGroup, PLAY); xEventGroupClearBits(audioGroup, STREAM); @@ -264,13 +264,13 @@ class WifiDisconnected : public StateMachine int n = WiFi.scanNetworks(); // WiFi.scanNetworks will return the number of networks found // or WIFI_SCAN_RUNNING (-1), WIFI_SCAN_FAILED (-2) - Serial.printf("WiFi scan done, result %d\n", n); + Serial.printf("WiFi scan done, result %d\r\n", n); if (n <= 0) { Serial.println("error or no networks found"); } else { for (int i = 0; i < n; ++i) { // Print metrics for each network found - Serial.printf("%d: BSSID: %s %ddBm, %d%% %s, %s (%d)\n", i + 1, WiFi.BSSIDstr(i).c_str(), WiFi.RSSI(i), constrain(2 * (WiFi.RSSI(i) + 100), 0, 100), + Serial.printf("%d: BSSID: %s %ddBm, %d%% %s, %s (%d)\r\n", i + 1, WiFi.BSSIDstr(i).c_str(), WiFi.RSSI(i), constrain(2 * (WiFi.RSSI(i) + 100), 0, 100), (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? "open " : "encrypted", WiFi.SSID(i).c_str(), WiFi.channel(i)); } } @@ -286,7 +286,7 @@ class WifiDisconnected : public StateMachine Serial.println("No network with SSID " WIFI_SSID " found!"); WiFi.begin(WIFI_SSID, WIFI_PASS); // try basic method anyway } else { - Serial.printf("SSID match found at index: %d\n", i + 1); + Serial.printf("SSID match found at index: %d\r\n", i + 1); WiFi.begin(WIFI_SSID, WIFI_PASS, 0, WiFi.BSSID(i)); // pass selected BSSID } #else @@ -561,7 +561,7 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties } else { - Serial.printf("Unhandled partial message received, topic '%s'", topic); + Serial.printf("Unhandled partial message received, topic '%s'\r\n", topic); } } } @@ -589,7 +589,7 @@ void I2Stask(void *p) { { if (!audioData.pop(data[i])) { - Serial.printf("Buffer underflow %d %ld\n", played + i, message_size); + Serial.printf("Buffer underflow %d %ld\r\n", played + i, message_size); vTaskDelay(60); bytes_to_write = (i)*2; } diff --git a/PlatformIO/src/devices/MatrixVoice.hpp b/PlatformIO/src/devices/MatrixVoice.hpp index df82e33..d41ecea 100644 --- a/PlatformIO/src/devices/MatrixVoice.hpp +++ b/PlatformIO/src/devices/MatrixVoice.hpp @@ -70,6 +70,11 @@ class MatrixVoice : public Device int fifoSize = 4096; int sampleRate, bitDepth, numChannels; int brightness = 15; + float sample_time = 1.0 / 16000; + uint32_t spiLength = 1024; + int sleep = int(spiLength * sample_time * 1000); + int count = 0; + }; MatrixVoice::MatrixVoice() @@ -170,20 +175,23 @@ void MatrixVoice::setWriteMode(int sampleRate, int bitDepth, int numChannels) { FIFOFlush(); speex_resampler_set_rate(resampler,sampleRate,16000); speex_resampler_skip_zeros(resampler); - if (numChannels == 1) { - writeSize = 512; - } else { - writeSize = 1024; - } - if (sampleRate == 16000) { + switch (sampleRate) + { + case 22050: + writeSize = 1411; + break; + case 44100: + writeSize = 2823; + break; + default: writeSize = 1024; + break; } - if (sampleRate == 44100) { - writeSize = 2822; - } - if (sampleRate == 22050) { - writeSize = 1411; + if (numChannels == 1) { + writeSize = writeSize / sizeof(uint16_t); } + count = 0; + spiLength = 1024; }; bool MatrixVoice::readAudio(uint8_t *data, size_t size) { @@ -196,57 +204,151 @@ bool MatrixVoice::readAudio(uint8_t *data, size_t size) { return true; } -void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { - *bytes_written = size; - float sample_time = 1.0 / 16000; - // std::valarray output; - // output.resize(size / sizeof(int16_t)); - uint32_t in_len = size / sizeof(int16_t); - uint32_t out_len; - int16_t input[in_len]; - int16_t output[512]; - int sleep = int(out_len * sizeof(int16_t) * sample_time * 1000); - for (int i = 0; i < size; i += 2) { - input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); +void MatrixVoice::writeAudio(uint8_t *data, size_t inputLength, size_t *bytes_written) { + *bytes_written = inputLength; + uint32_t outputLength = (numChannels == 1) ? inputLength * sizeof(int16_t) : inputLength; + int16_t output[outputLength]; + + if (numChannels == 1) { + uint32_t monoLength = inputLength / sizeof(int16_t); + int16_t mono[monoLength]; + int16_t stereo[inputLength]; + for (int i = 0; i < inputLength; i += 2) { + mono[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + } + interleave(mono, mono, stereo, monoLength); + for (int i = 0; i < inputLength; i++) { + output[i] = stereo[i]; + } + } else { + for (int i = 0; i < inputLength; i += 2) { + output[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + } } - //if (sampleRate != 16000) { - speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); - //} + + //At this point, we always have a stereo audio message, at whatever rate. + //The length of the bytes is dependant on the input sampleRate. + //1024 with 16000Hz, 2822 for 441000. (44100/16000) * 1024 = 2822 + //We might need to resample of the inputRate is higher than 16000 + uint16_t spiSamples[spiLength]; + if (sampleRate > 16000) { + int16_t resampled[spiLength]; + //Serial.printf("before resample %d, %d\r\n", spiLength, outputLength); + speex_resampler_process_interleaved_int(resampler, output, &outputLength, resampled, &spiLength); + //Serial.printf("after resample %d, %d\r\n", spiLength, outputLength); + for (int i = 0; i < spiLength; i++) { + spiSamples[i] = resampled[i]; + } + } else { + for (int i = 0; i < spiLength; i++) { + spiSamples[i] = output[i]; + } + } + + + if (GetFIFOStatus() > fifoSize * 3 / 4) { + std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + } + Serial.printf("Write %d, %d, %d, %d\r\n", spiLength, sizeof(spiSamples), sleep, count); + wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)spiSamples, spiLength); + count++; // if (numChannels == 1) { // // int16_t mono[size / sizeof(int16_t)]; + // // int16_t stereo[size]; // // for (int i = 0; i < size; i += 2) { // // mono[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); // // } - // // interleave(mono, mono, output, size / sizeof(int16_t)); - // } else { - // // uint32_t in_len; - // // uint32_t out_len; - // // in_len = size; - // // out_len = 512; - // // int16_t output[out_len]; - // // int16_t input[in_len]; - // // //Convert 8 bit to 16 bit - // // for (int i = 0; i < size; i += 2) { - // // input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); - // // } - // // speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); - + // // interleave(mono, mono, stereo, size / sizeof(int16_t)); // // if (fifo_status > fifoSize * 3 / 4) { - // // int sleep = int(size * sample_time * 1000); + // // int sleep = int(size * sizeof(int16_t) * sample_time * 1000); // // std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); // // } - // // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); - // } - - uint16_t fifo_status = GetFIFOStatus(); - if (fifo_status > fifoSize * 3 / 4) { - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)output, out_len * sizeof(int16_t)); + // // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)stereo, size * sizeof(int16_t)); + // } else { + // if (sampleRate == 44100) { + // uint32_t in_len = size / sizeof(int16_t); + // uint32_t out_len = 1024 / sizeof(int16_t); + // int16_t input[in_len]; + // int16_t output[out_len]; + // for (int i = 0; i < size; i += 2) { + // input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); + // } + // speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); + // if (fifo_status > fifoSize * 3 / 4) { + // int sleep = int( ( out_len / sizeof(int16_t)) * sample_time * 1000); + // std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + // } + // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)output, out_len * sizeof(int16_t)); + // } else { + // if (fifo_status > fifoSize * 3 / 4) { + // int sleep = int(size * sample_time * 1000); + // std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); + // } + // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); + // } + //} } +// void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { +// *bytes_written = size; +// float sample_time = 1.0 / 16000; +// uint16_t fifo_status = GetFIFOStatus(); +// uint32_t in_len = size / sizeof(int16_t); +// uint32_t out_len = size / sizeof(int16_t); +// int16_t input[in_len]; +// int16_t output[out_len]; +// int sleep = int(out_len * sizeof(int16_t) * sample_time * 1000); +// for (int i = 0; i < size; i += 2) { +// input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); +// } + +// if (numChannels == 1) { +// int16_t mono[size / sizeof(int16_t)]; +// for (int i = 0; i < size; i += 2) { +// mono[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); +// } +// interleave(mono, mono, output, size / sizeof(int16_t)); +// } else { +// // uint32_t in_len; +// // uint32_t out_len; +// // in_len = size; +// // out_len = 512; +// // int16_t output[out_len]; +// // int16_t input[in_len]; +// // //Convert 8 bit to 16 bit +// // for (int i = 0; i < size; i += 2) { +// // input[i/2] = ((data[i] & 0xff) | (data[i + 1] << 8)); +// // } +// // speex_resampler_process_interleaved_int(resampler, input, &in_len, output, &out_len); + +// // if (fifo_status > fifoSize * 3 / 4) { +// // int sleep = int(size * sample_time * 1000); +// // std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); +// // } +// // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); +// } + +// if (fifo_status > fifoSize * 3 / 4) { +// std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); +// } +// // wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)output, out_len * sizeof(int16_t)); +// } + + +// void MatrixVoice::writeAudioStereo1600OK(uint8_t *data, size_t size, size_t *bytes_written) { +// *bytes_written = size; +// float sample_time = 1.0 / 16000; +// int sleep = int(size * sample_time * 1000); +// uint16_t fifo_status = GetFIFOStatus(); + +// if (fifo_status > fifoSize * 3 / 4) { +// std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); +// } +// wb.SpiWrite(matrix_hal::kDACBaseAddress, (const uint8_t *)data, size); +// } + // void MatrixVoice::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { // *bytes_written = size; // uint32_t in_len; From 012dfbbf59d39c8760daad447c56d6e340b94b8a Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Thu, 19 Aug 2021 11:44:19 +0200 Subject: [PATCH 09/20] update colors when message processing is done --- PlatformIO/src/StateMachine.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index cca1b64..930ded9 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -494,6 +494,7 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties ota_colors[2] = root["update"][2]; ota_colors[3] = root["update"][3]; } + device->updateColors(COLORS_IDLE); if (saveNeeded) { saveConfiguration(configfile, config); } From 18649709ee95fed7e4a11eae10a356e4b7914f7d Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Fri, 20 Aug 2021 16:40:33 +0200 Subject: [PATCH 10/20] update brightness --- PlatformIO/src/StateMachine.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index 930ded9..60b3d04 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -458,6 +458,7 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties if (root.containsKey("brightness")) { if (config.brightness != (int)root["brightness"]) { config.brightness = (int)(root["brightness"]); + device->updateBrightness(config.brightness); saveNeeded = true; } } From c321eda7524c6958d6b1d3e3778773b54f754b7e Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Fri, 20 Aug 2021 16:43:57 +0200 Subject: [PATCH 11/20] limit brightness to 100 --- PlatformIO/src/devices/MatrixVoice.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PlatformIO/src/devices/MatrixVoice.hpp b/PlatformIO/src/devices/MatrixVoice.hpp index f3e9845..8dd2a51 100644 --- a/PlatformIO/src/devices/MatrixVoice.hpp +++ b/PlatformIO/src/devices/MatrixVoice.hpp @@ -86,6 +86,7 @@ void MatrixVoice::init() void MatrixVoice::updateBrightness(int brightness) { // all values below 10 is read as 0 in gamma8, we map 0 to 10 + if (brightness > 100) { brightness = 100; } MatrixVoice::brightness = brightness * 90 / 100 + 10; } From 34bb390a0d2c5b4d97bf725ee96f023b5396f2f1 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Fri, 20 Aug 2021 19:27:50 +0200 Subject: [PATCH 12/20] send Idle event instead of updating colors and add OTA state --- PlatformIO/src/General.hpp | 2 ++ PlatformIO/src/Satellite.cpp | 1 + PlatformIO/src/StateMachine.hpp | 24 ++++++++++++++++++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/PlatformIO/src/General.hpp b/PlatformIO/src/General.hpp index 178b2a3..9aa5a7d 100644 --- a/PlatformIO/src/General.hpp +++ b/PlatformIO/src/General.hpp @@ -94,6 +94,7 @@ struct WifiDisconnected; struct MQTTDisconnected; struct HotwordDetected; struct Idle; +struct Updating; struct PlayAudio; struct WifiDisconnectEvent : tinyfsm::Event { }; @@ -101,6 +102,7 @@ struct WifiConnectEvent : tinyfsm::Event { }; struct MQTTDisconnectedEvent : tinyfsm::Event { }; struct MQTTConnectedEvent : tinyfsm::Event { }; struct IdleEvent : tinyfsm::Event { }; +struct OtaEvent : tinyfsm::Event { }; struct StreamAudioEvent : tinyfsm::Event { }; struct PlayAudioEvent : tinyfsm::Event {}; struct HotwordDetectedEvent : tinyfsm::Event { }; diff --git a/PlatformIO/src/Satellite.cpp b/PlatformIO/src/Satellite.cpp index 0253553..a02eeb7 100644 --- a/PlatformIO/src/Satellite.cpp +++ b/PlatformIO/src/Satellite.cpp @@ -183,6 +183,7 @@ void setup() { ArduinoOTA .onStart([]() { Serial.println("Uploading..."); + send_event(OtaEvent()); }) .onEnd([]() { Serial.println("\nEnd"); diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index 60b3d04..086d1ad 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -13,6 +13,7 @@ class StateMachine virtual void react(MQTTDisconnectedEvent const &) {}; virtual void react(StreamAudioEvent const &) {}; virtual void react(IdleEvent const &) {}; + virtual void react(OtaEvent const &) {}; virtual void react(PlayAudioEvent const &) {}; virtual void react(HotwordDetectedEvent const &) {}; @@ -21,6 +22,19 @@ class StateMachine void exit(void) {}; }; +class Updating : public StateMachine +{ + void entry(void) override { + xEventGroupClearBits(audioGroup, PLAY); + xEventGroupClearBits(audioGroup, STREAM); + device->updateBrightness(config.brightness); + if (xSemaphoreTake(wbSemaphore, (TickType_t)10000) == pdTRUE) { + device->updateColors(COLORS_OTA); + xSemaphoreGive(wbSemaphore); + } + } +}; + class HotwordDetected : public StateMachine { void entry(void) override { @@ -104,6 +118,13 @@ class Idle : public StateMachine xEventGroupSetBits(audioGroup, PLAY); }; + void react(IdleEvent const &) override { + transit(); + } + + void react(OtaEvent const &) override { + transit(); + } }; class MQTTConnected : public StateMachine { @@ -458,7 +479,6 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties if (root.containsKey("brightness")) { if (config.brightness != (int)root["brightness"]) { config.brightness = (int)(root["brightness"]); - device->updateBrightness(config.brightness); saveNeeded = true; } } @@ -495,10 +515,10 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties ota_colors[2] = root["update"][2]; ota_colors[3] = root["update"][3]; } - device->updateColors(COLORS_IDLE); if (saveNeeded) { saveConfiguration(configfile, config); } + send_event(IdleEvent()); } else { publishDebug(err.c_str()); } From 975af3aefc9441a8e56e944c5b0235defba24f76 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sat, 28 Aug 2021 13:53:52 +0200 Subject: [PATCH 13/20] Add a state for speaking and better semaphore logic --- PlatformIO/src/General.hpp | 2 + PlatformIO/src/StateMachine.hpp | 94 ++++++++++++++++++++------ PlatformIO/src/devices/MatrixVoice.hpp | 32 ++++++++- 3 files changed, 105 insertions(+), 23 deletions(-) diff --git a/PlatformIO/src/General.hpp b/PlatformIO/src/General.hpp index 178b2a3..cab92c3 100644 --- a/PlatformIO/src/General.hpp +++ b/PlatformIO/src/General.hpp @@ -94,6 +94,7 @@ struct WifiDisconnected; struct MQTTDisconnected; struct HotwordDetected; struct Idle; +struct Speaking; struct PlayAudio; struct WifiDisconnectEvent : tinyfsm::Event { }; @@ -101,6 +102,7 @@ struct WifiConnectEvent : tinyfsm::Event { }; struct MQTTDisconnectedEvent : tinyfsm::Event { }; struct MQTTConnectedEvent : tinyfsm::Event { }; struct IdleEvent : tinyfsm::Event { }; +struct SpeakEvent : tinyfsm::Event { }; struct StreamAudioEvent : tinyfsm::Event { }; struct PlayAudioEvent : tinyfsm::Event {}; struct HotwordDetectedEvent : tinyfsm::Event { }; diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index f685aaf..246175b 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -13,6 +13,7 @@ class StateMachine virtual void react(MQTTDisconnectedEvent const &) {}; virtual void react(StreamAudioEvent const &) {}; virtual void react(IdleEvent const &) {}; + virtual void react(SpeakEvent const &) {}; virtual void react(PlayAudioEvent const &) {}; virtual void react(HotwordDetectedEvent const &) {}; @@ -21,6 +22,27 @@ class StateMachine void exit(void) {}; }; +class Speaking : public StateMachine +{ + void react(IdleEvent const &) override { + transit(); + } + + void react(HotwordDetectedEvent const &) override { + transit(); + } + + void react(StreamAudioEvent const &) override { + xEventGroupClearBits(audioGroup, PLAY); + xEventGroupSetBits(audioGroup, STREAM); + }; + + void react(PlayAudioEvent const &) override { + xEventGroupClearBits(audioGroup, STREAM); + xEventGroupSetBits(audioGroup, PLAY); + }; +}; + class HotwordDetected : public StateMachine { void entry(void) override { @@ -28,10 +50,9 @@ class HotwordDetected : public StateMachine xEventGroupClearBits(audioGroup, PLAY); xEventGroupClearBits(audioGroup, STREAM); device->updateBrightness(config.hotword_brightness); - if (xSemaphoreTake(wbSemaphore, (TickType_t)10000) == pdTRUE) { - device->updateColors(COLORS_HOTWORD); - xSemaphoreGive(wbSemaphore); - } + xSemaphoreTake(wbSemaphore, portMAX_DELAY); + device->updateColors(COLORS_HOTWORD); + xSemaphoreGive(wbSemaphore); initHeader(device->readSize, device->width, device->rate); xEventGroupSetBits(audioGroup, STREAM); } @@ -50,6 +71,10 @@ class HotwordDetected : public StateMachine transit(); } + void react(SpeakEvent const &) override { + transit(); + } + void react(WifiDisconnectEvent const &) override { transit(); }; @@ -65,10 +90,9 @@ class Idle : public StateMachine xEventGroupClearBits(audioGroup, PLAY); xEventGroupClearBits(audioGroup, STREAM); device->updateBrightness(config.brightness); - if (xSemaphoreTake(wbSemaphore, (TickType_t)10000) == pdTRUE) { - device->updateColors(COLORS_IDLE); - xSemaphoreGive(wbSemaphore); - } + xSemaphoreTake(wbSemaphore, portMAX_DELAY); + device->updateColors(COLORS_IDLE); + xSemaphoreGive(wbSemaphore); initHeader(device->readSize, device->width, device->rate); xEventGroupSetBits(audioGroup, STREAM); } @@ -104,6 +128,9 @@ class Idle : public StateMachine xEventGroupSetBits(audioGroup, PLAY); }; + void react(SpeakEvent const &) override { + transit(); + } }; class MQTTConnected : public StateMachine { @@ -425,10 +452,13 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties // Check if this is for us if (!err) { JsonObject root = doc.as(); - if (root["siteId"] == config.siteid.c_str() - && root.containsKey("reason") - && root["reason"] == "dialogueSession") { - send_event(HotwordDetectedEvent()); + if (root["siteId"] == config.siteid.c_str() && root.containsKey("reason")) { + if (root["reason"] == "dialogueSession") { + send_event(HotwordDetectedEvent()); + } + if (root["reason"] == "ttsSay") { + send_event(SpeakEvent()); + } } } } else if (topicstr.find("toggleOn") != std::string::npos) { @@ -438,10 +468,10 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties // Check if this is for us if (!err) { JsonObject root = doc.as(); - if (root["siteId"] == config.siteid.c_str() - && root.containsKey("reason") - && root["reason"] == "dialogueSession") { - send_event(IdleEvent()); + if (root["siteId"] == config.siteid.c_str() && root.containsKey("reason")) { + if (root["reason"] == "dialogueSession" || root["reason"] == "ttsSay") { + send_event(IdleEvent()); + } } } } @@ -568,15 +598,22 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties void I2Stask(void *p) { while (1) { - if (xEventGroupGetBits(audioGroup) == PLAY && xSemaphoreTake(wbSemaphore, (TickType_t)5000) == pdTRUE) { + if (xEventGroupGetBits(audioGroup) == PLAY) { size_t bytes_written; boolean timeout = false; int played = 44; + xSemaphoreTake(wbSemaphore, portMAX_DELAY); device->setWriteMode(sampleRate, bitDepth, numChannels); + xSemaphoreGive(wbSemaphore); while (played < message_size && timeout == false) { + if (fsm::is_in_state()) { + xSemaphoreTake(wbSemaphore, portMAX_DELAY); + device->animate(COLORS_OTA); + xSemaphoreGive(wbSemaphore); + } int bytes_to_write = device->writeSize; if (message_size - played < device->writeSize) { @@ -597,9 +634,10 @@ void I2Stask(void *p) { played = played + bytes_to_write; if (!config.mute_output) { + xSemaphoreTake(wbSemaphore, portMAX_DELAY); device->muteOutput(false); device->writeAudio((uint8_t*)data, bytes_to_write, &bytes_written); - + xSemaphoreGive(wbSemaphore); } else { @@ -611,16 +649,30 @@ void I2Stask(void *p) { } } asyncClient.publish(playFinishedTopic.c_str(), 0, false, finishedMsg.c_str()); + xSemaphoreTake(wbSemaphore, portMAX_DELAY); device->muteOutput(true); + xSemaphoreGive(wbSemaphore); audioData.clear(); Serial.println("Done"); - xSemaphoreGive(wbSemaphore); + // if (fsm::is_in_state() || fsm::is_in_state()) { + // xSemaphoreTake(wbSemaphore, portMAX_DELAY); + // device->updateColors(COLORS_IDLE); + // xSemaphoreGive(wbSemaphore); + // } + // if (fsm::is_in_state()) { + // xSemaphoreTake(wbSemaphore, portMAX_DELAY); + // device->updateColors(COLORS_HOTWORD); + // xSemaphoreGive(wbSemaphore); + // } send_event(StreamAudioEvent()); } - if (xEventGroupGetBits(audioGroup) == STREAM && !config.mute_input && xSemaphoreTake(wbSemaphore, (TickType_t)5000) == pdTRUE) { + if (xEventGroupGetBits(audioGroup) == STREAM && !config.mute_input) { + xSemaphoreTake(wbSemaphore, portMAX_DELAY); device->setReadMode(); + xSemaphoreGive(wbSemaphore); uint8_t data[device->readSize * device->width]; if (audioServer.connected()) { + xSemaphoreTake(wbSemaphore, portMAX_DELAY); if (device->readAudio(data, device->readSize * device->width)) { // only send audio if hotword_detection is HW_REMOTE. //TODO when LOCAL is supported: check if hotword is detected and send audio as well in that case @@ -642,11 +694,11 @@ void I2Stask(void *p) { //Loop, because otherwise this causes timeouts audioServer.loop(); } + xSemaphoreGive(wbSemaphore); } else { xEventGroupClearBits(audioGroup, STREAM); send_event(MQTTDisconnectedEvent()); } - xSemaphoreGive(wbSemaphore); } //Added for stability when neither PLAY or STREAM is set. diff --git a/PlatformIO/src/devices/MatrixVoice.hpp b/PlatformIO/src/devices/MatrixVoice.hpp index d41ecea..ffecce6 100644 --- a/PlatformIO/src/devices/MatrixVoice.hpp +++ b/PlatformIO/src/devices/MatrixVoice.hpp @@ -44,6 +44,7 @@ class MatrixVoice : public Device public: MatrixVoice(); void init(); + void animate(int colors); void updateColors(int colors); void updateBrightness(int brightness); void muteOutput(bool mute); @@ -74,7 +75,8 @@ class MatrixVoice : public Device uint32_t spiLength = 1024; int sleep = int(spiLength * sample_time * 1000); int count = 0; - + int position = 0; + long currentMillis, startMillis; }; MatrixVoice::MatrixVoice() @@ -92,7 +94,9 @@ void MatrixVoice::init() matrix_hal::MicrophoneCore mic_core(*mics); mic_core.Setup(&wb); uint16_t PCM_constant = 492; - wb.SpiWrite(matrix_hal::kConfBaseAddress + 9, (const uint8_t *)(&PCM_constant), sizeof(uint16_t)); + wb.SpiWrite(matrix_hal::kConfBaseAddress + 9, (const uint8_t *)(&PCM_constant), sizeof(uint16_t)); + currentMillis = millis(); + startMillis = millis(); }; void MatrixVoice::updateBrightness(int brightness) { @@ -100,6 +104,30 @@ void MatrixVoice::updateBrightness(int brightness) { MatrixVoice::brightness = brightness * 90 / 100 + 10; } +void MatrixVoice::animate(int colors) { + currentMillis = millis(); + if (currentMillis - startMillis > 10) { + startMillis = millis(); + int r = 0; + int g = 0; + int b = 0; + int w = 0; + for (int i = 0; i < image1d.leds.size(); i++) { + r = ((i + 1) * brightness / image1d.leds.size()) * ota_colors[0] / 100; + g = ((i + 1) * brightness / image1d.leds.size()) * ota_colors[1] / 100; + b = ((i + 1) * brightness / image1d.leds.size()) * ota_colors[2] / 100; + w = ((i + 1) * brightness / image1d.leds.size()) * ota_colors[3] / 100; + image1d.leds[(i + position) % image1d.leds.size()].red = pgm_read_byte(&gamma8[r]); + image1d.leds[(i + position) % image1d.leds.size()].green = pgm_read_byte(&gamma8[g]); + image1d.leds[(i + position) % image1d.leds.size()].blue = pgm_read_byte(&gamma8[b]); + image1d.leds[(i + position) % image1d.leds.size()].white = pgm_read_byte(&gamma8[w]); + } + position++; + position %= image1d.leds.size(); + everloop.Write(&image1d); + } +} + void MatrixVoice::updateColors(int colors) { int r = 0; int g = 0; From 53680c09119ffd65bd5f6dd2e8ffeb478b77cfc3 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sat, 28 Aug 2021 14:00:15 +0200 Subject: [PATCH 14/20] add animate to device --- PlatformIO/src/StateMachine.hpp | 10 ---------- PlatformIO/src/device.h | 2 ++ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index 246175b..e7e76cf 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -654,16 +654,6 @@ void I2Stask(void *p) { xSemaphoreGive(wbSemaphore); audioData.clear(); Serial.println("Done"); - // if (fsm::is_in_state() || fsm::is_in_state()) { - // xSemaphoreTake(wbSemaphore, portMAX_DELAY); - // device->updateColors(COLORS_IDLE); - // xSemaphoreGive(wbSemaphore); - // } - // if (fsm::is_in_state()) { - // xSemaphoreTake(wbSemaphore, portMAX_DELAY); - // device->updateColors(COLORS_HOTWORD); - // xSemaphoreGive(wbSemaphore); - // } send_event(StreamAudioEvent()); } if (xEventGroupGetBits(audioGroup) == STREAM && !config.mute_input) { diff --git a/PlatformIO/src/device.h b/PlatformIO/src/device.h index e4d2434..24d8197 100644 --- a/PlatformIO/src/device.h +++ b/PlatformIO/src/device.h @@ -35,6 +35,8 @@ class Device { virtual void init() {}; //If your device has leds, override these methods to set the colors and brightness virtual void updateColors(int colors) {}; + //You can create some animation here + virtual void animate(int colors) {}; virtual void updateBrightness(int brightness) {}; //It may be needed to switch between read and write, i.e. if the need the same PIN //Override both methods From 090e7cc9553835b002170182daee636a100e81af Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Mon, 30 Aug 2021 19:55:01 +0200 Subject: [PATCH 15/20] add saytopic for reactions --- PlatformIO/src/General.hpp | 2 ++ PlatformIO/src/StateMachine.hpp | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/PlatformIO/src/General.hpp b/PlatformIO/src/General.hpp index b437f05..a28f94a 100644 --- a/PlatformIO/src/General.hpp +++ b/PlatformIO/src/General.hpp @@ -77,6 +77,8 @@ std::string audioTopic = config.siteid + std::string("/audio"); std::string ledTopic = config.siteid + std::string("/led"); std::string debugTopic = config.siteid + std::string("/debug"); std::string restartTopic = config.siteid + std::string("/restart"); +std::string sayTopic = "hermes/tts/say"; +std::string sayFinishedTopic = "hermes/tts/sayFinished"; AsyncMqttClient asyncClient; WiFiClient net; PubSubClient audioServer(net); diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index b016167..786b1ab 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -165,6 +165,8 @@ class MQTTConnected : public StateMachine { asyncClient.subscribe(debugTopic.c_str(), 0); asyncClient.subscribe(ledTopic.c_str(), 0); asyncClient.subscribe(restartTopic.c_str(), 0); + asyncClient.subscribe(sayTopic.c_str(), 0); + asyncClient.subscribe(sayFinishedTopic.c_str(), 0); transit(); } @@ -465,7 +467,31 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties // complete or enf of message has been received if (len + index == total) { - if (topicstr.find("toggleOff") != std::string::npos) + if (topicstr.find(sayFinishedTopic.c_str()) != std::string::npos) + { + std::string payloadstr(payload); + StaticJsonDocument<300> doc; + DeserializationError err = deserializeJson(doc, payloadstr.c_str()); + // Check if this is for us + if (!err) { + JsonObject root = doc.as(); + if (root["siteId"] == config.siteid.c_str()) { + send_event(IdleEvent()); + } + } + } else if (topicstr.find(sayTopic.c_str()) != std::string::npos) + { + std::string payloadstr(payload); + StaticJsonDocument<300> doc; + DeserializationError err = deserializeJson(doc, payloadstr.c_str()); + // Check if this is for us + if (!err) { + JsonObject root = doc.as(); + if (root["siteId"] == config.siteid.c_str()) { + send_event(SpeakEvent()); + } + } + } else if (topicstr.find("toggleOff") != std::string::npos) { std::string payloadstr(payload); StaticJsonDocument<300> doc; From aa2d015791af36285938946ccc004f8cb489c5f8 Mon Sep 17 00:00:00 2001 From: Hendrik Langer Date: Sun, 10 Oct 2021 15:00:28 +0200 Subject: [PATCH 16/20] add new device: LilyGO/TTGO-TAudio --- PlatformIO/platformio.ini | 7 +- PlatformIO/settings.ini.example | 2 +- PlatformIO/src/Satellite.cpp | 4 + PlatformIO/src/devices/TAudio.hpp | 246 ++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 PlatformIO/src/devices/TAudio.hpp diff --git a/PlatformIO/platformio.ini b/PlatformIO/platformio.ini index 3302858..650298a 100644 --- a/PlatformIO/platformio.ini +++ b/PlatformIO/platformio.ini @@ -14,7 +14,7 @@ default_envs = esp32dev build_flags = '-DFIXED_POINT=1' '-DOUTSIDE_SPEEX=1' - + [env] extra_scripts = pre:load_settings.py platform = espressif32 @@ -39,6 +39,8 @@ lib_deps = m5stack/M5Atom fastled/FastLED yveaux/AC101 @ ^0.0.1 + celliesprojects/wm8978-esp32 + makuna/NeoPixelBus [env:esp32dev] @@ -60,3 +62,6 @@ build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=3 [env:inmp441Mmax98357a] build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=4 + +[env:taudio] +build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=6 diff --git a/PlatformIO/settings.ini.example b/PlatformIO/settings.ini.example index 8faaf70..6589a4a 100644 --- a/PlatformIO/settings.ini.example +++ b/PlatformIO/settings.ini.example @@ -2,7 +2,7 @@ hostname=192.168.43.140 deployhost=192.168.43.24 siteId=satellite -;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4 +;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4, TAUDIO=6 device_type=4 ;network_type: 0: WiFi, 1: Ethernet network_type=0 diff --git a/PlatformIO/src/Satellite.cpp b/PlatformIO/src/Satellite.cpp index a02eeb7..8474c4c 100644 --- a/PlatformIO/src/Satellite.cpp +++ b/PlatformIO/src/Satellite.cpp @@ -119,6 +119,7 @@ #define INMP441 3 #define INMP441MAX98357A 4 #define ESP32_POE_ISO 5 +#define TAUDIO 6 #ifdef PI_DEVICE_TYPE #undef DEVICE_TYPE @@ -146,6 +147,9 @@ #elif DEVICE_TYPE == ESP32_POE_ISO #include "devices/Esp32_poe_iso.hpp" Esp32_poe_iso *device = new Esp32_poe_iso(); +#elif DEVICE_TYPE == TAUDIO + #include "devices/TAudio.hpp" + TAudio *device = new TAudio(); #else #error DEVICE_TYPE is out of range #endif diff --git a/PlatformIO/src/devices/TAudio.hpp b/PlatformIO/src/devices/TAudio.hpp new file mode 100644 index 0000000..88928b4 --- /dev/null +++ b/PlatformIO/src/devices/TAudio.hpp @@ -0,0 +1,246 @@ +#pragma once +#include +#include + +#include +#include + +#include + +// Pins for the TTGO T-Audio (T9) +#define CONFIG_I2S_BCK_PIN 33 +#define CONFIG_I2S_LRCK_PIN 25 +#define CONFIG_I2S_DATA_PIN 26 +#define CONFIG_I2S_DATA_IN_PIN 27 + +//#define WM8978_I2S_CLK 0 +#define WM8978_SDA 19 +#define WM8978_SCL 18 +#define WS2812B_DATA_PIN 22 +#define WS2812B_NUM_LEDS 19 + +//#define KEY1_GPIO RST +#define KEY2_GPIO 39 +#define KEY3_GPIO 36 +#define KEY4_GPIO 34 +// alias +#define KEY_LISTEN KEY2_GPIO + +// #define SD MISO 2 +// #define SD SCK 14 +// #define SD CS 13 +// #define SD MOSI 15 + +#define I2S_NUM I2S_NUM_0 + + +NeoPixelBus strip(WS2812B_NUM_LEDS, WS2812B_DATA_PIN); + + +class TAudio : public Device { + public: + TAudio(); + void init(); + void updateColors(int colors); + void updateBrightness(int brightness); + void setReadMode(); + void setWriteMode(int sampleRate, int bitDepth, int numChannels); + void writeAudio(uint8_t *data, size_t size, size_t *bytes_written); + bool readAudio(uint8_t *data, size_t size); + void muteOutput(bool mute); + void ampOutput(int output); + void setVolume(uint16_t volume); + void setGain(uint16_t gain); + bool isHotwordDetected(); + int numAmpOutConfigurations() { return 3; }; + int readSize = 512; + int writeSize = 512; + int width = 2; + int rate = 16000; + + private: + void InitI2S(); + WM8978 dac; + + AmpOut out_amp = AMP_OUT_SPEAKERS; + uint8_t out_vol; + bool muted; + uint8_t brightness; +}; + +TAudio::TAudio() { +} + +void TAudio::init() { + // LEDs + strip.Begin(); + strip.ClearTo(RgbColor(0)); + brightness = 64; + strip.Show(); + + Serial.printf("Connect to WM8978 codec... "); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + REG_WRITE(PIN_CTRL, 0xFFFFFFF0); + while (!dac.begin(WM8978_SDA, WM8978_SCL)) + { + Serial.printf("Setting up DAC failed!\n"); + delay(1000); + } + dac.cfgInput(1, 0, 0); + dac.setMICgain(40); // 25 + dac.setHPF(1); + + dac.setSPKvol(58); // 63 + dac.setHPvol(48, 48); + out_vol = 58; muted = false; + + pinMode(KEY_LISTEN, INPUT); + + InitI2S(); +} + +void TAudio::InitI2S() { + esp_err_t err = ESP_OK; + + i2s_driver_uninstall(I2S_NUM); + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX), + .sample_rate = 16000, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 4, + .dma_buf_len = 512, + .use_apll = true + }; + i2s_config.tx_desc_auto_clear = true; + + err += i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); + i2s_pin_config_t tx_pin_config; + + tx_pin_config.bck_io_num = CONFIG_I2S_BCK_PIN; + tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN; + tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN; + tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN; + + err += i2s_set_pin(I2S_NUM, &tx_pin_config); + err += i2s_set_clk(I2S_NUM, 16000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); + + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + REG_WRITE(PIN_CTRL, 0xFFFFFFF0); + + return; +} + +void TAudio::updateColors(int colors) { + switch (colors) { + case COLORS_HOTWORD: + strip.ClearTo(RgbColor(RgbwColor(hotword_colors[0],hotword_colors[1],hotword_colors[2],hotword_colors[3])).Dim(brightness)); + break; + case COLORS_WIFI_CONNECTED: + strip.ClearTo(RgbColor(RgbwColor(wifi_conn_colors[0],wifi_conn_colors[1],wifi_conn_colors[2],wifi_conn_colors[3])).Dim(brightness)); + break; + case COLORS_IDLE: + strip.ClearTo(RgbColor(RgbwColor(idle_colors[0],idle_colors[1],idle_colors[2],idle_colors[3])).Dim(brightness)); + break; + case COLORS_WIFI_DISCONNECTED: + strip.ClearTo(RgbColor(RgbwColor(wifi_disc_colors[0],wifi_disc_colors[1],wifi_disc_colors[2],wifi_disc_colors[3])).Dim(brightness)); + break; + case COLORS_OTA: + strip.ClearTo(RgbColor(RgbwColor(ota_colors[0],ota_colors[1],ota_colors[2],ota_colors[3])).Dim(brightness)); + break; + } + strip.Show(); +} + +void TAudio::updateBrightness(int brightness) { + this->brightness = (brightness*255)/100; +} + +void TAudio::setWriteMode(int sampleRate, int bitDepth, int numChannels) { + if (mode != MODE_SPK) { + mode = MODE_SPK; + } + if (sampleRate > 0) { + //i2s_zero_dma_buffer(I2S_NUM); + i2s_set_clk(I2S_NUM, sampleRate, static_cast(bitDepth), static_cast(numChannels)); + } +} + +void TAudio::setReadMode() { + if (mode != MODE_MIC) { + //i2s_zero_dma_buffer(I2S_NUM); + i2s_set_clk(I2S_NUM, 16000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); + mode = MODE_MIC; + } +} + +void TAudio::writeAudio(uint8_t *data, size_t size, size_t *bytes_written) { + i2s_write(I2S_NUM, data, size, bytes_written, portMAX_DELAY); +} + +bool TAudio::readAudio(uint8_t *data, size_t size) { + size_t byte_read; + i2s_read(I2S_NUM, data, size, &byte_read, (100 / portTICK_RATE_MS)); + return true; +} + +void TAudio::muteOutput(bool mute) { + if (muted == mute) return; // already set + + if (mute) i2s_zero_dma_buffer(I2S_NUM); + dac.cfgOutput(mute ? 0 : 1, 0); + //setVolume(mute ? 0 : out_vol); + muted = mute; +} + +void TAudio::ampOutput(int output) { + out_amp = (AmpOut)output; + const uint8_t vol = (out_vol * 63)/100; + + switch (out_amp) + { + case AmpOut::AMP_OUT_SPEAKERS: + dac.setSPKvol(vol); + dac.setHPvol(0, 0); + break; + case AmpOut::AMP_OUT_HEADPHONE: + dac.setSPKvol(0); + dac.setHPvol(vol, vol); + break; + case AmpOut::AMP_OUT_BOTH: + dac.setSPKvol(vol); + dac.setHPvol(vol, vol); + break; + } +} + +void TAudio::setVolume(uint16_t volume) { + out_vol = volume; + // volume is 0 to 100, needs to be 0 to 63 + const uint8_t vol = (volume * 63) / 100; + + switch (out_amp) + { + case AmpOut::AMP_OUT_SPEAKERS: + dac.setSPKvol(vol); + break; + case AmpOut::AMP_OUT_HEADPHONE: + dac.setHPvol(vol, vol); + break; + case AmpOut::AMP_OUT_BOTH: + dac.setSPKvol(vol); + dac.setHPvol(vol, vol); + break; + } +} + +void TAudio::setGain(uint16_t gain) { + const uint8_t g = (gain * 63) / 8; + dac.setMICgain(g); +} + +bool TAudio::isHotwordDetected() { + return (digitalRead(KEY_LISTEN) == LOW); +} From 9a455e8318b3566fdd5854130120449f21e5a912 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sat, 16 Oct 2021 17:09:32 +0200 Subject: [PATCH 17/20] Add device 5 to settings example and remove IdleEvent in Idle --- PlatformIO/settings.ini.example | 2 +- PlatformIO/src/StateMachine.hpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/PlatformIO/settings.ini.example b/PlatformIO/settings.ini.example index 6589a4a..c66d2ef 100644 --- a/PlatformIO/settings.ini.example +++ b/PlatformIO/settings.ini.example @@ -2,7 +2,7 @@ hostname=192.168.43.140 deployhost=192.168.43.24 siteId=satellite -;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4, TAUDIO=6 +;supported: M5ATOMECHO=0, MATRIXVOICE=1, AUDIOKIT=2, INMP441=3, INMP441MAX98357A=4, ESP32_POE_ISO=5, TAUDIO=6 device_type=4 ;network_type: 0: WiFi, 1: Ethernet network_type=0 diff --git a/PlatformIO/src/StateMachine.hpp b/PlatformIO/src/StateMachine.hpp index 786b1ab..72d1854 100644 --- a/PlatformIO/src/StateMachine.hpp +++ b/PlatformIO/src/StateMachine.hpp @@ -25,6 +25,10 @@ class StateMachine class Speaking : public StateMachine { + void entry(void) override { + Serial.println("Enter Speaking"); + } + void react(IdleEvent const &) override { transit(); } @@ -47,6 +51,7 @@ class Speaking : public StateMachine class Updating : public StateMachine { void entry(void) override { + Serial.println("Enter Updating"); xEventGroupClearBits(audioGroup, PLAY); xEventGroupClearBits(audioGroup, STREAM); device->updateBrightness(config.brightness); @@ -145,10 +150,6 @@ class Idle : public StateMachine transit(); } - void react(IdleEvent const &) override { - transit(); - } - void react(OtaEvent const &) override { transit(); } From ad8874cea26fe451e9170c88c293173f50b4d65c Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sat, 16 Oct 2021 17:17:11 +0200 Subject: [PATCH 18/20] Update version info --- PlatformIO/src/Satellite.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PlatformIO/src/Satellite.cpp b/PlatformIO/src/Satellite.cpp index 8474c4c..a38cec4 100644 --- a/PlatformIO/src/Satellite.cpp +++ b/PlatformIO/src/Satellite.cpp @@ -97,6 +97,10 @@ - Adding better logic for saving settings in webUI - Add actual hardware capabilities in webUI - Restructure AudioKit code + v7.7 + - Added ESP32_POE_ISO and TAUDIO + - Added animation function, work in progress + - Added Speaking state for animation preparation (works for matrixvoice) * ************************************************************************ */ From de8aeb784bb0b52bc9389cffb08d508073d79d67 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sat, 16 Oct 2021 17:19:58 +0200 Subject: [PATCH 19/20] add esp32-poe-iso to builds --- PlatformIO/platformio.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PlatformIO/platformio.ini b/PlatformIO/platformio.ini index 650298a..18f0182 100644 --- a/PlatformIO/platformio.ini +++ b/PlatformIO/platformio.ini @@ -63,5 +63,8 @@ build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=3 [env:inmp441Mmax98357a] build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=4 +[env:esp32-poe-iso] +build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=5 + [env:taudio] build_flags = ${env.build_flags} -DPI_DEVICE_TYPE=6 From 6244d5d0bdbb63e7b65086fe2b310b9ae5070873 Mon Sep 17 00:00:00 2001 From: Paul Romkes Date: Sat, 16 Oct 2021 17:25:52 +0200 Subject: [PATCH 20/20] Update buildall.yml --- .github/workflows/buildall.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/buildall.yml b/.github/workflows/buildall.yml index 0423373..8d291e1 100644 --- a/.github/workflows/buildall.yml +++ b/.github/workflows/buildall.yml @@ -13,6 +13,8 @@ jobs: - "inmp441Mmax98357a" - "matrixvoice" - "m5atomecho" + - "esp32-poe-iso" + - "taudio" runs-on: ubuntu-latest