From 5a815c908f3afcf10cbf69ce4c4b9b1214376a31 Mon Sep 17 00:00:00 2001
From: Tomas Pilny <tomas.pilny@espressif.com>
Date: Wed, 9 Mar 2022 14:48:53 +0100
Subject: [PATCH 1/4] Implemented tone

---
 CMakeLists.txt        |  1 +
 cores/esp32/Arduino.h |  3 +++
 cores/esp32/Tone.cpp  | 23 +++++++++++++++++++++++
 3 files changed, 27 insertions(+)
 create mode 100644 cores/esp32/Tone.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 775baecf412..d952d51474e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,7 @@ set(CORE_SRCS
   cores/esp32/stdlib_noniso.c
   cores/esp32/Stream.cpp
   cores/esp32/StreamString.cpp
+  cores/esp32/Tone.cpp
   cores/esp32/HWCDC.cpp
   cores/esp32/USB.cpp
   cores/esp32/USBCDC.cpp
diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h
index b1e8f7cd7de..1e621146a5a 100644
--- a/cores/esp32/Arduino.h
+++ b/cores/esp32/Arduino.h
@@ -195,6 +195,9 @@ extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec,
 extern "C" void configTzTime(const char* tz,
         const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
 
+void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0, unsigned long duty = 50);
+void noTone(uint8_t _pin);
+
 // WMath prototypes
 long random(long);
 #endif /* __cplusplus */
diff --git a/cores/esp32/Tone.cpp b/cores/esp32/Tone.cpp
new file mode 100644
index 00000000000..adcc02486f5
--- /dev/null
+++ b/cores/esp32/Tone.cpp
@@ -0,0 +1,23 @@
+#include <Arduino.h>
+#include "esp32-hal-ledc.h"
+
+void noTone(uint8_t _pin){
+  ledcDetachPin(_pin);
+}
+
+// parameters:
+// _pin - pin number which will output the signal
+// frequency - PWM frequency in Hz
+// duration - time in ms - how long will the signal be outputted.
+//   If not provided, or 0 you must manually call noTone to end output
+// duty - PWM duty in % (default 50%)
+void tone(uint8_t _pin, unsigned int frequency, unsigned long duration, unsigned long duty){
+  ledcSetup(0, frequency, 11);
+  ledcAttachPin(_pin, 0);
+
+  ledcWrite(0, duty * 20);
+  if(duration){
+    vTaskDelay(pdMS_TO_TICKS(duration));
+    noTone(_pin);
+  }
+}

From 21606bbb5c73485795c16ea44c27c9c3aa1ca8c1 Mon Sep 17 00:00:00 2001
From: Tomas Pilny <tomas.pilny@espressif.com>
Date: Thu, 10 Mar 2022 08:53:34 +0100
Subject: [PATCH 2/4] Removed duty parameter in tone

---
 cores/esp32/Arduino.h | 2 +-
 cores/esp32/Tone.cpp  | 5 ++---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h
index 1e621146a5a..0d52fceecf7 100644
--- a/cores/esp32/Arduino.h
+++ b/cores/esp32/Arduino.h
@@ -195,7 +195,7 @@ extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec,
 extern "C" void configTzTime(const char* tz,
         const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
 
-void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0, unsigned long duty = 50);
+void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
 void noTone(uint8_t _pin);
 
 // WMath prototypes
diff --git a/cores/esp32/Tone.cpp b/cores/esp32/Tone.cpp
index adcc02486f5..fc7eb0c7ab2 100644
--- a/cores/esp32/Tone.cpp
+++ b/cores/esp32/Tone.cpp
@@ -10,12 +10,11 @@ void noTone(uint8_t _pin){
 // frequency - PWM frequency in Hz
 // duration - time in ms - how long will the signal be outputted.
 //   If not provided, or 0 you must manually call noTone to end output
-// duty - PWM duty in % (default 50%)
-void tone(uint8_t _pin, unsigned int frequency, unsigned long duration, unsigned long duty){
+void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){
   ledcSetup(0, frequency, 11);
   ledcAttachPin(_pin, 0);
 
-  ledcWrite(0, duty * 20);
+  ledcWrite(0, 1024);
   if(duration){
     vTaskDelay(pdMS_TO_TICKS(duration));
     noTone(_pin);

From b784c5ea6eca391df937910ca839d8aceb7fa509 Mon Sep 17 00:00:00 2001
From: Tomas Pilny <tomas.pilny@espressif.com>
Date: Thu, 10 Mar 2022 15:13:09 +0100
Subject: [PATCH 3/4] Tone uses queue; implemented setToneChannel

---
 cores/esp32/Arduino.h |   1 +
 cores/esp32/Tone.cpp  | 138 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 131 insertions(+), 8 deletions(-)

diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h
index 0d52fceecf7..c8be9222b39 100644
--- a/cores/esp32/Arduino.h
+++ b/cores/esp32/Arduino.h
@@ -195,6 +195,7 @@ extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec,
 extern "C" void configTzTime(const char* tz,
         const char* server1, const char* server2 = nullptr, const char* server3 = nullptr);
 
+void setToneChannel(uint8_t channel = 0);
 void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
 void noTone(uint8_t _pin);
 
diff --git a/cores/esp32/Tone.cpp b/cores/esp32/Tone.cpp
index fc7eb0c7ab2..6922d3a7ae3 100644
--- a/cores/esp32/Tone.cpp
+++ b/cores/esp32/Tone.cpp
@@ -1,8 +1,128 @@
 #include <Arduino.h>
 #include "esp32-hal-ledc.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+
+static TaskHandle_t _tone_task = NULL;
+static QueueHandle_t _tone_queue = NULL;
+static QueueHandle_t _tone_mutex = NULL;
+static uint8_t _channel = 0;
+
+typedef enum{
+  TONE_START,
+  TONE_END,
+  TONE_SET_CHANNEL
+} tone_cmd_t;
+
+typedef struct{
+  tone_cmd_t tone_cmd;
+  uint8_t pin;
+  unsigned int frequency;
+  unsigned long duration;
+  uint8_t channel;
+} tone_msg_t;
+
+static void tone_task(void*){
+  tone_msg_t tone_msg;
+  while(1){
+    xQueueReceive(_tone_queue, &tone_msg, portMAX_DELAY);
+    switch(tone_msg.tone_cmd){
+      case TONE_START:
+        log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%u ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
+        if(xSemaphoreTake(_tone_mutex, portMAX_DELAY) != pdTRUE ){
+          log_e("Tone mutex take returned with error");
+          break;
+        }
+        log_d("Setup LED controll on channel %d", _channel);
+        ledcSetup(_channel, tone_msg.frequency, 11);
+        ledcAttachPin(tone_msg.pin, _channel);
+        ledcWrite(_channel, 1024);
+        if(xSemaphoreGive(_tone_mutex) != pdTRUE){
+          log_e("Tone mutex give returned with error");
+        }
+
+        if(tone_msg.duration){
+          vTaskDelay(pdMS_TO_TICKS(tone_msg.duration));
+          ledcDetachPin(tone_msg.pin);
+        }
+        break;
+
+      case TONE_END:
+        log_d("Task received from queue TONE_END: pin=%d", tone_msg.pin);
+        ledcDetachPin(tone_msg.pin);
+        break;
+
+      case TONE_SET_CHANNEL:
+        _channel = tone_msg.channel;
+        break;
+
+      default: ; // do nothing
+    } // switch
+  } // infinite loop
+}
+
+static int tone_init(){
+  if(_tone_mutex == NULL){
+    log_v("Creating tone mutex");
+    _tone_mutex = xSemaphoreCreateMutex();
+    if(_tone_mutex == NULL){
+      log_e("Could not create tone mutex");
+      return 0; // ERR
+    }
+    log_v("Tone mutex created");
+  }
+
+
+  if(_tone_queue == NULL){
+    log_v("Creating tone queue");
+    _tone_queue = xQueueCreate(128, sizeof(tone_msg_t));
+    if(_tone_queue == NULL){
+      log_e("Could not create tone queue");
+      return 0; // ERR
+    }
+    log_v("Tone queue created");
+  }
+
+  if(_tone_task == NULL){
+    log_v("Creating tone task");
+    xTaskCreate(
+      tone_task, // Function to implement the task
+      "toneTask", // Name of the task
+      3500,  // Stack size in words
+      NULL,  // Task input parameter
+      1,  // Priority of the task
+      &_tone_task  // Task handle.
+      );
+    if(_tone_task == NULL){
+      log_e("Could not create tone task");
+      return 0; // ERR
+    }
+    log_v("Tone task created");
+  }
+  return 1; // OK
+}
+
+void setToneChannel(uint8_t channel){
+  log_d("channel=%d", channel);
+  if(tone_init()){
+    tone_msg_t tone_msg = {
+      .tone_cmd = TONE_SET_CHANNEL,
+      .channel = channel
+    };
+    xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
+  }
+}
 
 void noTone(uint8_t _pin){
-  ledcDetachPin(_pin);
+  log_d("noTone was called");
+  if(tone_init()){
+    tone_msg_t tone_msg = {
+      .tone_cmd = TONE_END,
+      .pin = _pin
+    };
+    xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
+  }
 }
 
 // parameters:
@@ -11,12 +131,14 @@ void noTone(uint8_t _pin){
 // duration - time in ms - how long will the signal be outputted.
 //   If not provided, or 0 you must manually call noTone to end output
 void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){
-  ledcSetup(0, frequency, 11);
-  ledcAttachPin(_pin, 0);
-
-  ledcWrite(0, 1024);
-  if(duration){
-    vTaskDelay(pdMS_TO_TICKS(duration));
-    noTone(_pin);
+  log_d("_pin=%d, frequency=%u Hz, duration=%u ms", _pin, frequency, duration);
+  if(tone_init()){
+    tone_msg_t tone_msg = {
+      .tone_cmd = TONE_START,
+      .pin = _pin,
+      .frequency = frequency,
+      .duration = duration
+    };
+    xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
   }
 }

From d4a5d0ea793102f1d2a7eb3643884d901d21f8fc Mon Sep 17 00:00:00 2001
From: Tomas Pilny <tomas.pilny@espressif.com>
Date: Thu, 10 Mar 2022 16:04:27 +0100
Subject: [PATCH 4/4] Tone update

---
 cores/esp32/Tone.cpp | 31 +++++++++----------------------
 1 file changed, 9 insertions(+), 22 deletions(-)

diff --git a/cores/esp32/Tone.cpp b/cores/esp32/Tone.cpp
index 6922d3a7ae3..ca69c10c13b 100644
--- a/cores/esp32/Tone.cpp
+++ b/cores/esp32/Tone.cpp
@@ -6,7 +6,6 @@
 
 static TaskHandle_t _tone_task = NULL;
 static QueueHandle_t _tone_queue = NULL;
-static QueueHandle_t _tone_mutex = NULL;
 static uint8_t _channel = 0;
 
 typedef enum{
@@ -30,30 +29,29 @@ static void tone_task(void*){
     switch(tone_msg.tone_cmd){
       case TONE_START:
         log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%u ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
-        if(xSemaphoreTake(_tone_mutex, portMAX_DELAY) != pdTRUE ){
-          log_e("Tone mutex take returned with error");
-          break;
-        }
+
         log_d("Setup LED controll on channel %d", _channel);
-        ledcSetup(_channel, tone_msg.frequency, 11);
+        // ledcSetup(_channel, tone_msg.frequency, 11);
+        // ledcAttachPin(tone_msg.pin, _channel);
+        // ledcWrite(_channel, 1024);
+        ledcWriteTone(_channel, tone_msg.frequency);
         ledcAttachPin(tone_msg.pin, _channel);
-        ledcWrite(_channel, 1024);
-        if(xSemaphoreGive(_tone_mutex) != pdTRUE){
-          log_e("Tone mutex give returned with error");
-        }
 
         if(tone_msg.duration){
-          vTaskDelay(pdMS_TO_TICKS(tone_msg.duration));
+          delay(tone_msg.duration);
           ledcDetachPin(tone_msg.pin);
+          ledcWriteTone(_channel, 0);
         }
         break;
 
       case TONE_END:
         log_d("Task received from queue TONE_END: pin=%d", tone_msg.pin);
         ledcDetachPin(tone_msg.pin);
+        ledcWriteTone(_channel, 0);
         break;
 
       case TONE_SET_CHANNEL:
+        log_d("Task received from queue TONE_SET_CHANNEL: channel=%d", tone_msg.channel);
         _channel = tone_msg.channel;
         break;
 
@@ -63,17 +61,6 @@ static void tone_task(void*){
 }
 
 static int tone_init(){
-  if(_tone_mutex == NULL){
-    log_v("Creating tone mutex");
-    _tone_mutex = xSemaphoreCreateMutex();
-    if(_tone_mutex == NULL){
-      log_e("Could not create tone mutex");
-      return 0; // ERR
-    }
-    log_v("Tone mutex created");
-  }
-
-
   if(_tone_queue == NULL){
     log_v("Creating tone queue");
     _tone_queue = xQueueCreate(128, sizeof(tone_msg_t));