forest-all-around/@bell/src/main.cpp
Dooho Yi 288ddd88d5 updates for simpler communication
+ peer book listing (debug)
+ no addressbook/peer list -> all go broadcast!
+ wifi_channel == 1 for later 
(https://github.com/espressif/arduino-esp32/issues/878#issuecomment-578885352)
2022-04-26 10:40:54 +09:00

362 lines
9 KiB
C++

//
// wirelessly connected cloud (Wireless Mesh Networking)
// MIDI-like
// spacial
// sampler keyboard
//
//
// Forest all/around @ MMCA, Seoul
//
//
// 2020 10 14
//
//==========<configurations>===========
//
// 'DISABLE_AP'
// --> disabling AP is for teensy audio samplers.
// they need this to reduce noise from AP beacon signals.
// but, then they cannot build-up net. by themselves.
// we need who can do AP..
// ==> TODO! just prepare some 'dummy' postmans around. w/ AP activated.
//
// 'DISABLE_I2C_REQ'
// --> a quirk.. due to bi-directional I2C hardship.
// ideally, we want to make this sampler node also speak.
// but, I2C doesn't work. maybe middleware bug.. we later want to change to diff. proto.
// for example, UART or so.
// ==> BEWARE! yet, still we need to take off this.. for 'osc' node.
//
// 'SET_ROOT'
// 'SET_CONTAINSROOT'
// --> for the network stability
// declare 1 root node and branches(constricted to 'contains the root')
// to improve the stability of the net
//
//==========</configurations>==========
//==========<preset>===========
#define SET_CONTAINSROOT
//==========</preset>==========
//============<gastank>============
#define BELL_HIT_KEY 105
//============</gastank>===========
//============<parameters>============
//
#define LED_PERIOD (11111)
#define LED_ONTIME (1)
#define LED_GAPTIME (222)
//
#define WIFI_CHANNEL 1
//
// '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
//
//============</parameters>===========
//arduino
#include <Arduino.h>
//post & addresses
#include "../../post.h"
//espnow
#include <ESP8266WiFi.h>
#include <espnow.h>
//task
#include <TaskScheduler.h>
Scheduler runner;
//-*-*-*-*-*-*-*-*-*-*-*-*-
// servo
#include <Servo.h>
#define SERVO_PIN D6
Servo myservo;
// #define HITTING_ANGLE 87
#define HITTING_ANGLE 90
#define RELEASE_ANGLE 60
#define STABILIZE_ANGLE 53
//
extern Task hit_task;
//
extern Task pcontrol_task;
bool pcontrol_new = false;
int pcontrol_start = 0;
int pcontrol_target = 0;
int control_count = 0;
//
extern Task servo_release_task;
// my tasks
// hit!
void hit() {
static int count = 0;
if (hit_task.isFirstIteration()) {
count = 0;
Serial.println("hit! start.");
}
if (count % 3 == 0) {
//
myservo.attach(SERVO_PIN);
myservo.write(RELEASE_ANGLE);
// servo_release_task.restartDelayed(200);
//
} else if (count % 3 == 1) {
//
myservo.attach(SERVO_PIN);
myservo.write(HITTING_ANGLE);
// servo_release_task.restartDelayed(200);
//
Serial.print("bell, bell, bell! : ");
Serial.print(HITTING_ANGLE);
Serial.println(" deg.");
//
} else {
//
myservo.attach(SERVO_PIN);
myservo.write(RELEASE_ANGLE);
servo_release_task.restartDelayed(200);
//
Serial.print("release to .. : ");
Serial.print(RELEASE_ANGLE);
Serial.println(" deg.");
// start stablizing..
pcontrol_new = true;
pcontrol_start = RELEASE_ANGLE;
pcontrol_target = STABILIZE_ANGLE;
pcontrol_task.restartDelayed(80);
//
control_count = 0;
}
//
count++;
}
Task hit_task(100, 3, &hit);
// pcontrol
void pcontrol() {
static int angle;
if (pcontrol_new == true) {
pcontrol_new = false;
angle = pcontrol_start;
}
int error = pcontrol_target - angle;
int sign = (error >= 0 ? 1 : -1);
//
Serial.print("step-by-step to.. : ");
Serial.println(sign);
//
if (error != 0) {
angle = angle + sign; // most gentle move : 1 step each time.
//
Serial.print("stablizing in action ==> next angle : ");
Serial.print(angle);
Serial.println(" deg.");
//
myservo.attach(SERVO_PIN);
myservo.write(angle);
servo_release_task.restartDelayed(50);
pcontrol_task.restartDelayed(400);
}
else {
// stand-by processes
if (control_count % 2 == 0) {
pcontrol_new = true;
pcontrol_start = STABILIZE_ANGLE;
pcontrol_target = RELEASE_ANGLE;
pcontrol_task.restartDelayed(300);
} else if (control_count % 2 == 1) {
pcontrol_new = true;
pcontrol_start = RELEASE_ANGLE;
pcontrol_target = STABILIZE_ANGLE;
pcontrol_task.restartDelayed(300);
}
//
control_count++;
}
}
Task pcontrol_task(0, TASK_ONCE, &pcontrol); // hit -> 100ms -> step back -> 50ms -> slowly move to rest pos.
// pcontrol release
void servo_release() {
myservo.detach();
}
Task servo_release_task(0, TASK_ONCE, &servo_release);
// mesh callbacks
void receivedCallback(uint32_t from, String & msg) { // REQUIRED
Serial.print("got msg.: ");
Serial.println(msg);
//parse now.
//parse letter string.
// letter frame ( '[' + 30 bytes + ']' )
// : [123456789012345678901234567890]
// 'MIDI' letter frame
// : [123456789012345678901234567890]
// : [KKKVVVG.......................]
// : KKK - Key
// .substring(1, 4);
// : VVV - Velocity (volume/amp.)
// .substring(4, 7);
// : G - Gate (note on/off)
// .substring(7, 8);
String str_key = msg.substring(1, 4);
String str_velocity = msg.substring(4, 7);
String str_gate = msg.substring(7, 8);
int key = str_key.toInt();
int velocity = str_velocity.toInt(); // 0 ~ 127
int gate = str_gate.toInt();
//is it for me, the bell?
if (key == BELL_HIT_KEY && gate == 1) {
hit_task.restartDelayed(10);
}
}
void changedConnectionCallback() {
Serial.println(mesh.getNodeList().size());
// check status -> modify status LED
if (mesh.getNodeList().size() > 0) {
// (still) connected.
onFlag = false; //reset flag stat.
statusblinks.set(LED_PERIOD, 2, &taskStatusBlink_slowblink_insync);
// statusblinks.set(0, 1, &taskStatusBlink_steadyOff);
statusblinks.enable();
Serial.println("connected!");
//
isConnected = true;
runner.addTask(nothappyalone_task);
nothappyalone_task.enable();
}
else {
// disconnected!!
statusblinks.set(0, 1, &taskStatusBlink_steadyOn);
statusblinks.enable();
//
isConnected = false;
}
// let I2C device know
/////
Serial.println("hi. client, we ve got a change in the net.");
}
void newConnectionCallback(uint32_t nodeId) {
Serial.println(mesh.getNodeList().size());
Serial.println("newConnectionCallback.");
changedConnectionCallback();
}
void setup() {
//led
pinMode(LED_PIN, OUTPUT);
//mesh
WiFiMode_t node_type = WIFI_AP_STA;
#if defined(DISABLE_AP)
system_phy_set_max_tpw(0);
node_type = WIFI_STA;
#endif
// mesh.setDebugMsgTypes(ERROR | DEBUG | CONNECTION);
mesh.setDebugMsgTypes( ERROR | STARTUP );
mesh.init(MESH_SSID, MESH_PASSWORD, &runner, MESH_PORT, node_type, MESH_CHANNEL);
//
// void init(String ssid, String password, Scheduler *baseScheduler, uint16_t port = 5555, WiFiMode_t connectMode = WIFI_AP_STA, uint8_t channel = 1, uint8_t hidden = 0, uint8_t maxconn = MAX_CONN);
// void init(String ssid, String password, uint16_t port = 5555, WiFiMode_t connectMode = WIFI_AP_STA, uint8_t channel = 1, uint8_t hidden = 0, uint8_t maxconn = MAX_CONN);
//
#if defined(SET_ROOT)
mesh.setRoot(true);
#endif
#if defined(SET_CONTAINSROOT)
mesh.setContainsRoot(true);
#endif
//callbacks
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
Serial.println(mesh.getNodeList().size());
//tasks
runner.addTask(statusblinks);
statusblinks.enable();
//serial
Serial.begin(115200);
delay(100);
Serial.println("hi, postman ready.");
#if defined(DISABLE_AP)
Serial.println("!NOTE!: we are in the WIFI_STA mode!");
#endif
//understanding what is 'the nodeId' ==> last 4 bytes of 'softAPmacAddress'
// uint32_t nodeId = tcp::encodeNodeId(MAC);
Serial.print("nodeId (dec) : ");
Serial.println(mesh.getNodeId(), DEC);
Serial.print("nodeId (hex) : ");
Serial.println(mesh.getNodeId(), HEX);
uint8_t MAC[] = {0, 0, 0, 0, 0, 0};
if (WiFi.softAPmacAddress(MAC) == 0) {
Serial.println("init(): WiFi.softAPmacAddress(MAC) failed.");
}
Serial.print("MAC : ");
Serial.print(MAC[0], HEX); Serial.print(", ");
Serial.print(MAC[1], HEX); Serial.print(", ");
Serial.print(MAC[2], HEX); Serial.print(", ");
Serial.print(MAC[3], HEX); Serial.print(", ");
Serial.print(MAC[4], HEX); Serial.print(", ");
Serial.println(MAC[5], HEX);
// for instance,
// a huzzah board
// nodeId (dec) : 3256120530
// nodeId (hex) : C21474D2
// MAC : BE, DD, C2, 14, 74, D2
// a esp8266 board (node mcu)
// nodeId (dec) : 758581767
// nodeId (hex) : 2D370A07
// MAC : B6, E6, 2D, 37, A, 7
//i2c master
Wire.begin();
//tasks
runner.addTask(hit_task);
runner.addTask(pcontrol_task);
runner.addTask(servo_release_task);
}
void loop() {
runner.execute();
mesh.update();
#if defined(ESP32)
digitalWrite(LED_PIN, onFlag); // value == true is ON.
#else
digitalWrite(LED_PIN, !onFlag); // value == false is ON. so onFlag == true is ON. (pull-up)
#endif
}