#include #include #include #include "config.h" #include "shalomorph.h" #include "shalom.h" #include "salam.h" #include "salamorph.h" #include "together.h" #include "talis.h" #include "metta.h" #include "loving.h" #include "kindness.h" #define DEBUG true #define BUTTON1PIN ((gpio_num_t)35) #define BUTTON2PIN ((gpio_num_t)0) #define INTRO_FREEZE_MILLIS 4000 #define INTRO_SCROLL_MILLIS 2000 #define PING_START_MILLIS 8000 // should be > INTRO_FREEZE_MILLIS + INTRO_SCROLL_MILLIS #define METTA_FREEZE_MILLIS 1000 #define METTA_SCROLL_MILLIS 2000 #define OUTRO_SCROLL_MILLIS 2000 #define OUTRO_FREEZE_MILLIS 1000 unsigned long outro_start; #define SEND_INTERVAL 3000 unsigned long next_send = 0; String my_mac; bool is_salam; bool metta_from_you; unsigned long metta_from_me_start = 0; #define MANTRA_I "May I be filled with loving kindness" #define MANTRA_WE "May we be filled with loving kindness" uint8_t peer_mac_addr[6]; esp_now_peer_info_t peerInfo; bool nearby = false; #define NUM_FRAMES 23 enum frameType { FRAME_ME, FRAME_ME2US, FRAME_US, FRAME_US2U, FRAME_U }; frameType frames[NUM_FRAMES] = { FRAME_ME, FRAME_ME2US, FRAME_US, FRAME_US2U, FRAME_U, FRAME_U, FRAME_U, FRAME_US2U, FRAME_US, FRAME_US, FRAME_US2U, FRAME_U, FRAME_U, FRAME_U, FRAME_US2U, FRAME_US, FRAME_ME2US, FRAME_ME, FRAME_ME, FRAME_ME, FRAME_ME, FRAME_ME, FRAME_ME }; const unsigned short *frame2image(frameType frame, bool is_salam) { switch (frame) { case FRAME_ME: return is_salam ? salam : shalom; case FRAME_ME2US: return is_salam ? salamorph : shalomorph; case FRAME_US: return together; case FRAME_US2U: return is_salam ? shalomorph : salamorph; case FRAME_U: return is_salam ? shalom : salam; } } int current_frame = 0; unsigned long last_flip = 0; #define DURATION 100 TFT_eSPI tft = TFT_eSPI(); TFT_eSprite background = TFT_eSprite(&tft); TFT_eSprite leftSprite = TFT_eSprite(&tft); TFT_eSprite rightSprite = TFT_eSprite(&tft); // lifted from MacAddress.c bool str2mac(char *buf, uint8_t *mac) { char cs[18]; char *token; char *next; //Unused but required int i; strncpy(cs, buf, sizeof(cs)); //strtok modifies the buffer: copy to working buffer. for (i = 0; i < 6; i++) { token = strtok((i == 0) ? cs : NULL, ":"); //Find first or next token if (!token) { //No more tokens found return false; } mac[i] = strtol(token, &next, 16); } return true; } void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { nearby = (status == ESP_NOW_SEND_SUCCESS); if (!nearby) { metta_from_you = false; } if (DEBUG) { Serial.println(nearby ? "Nearby" : "Not nearby"); } } void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) { metta_from_you = (data_len == strlen(MANTRA_WE)) && !strncmp((const char *)data, MANTRA_WE, data_len); if (DEBUG) { // char macStr[18]; // snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", // mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); // Serial.print("Packet Recv from: "); Serial.println(macStr); //String msg = ""; //for (int i = 0 ; i < data_len; i++) { // msg.concat(char(data[i])); //} //Serial.print("Packet Recv message: "); Serial.println(msg); Serial.print("Packet Recv message length: "); Serial.println(data_len); Serial.print("Metta from other: "); Serial.println(metta_from_you); } } void setup() { pinMode(BUTTON1PIN, INPUT_PULLUP); pinMode(BUTTON2PIN, INPUT_PULLUP); Serial.begin(115200); delay(1000); Serial.println("=== Talis-Metta ==="); // determine peer mac address my_mac = WiFi.macAddress(); Serial.println("My MAC:"); Serial.println(my_mac); if (my_mac.equals(SHALOM)) { if (DEBUG) { Serial.println("Shalom"); } is_salam = false; str2mac(SALAM, peer_mac_addr); } else { if (DEBUG) { Serial.println("Salam"); } is_salam = true; str2mac(SHALOM, peer_mac_addr); } outro_start = 0; metta_from_me_start = 0; metta_from_you = false; WiFi.mode(WIFI_STA); esp_now_init(); memcpy(peerInfo.peer_addr, peer_mac_addr, 6); peerInfo.channel = 0; peerInfo.encrypt = false; esp_now_add_peer(&peerInfo); esp_now_register_send_cb(OnDataSent); esp_now_register_recv_cb(OnDataRecv); tft.init(); tft.setRotation(3); // was 1 tft.setSwapBytes(true); tft.fillScreen(TFT_BLACK); background.createSprite(240, 135); background.setSwapBytes(true); leftSprite.createSprite(120, 135); leftSprite.setSwapBytes(true); leftSprite.pushImage(0, 0, 120, 135, talis); rightSprite.createSprite(120, 135); rightSprite.setSwapBytes(true); rightSprite.pushImage(0, 0, 120, 135, metta); } void do_scroll(const unsigned short *left_image, const unsigned short *right_image, unsigned long start_time, unsigned long freeze_duration, unsigned long scroll_duration, bool is_reverse) { unsigned long nowmillis = millis(); if (nowmillis >= start_time && nowmillis < start_time + freeze_duration + scroll_duration) { unsigned long freeze_start = is_reverse ? start_time + scroll_duration : start_time; unsigned long scroll_start = is_reverse ? start_time : start_time + freeze_duration; leftSprite.pushImage(0, 0, 120, 135, left_image); rightSprite.pushImage(0, 0, 120, 135, right_image); if (nowmillis >= freeze_start && nowmillis < freeze_start + freeze_duration) { leftSprite.pushToSprite(&background, 0, 0); rightSprite.pushToSprite(&background, 120, 0); } else { long scroll_pixels = 123 * (nowmillis - scroll_start) / scroll_duration; if (is_reverse) { scroll_pixels = 123 - scroll_pixels; } leftSprite.pushToSprite(&background, -scroll_pixels, 0); rightSprite.pushToSprite(&background, 120 + scroll_pixels, 0); } } } void loop() { unsigned long nowmillis = millis(); if (digitalRead(BUTTON1PIN) == LOW) { outro_start = nowmillis; } if (digitalRead(BUTTON2PIN) == LOW) { metta_from_me_start = nowmillis; } if (nowmillis > next_send) { if (DEBUG) { Serial.print("Sending: "); Serial.println(metta_from_me_start ? MANTRA_WE : MANTRA_I); } esp_now_send( peerInfo.peer_addr, metta_from_me_start ? (const uint8_t *)MANTRA_WE : (const uint8_t *)MANTRA_I, metta_from_me_start ? strlen(MANTRA_WE) : strlen(MANTRA_I)); next_send = nowmillis + SEND_INTERVAL; } if (nowmillis > PING_START_MILLIS) { if ((nowmillis - last_flip) > DURATION || nowmillis < last_flip) { current_frame = (current_frame + 1) % NUM_FRAMES; last_flip = nowmillis; background.pushSprite(0, 0); } } else { current_frame = 0; } // FRAME_ME or animation frame background.pushImage( 0, 0, 240, 135, frame2image((metta_from_me_start && metta_from_you) ? frames[current_frame] : FRAME_ME, is_salam)); // Scroll overlays if (outro_start) { // Outro scroll overlay if (nowmillis - outro_start > OUTRO_FREEZE_MILLIS + OUTRO_SCROLL_MILLIS) { // outro over. shut down esp_sleep_enable_ext0_wakeup(BUTTON1PIN, LOW); esp_deep_sleep_start(); } else { // do outro reverse scroll and freeze do_scroll(talis, metta, outro_start, OUTRO_FREEZE_MILLIS, OUTRO_SCROLL_MILLIS, true); } } else if (nowmillis < INTRO_FREEZE_MILLIS + INTRO_SCROLL_MILLIS) { // Intro scroll overlay do_scroll(talis, metta, 0, INTRO_FREEZE_MILLIS, INTRO_SCROLL_MILLIS, false); } else if (metta_from_me_start && nowmillis < metta_from_me_start + METTA_FREEZE_MILLIS + METTA_SCROLL_MILLIS) { do_scroll(loving, kindness, metta_from_me_start, METTA_FREEZE_MILLIS, METTA_SCROLL_MILLIS, false); } background.pushSprite(0, 0); }