├── bins ├── t └── TC0xA-bins.zip ├── OxA-workshop.pdf ├── AudioStreaming ├── microphone_driver.ino └── AudioStreaming.ino ├── LEDs └── LEDs.ino ├── SoundBoard └── SoundBoard.ino └── README.md /bins/t: -------------------------------------------------------------------------------- 1 | v 2 | -------------------------------------------------------------------------------- /OxA-workshop.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poplicola/Thotcon0xA_Pub/HEAD/OxA-workshop.pdf -------------------------------------------------------------------------------- /bins/TC0xA-bins.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/poplicola/Thotcon0xA_Pub/HEAD/bins/TC0xA-bins.zip -------------------------------------------------------------------------------- /AudioStreaming/microphone_driver.ino: -------------------------------------------------------------------------------- 1 | void microphone_driver() { 2 | esp_err_t err; 3 | 4 | // The I2S config as per the example 5 | const i2s_config_t i2s_config = { 6 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer 7 | .sample_rate = 16000, // 16KHz 8 | .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits 9 | .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // although the SEL config should be left, it seems to transmit on right 10 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 11 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1 12 | .dma_buf_count = 4, // number of buffers 13 | .dma_buf_len = 8 // 8 samples per buffer (minimum) 14 | }; 15 | 16 | // The pin config as per the setup 17 | const i2s_pin_config_t pin_config = { 18 | .bck_io_num = 23, // BCKL 19 | .ws_io_num = 22, // LRCL 20 | .data_out_num = -1, // not used (only for speakers) 21 | .data_in_num = 25 // DOUT 22 | }; 23 | 24 | // Configuring the I2S driver and pins. 25 | // This function must be called before any I2S driver read/write operations. 26 | 27 | err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 28 | if (err != ESP_OK) { 29 | Serial.printf("Failed installing driver: %d\n", err); 30 | while (true); 31 | } 32 | err = i2s_set_pin(I2S_PORT, &pin_config); 33 | if (err != ESP_OK) { 34 | Serial.printf("Failed setting pin: %d\n", err); 35 | while (true); 36 | } 37 | Serial.println("I2S driver installed."); 38 | } 39 | -------------------------------------------------------------------------------- /LEDs/LEDs.ino: -------------------------------------------------------------------------------- 1 | int threshold = 40; 2 | bool touch1detected = false; 3 | bool touch2detected = false; 4 | bool touch3detected = false; 5 | bool touch4detected = false; 6 | bool touch5detected = false; 7 | 8 | void gotTouch1(){ 9 | touch1detected = true; 10 | } 11 | 12 | void gotTouch2(){ 13 | touch2detected = true; 14 | } 15 | 16 | void gotTouch3(){ 17 | touch3detected = true; 18 | } 19 | 20 | void gotTouch4(){ 21 | touch4detected = true; 22 | } 23 | 24 | void gotTouch5(){ 25 | touch5detected = true; 26 | } 27 | 28 | void setup() { 29 | Serial.begin(115200); 30 | touchAttachInterrupt(T4, gotTouch1, threshold); 31 | touchAttachInterrupt(T6, gotTouch2, threshold); 32 | touchAttachInterrupt(T3, gotTouch3, threshold); 33 | touchAttachInterrupt(T7, gotTouch4, threshold); 34 | touchAttachInterrupt(T2, gotTouch5, threshold); 35 | pinMode(21, OUTPUT); 36 | pinMode(19, OUTPUT); 37 | pinMode(18, OUTPUT); 38 | pinMode(17, OUTPUT); 39 | pinMode(16, OUTPUT); 40 | pinMode(5, OUTPUT); 41 | } 42 | 43 | void loop() { 44 | if (touch1detected){ 45 | touch1detected = false; 46 | digitalWrite(18, HIGH); //left mustache 47 | delay(200); 48 | digitalWrite(18, LOW); 49 | } 50 | 51 | if (touch2detected){ 52 | touch2detected = false; 53 | digitalWrite(16, HIGH); //right eye 54 | } 55 | 56 | if (touch3detected){ 57 | touch3detected = false; 58 | digitalWrite(19, HIGH); //left eye 59 | 60 | } 61 | 62 | if (touch4detected){ 63 | touch4detected = false; 64 | digitalWrite(5, HIGH); //right mustache 65 | 66 | } 67 | 68 | if (touch5detected){ 69 | touch5detected = false; 70 | digitalWrite(17, HIGH); //right ear 71 | digitalWrite(21, HIGH); //left ear 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /SoundBoard/SoundBoard.ino: -------------------------------------------------------------------------------- 1 | #include "SoundData.h"; 2 | #include "XT_DAC_Audio.h"; 3 | 4 | XT_DAC_Audio_Class DacAudio(26,0); 5 | 6 | XT_Wav_Class soundTrombone(trombone); 7 | XT_Wav_Class soundHorn(airhorn); 8 | XT_Wav_Class soundDixie(dixie); 9 | 10 | int threshold = 40; 11 | bool touch1detected = false; 12 | bool touch2detected = false; 13 | bool touch3detected = false; 14 | bool touch4detected = false; 15 | bool touch5detected = false; 16 | 17 | void gotTouch1(){ 18 | touch1detected = true; 19 | } 20 | 21 | void gotTouch2(){ 22 | touch2detected = true; 23 | } 24 | 25 | void gotTouch3(){ 26 | touch3detected = true; 27 | } 28 | 29 | void gotTouch4(){ 30 | touch4detected = true; 31 | } 32 | 33 | void gotTouch5(){ 34 | touch5detected = true; 35 | } 36 | 37 | void setup() { 38 | Serial.begin(115200); 39 | touchAttachInterrupt(T4, gotTouch1, threshold); 40 | touchAttachInterrupt(T6, gotTouch2, threshold); 41 | touchAttachInterrupt(T3, gotTouch3, threshold); 42 | touchAttachInterrupt(T7, gotTouch4, threshold); 43 | touchAttachInterrupt(T2, gotTouch5, threshold); 44 | } 45 | 46 | void loop() { 47 | DacAudio.FillBuffer(); 48 | if (touch1detected){ 49 | touch1detected = false; 50 | DacAudio.Play(&soundHorn); 51 | delay(200); 52 | } 53 | 54 | if (touch2detected){ 55 | delay(200); 56 | DacAudio.FillBuffer(); 57 | touch2detected = false; 58 | soundTrombone.Speed=2; 59 | DacAudio.Play(&soundTrombone); 60 | delay(200); 61 | } 62 | 63 | if (touch3detected){ 64 | delay(200); 65 | DacAudio.FillBuffer(); 66 | touch3detected = false; 67 | soundDixie.Speed=2; 68 | DacAudio.Play(&soundDixie); 69 | delay(200); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /AudioStreaming/AudioStreaming.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define AUDIO_BUFFER_MAX 200 7 | 8 | uint8_t audioBuffer[AUDIO_BUFFER_MAX]; 9 | uint32_t transmitBuffer[AUDIO_BUFFER_MAX]; 10 | uint32_t bufferPointer = 0; 11 | 12 | const char* ssid = "YourWiFi"; 13 | const char* password = "YourPassword"; 14 | const char* host = "ServerIP"; 15 | 16 | bool transmitNow = false; 17 | int read_raw; 18 | 19 | WiFiClient client; 20 | 21 | hw_timer_t * timer = NULL; // our timer 22 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 23 | 24 | const i2s_port_t I2S_PORT = I2S_NUM_0; 25 | 26 | void setup() { 27 | Serial.begin(115200); 28 | 29 | WiFi.mode(WIFI_STA); 30 | WiFi.begin(ssid, password); 31 | 32 | while (WiFi.status() != WL_CONNECTED) { 33 | delay(500); 34 | Serial.print("."); 35 | } 36 | 37 | Serial.println(""); 38 | Serial.println("WiFi connected"); 39 | Serial.println("MY IP address: "); 40 | Serial.println(WiFi.localIP()); 41 | 42 | const int port = 4444; 43 | while (!client.connect(host, port)) { 44 | Serial.println("connection failed"); 45 | delay(1000); 46 | } 47 | 48 | Serial.println("connected to server"); 49 | 50 | microphone_driver(); 51 | 52 | } 53 | 54 | void loop() { 55 | int32_t sample = 0; 56 | for (uint8_t i=0; i< (AUDIO_BUFFER_MAX); i++) 57 | { 58 | int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout 59 | if (bytes_read>0) 60 | { 61 | transmitBuffer[i] = sample; 62 | 63 | } 64 | } 65 | // if (bytes_read>0) { // checks if the buffer is full 66 | client.write((const uint8_t *)transmitBuffer,sizeof(transmitBuffer)); // sending the buffer to our server 67 | //} 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Restoring your badge to stock firmware 3 | 4 | esptool.py --chip esp32 --port "" --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader_dio_40m.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 TC0xA.bin 5 | 6 | 7 | # Examples for Thotcon 0xA Badge 8 | 9 | ## Introduction 10 | The Thotcon 0xA badge runs off the Sparkfun ESP32 Thingdev board. Sparkfun has an excellent hookup guide [over on their website](https://learn.sparkfun.com/tutorials/esp32-thing-hookup-guide#introduction). 11 | 12 | Some quick notes about pins on the 0xA badge: 13 | * The touch pads for the device are on t4, 6, 3, 7, 2. These are, respectively, right, up, left, down, and select. 14 | * LEDS: 21, 19, 18, 17, 16, 5. These are, respectively, left ear, left eye, left mustache, right ear, right eye, right mustache. 15 | * Speaker: 26 16 | * Mic Pin: 25 17 | * Mic_clock: 23 18 | * Mic_ws: 22 19 | 20 | ## Getting Started with the Badge 21 | 1. Download/Install [Arduino](https://www.arduino.cc/) 22 | 2. Install [ESP32 board](https://github.com/espressif/arduino-esp32#installation-instructions) on Arduino platform (recommendation is to follow instructions under "Instructions for Boards Manager") 23 | 24 | ## LEDs (Hello World) 25 | There are six backlit LEDs on the Thotcon 0xA badge. An example of how to activate these LEDs and utilize them is located in the LEDs directory of this GitHub. 26 | 27 | ## SoundBoard 28 | The sound board maps sounds to three of the capacitive touch pads on the badge. The SoundBoard utilizes the audio library [XT_DAC_AUDIO](https://www.xtronical.com/the-dacaudio-library-download-and-installation/). Make sure this is included in any project that utilizes the speaker. Example code for this is located in in the SoundBoard directory. 29 | 30 | Also note that all audio files must be converted before being uploaded to the badge. A brief explanation of how to convert audio for the badge follows. 31 | 32 | ### Converting Audio for the Badge 33 | 1. Download [Audacity](https://sourceforge.net/projects/audacity/) 34 | 2. Download a hex editor (suggestions for [Mac](https://ridiculousfish.com/hexfiend/), [Linux](https://github.com/bwrsandman/Bless), and [Windows](https://mh-nexus.de/en/hxd/)) 35 | 3. Open file in Audacity and convert to correct format by choosing the appropriate settings (instructions [here](https://www.xtronical.com/basics/audio/dacs-for-sound/playing-wav-files/)) 36 | 4. Open file in hex editor and copy/paste into a txt file. Save 37 | 5. Open txt file (in vi or otherwise) and run regex command: `%s/ /,0x/gi` 38 | 6. After running command, make sure to additionally add 0x to the beginning of the first hex value in the file. 39 | 7. Get the size of array (one easy way to do this is by doing an "edit>find" on 0x). There is likely a smarter way to do these last three steps, but I don't have the time. 40 | 8. Save, copy text, and paste into an array into Arduino in a header file (example uses SoundData.h). Array container works thusly: const unsigned char StarWarsWav[SIZE_OF_ARRAY] = { YOUR_ARRAY }; 41 | 42 | ## Audio Streaming 43 | The Thotcon 0xA badge comes with a microphone that allows for streaming audio. An example of how to utilize this can be found in the AudioStreaming directory. Note that the 0xA badge has its own special driver for the microphone (located in the microphone_driver file). This must be included in any project that uses the mic. 44 | 45 | On the server side, run this command in Terminal `nc -nlvp 4444 | aplay -b 16000 -f S32LE` 46 | 47 | ## Recognition 48 | We relied heavily on this website for speaker audio, including the library that its owner created: 49 | * https://www.xtronical.com 50 | 51 | Microphone Code: 52 | * How to do microphone driver init: https://github.com/maspetsberger/esp32-i2s-mems/blob/master/examples/InputSerialPlotter/InputSerialPlotter.ino 53 | 54 | Speaker Code: 55 | * Library for playing sound: https://www.xtronical.com/basics/audio/dacs-for-sound/playing-wav-files/ 56 | 57 | Audio Streaming: 58 | * https://www.hackster.io/julianfschroeter/stream-your-audio-on-the-esp32-2e4661 59 | * https://github.com/Edzelf/ESP32-Radio 60 | 61 | ESP32 Radio: 62 | * https://github.com/Edzelf/ESP32-Radio 63 | 64 | Documentation 65 | * Espressif documentation on using audio with their chip. Notable, they mention one main consideration being “Ethernet interface to obtain an audio data stream from the internet” https://docs.espressif.com/projects/esp-adf/en/latest/design-guide/project-design.html 66 | 67 | "_History_ repeats itself, first as tragedy, second as farce." - Karl Marx 68 | --------------------------------------------------------------------------------