From 30e90fdfe2a190ca94d46c723e8dd408418e1627 Mon Sep 17 00:00:00 2001 From: Dooho Yi Date: Sun, 10 Oct 2021 09:30:57 +0900 Subject: [PATCH] add p (qlist sender) - q sender but doesn't play itself. - hold a complex q list --- @postman/src/main.cpp | 4 +- p/.gitignore | 1 + p/include/README | 39 ++++ p/lib/README | 46 +++++ p/platformio.ini | 19 ++ p/src/main.cpp | 444 ++++++++++++++++++++++++++++++++++++++++++ p/test/README | 11 ++ post.h | 25 +++ 8 files changed, 587 insertions(+), 2 deletions(-) create mode 100644 p/.gitignore create mode 100644 p/include/README create mode 100644 p/lib/README create mode 100644 p/platformio.ini create mode 100644 p/src/main.cpp create mode 100644 p/test/README diff --git a/@postman/src/main.cpp b/@postman/src/main.cpp index b263525..a81d824 100644 --- a/@postman/src/main.cpp +++ b/@postman/src/main.cpp @@ -23,10 +23,10 @@ //======================== // #define MY_GROUP_ID (20000) -#define MY_ID (MY_GROUP_ID + 1000 + 999) +#define MY_ID (MY_GROUP_ID + 1000 + 21) #define MY_SIGN ("@POSTMAN|REPEATER") // -#define ADDRESSBOOK_TITLE ("1st floor") +#define ADDRESSBOOK_TITLE ("3rd floor") // //======================== diff --git a/p/.gitignore b/p/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/p/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/p/include/README b/p/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/p/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/p/lib/README b/p/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/p/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/p/platformio.ini b/p/platformio.ini new file mode 100644 index 0000000..d93d430 --- /dev/null +++ b/p/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = + adafruit/Adafruit SSD1306@^2.4.5 + adafruit/Adafruit BusIO@^1.7.3 + arkhipenko/TaskScheduler@^3.3.0 +upload_speed = 921600 ; 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 diff --git a/p/src/main.cpp b/p/src/main.cpp new file mode 100644 index 0000000..9a1fa50 --- /dev/null +++ b/p/src/main.cpp @@ -0,0 +1,444 @@ +// +// wirelessly connected cloud (based on ESP-NOW, a kind of LPWAN?) +// + +// +// 0set performance 'Georidugi'/Distancing +// @ 2021 Jun 15 ~ 17 +// + +// +// 2021 june +// +// esp32 based sampler + 'note' sequence generator! +// + +//======================== +// +#define MY_GROUP_ID (80000) +#define MY_ID (MY_GROUP_ID + 1) +#define MY_SIGN ("P") +// +#define ADDRESSBOOK_TITLE ("1st floor") +//======================== + +//===================== +// +// 'DISABLE_AP' +// --> (questioning)... +// +// 'GEN_NOTE_REQ' +// --> this will generate 'note' msg. +// +//==================== +// +#define DISABLE_AP +#define GEN_NOTE_REQ + +//======================== +// +#define SCREEN_PERIOD (200) //200ms = 5hz +// +#define WIFI_CHANNEL 5 +// +// 'MONITORING_SERIAL' +// +// --> sometimes, the 'Serial' is in use (for example, 'osc' node) +// then, use 'Serial1' - D4/GPIO2/TDX1 @ nodemcu (this is TX only.) +// +// --> otherwise, MONITORING_SERIAL == Serial. +// +#if defined(SERIAL_SWAP) +#define MONITORING_SERIAL (Serial1) +#else +#define MONITORING_SERIAL (Serial) +#endif +// +//======================= + +//======================== +//======================= + +//arduino +#include + +//post & addresses +#include "../../post.h" + +//espnow +#include +#include +AddressLibrary lib; + +//task +#include +Scheduler runner; + +//screen +#include +#include +#define MAKEPYTHON_ESP32_SDA 4 +#define MAKEPYTHON_ESP32_SCL 5 +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels +#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +//-*-*-*-*-*-*-*-*-*-*-*-*- +// my tasks + +// q list +std::vector qlist; +std::vector qlist_desc; +void init_qlist() { + // + qlist.push_back(Note(20000, 40, 60, 1, 0, 0, 0, 0, 0)); //guide A: start song + qlist_desc.push_back("guide A: start song"); + // + qlist.push_back(Note(20000, 30, 0, 0, 0, 0, 0, 0, 0)); //stop all. + qlist_desc.push_back("stop all."); + // + qlist.push_back(Note(20000, 30, 60, 1, 0, 0, 0, 0, 0)); //tour start + qlist_desc.push_back("tour start"); + // + qlist.push_back(Note(20000, 30, 0, 0, 0, 0, 0, 0, 0)); //stop all. + qlist_desc.push_back("stop all."); + // + qlist.push_back(Note(20000, 31, 70, 1, 0, 0, 0, 0, 0)); //tour end + qlist_desc.push_back("tour end"); + // + qlist.push_back(Note(20000, 30, 0, 0, 0, 0, 0, 0, 0)); //stop all. + qlist_desc.push_back("stop all."); + // + qlist.push_back(Note(20000, 41, 60, 1, 0, 0, 0, 0, 0)); //guide A: end song + qlist_desc.push_back("guide A: end song"); + // + qlist.push_back(Note(20000, 40, 60, 1, 0, 0, 0, 0, 0)); //guide B: start song + qlist_desc.push_back("guide B: start song"); + // + qlist.push_back(Note(20000, 30, 0, 0, 0, 0, 0, 0, 0)); //stop all. + qlist_desc.push_back("stop all."); + // + qlist.push_back(Note(20000, 30, 60, 1, 0, 0, 0, 0, 0)); //tour start + qlist_desc.push_back("tour start"); + // + qlist.push_back(Note(20000, 30, 0, 0, 0, 0, 0, 0, 0)); //stop all. + qlist_desc.push_back("stop all."); + // + qlist.push_back(Note(20000, 31, 70, 1, 0, 0, 0, 0, 0)); //tour end + qlist_desc.push_back("tour end"); + // + qlist.push_back(Note(20000, 30, 0, 0, 0, 0, 0, 0, 0)); //stop all. + qlist_desc.push_back("stop all."); + // + qlist.push_back(Note(20000, 51, 60, 1, 0, 0, 0, 0, 0)); //guide B: end song + qlist_desc.push_back("guide B: end song"); +} + +//buttons +const int pin_vol_up = 39; +const int pin_vol_down = 36; +const int pin_mute = 35; +const int pin_previous = 15; +const int pin_pause = 33; +const int pin_next = 2; + +//screen task +String screen_cmd = "XXX..composing..XXX"; +String screen_filename = "***.mp3"; + +// +extern Task screen_req_notify_task; +bool req_notify = false; +void screen_req_notify() { + if (screen_req_notify_task.isFirstIteration()) req_notify = true; + else if (screen_req_notify_task.isLastIteration()) req_notify = false; + else req_notify = !req_notify; +} +Task screen_req_notify_task(500, 8, &screen_req_notify, &runner, false); + +// +extern Task screen_task; +void screen() { + + // + if (screen_task.isFirstIteration()) { + init_qlist(); + } + + // button job! + static int btn_vol_up = 0; + static int btn_vol_down = 0; + static int btn_mute = 0; + static int btn_previous = 0; + static int btn_pause = 0; + static int btn_next = 0; + // + int a; + static int qselect = 0; + bool nowsend = false; + // + a = digitalRead(pin_vol_up); + if(btn_vol_up != a) { + btn_vol_up = a; + if(a == 0) { + // 'vol_up' button pressed. + + qselect = qselect + 1; + if (qselect > (qlist.size() - 1)) qselect = 0; + } + } + // + a = digitalRead(pin_vol_down); + if(btn_vol_down != a) { + btn_vol_down = a; + if(a == 0) { + // 'vol_down' button pressed. + + qselect = qselect - 1; + if (qselect < 0) qselect = (qlist.size() - 1); + } + } + // + a = digitalRead(pin_mute); + if(btn_mute != a) { + btn_mute = a; + if(a == 0) { + // 'mute' button pressed. + + nowsend = true; + } + } + // + a = digitalRead(pin_previous); + if(btn_previous != a) { + btn_previous = a; + if(a == 0) { + // 'previous' button pressed. + + qselect = qselect - 1; + if (qselect < 0) qselect = (qlist.size() - 1); + } + } + // + a = digitalRead(pin_pause); + if(btn_pause != a) { + btn_pause = a; + if(a == 0) { + // 'pause' button pressed. + + nowsend = true; + } + } + // + a = digitalRead(pin_next); + if(btn_next != a) { + btn_next = a; + if(a == 0) { + // 'next' button pressed. + + qselect = qselect + 1; + if (qselect > (qlist.size() - 1)) qselect = 0; + } + } + + if (nowsend == true) { + nowsend = false; + // create a NOTE req. and send it out. + // + uint8_t frm_size = sizeof(Note) + 2; + uint8_t frm[frm_size]; + frm[0] = '['; + memcpy(frm + 1, (uint8_t *) &qlist[qselect], sizeof(Note)); + frm[frm_size - 1] = ']'; + // + esp_now_send(NULL, frm, frm_size); // to all peers in the list. + // + MONITORING_SERIAL.print("# posting a req.# ==> "); + MONITORING_SERIAL.println(qlist[qselect].to_string()); + // + + //+ fancy stuff + screen_req_notify_task.restart(); + } + + //clear screen + a + int line_step = 12; + int line = 0; + display.clearDisplay(); + display.setTextColor(SSD1306_WHITE); + display.setTextSize(1); + + //button status (DEBUG) + // int b = digitalRead(pin_vol_up); + // b = b*10 + digitalRead(pin_vol_down); + // b = b*10 + digitalRead(pin_mute); + // b = b*10 + digitalRead(pin_previous); + // b = b*10 + digitalRead(pin_pause); + // b = b*10 + digitalRead(pin_next); + + //line1 - q description. + display.setTextSize(1); + display.setCursor(0, line); + display.println("[" + String(qselect) + "] " + qlist_desc[qselect]); + line += line_step; + + //line2 - q sent notify + display.setCursor(0, line); + if (req_notify) { + display.setCursor(25, line); + display.println("~~ d[+=+]b ~~ >>>"); + } + line += line_step; + + //line3 - note dump + display.setTextSize(1); + display.setCursor(0, line); + display.println(qlist[qselect].to_string()); + line += line_step; + + // + display.display(); + // +} +Task screen_task(SCREEN_PERIOD, TASK_FOREVER, &screen, &runner, true); +//*-*-*-*-*-*-*-*-*-*-*-*-* + +// on 'receive' +void onDataReceive(const uint8_t * mac, const uint8_t *incomingData, int32_t len) { + + // open => identify => use. + if (incomingData[0] == '{' && incomingData[len - 1] == '}' && len == (sizeof(Hello) + 2)) { + Hello hello(""); + memcpy((uint8_t *) &hello, incomingData + 1, sizeof(Hello)); + // + MONITORING_SERIAL.println(hello.to_string()); + // + } + + // open => identify => use. + if (incomingData[0] == '[' && incomingData[len - 1] == ']' && len == (sizeof(Note) + 2)) { + Note note; + memcpy((uint8_t *) ¬e, incomingData + 1, sizeof(Note)); + // + MONITORING_SERIAL.println(note.to_string()); + // + } +} + +// on 'sent' +void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t sendStatus) { + if (sendStatus != 0) MONITORING_SERIAL.println("Delivery failed!"); +} + +void lcd_text(String str) { + display.clearDisplay(); + display.setTextColor(SSD1306_WHITE); + display.setTextSize(1); + display.setCursor(0, 0); + display.println(str.c_str()); + display.display(); +} + +// +void setup() { + + //buttons + pinMode(pin_vol_up, INPUT_PULLUP); + pinMode(pin_vol_down, INPUT_PULLUP); + pinMode(pin_mute, INPUT_PULLUP); + pinMode(pin_previous, INPUT_PULLUP); + pinMode(pin_pause, INPUT_PULLUP); + pinMode(pin_next, INPUT_PULLUP); + + //serial + Serial.begin(115200); + delay(100); + + //screen + Wire.begin(MAKEPYTHON_ESP32_SDA, MAKEPYTHON_ESP32_SCL); + // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally + if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 + Serial.println(F("SSD1306 allocation failed")); + for (;;) + ; // Don't proceed, loop forever + } + display.clearDisplay(); + + //info + Serial.println(); + Serial.println(); + Serial.println("\"hi, i m your postman.\""); + Serial.println("-"); + Serial.println("- my id: " + String(MY_ID) + ", gid: " + String(MY_GROUP_ID) + ", call me ==> \"" + String(MY_SIGN) + "\""); + Serial.println("- mac address: " + WiFi.macAddress() + ", channel: " + String(WIFI_CHANNEL)); +#if defined(DISABLE_AP) + Serial.println("- ======== 'DISABLE_AP' ========"); +#endif +#if defined(GEN_NOTE_REQ) + Serial.println("- ======== 'GEN_NOTE_REQ' ========"); +#endif + Serial.println("-"); + + //wifi + WiFiMode_t node_type = WIFI_AP_STA; +#if defined(DISABLE_AP) + // system_phy_set_max_tpw(0); + WiFi.setTxPower(WIFI_POWER_MINUS_1dBm); // Set WiFi RF power output to lowest level + node_type = WIFI_STA; +#endif + WiFi.mode(node_type); + + //esp-now + if (esp_now_init() != 0) { + Serial.println("Error initializing ESP-NOW"); + return; + } + esp_now_register_send_cb(onDataSent); + esp_now_register_recv_cb(onDataReceive); + + //fetch & read addressbook + String addressbook_title = ADDRESSBOOK_TITLE; +// #if defined(ADDRESSBOOK_TITLE_CLI) +// addressbook_title = ADDRESSBOOK_TITLE_CLI; +// #endif +// +// NOTE: there is a way to give a define value here like: +// export PLATFORMIO_SRC_BUILD_FLAGS="'-DADDRESSBOOK_TITLE_CLI=\"broadcast only\"'" && pio run +// but, everytime i change this, whole arduino framework + libraries rebuild. +// PLATFORMIO_SRC_BUILD_FLAGS supposed to work only to src/ but strange. +// this takes up too much time, not really haptic. later, investigate the issues. +// + AddressBook * book = lib.getBookByTitle(addressbook_title); + if (book == NULL) { + Serial.println("- ! wrong book !! :" + addressbook_title); while(1); + } else { + Serial.println("- ! reading book ...."); + Serial.println(" -----------------"); + Serial.println(" { " + addressbook_title + " }"); + Serial.println(" -----------------"); + Serial.println(); + } + for (int idx = 0; idx < book->list.size(); idx++) { + Serial.println("- ! (esp_now_add_peer) ==> add a '" + book->list[idx].name + "'."); +#if defined(ESP32) + esp_now_peer_info_t peerInfo; + memcpy(peerInfo.peer_addr, book->list[idx].mac, 6); + peerInfo.channel = 0; + peerInfo.encrypt = false; + esp_now_add_peer(&peerInfo); +#else + esp_now_add_peer(book->list[idx].mac, ESP_NOW_ROLE_COMBO, 1, NULL, 0); +#endif + } + // + Serial.println("-"); + Serial.println("\".-.-.-. :)\""); + Serial.println(); +} + +void loop() { + // + runner.execute(); + // +} diff --git a/p/test/README b/p/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/p/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/post.h b/post.h index 32ce904..2505099 100644 --- a/post.h +++ b/post.h @@ -116,6 +116,7 @@ struct AddressLibrary { book.add(Address(0x30, 0x83, 0x98, 0xB2, 0x77, 0xE6, "slopeway 12")); book.add(Address(0xBC, 0xDD, 0xC2, 0x14, 0x63, 0x8E, "slopeway a ")); //+ + book.add(Address(0xE0, 0xE2, 0xE6, 0xCD, 0x0A, 0xCC, "TEST")); book.add(Address(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, "BROADCAST")); //a broadcast //12 // lib.push_back(book); @@ -342,6 +343,30 @@ struct Note { float x4; float ps; // + Note() { + id = 0; + pitch = 0; + velocity = 0; + onoff = 0; + x1 = 0; + x2 = 0; + x3 = 0; + x4 = 0; + ps = 0; + } + Note(int32_t id_, float pitch_, float velocity_, float onoff_, float x1_, float x2_, float x3_, float x4_, float ps_) + { + id = id_; + pitch = pitch_; + velocity = velocity_; + onoff = onoff_; + x1 = x1_; + x2 = x2_; + x3 = x3_; + x4 = x4_; + ps = ps_; + } + // void clear() { id = 0; pitch = 0;