diff --git a/HansonServo.ino b/HansonServo.ino index 69e483e..8e21dd6 100644 --- a/HansonServo.ino +++ b/HansonServo.ino @@ -2,6 +2,7 @@ #include #include "feetech.h" #include "animation.h" +#include "nodegraph.h" #define DEVICE_NAME "Little Sophia" #define FIRMWARE_VERSION "0.0.1" @@ -101,6 +102,7 @@ const uint16_t testPayloadLength = sizeof(testPayload); void setup() { Serial.begin(1000000); + Serial.setRxBufferSize(1024); for (int i = 0; i < 5; i++) { Serial.println(i); delay(500); @@ -137,11 +139,11 @@ void setup() { // anim.saveToFile("/scurve.anim"); // Serial.println("SAVED"); - //handleSaveFile(testPayload, testPayloadLength); - Serial.println("Loading test.anim"); - anim.loadFromFile("/test.anim"); - Serial.println(anim.header.frameCount); - anim.printCurves(); + //handleSaveFile(testPayload, testPayloadLength); + Serial.println("Loading test.anim"); + anim.loadFromFile("/test.anim"); + Serial.println(anim.header.frameCount); + anim.printCurves(); // Serial.print("CurveSegment size: "); // Serial.println(sizeof(CurveSegment)); //anim.createBasicSCurve(); @@ -682,6 +684,25 @@ bool parseAnimationPayload(const uint8_t* payload, uint16_t length, Animation& a ptr += sizeof(CurveSegment); } + // ✅ Advance ptr to node graph payload + //ptr += curveCount * sizeof(CurveSegment); + + // 🔹 Parse node graph + uint8_t nodeCount = ptr[0]; + Serial.print("Node count: "); + Serial.println(nodeCount); + sendMessage(String("Node count: ") + String(nodeCount)); + sendMessage(String("ptr offset: ") + String(ptr - payload)); + + + uint16_t remainingLength = length - (ptr - payload); + if (remainingLength > 0) { + loadNodeGraph(ptr, remainingLength, animation.nodeGraph); + } else { + Serial.println("No node graph data found"); + } +sendMessage(printNodeGraph(animation.nodeGraph)); + // 🔹 Save using received filename animation.saveToFile(("/" + String(filename)).c_str()); diff --git a/animation.h b/animation.h index fde2ee6..0fd2054 100644 --- a/animation.h +++ b/animation.h @@ -1,10 +1,10 @@ -#ifndef ANIMATION_FILE_H -#define ANIMATION_FILE_H +#pragma once #include #include "FS.h" #include "FFat.h" #include +#include "nodegraph.h" #define NUM_CHANNELS 5 @@ -60,6 +60,8 @@ public: void createBasicSCurve(); void createEaseOutCurve(); AnimationHeader header; + NodeGraph nodeGraph; + private: //uint16_t data[MAX_FRAMES][NUM_CHANNELS]; @@ -67,4 +69,3 @@ private: }; -#endif diff --git a/nodegraph.cpp b/nodegraph.cpp new file mode 100644 index 0000000..f80fe1c --- /dev/null +++ b/nodegraph.cpp @@ -0,0 +1,137 @@ +#include "nodegraph.h" +#include + +// CurveNode evaluation +void CurveNode::evaluate(uint32_t tick) { + //outputValue = getCurveValue(curveID, tick); +} + +// ServoNode evaluation +void ServoNode::evaluate(uint32_t tick) { + //setMotorPWM(motorID, inputValue); +} + +// NodeGraph tick +void NodeGraph::tick(uint32_t currentTick) { + // First pass: evaluate all nodes + for (Node* node : nodes) { + node->evaluate(currentTick); + } + + // Optional: if you want to simulate wiring between nodes, + // you could add a second pass here to propagate values +} + +void loadNodeGraph(const uint8_t* packet, size_t length, NodeGraph& graph) { + size_t offset = 0; + + // Read node count + uint16_t nodeCount = packet[offset]; + offset += 1; + + // Parse nodes + for (uint16_t i = 0; i < nodeCount; ++i) { + if (offset + 6 > length) break; // safety check + + uint8_t type = packet[offset++]; + uint8_t id = packet[offset++]; + uint16_t x = packet[offset] | (packet[offset + 1] << 8); offset += 2; + uint16_t y = packet[offset] | (packet[offset + 1] << 8); offset += 2; + + Node* node = nullptr; + + switch (type) { + case TYPE_CURVENODE: { // CurveNode + if (offset + 1 > length) break; + uint8_t curveID = packet[offset++]; + auto* curve = new CurveNode(); + curve->id = id; + curve->type = type; + curve->x = x; + curve->y = y; + curve->curveID = curveID; + node = curve; + break; + } + case TYPE_SERVONODE: { // ServoNode + if (offset + 1 > length) break; + uint8_t motorID = packet[offset++]; + auto* servo = new ServoNode(); + servo->id = id; + servo->type = type; + servo->x = x; + servo->y = y; + servo->motorID = motorID; + node = servo; + break; + } + case TYPE_NOISENODE: { // NoiseNode + if (offset + 17 > length) break; + offset += 17; // skip for now + break; + } + default: + break; + } + + if (node) { + + graph.nodes.push_back(node); + } + } + + // Parse connections + if (offset + 2 > length) return; + uint16_t connectionCount = packet[offset]; + offset += 1; + + for (uint16_t i = 0; i < connectionCount; ++i) { + if (offset + 2 > length) break; + uint8_t fromID = packet[offset++]; + uint8_t toID = packet[offset++]; + + graph.connections.push_back({fromID, toID}); + } +} + +String printNodeGraph(const NodeGraph& graph) { + String output = "📦 NodeGraph Dump\n"; + + output += "Nodes:\n"; + for (const Node* node : graph.nodes) { + output += " ID " + String(node->id); + output += " | Type " + String(node->type); + output += " | Pos (" + String(node->x) + ", " + String(node->y) + ")"; + + switch (node->type) { + case TYPE_CURVENODE: { // CurveNode + const CurveNode* curve = static_cast(node); + output += " | CurveID " + String(curve->curveID); + break; + } + case TYPE_SERVONODE: { // ServoNode + const ServoNode* servo = static_cast(node); + output += " | MotorID " + String(servo->motorID); + break; + } + // case 2: { // NoiseNode + // const NoiseNode* noise = static_cast(node); + // output += " | Noise a=" + String(noise->a, 2); + // output += " b=" + String(noise->b, 2); + // output += " c=" + String(noise->c, 2); + // output += " d=" + String(noise->d, 2); + // output += " seed=" + String(noise->seed); + // break; + // } + } + + output += "\n"; + } + + output += "Connections:\n"; + for (const auto& conn : graph.connections) { + output += " " + String(conn.fromID) + " → " + String(conn.toID) + "\n"; + } + + return output; +} diff --git a/nodegraph.h b/nodegraph.h new file mode 100644 index 0000000..4f137c3 --- /dev/null +++ b/nodegraph.h @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include + +#define TYPE_NODE 0x01 +#define TYPE_SERVONODE 0x02 +#define TYPE_CURVENODE 0x03 +#define TYPE_NOISENODE 0x04 + + + +// Base Node class +struct Node { + uint8_t id; + uint8_t type; + uint16_t x; + uint16_t y; + virtual void evaluate(uint32_t tick) = 0; + virtual ~Node() {} +}; + +// CurveNode: evaluates a curve at a given tick +struct CurveNode : public Node { + uint8_t curveID; + uint16_t outputValue; + + void evaluate(uint32_t tick) override; +}; + +// ServoNode: sends a value to a motor +struct ServoNode : public Node { + uint8_t motorID; + uint16_t inputValue; + + void evaluate(uint32_t tick) override; +}; + +// NodeGraph container +struct NodeConnection { + uint8_t fromID; + uint8_t toID; +}; + +class NodeGraph { +public: + std::vector nodes; + std::vector connections; + + void tick(uint32_t currentTick); +}; + + + +// Loader function +void loadNodeGraph(const uint8_t* packet, size_t length, NodeGraph& graph); +String printNodeGraph(const NodeGraph& graph);