feat: shuffle mode

This commit is contained in:
2025-11-15 16:53:23 +01:00
parent 331258692b
commit 7aec14cbb9
14 changed files with 167 additions and 2358 deletions
+4 -2
View File
@@ -6,7 +6,7 @@
namespace spit {
static const char *TAG = "SPIT";
static fos::Queue<vector<char>> incommingSpit(64);
static fos::Queue<vector<char>> incommingSpit(128);
/**
@@ -1194,8 +1194,10 @@ void SClient::parseReportPlayStatus(Message::ReportPlayStatus &message) {
*/
void SClient::sendRemoteObject(string p_SPITObjectID, int valuePpm, char valueFlag) {
SObject *ptrRemoteSPITObject = mRemoteSpitObjects.getEntry(p_SPITObjectID);
if (ptrRemoteSPITObject == nullptr)
if (ptrRemoteSPITObject == nullptr) {
ESP_LOGD(TAG, "Unknown ID %s", p_SPITObjectID.c_str());
return;
}
Message::PlayStart playSPITStart(mID, mProjName, PLAYERTYPE_DISCRETE);
playSPITStart.setPlayerIsRunning(false);
+33 -34
View File
@@ -1,3 +1,5 @@
-- COPY to: /usr/lib/x86_64-linux-gnu/wireshark/plugins/spit.lua
-- LiveShowSoftware SPIT-Protocol
spit_proto = Proto("spit", "LiveShowSoftware SPIT")
spit_sad_proto = Proto("spit_sad", "LiveShowSoftware SPIT SAD")
@@ -9,7 +11,7 @@ local f_hLen = ProtoField.uint32("spit.len", "Length")
local f_hSerId = ProtoField.string("spit.serverId", "ServerID")
local f_hCliId = ProtoField.string("spit.clientId", "ClientID")
local f_hType = ProtoField.uint8("spit.msgType", "MsgType")
local f_pLen = ProtoField.uint32("spit.paylen", "Length")
local f_pLen = ProtoField.uint32("spit.paylen", "Payload Length")
local f_pSession = ProtoField.string("spit.key", "Spit Session")
local f_pKey = ProtoField.string("spit.key", "Spit Key")
@@ -94,6 +96,17 @@ function extractVersionString(buffer)
end
function addBigEndianValue(tree, proto, buffer)
local val = -1;
-- local val = buffer(99,4):le_uint()
if proto.type == ftypes.UINT32 then
val = buffer:le_uint()
elseif proto.type == ftypes.UINT64 then
val = buffer:le_uint64()
end
tree:add(proto, buffer):set_text(proto.name .. ": " .. val)
end
-- Heuristic dissector function
function spit_proto.dissector(buffer, pinfo, tree)
if buffer:len() < 6 then return false end
@@ -114,8 +127,9 @@ function spit_proto.dissector(buffer, pinfo, tree)
hTree:add(f_hType, buffer(98,1))
local pTree = subtree:add("Payload")
local pLen = buffer(99,4):le_uint()
pTree:add(f_pLen, buffer(99,4)):set_text("Pyload Length: " .. pLen)
-- local pLen = buffer(99,4):le_uint()
-- pTree:add(f_pLen, buffer(99,4)):set_text("Pyload Length: " .. pLen)
addBigEndianValue(pTree, f_pLen, buffer(99,4))
local info_text = "Type: " .. type
if type == 1 then -- Connect
@@ -166,7 +180,7 @@ function spit_proto.dissector(buffer, pinfo, tree)
pTree:add(f_pProjectId, buffer(103,41))
pTree:add(f_pProjectName, buffer(144,64))
pTree:add(f_pFramesPerSec, buffer(208,4))
addBigEndianValue(pTree, f_pFramesPerSec, buffer(208,4))
info_text = string.format("%s -> %s | Report Project | Project: %s / %s",
sessionInfos[tostring(pinfo.src)], sessionInfos[tostring(pinfo.dst)], buffer(103,41):string(), buffer(144,64):string())
@@ -202,8 +216,8 @@ function spit_proto.dissector(buffer, pinfo, tree)
pTree:add(f_pProjIndep, buffer(147,1))
pTree:add(f_pTypeGroupName, buffer(148,39))
pTree:add(f_pTypeName, buffer(187,64))
pTree:add(f_pDelay, buffer(251,8))
pTree:add(f_pDuration, buffer(259,8))
addBigEndianValue(pTree, f_pDelay, buffer(251,8))
addBigEndianValue(pTree, f_pDuration, buffer(259,8))
local group = buffer(148,39):string()
local name = buffer(187,64):string()
@@ -226,17 +240,16 @@ function spit_proto.dissector(buffer, pinfo, tree)
pTree:add(f_pObjectName, buffer(147,64))
pTree:add(f_pTypeId, buffer(211,41))
pTree:add(f_pSrvParam, buffer(252,64))
pTree:add(f_pFrameStart, buffer(316,8))
pTree:add(f_pFrameLength, buffer(324,8))
pTree:add(f_pFrameFadeIn, buffer(332,8))
pTree:add(f_pFrameFadeOut, buffer(340,8))
local valueFactor = buffer(348,4):le_uint()
pTree:add(f_pValueFactor, buffer(348,4)):set_text("Value Factor" .. valueFactor)
addBigEndianValue(pTree, f_pFrameStart, buffer(316,8))
addBigEndianValue(pTree, f_pFrameLength, buffer(324,8))
addBigEndianValue(pTree, f_pFrameFadeIn, buffer(332,8))
addBigEndianValue(pTree, f_pFrameFadeOut, buffer(340,8))
addBigEndianValue(pTree, f_pValueFactor, buffer(348,4))
pTree:add(f_pValueUse, buffer(349,1))
pTree:add(f_pTrack, buffer(350,4))
addBigEndianValue(pTree, f_pTrack, buffer(350,4))
pTree:add(f_pRemark, buffer(354,64))
pTree:add(f_pDelay, buffer(418,8))
pTree:add(f_pDuration, buffer(426,8))
addBigEndianValue(pTree, f_pDelay, buffer(418,8))
addBigEndianValue(pTree, f_pDuration, buffer(426,8))
pTree:add(f_pAssigned, buffer(435,1))
local name = buffer(147,64):string()
@@ -257,17 +270,16 @@ function spit_proto.dissector(buffer, pinfo, tree)
pTree:add(f_pPlayerName, buffer(144,64))
pTree:add(f_pPlayerType, buffer(208,1))
pTree:add(f_pPlayerRunning, buffer(209,1))
pTree:add(f_pPlayerFrames, buffer(210,8))
addBigEndianValue(pTree, f_pPlayerFrames, buffer(210,8))
info_text = string.format("Play SPIT Start")
elseif type == 38 then -- Play Spit object
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pPlayerId, buffer(103,41))
pTree:add(f_pObjectId, buffer(144,41))
pTree:add(f_pObjectsFrames, buffer(185,8))
addBigEndianValue(pTree, f_pObjectsFrames, buffer(185,8))
pTree:add(f_pPlayerPrePos, buffer(193,1))
pTree:add(f_pValue, buffer(194,4))
addBigEndianValue(pTree, f_pValue, buffer(194,4))
pTree:add(f_pValueFlag, buffer(198,1))
local oId = buffer(144,41):string()
@@ -281,10 +293,9 @@ function spit_proto.dissector(buffer, pinfo, tree)
elseif type == 40 then
pTree:add(f_pSession, extractSession(buffer, pinfo))
pTree:add(f_pObjectId, buffer(103,41))
pTree:add(f_pObjectsFrames, buffer(144,8))
pTree:add(f_pValue, buffer(152,4))
addBigEndianValue(pTree, f_pObjectsFrames, buffer(144,8))
addBigEndianValue(pTree, f_pValue, buffer(152,4))
info_text = string.format("Report Play Status")
else
@@ -348,15 +359,3 @@ spit_proto:register_heuristic("udp", spit_proto.dissector)
spit_sad_proto:register_heuristic("udp", spit_sad_proto.dissector)
-- local f_pFramesPerSec = ProtoField.uint32("spit.framesPerSec", "Frames per second")
-- local f_pTrack = ProtoField.uint32("spit.track", "Track")
-- local f_pObjectsFrames = ProtoField.uint64("spit.ObjectFrames", "Object Frames")
-- local f_pValue = ProtoField.uint64("spit.Value", "Value")
-- local f_pFrameStart = ProtoField.uint64("spit.frameStart", "Frame Start")
-- local f_pFrameLength = ProtoField.uint64("spit.frameLength", "Frame Length")
-- local f_pFrameFadeIn = ProtoField.uint64("spit.fadeInLength", "Fade In Length")
-- local f_pFrameFadeOut = ProtoField.uint64("spit.fadeOutLength", "Fade Out Length")
-- local f_pDelay = ProtoField.uint64("spit.delay", "Delay")
-- local f_pDuration = ProtoField.uint64("spit.duration", "Duration")
-- local f_pPlayerFrames = ProtoField.uint64("spit.PlayerFrame", "Player Frames")
+10 -4
View File
@@ -3,13 +3,14 @@
#include "stepperDrv.hpp"
#include "stepperMotor.hpp"
#include <cmath>
#include "syslog.hpp"
class WatchMotor {
static constexpr uint8_t Positions = 6;
public:
using AllmostFinishedCb = void (*)(uint8_t newIdx);
WatchMotor(IStepperMotor &stepper, AllmostFinishedCb onDone)
using AlmostFinishedCb = void (*)(uint8_t newIdx);
WatchMotor(IStepperMotor &stepper, AlmostFinishedCb onDone)
: _stepper(stepper),
_onFinCb(onDone) {
}
@@ -44,7 +45,12 @@ class WatchMotor {
ESP_LOGD("MV", "Moving to %d by %.2f + %.2f", sign, delta, corr);
_stepper.moveBy(delta + corr, profile, accel, speed, [&]() {
_stepper.moveBy(delta + corr, profile, accel, speed, [&](int diff) {
Syslog::logv(Syslog::Severity::Debug,"Almost done with head=%i",diff);
if (diff < 6) {
Syslog::logv(Syslog::Severity::Warning,"Low headroom in Profile pipeline=%i",diff);
}
if (_onFinCb) {
_onFinCb(position);
}
@@ -58,5 +64,5 @@ class WatchMotor {
private:
IStepperMotor &_stepper;
uint8_t _currentIndex{};
AllmostFinishedCb _onFinCb{};
AlmostFinishedCb _onFinCb{};
};
@@ -19,7 +19,7 @@ class StepperMotorMock : public IStepperMotor {
lastAngle = angle;
lastProfile = profile;
}
void moveBy(float angle, uint8_t profile, float accel, float speed, std::function<void()> profileDone = nullptr) override {
void moveBy(float angle, uint8_t profile, float accel, float speed, std::function<void(int diff)> profileDone = nullptr) override {
lastAngle = angle;
lastProfile = profile;
}
+1 -1
Submodule core updated: e09e7dc576...acdd1ee930
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,6 +7,7 @@ struct {
const char *mqttBroker = "mqttBroker"; // example: "172.16.16.10"
const char *mqttPrefix = "mqttPrefix"; // example: "SomeTag"
const char *spitServer = "spitServer"; // example: "172.16.16.10"
const char *motorPower = "motorPower"; // example: "50"
} ConfigKeys;
// MQTT Topics
+114 -39
View File
@@ -17,7 +17,7 @@
// activeState.speed = (min .5 / max 3)
#include "watchMain.hpp"
#include "interconConfig.hpp"
#include "config.hpp"
using namespace spit;
@@ -104,7 +104,7 @@ void testPictoIllum(Cli::CArgs args) {
int p = std::stoi(args[0]);
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(p));
} catch (const std::exception &e) {
ESP_LOGI(TAG, "Failed to parse %s and %s", args[0].c_str(), args[1].c_str());
ESP_LOGI(TAG, "Failed to parse %s", args[0].c_str());
}
}
@@ -121,10 +121,10 @@ void testMovement(Cli::CArgs args) {
activeState.profile = std::min(4, std::stoi(args[1]));
}
if (args.size() >= 3) {
activeState.minJumps = std::min(20, std::stoi(args[2])) ;
activeState.minJumps = std::min(20, std::stoi(args[2]));
}
if (args.size() >= 4) {
activeState.minJumps = std::min(40, std::stoi(args[3])) ;
activeState.minJumps = std::min(40, std::stoi(args[3]));
}
commandQueue.enqueue(std::make_unique<MoveCommand>(MoveType::StepTo, p));
} catch (const std::exception &e) {
@@ -132,6 +132,25 @@ void testMovement(Cli::CArgs args) {
}
}
void testFeedback(Cli::CArgs args) {
ESP_LOGI(TAG, "on triggerMovement:");
if (args.size() != 1) {
pShell->writeLine("need target position (1..6) or 0 for moving");
return;
}
try {
int p = std::stoi(args[0]);
if (p == 0) {
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StartMoving, 0));
} else {
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, p));
}
} catch (const std::exception &e) {
ESP_LOGI(TAG, "Failed to parse %s", args[0].c_str());
}
}
void setConfig(Cli::CArgs args) {
if (args.size() != 2) {
pShell->writeLine("Needs string key and value");
@@ -179,7 +198,7 @@ void showProcessValues(Cli::CArgs args) {
pShell->writeLine("Process values:");
char buff[256];
sprintf(buff, "%02x,%02x,%02x", activeState.color.getRed(),activeState.color.getGreen(),activeState.color.getBlue());
sprintf(buff, "%02x,%02x,%02x", activeState.color.getRed(), activeState.color.getGreen(), activeState.color.getBlue());
pShell->writeLine(std::string{" Color RGB: "} + buff);
sprintf(buff, "%.2f / %.2f", activeState.accel, activeState.speed);
pShell->writeLine(std::string{" Accel/Speed: "} + buff);
@@ -187,9 +206,22 @@ void showProcessValues(Cli::CArgs args) {
pShell->writeLine(std::string{" Provile: "} + std::to_string((int)activeState.profile));
}
void startDemoMovement(Cli::CArgs args) {
ESP_LOGI(TAG, "on startDemoMovement:");
commandQueue.enqueue(std::make_unique<MoveCommand>(MoveType::Demo));
void setSyslogLevel(Cli::CArgs args) {
if (args.size() != 1) {
pShell->writeLine("Needs SyslogLevel Warning = 4, Notice = 5, Informational = 6, Debug = 7");
return;
}
try {
auto lvl = std::stoi(args[0]);
if (lvl >= (int)Syslog::Severity::Warning && lvl <= (int)Syslog::Severity::Debug) {
Syslog::setSeverity((Syslog::Severity)lvl);
} else {
pShell->writeLine("New level was not accepted");
}
} catch (const std::exception &e) {
ESP_LOGI(TAG, "Failed to parse %s", args[0].c_str());
}
}
/**
@@ -209,8 +241,11 @@ static void telnetSocketTask(int addrFamily) {
{"update", "Start OTA-Update-Process",
[](Cli::CArgs a) { startUpdate(a); }});
pShell->addBinding(
{"logserver_set", "Set log server config ip",
{"setLogserver", "Set log server config ip",
[](Cli::CArgs a) { setLogServerConfig(a); }});
pShell->addBinding(
{"setLogLevel", "Set severity log server",
[](Cli::CArgs a) { setSyslogLevel(a); }});
pShell->addBinding(
{"getcfg", "Get configuration value for key",
@@ -220,7 +255,7 @@ static void telnetSocketTask(int addrFamily) {
[](Cli::CArgs a) { setConfig(a); }});
pShell->addBinding(
{"dyn_set", "set dynamics of movement (velocity,accelerations) as floats",
{"setDyn", "set dynamics of movement (velocity,accelerations) as floats",
[](Cli::CArgs a) { setDynamics(a); }});
pShell->addBinding(
{"tstMove", "start movement (profile-idx,steps) as integers ",
@@ -228,9 +263,12 @@ static void telnetSocketTask(int addrFamily) {
pShell->addBinding(
{"tstIllum", "test illumination command 0=off /1..6",
[](Cli::CArgs a) { testPictoIllum(a); }});
pShell->addBinding(
{"tstFb", "test feedback-channel to control 0=Move /1..6=FinalPos",
[](Cli::CArgs a) { testFeedback(a); }});
pShell->addBinding(
{"showData", "Show process values that are input by DMX, MQTT and SPIT",
[](Cli::CArgs a) { showProcessValues(a); }});
[](Cli::CArgs a) { showProcessValues(a); }});
},
[](TcpSession &session) {
pShell->process();
@@ -404,28 +442,28 @@ static void initialize_ethernet(void) {
}
namespace Effect {
extern const WaveForm_t OffsetPulseWave{gau8_offsetPulse, cu16_TemplateLength};
extern const WaveForm_t InitSlopeWave{gau8_initSlope, cu16_TemplateLength};
extern const WaveForm_t OffsetSlopeWave{gau8_offsetSlope, cu16_TemplateLength};
extern const WaveForm_t FullSlopeWave{gau8_fullSlope, cu16_TemplateLength};
extern const WaveForm_t FullPulseWave{gau8_fullPulse, cu16_TemplateLength};
extern const WaveForm_t OffsetPulseWave{gau8_offsetPulse, cu16_TemplateLength};
extern const WaveForm_t InitSlopeWave{gau8_initSlope, cu16_TemplateLength};
extern const WaveForm_t OffsetSlopeWave{gau8_offsetSlope, cu16_TemplateLength};
extern const WaveForm_t FullSlopeWave{gau8_fullSlope, cu16_TemplateLength};
extern const WaveForm_t FullPulseWave{gau8_fullPulse, cu16_TemplateLength};
const Macro macDemoStart = {
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
{32, 1, StateMachine::UpdateIdle, 0xFF},
};
const Macro macDemoStart = {
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
{32, 1, StateMachine::UpdateIdle, 0xFF},
};
const Macro macDemoPulse = {
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
{32, 2, StateMachine::UpdateIdle, 0xFF},
{64, 1, &OffsetPulseWave, StateMachine::UpdateWave, 0xFF},
};
const Macro macDemoPulse = {
{64, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
{32, 2, StateMachine::UpdateIdle, 0xFF},
{64, 1, &OffsetPulseWave, StateMachine::UpdateWave, 0xFF},
};
const Macro macDemoFlicker = {
{16, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
{32, 1, StateMachine::UpdateFlicker, 0xFF},
};
}
const Macro macDemoFlicker = {
{16, 1, &InitSlopeWave, StateMachine::UpdateWave, 0xFF},
{32, 1, StateMachine::UpdateFlicker, 0xFF},
};
} // namespace Effect
void LightingTask() {
ESP_LOGI(TAG, "Start Lighting");
@@ -520,7 +558,20 @@ void MovementTask() {
{LEDC_CHANNEL_0, LEDC_CHANNEL_1, LEDC_CHANNEL_2, LEDC_CHANNEL_3},
{GPIO_NUM_21, GPIO_NUM_20, GPIO_NUM_23, GPIO_NUM_22},
};
StepperDriverDrv8833 stepperDriver(stepperPins, MicroSteps, 0.25F);
float power = 0.25F;
// try
// {
// auto pwr = store.getValue(ConfigKeys.motorPower);
// power = std::stof(pwr);
// }
// catch(...)
// {
// std::cerr << e.what() << '\n';
// ESP_LOGI("Stepper", "Applying default");
// }
StepperDriverDrv8833 stepperDriver(stepperPins, MicroSteps, power);
stepperDriver.setPos(0);
StepperConfig stepperCfg{1.8F, MicroSteps};
@@ -583,6 +634,33 @@ void MovementTask() {
// pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(newPos));
// responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, newPos));
}
} else if (cmd->type == MoveType::Shuffle) {
Syslog::logv(Syslog::Severity::Informational,
"Starting Shuffle mode");
while (true) {
int pos = Random::randomWithIn(1,6);
int profile = Random::randomWithIn(0,3);
if (stepper.isIdle()) {
Syslog::logv(Syslog::Severity::Notice,
"Running Stepper to %i by min%i steps with prof=%i a=%.2f w=%.2f",
pos, activeState.minJumps, activeState.profile, activeState.accel, activeState.speed);
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(0));
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StartMoving, 0));
auto &as = activeState;
watch.moveTo(pos, profile, as.minJumps, as.accel, as.speed);
}
// int delay = Random::randomWithIn(20000,100000)/portTICK_PERIOD_MS;
int delay = Random::randomWithIn(2000,3000)/portTICK_PERIOD_MS;
Syslog::logv(Syslog::Severity::Informational,
"ShuffleMode Wait for %i", delay);
auto cmd = commandQueue.dequeue(delay);
if (cmd) {
if (cmd->type != MoveType::Shuffle) {
commandQueue.enqueue(std::move(cmd));
break;
}
}
}
} else if (cmd->type == MoveType::Demo) {
ESP_LOGI(TAG, "Running Demo");
for (size_t i = ProfileGenerator::Smooth; i < ProfileGenerator::NumProfiles; i++) {
@@ -666,7 +744,7 @@ void onProjectUpdate(SClient::ProjUpdate state, string projectId) {
}
bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
return true; // Bypass veto
return true; // Bypass veto
if (!knownType || !createdByClient) { // Don't allow foreign SPITTypes
return false;
}
@@ -913,12 +991,11 @@ void app_main(void) {
initialize_ethernet();
NvsApi::init();
static fos::Task lightingTask(LightingTask, "Lights", 0x8000uL);
static fos::Task movementTask(MovementTask, "Motor", 0x8000uL);
static fos::Task movementTask(MovementTask, "Motor", 0x8000uL, fos::Task::MAX_PRIORITY-4 );
etherActive.take();
fos::Task::delayMs(10000);
ESP_LOGI(TAG, "Start net services");
// esp_log_level_set("SPIT", esp_log_level_t::ESP_LOG_DEBUG);
static int ipVersion = AF_INET;
static fos::TaskT<int> telnetSocket(telnetSocketTask, ipVersion, "tcpServer", 4096);
@@ -942,10 +1019,8 @@ void app_main(void) {
while (true) {
fos::Task::delayMs(5000);
// ToDo send
Syslog::logv(Syslog::Severity::Notice, "Health state");
// ESP_LOGI(TAG, "Min heap size: %" PRIu32 " / FreeHeap %" PRIu32 "\n",
// ESP_LOGI(TAG, "Min heap size: %u / FreeHeap %lu",
// heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT),
// esp_get_free_heap_size());
Syslog::logv(Syslog::Severity::Notice, "Min heap size: %u / FreeHeap %lu",
heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT),
esp_get_free_heap_size());
}
}
+1
View File
@@ -40,6 +40,7 @@
#include "nvsFunctions.hpp"
#include "mqttClient.hpp"
#include "watchFace.hpp"
#include "random.hpp"
// #include "esp_chip_info.h"
// #include "esp_flash.h"
File diff suppressed because it is too large Load Diff