diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Client/Client.ino b/ESP32_TTGO/Walkie-Talkie_Project/Client/Client.ino new file mode 100644 index 0000000..f1bc9d7 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Client/Client.ino @@ -0,0 +1,201 @@ +///////////////////////////////////////////////////////////////// +/* + ESP32 | Walkie-Talkie, Half-duplex communication based on WebSocket + Video Tutorial: https://youtu.be/kw30vLdrGE8 + Created by Eric Nam (ThatProject) +*/ +///////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "Free_Fonts.h" +#include "driver/i2s.h" +#include "Button2.h"; +#include "I2s_Setting.h" +#include "Const.h" +#define RIGHT_BUTTON_PIN 35 +Button2 rButton = Button2(RIGHT_BUTTON_PIN); + +using namespace websockets; +WebsocketsClient client; + +TFT_eSPI tft = TFT_eSPI(); +TFT_eSprite logScreen = TFT_eSprite(&tft); + +unsigned long timeStampOffset = 0; +unsigned long requestTimestamp; +TaskHandle_t i2sReadTaskHandler = NULL; + +void setup() { + Serial.begin(115200); + display_init(); + display_ready_screen(); + button_init(); + i2s_buff_init(); + start_to_connect(); + + xTaskCreate(ping_task, "ping_task", 2048, NULL, 1, NULL); +} + +void loop() { + rButton.loop(); + if (client.available()) { + client.poll(); + } +} + +void onEventsCallback(WebsocketsEvent event, String data) { + if(event == WebsocketsEvent::ConnectionClosed) { + ESP.restart(); + } +} + +void onMessageCallback(WebsocketsMessage message) { + int msgLength = message.length(); + if(message.type() == MessageType::Binary){ + if(states == Listening && msgLength > 0){ + i2s_write_data((char*)message.c_str(), msgLength); + } + + }else if(message.type() == MessageType::Text){ + unsigned long timeResponse = message.data().toInt(); + actionCommand(timeResponse); + } +} + +void actionCommand(unsigned long timestamp){ + if(timeStampOffset == 0){ + unsigned long currentTimestamp = millis(); + timeStampOffset = currentTimestamp >= timestamp? currentTimestamp - timestamp : timestamp - currentTimestamp; + return; + } + + if(requestTimestamp == timestamp && states == Idle){ + states = Speaking; + print_log_screen("* Speaking Mode *"); + i2s_RX_init(); + xTaskCreate(i2s_read_task, "i2s_read_task", 4096, NULL, 1, &i2sReadTaskHandler); + }else if(requestTimestamp != timestamp ){ + if(states == Idle){ + states = Listening; + i2s_TX_init(); + print_log_screen("* Listening Mode *"); + }else if(states == Listening){ + states = Idle; + i2s_TX_uninst(); + print_log_screen("* IDLE Mode *"); + } + } +} + +void start_to_connect(){ + WiFi.begin(ssid, password); + print_log_screen("- WiFi Connecting"); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + print_log_screen("+ WiFi Connected"); + print_log_screen("- Socket Connecting"); + + client.onMessage(onMessageCallback); + client.onEvent(onEventsCallback); + while(!client.connect(websockets_server_host, websockets_server_port, "/")){ + delay(500); + Serial.print("."); + } + + print_log_screen("+ Socket Connected"); +} + +static void i2s_read_task(void *arg){ + while (1) { + i2s_read_data(); + client.sendBinary((const char*)flash_write_buff, I2S_READ_LEN); + } +} + +static void ping_task(void *arg){ + char dummy_buffer [1]; + while (1) { + if(states == Idle){ + client.sendBinary(dummy_buffer, 1); + } + vTaskDelay(1000); + } +} + +void pressed(Button2& btn) { + if(btn == rButton && states == Idle){ + client.send(getStrTimestamp()); + } +} + +void released(Button2& btn) { + if(btn == rButton && states == Speaking){ + states = Idle; + print_log_screen("* IDLE Mode *"); + + delay(100); + if( i2sReadTaskHandler != NULL ){ + vTaskDelete( i2sReadTaskHandler ); + i2sReadTaskHandler = NULL; + } + + delay(100); + client.send(getStrTimestamp()); + i2s_RX_uninst(); + } +} + +String getStrTimestamp(){ + requestTimestamp = millis() + timeStampOffset; + return (String)requestTimestamp; +} + +void button_init(){ + rButton.setPressedHandler(pressed); + rButton.setReleasedHandler(released); +} + +void display_init(){ + tft.begin(); + tft.setRotation(0); + tft.setTextColor(TFT_WHITE,TFT_BLACK); + tft.fillScreen(TFT_BLACK); + + logScreen.setColorDepth(8); + logScreen.createSprite(tft.width(), tft.height()/2); + logScreen.fillSprite(TFT_BLUE); + logScreen.setScrollRect(0, 0, tft.width(), tft.height()/2, TFT_BLUE); + logScreen.setTextColor(TFT_WHITE); + logScreen.setTextDatum(TL_DATUM); +} + +void display_ready_screen(){ + tft.fillScreen(TFT_BLACK); + tft.setTextDatum(TL_DATUM); + + tft.setFreeFont(FF21); + tft.setTextColor(TFT_SKYBLUE, TFT_BLACK); + tft.drawString("ESP32-ESP32", 0, 10, GFXFF); + + tft.setFreeFont(FF23); + tft.setTextColor(TFT_SILVER, TFT_BLACK); + tft.drawString("Walkie", 0, 35, GFXFF); + tft.setTextColor(TFT_GOLD, TFT_BLACK); + tft.drawString("Talkie", 30, 60, GFXFF); + + tft.setTextDatum(MC_DATUM); + tft.setFreeFont(FF21); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + tft.drawString(deviceRole == Server ? "[Server Ready]" : "[Clinet Ready]", tft.width()/2, 100, GFXFF); +} + +void print_log_screen(String text){ + logScreen.drawString(text, 0, -1, 2); + logScreen.pushSprite(0, tft.height()/2); + logScreen.scroll(0,16); +} \ No newline at end of file diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Client/Const.h b/ESP32_TTGO/Walkie-Talkie_Project/Client/Const.h new file mode 100644 index 0000000..ceb7396 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Client/Const.h @@ -0,0 +1,11 @@ +typedef enum STATES {Idle, Listening, Speaking}; +STATES states = Idle; + +typedef enum ROLE {Server, Client}; +ROLE deviceRole = Client; + +const char* ssid = "ESP32-THAT-PROJECT"; +const char* password = "California"; + +const char* websockets_server_host = "192.168.4.1"; +const uint16_t websockets_server_port = 8888; \ No newline at end of file diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Client/Free_Fonts.h b/ESP32_TTGO/Walkie-Talkie_Project/Client/Free_Fonts.h new file mode 100644 index 0000000..7c0a264 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Client/Free_Fonts.h @@ -0,0 +1,379 @@ +// Attach this header file to your sketch to use the GFX Free Fonts. You can write +// sketches without it, but it makes referencing them easier. + +// This calls up ALL the fonts but they only get loaded if you actually +// use them in your sketch. +// +// No changes are needed to this header file unless new fonts are added to the +// library "Fonts/GFXFF" folder. +// +// To save a lot of typing long names, each font can easily be referenced in the +// sketch in three ways, either with: +// +// 1. Font file name with the & in front such as &FreeSansBoldOblique24pt7b +// an example being: +// +// tft.setFreeFont(&FreeSansBoldOblique24pt7b); +// +// 2. FF# where # is a number determined by looking at the list below +// an example being: +// +// tft.setFreeFont(FF32); +// +// 3. An abbreviation of the file name. Look at the list below to see +// the abbreviations used, for example: +// +// tft.setFreeFont(FSSBO24) +// +// Where the letters mean: +// F = Free font +// M = Mono +// SS = Sans Serif (double S to distinguish is form serif fonts) +// S = Serif +// B = Bold +// O = Oblique (letter O not zero) +// I = Italic +// # = point size, either 9, 12, 18 or 24 +// +// Setting the font to NULL will select the GLCD font: +// +// tft.setFreeFont(NULL); // Set font to GLCD + + +#ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h + +// Use these when printing or drawing text in GLCD and high rendering speed fonts +// Call up the font using tft.setTextFont() +#define GFXFF 1 +#define GLCD 0 +#define FONT2 2 +#define FONT4 4 +#define FONT6 6 +#define FONT7 7 +#define FONT8 8 + +// Use the following when calling tft.setFreeFont() +// +// Reserved for GLCD font // FF0 +// + +#define TT1 &TomThumb + +#define FM9 &FreeMono9pt7b +#define FM12 &FreeMono12pt7b +#define FM18 &FreeMono18pt7b +#define FM24 &FreeMono24pt7b + +#define FMB9 &FreeMonoBold9pt7b +#define FMB12 &FreeMonoBold12pt7b +#define FMB18 &FreeMonoBold18pt7b +#define FMB24 &FreeMonoBold24pt7b + +#define FMO9 &FreeMonoOblique9pt7b +#define FMO12 &FreeMonoOblique12pt7b +#define FMO18 &FreeMonoOblique18pt7b +#define FMO24 &FreeMonoOblique24pt7b + +#define FMBO9 &FreeMonoBoldOblique9pt7b +#define FMBO12 &FreeMonoBoldOblique12pt7b +#define FMBO18 &FreeMonoBoldOblique18pt7b +#define FMBO24 &FreeMonoBoldOblique24pt7b + +#define FSS9 &FreeSans9pt7b +#define FSS12 &FreeSans12pt7b +#define FSS18 &FreeSans18pt7b +#define FSS24 &FreeSans24pt7b + +#define FSSB9 &FreeSansBold9pt7b +#define FSSB12 &FreeSansBold12pt7b +#define FSSB18 &FreeSansBold18pt7b +#define FSSB24 &FreeSansBold24pt7b + +#define FSSO9 &FreeSansOblique9pt7b +#define FSSO12 &FreeSansOblique12pt7b +#define FSSO18 &FreeSansOblique18pt7b +#define FSSO24 &FreeSansOblique24pt7b + +#define FSSBO9 &FreeSansBoldOblique9pt7b +#define FSSBO12 &FreeSansBoldOblique12pt7b +#define FSSBO18 &FreeSansBoldOblique18pt7b +#define FSSBO24 &FreeSansBoldOblique24pt7b + +#define FS9 &FreeSerif9pt7b +#define FS12 &FreeSerif12pt7b +#define FS18 &FreeSerif18pt7b +#define FS24 &FreeSerif24pt7b + +#define FSI9 &FreeSerifItalic9pt7b +#define FSI12 &FreeSerifItalic12pt7b +#define FSI19 &FreeSerifItalic18pt7b +#define FSI24 &FreeSerifItalic24pt7b + +#define FSB9 &FreeSerifBold9pt7b +#define FSB12 &FreeSerifBold12pt7b +#define FSB18 &FreeSerifBold18pt7b +#define FSB24 &FreeSerifBold24pt7b + +#define FSBI9 &FreeSerifBoldItalic9pt7b +#define FSBI12 &FreeSerifBoldItalic12pt7b +#define FSBI18 &FreeSerifBoldItalic18pt7b +#define FSBI24 &FreeSerifBoldItalic24pt7b + +#define FF0 NULL //ff0 reserved for GLCD +#define FF1 &FreeMono9pt7b +#define FF2 &FreeMono12pt7b +#define FF3 &FreeMono18pt7b +#define FF4 &FreeMono24pt7b + +#define FF5 &FreeMonoBold9pt7b +#define FF6 &FreeMonoBold12pt7b +#define FF7 &FreeMonoBold18pt7b +#define FF8 &FreeMonoBold24pt7b + +#define FF9 &FreeMonoOblique9pt7b +#define FF10 &FreeMonoOblique12pt7b +#define FF11 &FreeMonoOblique18pt7b +#define FF12 &FreeMonoOblique24pt7b + +#define FF13 &FreeMonoBoldOblique9pt7b +#define FF14 &FreeMonoBoldOblique12pt7b +#define FF15 &FreeMonoBoldOblique18pt7b +#define FF16 &FreeMonoBoldOblique24pt7b + +#define FF17 &FreeSans9pt7b +#define FF18 &FreeSans12pt7b +#define FF19 &FreeSans18pt7b +#define FF20 &FreeSans24pt7b + +#define FF21 &FreeSansBold9pt7b +#define FF22 &FreeSansBold12pt7b +#define FF23 &FreeSansBold18pt7b +#define FF24 &FreeSansBold24pt7b + +#define FF25 &FreeSansOblique9pt7b +#define FF26 &FreeSansOblique12pt7b +#define FF27 &FreeSansOblique18pt7b +#define FF28 &FreeSansOblique24pt7b + +#define FF29 &FreeSansBoldOblique9pt7b +#define FF30 &FreeSansBoldOblique12pt7b +#define FF31 &FreeSansBoldOblique18pt7b +#define FF32 &FreeSansBoldOblique24pt7b + +#define FF33 &FreeSerif9pt7b +#define FF34 &FreeSerif12pt7b +#define FF35 &FreeSerif18pt7b +#define FF36 &FreeSerif24pt7b + +#define FF37 &FreeSerifItalic9pt7b +#define FF38 &FreeSerifItalic12pt7b +#define FF39 &FreeSerifItalic18pt7b +#define FF40 &FreeSerifItalic24pt7b + +#define FF41 &FreeSerifBold9pt7b +#define FF42 &FreeSerifBold12pt7b +#define FF43 &FreeSerifBold18pt7b +#define FF44 &FreeSerifBold24pt7b + +#define FF45 &FreeSerifBoldItalic9pt7b +#define FF46 &FreeSerifBoldItalic12pt7b +#define FF47 &FreeSerifBoldItalic18pt7b +#define FF48 &FreeSerifBoldItalic24pt7b + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// Now we define "s"tring versions for easy printing of the font name so: +// tft.println(sFF5); +// will print +// Mono bold 9 +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +#define sFF0 "GLCD" +#define sTT1 "Tom Thumb" +#define sFF1 "Mono 9" +#define sFF2 "Mono 12" +#define sFF3 "Mono 18" +#define sFF4 "Mono 24" + +#define sFF5 "Mono bold 9" +#define sFF6 "Mono bold 12" +#define sFF7 "Mono bold 18" +#define sFF8 "Mono bold 24" + +#define sFF9 "Mono oblique 9" +#define sFF10 "Mono oblique 12" +#define sFF11 "Mono oblique 18" +#define sFF12 "Mono oblique 24" + +#define sFF13 "Mono bold oblique 9" +#define sFF14 "Mono bold oblique 12" +#define sFF15 "Mono bold oblique 18" +#define sFF16 "Mono bold oblique 24" // Full text line is too big for 480 pixel wide screen + +#define sFF17 "Sans 9" +#define sFF18 "Sans 12" +#define sFF19 "Sans 18" +#define sFF20 "Sans 24" + +#define sFF21 "Sans bold 9" +#define sFF22 "Sans bold 12" +#define sFF23 "Sans bold 18" +#define sFF24 "Sans bold 24" + +#define sFF25 "Sans oblique 9" +#define sFF26 "Sans oblique 12" +#define sFF27 "Sans oblique 18" +#define sFF28 "Sans oblique 24" + +#define sFF29 "Sans bold oblique 9" +#define sFF30 "Sans bold oblique 12" +#define sFF31 "Sans bold oblique 18" +#define sFF32 "Sans bold oblique 24" + +#define sFF33 "Serif 9" +#define sFF34 "Serif 12" +#define sFF35 "Serif 18" +#define sFF36 "Serif 24" + +#define sFF37 "Serif italic 9" +#define sFF38 "Serif italic 12" +#define sFF39 "Serif italic 18" +#define sFF40 "Serif italic 24" + +#define sFF41 "Serif bold 9" +#define sFF42 "Serif bold 12" +#define sFF43 "Serif bold 18" +#define sFF44 "Serif bold 24" + +#define sFF45 "Serif bold italic 9" +#define sFF46 "Serif bold italic 12" +#define sFF47 "Serif bold italic 18" +#define sFF48 "Serif bold italic 24" + +#else // LOAD_GFXFF not defined so setup defaults to prevent error messages + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// Free fonts are not loaded in User_Setup.h so we must define all as font 1 +// to prevent compile error messages +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +#define GFXFF 1 +#define GLCD 1 +#define FONT2 2 +#define FONT4 4 +#define FONT6 6 +#define FONT7 7 +#define FONT8 8 + +#define TT1 1 + +#define FF0 1 +#define FF1 1 +#define FF2 1 +#define FF3 1 +#define FF4 1 +#define FF5 1 +#define FF6 1 +#define FF7 1 +#define FF8 1 +#define FF9 1 +#define FF10 1 +#define FF11 1 +#define FF12 1 +#define FF13 1 +#define FF14 1 +#define FF15 1 +#define FF16 1 +#define FF17 1 +#define FF18 1 +#define FF19 1 +#define FF20 1 +#define FF21 1 +#define FF22 1 +#define FF23 1 +#define FF24 1 +#define FF25 1 +#define FF26 1 +#define FF27 1 +#define FF28 1 +#define FF29 1 +#define FF30 1 +#define FF31 1 +#define FF32 1 +#define FF33 1 +#define FF34 1 +#define FF35 1 +#define FF36 1 +#define FF37 1 +#define FF38 1 +#define FF39 1 +#define FF40 1 +#define FF41 1 +#define FF42 1 +#define FF43 1 +#define FF44 1 +#define FF45 1 +#define FF46 1 +#define FF47 1 +#define FF48 1 + +#define FM9 1 +#define FM12 1 +#define FM18 1 +#define FM24 1 + +#define FMB9 1 +#define FMB12 1 +#define FMB18 1 +#define FMB24 1 + +#define FMO9 1 +#define FMO12 1 +#define FMO18 1 +#define FMO24 1 + +#define FMBO9 1 +#define FMBO12 1 +#define FMBO18 1 +#define FMBO24 1 + +#define FSS9 1 +#define FSS12 1 +#define FSS18 1 +#define FSS24 1 + +#define FSSB9 1 +#define FSSB12 1 +#define FSSB18 1 +#define FSSB24 1 + +#define FSSO9 1 +#define FSSO12 1 +#define FSSO18 1 +#define FSSO24 1 + +#define FSSBO9 1 +#define FSSBO12 1 +#define FSSBO18 1 +#define FSSBO24 1 + +#define FS9 1 +#define FS12 1 +#define FS18 1 +#define FS24 1 + +#define FSI9 1 +#define FSI12 1 +#define FSI19 1 +#define FSI24 1 + +#define FSB9 1 +#define FSB12 1 +#define FSB18 1 +#define FSB24 1 + +#define FSBI9 1 +#define FSBI12 1 +#define FSBI18 1 +#define FSBI24 1 + +#endif // LOAD_GFXFF diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Client/I2s_Setting.h b/ESP32_TTGO/Walkie-Talkie_Project/Client/I2s_Setting.h new file mode 100644 index 0000000..6681517 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Client/I2s_Setting.h @@ -0,0 +1,95 @@ +#define I2S_WS_TX 12 +#define I2S_SCK_TX 13 +#define I2S_DATA_OUT_TX 15 +#define I2S_PORT_TX I2S_NUM_0 + +#define I2S_WS_RX 33 +#define I2S_SCK_RX 25 +#define I2S_SD_RX 26 +#define I2S_PORT_RX I2S_NUM_1 + +#define I2S_SAMPLE_RATE (16000) +#define I2S_SAMPLE_BITS (32) +#define I2S_READ_LEN (1024) + +char* i2s_read_buff; +uint8_t* flash_write_buff; + +const i2s_config_t i2s_config_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 = 32, + .dma_buf_len = 64 +}; + +const i2s_pin_config_t pin_config_tx = { + .bck_io_num = I2S_SCK_TX, + .ws_io_num = I2S_WS_TX, + .data_out_num = I2S_DATA_OUT_TX, + .data_in_num = I2S_PIN_NO_CHANGE +}; + +const i2s_config_t i2s_config_rx = { + .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 = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 32, + .dma_buf_len = 64 +}; + +const i2s_pin_config_t pin_config_rx = { + .bck_io_num = I2S_SCK_RX, + .ws_io_num = I2S_WS_RX, + .data_out_num = I2S_PIN_NO_CHANGE, + .data_in_num = I2S_SD_RX +}; + +void i2s_RX_init(){ + i2s_driver_install(I2S_PORT_RX, &i2s_config_rx, 0, NULL); + i2s_set_pin(I2S_PORT_RX, &pin_config_rx); +} + +void i2s_RX_uninst(){ + i2s_driver_uninstall(I2S_PORT_RX); +} + +void i2s_TX_init(){ + i2s_driver_install(I2S_PORT_TX, &i2s_config_tx, 0, NULL); + i2s_set_pin(I2S_PORT_TX, &pin_config_tx); +} + +void i2s_TX_uninst(){ + i2s_driver_uninstall(I2S_PORT_TX); +} + +void i2s_adc_data_scale(uint8_t * d_buff, uint8_t* s_buff, uint32_t len){ + uint32_t j = 0; + uint32_t dac_value = 0; + for (int i = 0; i < len; i += 2) { + dac_value = ((((uint16_t) (s_buff[i + 1] & 0xf) << 8) | ((s_buff[i + 0])))); + d_buff[j++] = 0; + d_buff[j++] = dac_value * 256 / 1024 ; + } +} + +void i2s_read_data(){ + size_t bytes_read; + i2s_read(I2S_PORT_RX, (void*) i2s_read_buff, I2S_READ_LEN, &bytes_read, portMAX_DELAY); + i2s_adc_data_scale(flash_write_buff, (uint8_t*)i2s_read_buff, I2S_READ_LEN); +} + +void i2s_write_data(char *buf_ptr, int buf_size){ + i2s_write_bytes(I2S_PORT_TX, buf_ptr, buf_size, portMAX_DELAY); +} + +void i2s_buff_init(){ + i2s_read_buff = (char*) calloc(I2S_READ_LEN, sizeof(char)); + flash_write_buff = (uint8_t*) calloc(I2S_READ_LEN, sizeof(char)); +} diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Server/Const.h b/ESP32_TTGO/Walkie-Talkie_Project/Server/Const.h new file mode 100644 index 0000000..053e475 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Server/Const.h @@ -0,0 +1,8 @@ +typedef enum STATES {Idle, Listening, Speaking}; +STATES states = Idle; + +typedef enum ROLE {Server, Client}; +ROLE deviceRole = Server; + +const char* ssid = "ESP32-THAT-PROJECT"; +const char* password = "California"; \ No newline at end of file diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Server/Free_Fonts.h b/ESP32_TTGO/Walkie-Talkie_Project/Server/Free_Fonts.h new file mode 100644 index 0000000..7c0a264 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Server/Free_Fonts.h @@ -0,0 +1,379 @@ +// Attach this header file to your sketch to use the GFX Free Fonts. You can write +// sketches without it, but it makes referencing them easier. + +// This calls up ALL the fonts but they only get loaded if you actually +// use them in your sketch. +// +// No changes are needed to this header file unless new fonts are added to the +// library "Fonts/GFXFF" folder. +// +// To save a lot of typing long names, each font can easily be referenced in the +// sketch in three ways, either with: +// +// 1. Font file name with the & in front such as &FreeSansBoldOblique24pt7b +// an example being: +// +// tft.setFreeFont(&FreeSansBoldOblique24pt7b); +// +// 2. FF# where # is a number determined by looking at the list below +// an example being: +// +// tft.setFreeFont(FF32); +// +// 3. An abbreviation of the file name. Look at the list below to see +// the abbreviations used, for example: +// +// tft.setFreeFont(FSSBO24) +// +// Where the letters mean: +// F = Free font +// M = Mono +// SS = Sans Serif (double S to distinguish is form serif fonts) +// S = Serif +// B = Bold +// O = Oblique (letter O not zero) +// I = Italic +// # = point size, either 9, 12, 18 or 24 +// +// Setting the font to NULL will select the GLCD font: +// +// tft.setFreeFont(NULL); // Set font to GLCD + + +#ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h + +// Use these when printing or drawing text in GLCD and high rendering speed fonts +// Call up the font using tft.setTextFont() +#define GFXFF 1 +#define GLCD 0 +#define FONT2 2 +#define FONT4 4 +#define FONT6 6 +#define FONT7 7 +#define FONT8 8 + +// Use the following when calling tft.setFreeFont() +// +// Reserved for GLCD font // FF0 +// + +#define TT1 &TomThumb + +#define FM9 &FreeMono9pt7b +#define FM12 &FreeMono12pt7b +#define FM18 &FreeMono18pt7b +#define FM24 &FreeMono24pt7b + +#define FMB9 &FreeMonoBold9pt7b +#define FMB12 &FreeMonoBold12pt7b +#define FMB18 &FreeMonoBold18pt7b +#define FMB24 &FreeMonoBold24pt7b + +#define FMO9 &FreeMonoOblique9pt7b +#define FMO12 &FreeMonoOblique12pt7b +#define FMO18 &FreeMonoOblique18pt7b +#define FMO24 &FreeMonoOblique24pt7b + +#define FMBO9 &FreeMonoBoldOblique9pt7b +#define FMBO12 &FreeMonoBoldOblique12pt7b +#define FMBO18 &FreeMonoBoldOblique18pt7b +#define FMBO24 &FreeMonoBoldOblique24pt7b + +#define FSS9 &FreeSans9pt7b +#define FSS12 &FreeSans12pt7b +#define FSS18 &FreeSans18pt7b +#define FSS24 &FreeSans24pt7b + +#define FSSB9 &FreeSansBold9pt7b +#define FSSB12 &FreeSansBold12pt7b +#define FSSB18 &FreeSansBold18pt7b +#define FSSB24 &FreeSansBold24pt7b + +#define FSSO9 &FreeSansOblique9pt7b +#define FSSO12 &FreeSansOblique12pt7b +#define FSSO18 &FreeSansOblique18pt7b +#define FSSO24 &FreeSansOblique24pt7b + +#define FSSBO9 &FreeSansBoldOblique9pt7b +#define FSSBO12 &FreeSansBoldOblique12pt7b +#define FSSBO18 &FreeSansBoldOblique18pt7b +#define FSSBO24 &FreeSansBoldOblique24pt7b + +#define FS9 &FreeSerif9pt7b +#define FS12 &FreeSerif12pt7b +#define FS18 &FreeSerif18pt7b +#define FS24 &FreeSerif24pt7b + +#define FSI9 &FreeSerifItalic9pt7b +#define FSI12 &FreeSerifItalic12pt7b +#define FSI19 &FreeSerifItalic18pt7b +#define FSI24 &FreeSerifItalic24pt7b + +#define FSB9 &FreeSerifBold9pt7b +#define FSB12 &FreeSerifBold12pt7b +#define FSB18 &FreeSerifBold18pt7b +#define FSB24 &FreeSerifBold24pt7b + +#define FSBI9 &FreeSerifBoldItalic9pt7b +#define FSBI12 &FreeSerifBoldItalic12pt7b +#define FSBI18 &FreeSerifBoldItalic18pt7b +#define FSBI24 &FreeSerifBoldItalic24pt7b + +#define FF0 NULL //ff0 reserved for GLCD +#define FF1 &FreeMono9pt7b +#define FF2 &FreeMono12pt7b +#define FF3 &FreeMono18pt7b +#define FF4 &FreeMono24pt7b + +#define FF5 &FreeMonoBold9pt7b +#define FF6 &FreeMonoBold12pt7b +#define FF7 &FreeMonoBold18pt7b +#define FF8 &FreeMonoBold24pt7b + +#define FF9 &FreeMonoOblique9pt7b +#define FF10 &FreeMonoOblique12pt7b +#define FF11 &FreeMonoOblique18pt7b +#define FF12 &FreeMonoOblique24pt7b + +#define FF13 &FreeMonoBoldOblique9pt7b +#define FF14 &FreeMonoBoldOblique12pt7b +#define FF15 &FreeMonoBoldOblique18pt7b +#define FF16 &FreeMonoBoldOblique24pt7b + +#define FF17 &FreeSans9pt7b +#define FF18 &FreeSans12pt7b +#define FF19 &FreeSans18pt7b +#define FF20 &FreeSans24pt7b + +#define FF21 &FreeSansBold9pt7b +#define FF22 &FreeSansBold12pt7b +#define FF23 &FreeSansBold18pt7b +#define FF24 &FreeSansBold24pt7b + +#define FF25 &FreeSansOblique9pt7b +#define FF26 &FreeSansOblique12pt7b +#define FF27 &FreeSansOblique18pt7b +#define FF28 &FreeSansOblique24pt7b + +#define FF29 &FreeSansBoldOblique9pt7b +#define FF30 &FreeSansBoldOblique12pt7b +#define FF31 &FreeSansBoldOblique18pt7b +#define FF32 &FreeSansBoldOblique24pt7b + +#define FF33 &FreeSerif9pt7b +#define FF34 &FreeSerif12pt7b +#define FF35 &FreeSerif18pt7b +#define FF36 &FreeSerif24pt7b + +#define FF37 &FreeSerifItalic9pt7b +#define FF38 &FreeSerifItalic12pt7b +#define FF39 &FreeSerifItalic18pt7b +#define FF40 &FreeSerifItalic24pt7b + +#define FF41 &FreeSerifBold9pt7b +#define FF42 &FreeSerifBold12pt7b +#define FF43 &FreeSerifBold18pt7b +#define FF44 &FreeSerifBold24pt7b + +#define FF45 &FreeSerifBoldItalic9pt7b +#define FF46 &FreeSerifBoldItalic12pt7b +#define FF47 &FreeSerifBoldItalic18pt7b +#define FF48 &FreeSerifBoldItalic24pt7b + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// Now we define "s"tring versions for easy printing of the font name so: +// tft.println(sFF5); +// will print +// Mono bold 9 +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +#define sFF0 "GLCD" +#define sTT1 "Tom Thumb" +#define sFF1 "Mono 9" +#define sFF2 "Mono 12" +#define sFF3 "Mono 18" +#define sFF4 "Mono 24" + +#define sFF5 "Mono bold 9" +#define sFF6 "Mono bold 12" +#define sFF7 "Mono bold 18" +#define sFF8 "Mono bold 24" + +#define sFF9 "Mono oblique 9" +#define sFF10 "Mono oblique 12" +#define sFF11 "Mono oblique 18" +#define sFF12 "Mono oblique 24" + +#define sFF13 "Mono bold oblique 9" +#define sFF14 "Mono bold oblique 12" +#define sFF15 "Mono bold oblique 18" +#define sFF16 "Mono bold oblique 24" // Full text line is too big for 480 pixel wide screen + +#define sFF17 "Sans 9" +#define sFF18 "Sans 12" +#define sFF19 "Sans 18" +#define sFF20 "Sans 24" + +#define sFF21 "Sans bold 9" +#define sFF22 "Sans bold 12" +#define sFF23 "Sans bold 18" +#define sFF24 "Sans bold 24" + +#define sFF25 "Sans oblique 9" +#define sFF26 "Sans oblique 12" +#define sFF27 "Sans oblique 18" +#define sFF28 "Sans oblique 24" + +#define sFF29 "Sans bold oblique 9" +#define sFF30 "Sans bold oblique 12" +#define sFF31 "Sans bold oblique 18" +#define sFF32 "Sans bold oblique 24" + +#define sFF33 "Serif 9" +#define sFF34 "Serif 12" +#define sFF35 "Serif 18" +#define sFF36 "Serif 24" + +#define sFF37 "Serif italic 9" +#define sFF38 "Serif italic 12" +#define sFF39 "Serif italic 18" +#define sFF40 "Serif italic 24" + +#define sFF41 "Serif bold 9" +#define sFF42 "Serif bold 12" +#define sFF43 "Serif bold 18" +#define sFF44 "Serif bold 24" + +#define sFF45 "Serif bold italic 9" +#define sFF46 "Serif bold italic 12" +#define sFF47 "Serif bold italic 18" +#define sFF48 "Serif bold italic 24" + +#else // LOAD_GFXFF not defined so setup defaults to prevent error messages + +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// Free fonts are not loaded in User_Setup.h so we must define all as font 1 +// to prevent compile error messages +// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +#define GFXFF 1 +#define GLCD 1 +#define FONT2 2 +#define FONT4 4 +#define FONT6 6 +#define FONT7 7 +#define FONT8 8 + +#define TT1 1 + +#define FF0 1 +#define FF1 1 +#define FF2 1 +#define FF3 1 +#define FF4 1 +#define FF5 1 +#define FF6 1 +#define FF7 1 +#define FF8 1 +#define FF9 1 +#define FF10 1 +#define FF11 1 +#define FF12 1 +#define FF13 1 +#define FF14 1 +#define FF15 1 +#define FF16 1 +#define FF17 1 +#define FF18 1 +#define FF19 1 +#define FF20 1 +#define FF21 1 +#define FF22 1 +#define FF23 1 +#define FF24 1 +#define FF25 1 +#define FF26 1 +#define FF27 1 +#define FF28 1 +#define FF29 1 +#define FF30 1 +#define FF31 1 +#define FF32 1 +#define FF33 1 +#define FF34 1 +#define FF35 1 +#define FF36 1 +#define FF37 1 +#define FF38 1 +#define FF39 1 +#define FF40 1 +#define FF41 1 +#define FF42 1 +#define FF43 1 +#define FF44 1 +#define FF45 1 +#define FF46 1 +#define FF47 1 +#define FF48 1 + +#define FM9 1 +#define FM12 1 +#define FM18 1 +#define FM24 1 + +#define FMB9 1 +#define FMB12 1 +#define FMB18 1 +#define FMB24 1 + +#define FMO9 1 +#define FMO12 1 +#define FMO18 1 +#define FMO24 1 + +#define FMBO9 1 +#define FMBO12 1 +#define FMBO18 1 +#define FMBO24 1 + +#define FSS9 1 +#define FSS12 1 +#define FSS18 1 +#define FSS24 1 + +#define FSSB9 1 +#define FSSB12 1 +#define FSSB18 1 +#define FSSB24 1 + +#define FSSO9 1 +#define FSSO12 1 +#define FSSO18 1 +#define FSSO24 1 + +#define FSSBO9 1 +#define FSSBO12 1 +#define FSSBO18 1 +#define FSSBO24 1 + +#define FS9 1 +#define FS12 1 +#define FS18 1 +#define FS24 1 + +#define FSI9 1 +#define FSI12 1 +#define FSI19 1 +#define FSI24 1 + +#define FSB9 1 +#define FSB12 1 +#define FSB18 1 +#define FSB24 1 + +#define FSBI9 1 +#define FSBI12 1 +#define FSBI18 1 +#define FSBI24 1 + +#endif // LOAD_GFXFF diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Server/I2s_Setting.h b/ESP32_TTGO/Walkie-Talkie_Project/Server/I2s_Setting.h new file mode 100644 index 0000000..6681517 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Server/I2s_Setting.h @@ -0,0 +1,95 @@ +#define I2S_WS_TX 12 +#define I2S_SCK_TX 13 +#define I2S_DATA_OUT_TX 15 +#define I2S_PORT_TX I2S_NUM_0 + +#define I2S_WS_RX 33 +#define I2S_SCK_RX 25 +#define I2S_SD_RX 26 +#define I2S_PORT_RX I2S_NUM_1 + +#define I2S_SAMPLE_RATE (16000) +#define I2S_SAMPLE_BITS (32) +#define I2S_READ_LEN (1024) + +char* i2s_read_buff; +uint8_t* flash_write_buff; + +const i2s_config_t i2s_config_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 = 32, + .dma_buf_len = 64 +}; + +const i2s_pin_config_t pin_config_tx = { + .bck_io_num = I2S_SCK_TX, + .ws_io_num = I2S_WS_TX, + .data_out_num = I2S_DATA_OUT_TX, + .data_in_num = I2S_PIN_NO_CHANGE +}; + +const i2s_config_t i2s_config_rx = { + .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 = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 32, + .dma_buf_len = 64 +}; + +const i2s_pin_config_t pin_config_rx = { + .bck_io_num = I2S_SCK_RX, + .ws_io_num = I2S_WS_RX, + .data_out_num = I2S_PIN_NO_CHANGE, + .data_in_num = I2S_SD_RX +}; + +void i2s_RX_init(){ + i2s_driver_install(I2S_PORT_RX, &i2s_config_rx, 0, NULL); + i2s_set_pin(I2S_PORT_RX, &pin_config_rx); +} + +void i2s_RX_uninst(){ + i2s_driver_uninstall(I2S_PORT_RX); +} + +void i2s_TX_init(){ + i2s_driver_install(I2S_PORT_TX, &i2s_config_tx, 0, NULL); + i2s_set_pin(I2S_PORT_TX, &pin_config_tx); +} + +void i2s_TX_uninst(){ + i2s_driver_uninstall(I2S_PORT_TX); +} + +void i2s_adc_data_scale(uint8_t * d_buff, uint8_t* s_buff, uint32_t len){ + uint32_t j = 0; + uint32_t dac_value = 0; + for (int i = 0; i < len; i += 2) { + dac_value = ((((uint16_t) (s_buff[i + 1] & 0xf) << 8) | ((s_buff[i + 0])))); + d_buff[j++] = 0; + d_buff[j++] = dac_value * 256 / 1024 ; + } +} + +void i2s_read_data(){ + size_t bytes_read; + i2s_read(I2S_PORT_RX, (void*) i2s_read_buff, I2S_READ_LEN, &bytes_read, portMAX_DELAY); + i2s_adc_data_scale(flash_write_buff, (uint8_t*)i2s_read_buff, I2S_READ_LEN); +} + +void i2s_write_data(char *buf_ptr, int buf_size){ + i2s_write_bytes(I2S_PORT_TX, buf_ptr, buf_size, portMAX_DELAY); +} + +void i2s_buff_init(){ + i2s_read_buff = (char*) calloc(I2S_READ_LEN, sizeof(char)); + flash_write_buff = (uint8_t*) calloc(I2S_READ_LEN, sizeof(char)); +} diff --git a/ESP32_TTGO/Walkie-Talkie_Project/Server/Server.ino b/ESP32_TTGO/Walkie-Talkie_Project/Server/Server.ino new file mode 100644 index 0000000..99a7675 --- /dev/null +++ b/ESP32_TTGO/Walkie-Talkie_Project/Server/Server.ino @@ -0,0 +1,195 @@ +///////////////////////////////////////////////////////////////// +/* + ESP32 | Walkie-Talkie, Half-duplex communication based on WebSocket + Video Tutorial: https://youtu.be/kw30vLdrGE8 + Created by Eric Nam (ThatProject) +*/ +///////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "Free_Fonts.h" +#include "driver/i2s.h" +#include "Button2.h"; +#include "I2s_Setting.h" +#include "Const.h" +#define RIGHT_BUTTON_PIN 35 +Button2 rButton = Button2(RIGHT_BUTTON_PIN); + +using namespace websockets; +WebsocketsServer server; +WebsocketsClient client; + +TFT_eSPI tft = TFT_eSPI(); +TFT_eSprite logScreen = TFT_eSprite(&tft); + +unsigned long requestTimestamp; +TaskHandle_t i2sReadTaskHandler = NULL; + +void setup() { + Serial.begin(115200); + + WiFi.softAP(ssid, password); + server.listen(8888); + + display_init(); + display_ready_screen(); + button_init(); + i2s_buff_init(); + print_log_screen("+ All Ready"); + + xTaskCreate(pong_task, "pong_task", 2048, NULL, 1, NULL); +} + +void loop() { + rButton.loop(); + listenForClient(); + pollClient(); +} + +void listenForClient() { + if (server.poll()) { + print_log_screen("+ Client Connected!"); + client = server.accept(); + client.onMessage(handleMessage); + client.onEvent(handleEvent); + client.send(getStrTimestamp()); + requestTimestamp = millis(); + } +} + +void pollClient() { + client.poll(); +} + +void handleMessage(WebsocketsClient &client, WebsocketsMessage message) { + requestTimestamp = millis(); + int msgLength = message.length(); + + if(message.type() == MessageType::Binary){ + if(states == Listening && msgLength > 0){ + i2s_write_data((char*)message.c_str(), msgLength); + } + + }else if(message.type() == MessageType::Text){ + if(states == Idle){ + states = Listening; + i2s_TX_init(); + client.send(message.data()); + print_log_screen("* Listening Mode *"); + }else if(states == Listening){ + states = Idle; + i2s_TX_uninst(); + print_log_screen("* IDLE Mode *"); + } + } +} + +void handleEvent(WebsocketsClient &client, WebsocketsEvent event, String data) { + if (event == WebsocketsEvent::ConnectionClosed) { + print_log_screen("- Client Disconnected!"); + if(states == Listening){ + states = Idle; + i2s_TX_uninst(); + } + } +} + +static void i2s_read_task(void *arg) +{ + while (1) { + i2s_read_data(); + if(client.available() && states == Speaking){ + requestTimestamp = millis(); + client.sendBinary((const char*)flash_write_buff, I2S_READ_LEN); + } + } +} + +static void pong_task(void *arg){ + while (1) { + if(client.available() && millis() - requestTimestamp > 5000) { + client.close(); + } + vTaskDelay(1000); + } +} + +void pressed(Button2& btn) { + if(btn == rButton && states == Idle){ + print_log_screen("* Speaking Mode *"); + + client.send(getStrTimestamp()); + states = Speaking; + i2s_RX_init(); + + xTaskCreate(i2s_read_task, "i2s_read_task", 4096, NULL, 1, &i2sReadTaskHandler); + } +} + +void released(Button2& btn) { + if(btn == rButton && states == Speaking){ + states = Idle; + print_log_screen("* IDLE Mode *"); + + delay(100); + if( i2sReadTaskHandler != NULL ){ + vTaskDelete( i2sReadTaskHandler ); + i2sReadTaskHandler = NULL; + } + + delay(100); + client.send(getStrTimestamp()); + i2s_RX_uninst(); + } +} + +String getStrTimestamp(){ + return (String)millis(); +} + +void button_init(){ + rButton.setPressedHandler(pressed); + rButton.setReleasedHandler(released); +} + +void display_init(){ + tft.begin(); + tft.setRotation(0); + tft.setTextColor(TFT_WHITE,TFT_BLACK); + tft.fillScreen(TFT_BLACK); + + logScreen.setColorDepth(8); + logScreen.createSprite(tft.width(), tft.height()/2); + logScreen.fillSprite(TFT_BLUE); + logScreen.setScrollRect(0, 0, tft.width(), tft.height()/2, TFT_BLUE); + logScreen.setTextColor(TFT_WHITE); + logScreen.setTextDatum(TL_DATUM); +} + +void display_ready_screen(){ + tft.fillScreen(TFT_BLACK); + tft.setTextDatum(TL_DATUM); + + tft.setFreeFont(FF21); + tft.setTextColor(TFT_SKYBLUE, TFT_BLACK); + tft.drawString("ESP32-ESP32", 0, 10, GFXFF); + + tft.setFreeFont(FF23); + tft.setTextColor(TFT_SILVER, TFT_BLACK); + tft.drawString("Walkie", 0, 35, GFXFF); + tft.setTextColor(TFT_GOLD, TFT_BLACK); + tft.drawString("Talkie", 30, 60, GFXFF); + + tft.setTextDatum(MC_DATUM); + tft.setFreeFont(FF21); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + tft.drawString(deviceRole == Server ? "[Server Ready]" : "[Clinet Ready]", tft.width()/2, 100, GFXFF); +} + +void print_log_screen(String text){ + logScreen.drawString(text, 0, -1, 2); + logScreen.pushSprite(0, tft.height()/2); + logScreen.scroll(0,16); +} \ No newline at end of file