diff --git a/.vscode/settings.json b/.vscode/settings.json index 01c91b0..bb7a9e2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -78,5 +78,5 @@ }, "idf.currentSetup": "C:\\esp\\v5.4.3\\esp-idf", - "idf.port": "COM4" + "idf.port": "COM16" } diff --git a/core b/core index e584259..8d92153 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit e584259b318da9775d54d511bbf151e570324247 +Subproject commit 8d92153e82e97d19287a79a61bdac89ebba7b4b9 diff --git a/main/lighsMain.hpp b/main/lighsMain.hpp index 2d7f4ce..a7fe8bf 100644 --- a/main/lighsMain.hpp +++ b/main/lighsMain.hpp @@ -10,6 +10,11 @@ #include #include #include +#include +#include +#include +#include + #include "sdkconfig.h" #include "esp_event.h" #include "esp_log.h" @@ -43,7 +48,5 @@ #include "spit_player.hpp" #include "spit_type.hpp" #include "spit_client.hpp" -#include -#include -#include -#include +#include "addressableLeRtz.hpp" +#include "systemFunctions.hpp" diff --git a/main/lightsMain.cpp b/main/lightsMain.cpp index 6195887..19c66c0 100644 --- a/main/lightsMain.cpp +++ b/main/lightsMain.cpp @@ -13,6 +13,9 @@ // ETH_PHY_LAN8720, // eth_type, // ETH_CLOCK_GPIO0_IN // eth_clk_mode as input // }, +// +// LED-Strips: 14 - 22 - 30 +// update http://172.16.16.10:8000/WatchController.bin #include "config.hpp" #include "lighsMain.hpp" @@ -22,6 +25,8 @@ using namespace std; string ClientName = "LeoLightsDev"; string ProjectName = "LeoLightsProj"; +gpio_num_t LedPin = gpio_num_t::GPIO_NUM_16; +gpio_num_t RelayPin = gpio_num_t::GPIO_NUM_18; extern "C" { // This switch allows the ROS C-implementation to find this main void app_main(void); @@ -32,52 +37,24 @@ struct DeviceState { vector counts; vector times; }; -struct StartCommand { +struct MasterRequest { uint8_t pos; // 0 for none / Valid indexes 1 .. 6 }; -static fos::Queue commandQ(2); +struct SlaveResponse { + uint8_t pos; // 0 for none / Valid indexes 1 .. 6 +}; +static fos::Queue commandQ(2); +static fos::Queue responseQ(2); DeviceState State; static const char* TAG = "Light"; - +static const char* VERSION = "V 0.6.0"; unique_ptr pShell; void onCommand(string name, Cli::CArgs args) { ESP_LOGI(TAG, "Invoking: %s", name.c_str()); } -void startUpdate(Cli::CArgs args) { - ESP_LOGI(TAG, "Invoking Update"); - if (args.size() != 1) { - pShell->writeLine("Need URL to application"); - return; - } - // @ToDo: Start Update here -} - -void getConfig(Cli::CArgs args) { - if (args.size() != 1) { - pShell->writeLine("Needs string key for query"); - return; - } - auto key = args[0]; - auto& store = NvsApi::getInstance(); - auto val = store.getValue(key); - pShell->writeLine(key + ": " + val + ""); -} - -void setConfig(Cli::CArgs args) { - if (args.size() != 2) { - pShell->writeLine("Needs string key and value"); - return; - } - auto key = args[0]; - auto val = args[1]; - - auto& store = NvsApi::getInstance(); - pShell->writeLine(string{"Storing value = '"} + val + "'"); - store.setValue(key, val); -} void setLogServerConfig(Cli::CArgs args) { ESP_LOGI(TAG, "on showLogServerConfig:"); @@ -94,7 +71,7 @@ void setLogServerConfig(Cli::CArgs args) { void testLights(Cli::CArgs args) { ESP_LOGI(TAG, "on testLights:"); - commandQ.enqueue(make_unique()); + commandQ.enqueue(make_unique()); } void showProcessValues(Cli::CArgs args) { @@ -146,22 +123,16 @@ static void telnetSocketTask(int addrFamily) { telnet.run( [](TcpSession& session) { pShell = make_unique(session, [](string n, Cli::CArgs a) { onCommand(n, a); }); - pShell->addBinding( - {"update", "Start OTA-Update-Process", - [](Cli::CArgs a) { startUpdate(a); }}); pShell->addBinding( {"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", - [](Cli::CArgs a) { getConfig(a); }}); - pShell->addBinding( - {"setcfg", "Set configuration value by key and value", - [](Cli::CArgs a) { setConfig(a); }}); + + auto& store = NvsApi::getInstance(); + store.registerCli(*pShell); + SystemFunctions::registerCli(*pShell); pShell->addBinding( {"setDyn", "set dynamics of movement (velocity,accelerations) as floats", @@ -184,29 +155,62 @@ void startShow(string data) { ESP_LOGI(TAG, "StartShuffle command %s", data.c_str()); try { Syslog::logv(Syslog::Severity::Informational, "got Shuffle-Command"); - commandQ.enqueue(make_unique()); + commandQ.enqueue(make_unique()); } catch (const exception& e) { ESP_LOGE(TAG, "Error to process data %s, with ex: %s", data.c_str(), e.what()); } } +constexpr uint32_t DmxUniverse = 0; +constexpr int DmxChannelCount = 9; +array LedData; + +static void UniverseCallback(const uint8_t* data, const uint16_t size) { + ESP_LOGD(TAG, "Got DMX"); + ESP_LOG_BUFFER_HEXDUMP("DMX", data, size, ESP_LOG_DEBUG); + Syslog::logv(Syslog::Severity::Debug, "Got DMX: r%0x g%0x b%0x i%0x ...", + /* RGB*/ data[0], data[1], data[2], /*Intens*/ data[3]); + + // DMX 512 + for (int i = 0; i < LedData.size() / 4;) { + LedData[i] = data[i]; + i++; + LedData[i] = data[i]; + i++; + LedData[i] = data[i]; + i++; + LedData[i] = data[i]; + i++; + } +} + /** * @brief DMX-Socket for ArtNet TCP/IP * * @details Tested with [Q Light Controller+](https://www.qlcplus.org/) * @param args ignored task argument */ -static void dmxSocketSenderTask(UdpSocket& socket) { +static void dmxSocketTask(int addrFamily) { + ESP_LOGI(TAG, "Starting ArtNet task"); + constexpr uint16_t ArtNetPort = arx::artnet::DEFAULT_PORT; + IpAdr address = addrFamily == AF_INET ? IpAdr(INADDR_ANY, ArtNetPort) : IpAdr(ArtNetPort); + try { - ArtnetSender artnet(socket); - array data; - while (socket.isActive()) { - data[0]++; - artnet.send("", 0, data.data(), data.size()); - fos::Task::delayMs(500); + while (true) { + UdpSocket socket(address); + socket.bindTo(); + + ArtnetReceiver artnet(socket); + artnet.subscribe(DmxUniverse, UniverseCallback); + artnet.parse(); + // parse artnet as long socket is active, then restart socket + while (socket.isActive()) { + ESP_LOGD(TAG, "Waiting for data"); + artnet.parse(); + } } - } catch (const exception& e) { + } catch (const std::exception& e) { ESP_LOGE("UDP", "%s", e.what()); } } @@ -285,31 +289,19 @@ const Macro macDemoFlicker = { void LightingTask() { ESP_LOGI(TAG, "Start Lighting"); auto const& colorSource = State.color; - array processors{ - Effect::EffectProcessor(8), - Effect::EffectProcessor(8)}; - processors[0].setEffect(Effect::macDark, &colorSource, 0); - processors[1].setEffect(Effect::macDark, &colorSource, 0); - const array PictoEffects{ - Effect::macDemoPulse, - Effect::macDemoPulse}; + AddressableLeRtz strip(LedPin, AddressableLeRtz::Type::Rgb, LedData.size()/4); + OutputPort relay(RelayPin); + relay.write(true); while (true) { - // ESP_LOGI(TAG, "Current color set r%i g%i b%i ", - // State.color.getRed(), State.color.getGreen(), State.color.getBlue()); - // processors[0].setEffect(Effect::macDark, &colorSource, 0); - // auto idx = 0; - // Syslog::logv(Syslog::Severity::Informational, "Running show"); - // processors[idx].setEffect(PictoEffects[idx], &colorSource, 0); - - // for (size_t i = 0; i < processors.size(); i++) { - // auto col = processors[i].tick(); - // } - // fos::Task::delayMs(40); - static int cnt{}; - fos::Task::delayMs(1000); - printf("running %d\n", cnt++); + for (int i = 0; i < (LedData.size() / 4); i++) { + auto* c = &LedData[i * 4]; + Color C{c[0], c[1], c[2], c[3]}; + strip.set(C, i, 1); + } + strip.send(); // takes ca. 5ms to send all the data + fos::Task::delayMs(20); } } @@ -318,7 +310,7 @@ struct LocalSpitObj { string groupName; string name; }; -map ProvidedSpitActions; +map ProvidedSpitActions; map ExpectedObjects; void onServerEvent(SClient::ServerEvent event, const SadDetectedServer& p_DetectedServer) { @@ -514,7 +506,7 @@ void onPlaySpitType(string p_PlayerID, string spitTypeId, bool p_PlayerIsRunning if (p_Started == true) { auto command = ProvidedSpitActions[spitTypeId]; // ESP_LOGI(TAG, "Player: %s is running: %s Object", p_PlayerID.data(), spitTypeId.c_str()); - commandQ.enqueue(make_unique()); + commandQ.enqueue(make_unique()); Syslog::logv(Syslog::Severity::Informational, "Got SPIT command for move ot : r%d", command.pos); } } @@ -531,90 +523,83 @@ void onPlayRemoteObjectStatus(const SType& sType, const SObject& sObject, uint64 ESP_EARLY_LOGD(TAG, "eventPlayRemoteObjectStatus RemoteSPITType: %s RemoteSPITObject: %s Position: %lld Value: %d", sType.Name.get().data(), sObject.Name.get().data(), frameInsideObject, value); } -// void SpitClientApp() { -// ESP_LOGI(TAG, "Starting SPIT task"); +void SpitClientApp() { + ESP_LOGI(TAG, "Starting SPIT task"); -// auto& provided = SpitTypes.Provided; -// auto& expected = SpitTypes.Expected; -// vector ProvidedObj; -// ProvidedSpitActions[provided.startShuffle] = MoveCommand{.type = MoveType::Shuffle, .pos = 0}; -// ProvidedObj.push_back(LocalSpitObj{.iD = provided.startShuffle, .groupName = provided.group, .name = provided.startShuffle}); -// ExpectedObjects[expected.changingPos] = ""; -// for (size_t i = 0; i < 6; i++) { -// ProvidedSpitActions[provided.moveToX[i]] = MoveCommand{.type = MoveType::StepTo, .pos = (uint8_t)(i + 1)}; -// ProvidedObj.push_back(LocalSpitObj{.iD = provided.moveToX[i], .groupName = provided.group, .name = provided.moveToX[i]}); -// ExpectedObjects[expected.inPosX[i]] = ""; -// } + auto& provided = SpitTypes.Provided; + auto& expected = SpitTypes.Expected; -// auto ip = spit::Socket::getAdaptersInfo(); -// spit::Socket socket(ip); -// SClient spitClient(ClientName, ProjectName, socket, -// { -// .onServerEvent = onServerEvent, -// .onConnectionStatus = onConnectionStatus, -// .onProjectUpdate = onProjectUpdate, -// .onSpitType = onSpitType, -// .onSpitObject = onSpitObject, -// .onPlay = onPlay, -// .onPlaySpitType = onPlaySpitType, -// .onPlayRemoteObjectStatus = onPlayRemoteObjectStatus, -// .onCheckSpitTypeVeto = onCheckSpitTypeVeto, -// .onCheckSpitObjectVeto = onCheckSpitObjectVeto, -// }); + vector ProvidedObj; + ProvidedSpitActions[provided.group] = MasterRequest{.pos = 0}; + ProvidedObj.push_back(LocalSpitObj{.iD = provided.group, .groupName = provided.group, .name = provided.group}); + ProvidedSpitActions[provided.startShow] = MasterRequest{.pos = 0}; + ProvidedObj.push_back(LocalSpitObj{.iD = provided.startShow, .groupName = provided.group, .name = provided.startShow}); -// for (auto& obj : ProvidedObj) { -// SType* ptrSPITType1Fix = spitClient.createTypeFixed(obj.iD, obj.groupName, obj.name, 0, 0); -// spitClient.setActionType(ptrSPITType1Fix->getID(), true); // should be executed whenever a SPITObject with this SPITType is played -// } -// spitClient.clientProjectLoaded(); -// spitClient.startServerAutoDetect(); + ExpectedObjects[expected.showDone] = ""; -// spitProjectFinish.take(); -// string serverProjectID = spitClient.getServerProjectID(); -// string serverProjectName = spitClient.getClientProjectName(); -// int serverFramesPerSecond = spitClient.getServerFramesPerSecond(); // set when the server reports his project, see eventProjectReport -// ESP_LOGI(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", serverProjectID.data(), serverProjectName.data(), serverFramesPerSecond); + auto ip = spit::Socket::getAdaptersInfo(); + spit::Socket socket(ip); + SClient spitClient(ClientName, ProjectName, socket, + { + .onServerEvent = onServerEvent, + .onConnectionStatus = onConnectionStatus, + .onProjectUpdate = onProjectUpdate, + .onSpitType = onSpitType, + .onSpitObject = onSpitObject, + .onPlay = onPlay, + .onPlaySpitType = onPlaySpitType, + .onPlayRemoteObjectStatus = onPlayRemoteObjectStatus, + .onCheckSpitTypeVeto = onCheckSpitTypeVeto, + .onCheckSpitObjectVeto = onCheckSpitObjectVeto, + }); -// for (auto&& obj : ExpectedObjects) { -// if (obj.second == "") { -// ESP_LOGE(TAG, "No matching Remote ID for %s", obj.first.c_str()); -// } -// } + for (auto& obj : ProvidedObj) { + SType* ptrSPITType1Fix = spitClient.createTypeFixed(obj.iD, obj.groupName, obj.name, 0, 0); + spitClient.setActionType(ptrSPITType1Fix->getID(), true); // should be executed whenever a SPITObject with this SPITType is played + } + spitClient.clientProjectLoaded(); + spitClient.startServerAutoDetect(); -// while (true) { -// auto res = responseQueue.dequeue(); -// if (res->type == ResponseType::StartMoving) { -// spitClient.sendRemoteObject(ExpectedObjects[expected.changingPos]); -// } else if (res->type == ResponseType::StepAt) { -// spitClient.sendRemoteObject(ExpectedObjects[expected.inPosX[res->pos - 1]]); -// } -// } -// } + spitProjectFinish.take(); + string serverProjectID = spitClient.getServerProjectID(); + string serverProjectName = spitClient.getClientProjectName(); + int serverFramesPerSecond = spitClient.getServerFramesPerSecond(); // set when the server reports his project, see eventProjectReport + ESP_LOGI(TAG, "eventProjectReport ID: %s Name: %s FramesPerSecond: %d", serverProjectID.data(), serverProjectName.data(), serverFramesPerSecond); -// void MqttThread() { -// ESP_LOGI(TAG, "Starting MQTT task"); + for (auto&& obj : ExpectedObjects) { + if (obj.second == "") { + ESP_LOGE(TAG, "No matching Remote ID for %s", obj.first.c_str()); + } + } -// auto& store = NvsApi::getInstance(); -// auto broker = store.getValue(ConfigKeys.mqttBroker); -// if (broker != "") { -// ESP_LOGI(TAG, "Initializing MQTT"); -// auto prefix = store.getValue(ConfigKeys.mqttPrefix); -// auto& client = MqttClient::init(broker, prefix); -// if (!client.isRunning()) { -// client.addSubscription(MqttTopics.moveTo, [](string d) { startShuffle(d); }); -// client.start(); -// } + while (true) { + auto res = responseQ.dequeue(); + spitClient.sendRemoteObject(ExpectedObjects[expected.showDone]); + } +} -// while (true) { -// auto res = responseQueue.dequeue(); -// if (res->type == ResponseType::StartMoving) { -// client.publish(MqttTopics.showDone, ""); -// } else if (res->type == ResponseType::StepAt) { -// client.publish(MqttTopics.inPosition, to_string(res->pos)); -// } -// } -// } -// } +void MqttThread() { + ESP_LOGI(TAG, "Starting MQTT task"); + + auto& store = NvsApi::getInstance(); + auto broker = store.getValue(ConfigKeys.mqttBroker); + if (broker != "") { + ESP_LOGI(TAG, "Initializing MQTT"); + auto prefix = store.getValue(ConfigKeys.mqttPrefix); + auto& client = MqttClient::init(broker, prefix); + if (!client.isRunning()) { + client.addSubscription(MqttTopics.startShow, [](string d) { + commandQ.enqueue(make_unique()); + }); + client.start(); + } + + while (true) { + auto res = responseQ.dequeue(); + client.publish(MqttTopics.showDone, ""); + } + } +} void app_main(void) { initialize_ethernet(); @@ -624,11 +609,11 @@ void app_main(void) { etherActive.take(); ESP_LOGI(TAG, "Start net services"); - // static int ipVersion = AF_INET; - // static fos::TaskT telnetSocket(telnetSocketTask, ipVersion, "tcpServer", 4096); + static int ipVersion = AF_INET; + static fos::TaskT telnetSocket(telnetSocketTask, ipVersion, "tcpServer", 4096); // static fos::Task spit(SpitClientApp, "SpitClient"); - // // static fos::Task mqtt(MqttThread, "MqttEndpoint"); - // // static Task otaUpdate(SystemFunctions::OtaTaskEntry, "otaTask", 8192); + // static fos::Task mqtt(MqttThread, "MqttEndpoint"); + static fos::TaskT dmxNode(dmxSocketTask, ipVersion, "dmxNode", 4096); auto& store = NvsApi::getInstance(); auto logger = store.getValue(ConfigKeys.syslogDest); @@ -638,9 +623,12 @@ void app_main(void) { ESP_LOGI(TAG, "Configuration"); ESP_LOGI(TAG, "%s: %s", ConfigKeys.syslogDest, store.getValue(ConfigKeys.syslogDest).c_str()); - ESP_LOGI(TAG, "%s: %s", ConfigKeys.mqttBroker, store.getValue(ConfigKeys.mqttBroker).c_str()); - ESP_LOGI(TAG, "%s: %s", ConfigKeys.mqttPrefix, store.getValue(ConfigKeys.mqttPrefix).c_str()); - ESP_LOGI(TAG, "%s: %s", ConfigKeys.spitServer, store.getValue(ConfigKeys.spitServer).c_str()); + // ESP_LOGI(TAG, "%s: %s", ConfigKeys.mqttBroker, store.getValue(ConfigKeys.mqttBroker).c_str()); + // ESP_LOGI(TAG, "%s: %s", ConfigKeys.mqttPrefix, store.getValue(ConfigKeys.mqttPrefix).c_str()); + // ESP_LOGI(TAG, "%s: %s", ConfigKeys.spitServer, store.getValue(ConfigKeys.spitServer).c_str()); + + ESP_LOGI(TAG, "## Starting : %s : %s", + CONFIG_LWIP_LOCAL_HOSTNAME, VERSION); while (true) { fos::Task::delayMs(5000);