MAJOR update. More like a Backup before things get Crazy
Added Websocket Support Added Universal Message Handling for both MQTT and WS Added Timekeeper Class, that handles Physical Clock and Scheduling Added Bell Assignment Settings, Note to Bell mapping
This commit is contained in:
@@ -1,21 +1,27 @@
|
||||
// MELODY PLAYBACK WILL BE HANDLED HERE
|
||||
#include <vector>
|
||||
|
||||
extern Player player;
|
||||
|
||||
// Define a structure to track active solenoids
|
||||
struct ActiveRelay {
|
||||
uint8_t relayIndex; // Index of the relay
|
||||
uint8_t relayIndex; // Physical relay index (0-15)
|
||||
uint8_t bellIndex; // Bell index for duration lookup
|
||||
uint64_t activationTime; // Activation start time
|
||||
uint16_t duration; // Duration for which it should remain active
|
||||
};
|
||||
|
||||
// Array of durations for each relay (configure remotely)
|
||||
uint16_t relayDurations[16] = {90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90};
|
||||
// Duration per BELL (not per relay output)
|
||||
uint16_t bellDurations[16] = {90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90};
|
||||
|
||||
// Level 1: Bell to Physical Output mapping (bell index -> relay index)
|
||||
// bellOutputs[0] = which relay controls Bell #0, etc.
|
||||
uint16_t bellOutputs[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // 0-based indexing
|
||||
|
||||
// Vector to track active solenoids
|
||||
std::vector<ActiveRelay> activeRelays;
|
||||
|
||||
|
||||
// Locks for Writing the Counters
|
||||
portMUX_TYPE mySpinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
void loop_playback(std::vector<uint16_t> &melody_steps);
|
||||
void bellEngine(void *parameter);
|
||||
@@ -23,6 +29,7 @@ void relayControlTask(void *param);
|
||||
void itsHammerTime(uint16_t note);
|
||||
void turnOffRelays(uint64_t now);
|
||||
|
||||
// Main Bell Engine. Activates Relays on the exact timing required.
|
||||
void bellEngine(void *parameter) {
|
||||
// SETUP TASK
|
||||
for (;;) {
|
||||
@@ -36,7 +43,7 @@ void bellEngine(void *parameter) {
|
||||
}
|
||||
}
|
||||
|
||||
// Task to deactivate relays dynamically
|
||||
// Task to deactivate relays dynamically after set timers
|
||||
void relayControlTask(void *param) {
|
||||
while (true) {
|
||||
uint64_t now = millis();
|
||||
@@ -49,14 +56,15 @@ void relayControlTask(void *param) {
|
||||
++it; // Move to the next relay
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10)); // Check every 10ms
|
||||
}
|
||||
}
|
||||
|
||||
// Function to wait for tempo, then loop to the next beat.
|
||||
void loop_playback(std::vector<uint16_t> &melody_steps) {
|
||||
|
||||
while(player.isPlaying && !player.isPaused){
|
||||
while(player.isPlaying && !player.isPaused){
|
||||
LOG_DEBUG("(BellEngine) Single Loop Starting.");
|
||||
|
||||
// iterate through the beats and call the bell mechanism on each beat
|
||||
for (uint16_t note : melody_steps) {
|
||||
@@ -66,21 +74,92 @@ void loop_playback(std::vector<uint16_t> &melody_steps) {
|
||||
vTaskDelay(pdMS_TO_TICKS(tempo));
|
||||
}
|
||||
|
||||
LOG_DEBUG("Single Loop Over.");
|
||||
//if (!player.isPlaying) break; // Stop playback only after completing the loop
|
||||
player.segmentCmpltTime = millis();
|
||||
LOG_DEBUG("(BellEngine) Single Full Loop Complete");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Function to activate relays for a specific note
|
||||
void itsHammerTime(uint16_t note) {
|
||||
uint64_t now = millis();
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
if (note & (1 << i)) { // Check if this relay needs to activate
|
||||
relays.digitalWrite(i, LOW); // Activate the relay
|
||||
// First, determine which bells should ring based on the note pattern
|
||||
for (uint8_t noteIndex = 0; noteIndex < 16; noteIndex++) {
|
||||
if (note & (1 << noteIndex)) { // This note should be played
|
||||
|
||||
// Add to the activeRelays list
|
||||
activeRelays.push_back({i, now, relayDurations[i]});
|
||||
// Level 2: Map note to bell using noteAssignments
|
||||
uint8_t bellIndex = player.noteAssignments[noteIndex];
|
||||
|
||||
// Skip if no bell assigned to this note (0 means no assignment)
|
||||
if (bellIndex == 0) continue;
|
||||
|
||||
// Convert to 0-based indexing (noteAssignments uses 1-based)
|
||||
bellIndex = bellIndex - 1;
|
||||
|
||||
// Level 1: Map bell to physical relay output
|
||||
uint8_t relayIndex = bellOutputs[bellIndex];
|
||||
|
||||
// Activate the relay
|
||||
relays.digitalWrite(relayIndex, LOW);
|
||||
|
||||
// Add to the activeRelays list with bell-specific duration
|
||||
activeRelays.push_back({
|
||||
relayIndex,
|
||||
bellIndex,
|
||||
now,
|
||||
bellDurations[bellIndex]
|
||||
});
|
||||
|
||||
// Write ring to counter (count per bell, not per relay)
|
||||
portENTER_CRITICAL(&mySpinlock);
|
||||
strikeCounters[bellIndex]++; // Count strikes per bell
|
||||
bellLoad[bellIndex]++; // Load per bell
|
||||
coolingActive = true;
|
||||
portEXIT_CRITICAL(&mySpinlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Helper function to update bell-to-output mapping via JSON
|
||||
void updateBellOutputs(JsonVariant doc) {
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
String key = String("b") + (i + 1);
|
||||
if (doc.containsKey(key)) {
|
||||
bellOutputs[i] = doc[key].as<uint16_t>()-1; // -1 to convert to 0 based indexing
|
||||
LOG_DEBUG("Bell %d Output set to Relay #%d", i + 1, bellOutputs[i]+1);
|
||||
} else {
|
||||
LOG_DEBUG("Bell %d not found in JSON payload. Keeping previous Output: Relay #%d", i + 1, bellOutputs[i]+1);
|
||||
}
|
||||
}
|
||||
LOG_INFO("Updated Relay Outputs.")
|
||||
StaticJsonDocument<128> response;
|
||||
response["status"] = "OK";
|
||||
response["type"] = "set_relay_outputs";
|
||||
char jsonOut[128]; // Create Char Buffer
|
||||
serializeJson(response, jsonOut); // Serialize to Buffer
|
||||
replyOnWebSocket(activeClient, jsonOut); // Reply on WebSocket
|
||||
}
|
||||
|
||||
// Sets Incoming Relay Durations to RAM and then call funtion to save them to file.
|
||||
void updateRelayTimings(JsonVariant doc) {
|
||||
// Iterate through the relays in the JSON payload
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
String key = String("b") + (i + 1); // Generate "b1", "b2", ...
|
||||
if (doc.containsKey(key)) {
|
||||
bellDurations[i] = doc[key].as<uint16_t>();
|
||||
LOG_DEBUG("Relay %d duration set to %d ms", i + 1, bellDurations[i]);
|
||||
} else {
|
||||
LOG_DEBUG("Relay %d not found in JSON payload. Keeping previous duration: %d ms", i + 1, bellDurations[i]);
|
||||
}
|
||||
}
|
||||
saveRelayTimings();
|
||||
LOG_INFO("Updated Relay Timings.")
|
||||
StaticJsonDocument<128> response;
|
||||
response["status"] = "OK";
|
||||
response["type"] = "set_relay_timings";
|
||||
char jsonOut[128]; // Create Char Buffer
|
||||
serializeJson(response, jsonOut); // Serialize to Buffer
|
||||
replyOnWebSocket(activeClient, jsonOut); // Reply on WebSocket
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user