From 64a05b1640ed4c8042089bfeee90fa6df9f4949e Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 15:41:35 -0400 Subject: [PATCH 01/60] have secondary constructor delegate to the primary one That way the secondary constructor only has to concentrate on what is different about it from the primary, which in this case is the kinect manager object. --- src/ShapeDisplayManagers/TransformIOManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 3051eed..def8c73 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -13,8 +13,8 @@ TransformIOManager::TransformIOManager() { configureBoards(); } -TransformIOManager::TransformIOManager(KinectManager* kinectRef) { - configureBoards(); +// Secondary Constructor delegates to the primary constructor and adds the kinect reference. +TransformIOManager::TransformIOManager(KinectManager* kinectRef) : TransformIOManager() { m_kinectManagerRef = kinectRef; } From 7d90545f19e20ec20236ffa0203b9f20c9b7c275 Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 15:45:30 -0400 Subject: [PATCH 02/60] adds and initializes first set of moved constants They are defined as protected class members in the superclass that are designed to be defined in the subclass. By defining them in the superclass they become directly available to functions in the superclass, but the values can be set in the subclass. --- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 8 ++++++++ src/ShapeDisplayManagers/TransformIOManager.cpp | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 328ceaf..e7d7659 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -123,6 +123,14 @@ class SerialShapeIOManager : public ShapeIOManager { ofPixels feebsTEMP; KinectManager* m_kinectManagerRef; + + // Shape display hardware constants (previously defined using #define preprocessor statements. + // These values are designed to be overridden by their respective individual shape display sub-classes (Transform, Inform, Cooperform, ets.) + + int pinHeightMin; + int pinHeightMax; + int pinHeightRange; + }; #endif /* SerialShapeIOManager_hpp */ diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index def8c73..5b25ae4 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -10,6 +10,12 @@ // Create new transformIOManager instance, setting up transFORM-specific board // configuration TransformIOManager::TransformIOManager() { + // Set the Transform specific hardware parameters here. + + pinHeightMin = 50; + pinHeightMax = 210; + pinHeightRange = pinHeightMax - pinHeightMin; + configureBoards(); } From 564471d909be4514347c26480bbd4cfe23c63388 Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 15:47:36 -0400 Subject: [PATCH 03/60] remove constants that have been moved to the specific shape display class definition. Also update the function code to use the new references. --- src/Constants/constants.h | 4 ---- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Constants/constants.h b/src/Constants/constants.h index 1604271..ef65ac1 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -65,9 +65,6 @@ const string SERIAL_PORTS[NUM_SERIAL_CONNECTIONS] = { #define SHAPE_DISPLAY_CAN_TALK_BACK 1 -#define HEIGHT_MIN 50 -#define HEIGHT_MAX 210 - #define PINBLOCK_0_X_OFFSET 13 #define PINBLOCK_0_WIDTH 16 @@ -79,7 +76,6 @@ const string SERIAL_PORTS[NUM_SERIAL_CONNECTIONS] = { // shape display derived dimensions, for convenience #define SHAPE_DISPLAY_SIZE_2D (SHAPE_DISPLAY_SIZE_X * SHAPE_DISPLAY_SIZE_Y) -#define HEIGHT_RANGE (HEIGHT_MAX - HEIGHT_MIN) // TRANSFORM pin config defaults #define DEFAULT_GAIN_P 1.5 diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 59cf5f5..652d45f 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -236,17 +236,17 @@ void SerialShapeIOManager::toggleStuckPins() { // Clip all values to fit within the allowed range void SerialShapeIOManager::clipAllHeightValuesToBeWithinRange() { - float thresholdScalar = 1.0 * HEIGHT_RANGE / 255; + float thresholdScalar = 1.0 * pinHeightRange / 255; for (int i = 0; i < SHAPE_DISPLAY_SIZE_X; i++) { for (int j = 0; j < SHAPE_DISPLAY_SIZE_Y; j++) { // to rescale the values instead of clipping them, use this line: - //heightsForShapeDisplay[i][j] = heightsForShapeDisplay[i][j] * thresholdScalar + HEIGHT_MIN; + //heightsForShapeDisplay[i][j] = heightsForShapeDisplay[i][j] * thresholdScalar + pinHeightMin; - if (heightsForShapeDisplay[i][j] <= HEIGHT_MIN) { - heightsForShapeDisplay[i][j] = (unsigned char) HEIGHT_MIN; + if (heightsForShapeDisplay[i][j] <= pinHeightMin) { + heightsForShapeDisplay[i][j] = (unsigned char) pinHeightMin; } - else if (heightsForShapeDisplay[i][j] >= HEIGHT_MAX) { - heightsForShapeDisplay[i][j] = (unsigned char) HEIGHT_MAX; + else if (heightsForShapeDisplay[i][j] >= pinHeightMax) { + heightsForShapeDisplay[i][j] = (unsigned char) pinHeightMax; } } } From 88e38635cba0357e9f5d77e099a9cd0ad3cc230c Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 16:41:34 -0400 Subject: [PATCH 04/60] switch to protected member variables for pin config --- src/AppManager.cpp | 10 +++++----- src/Constants/constants.h | 8 -------- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 13 +++++++++++++ src/ShapeDisplayManagers/TransformIOManager.cpp | 7 +++++++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 470f584..c63bf6a 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -80,11 +80,11 @@ void AppManager::setupShapeDisplayManagement() { // initialize shape display pin configs PinConfigs pinConfigs; pinConfigs.timeOfUpdate = elapsedTimeInSeconds(); - pinConfigs.gainP = DEFAULT_GAIN_P; - pinConfigs.gainI = DEFAULT_GAIN_I; - pinConfigs.maxI = DEFAULT_MAX_I; - pinConfigs.deadZone = DEFAULT_DEAD_ZONE; - pinConfigs.maxSpeed = DEFAULT_MAX_SPEED; + pinConfigs.gainP = m_serialShapeIOManager->getGainP(); + pinConfigs.gainI = m_serialShapeIOManager->getGainI(); + pinConfigs.maxI = m_serialShapeIOManager->getMaxI(); + pinConfigs.deadZone = m_serialShapeIOManager->getDeadZone(); + pinConfigs.maxSpeed = m_serialShapeIOManager->getMaxSpeed(); m_serialShapeIOManager->setGlobalPinConfigs(pinConfigs); timeOfLastPinConfigsUpdate = elapsedTimeInSeconds(); diff --git a/src/Constants/constants.h b/src/Constants/constants.h index ef65ac1..e85a49e 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -77,13 +77,5 @@ const string SERIAL_PORTS[NUM_SERIAL_CONNECTIONS] = { // shape display derived dimensions, for convenience #define SHAPE_DISPLAY_SIZE_2D (SHAPE_DISPLAY_SIZE_X * SHAPE_DISPLAY_SIZE_Y) -// TRANSFORM pin config defaults -#define DEFAULT_GAIN_P 1.5 -#define DEFAULT_GAIN_I 0.045 -#define DEFAULT_MAX_I 25 -#define DEFAULT_DEAD_ZONE 2 -#define DEFAULT_MAX_SPEED 200 - - #endif /* constants_h */ diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index e7d7659..3480861 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -60,6 +60,13 @@ class SerialShapeIOManager : public ShapeIOManager { // Virtual class for hardware specific pin layouts. virtual std::vector createSections(float pixelsPerInch) {}; + // Public getters for protected hardware constants, these are specific to the pin configs so might be abstracted into a single array of values. + float getGainP() const { return gainP; } + float getGainI() const { return gainI; } + int getMaxI() const { return maxI; } + int getDeadZone() const { return deadZone; } + int getMaxSpeed() const { return maxSpeed; } + protected: // manage the connection to the shape display @@ -131,6 +138,12 @@ class SerialShapeIOManager : public ShapeIOManager { int pinHeightMax; int pinHeightRange; + float gainP; + float gainI; + int maxI; + int deadZone; + int maxSpeed; + }; #endif /* SerialShapeIOManager_hpp */ diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 5b25ae4..3077b29 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -16,6 +16,13 @@ TransformIOManager::TransformIOManager() { pinHeightMax = 210; pinHeightRange = pinHeightMax - pinHeightMin; + // Pin config values, might be abstracted into a single array. + gainP = 1.5; + gainI = 0.045; + maxI = 25; + deadZone = 2; + maxSpeed = 200; + configureBoards(); } From 6f6f5d1b98f17834f57f3509884af35ac928fdbb Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 16:54:17 -0400 Subject: [PATCH 05/60] add comment --- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 3480861..38a098e 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -138,6 +138,7 @@ class SerialShapeIOManager : public ShapeIOManager { int pinHeightMax; int pinHeightRange; + // Pin configs, maybe split out into a single array instead of separate values. float gainP; float gainI; int maxI; From fbd3771910a0e5bd6caee65ec621a25d190bb417 Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 17:13:30 -0400 Subject: [PATCH 06/60] move invocation of connectToDisplay from superclass to subclass. This will enable connectToDisplay to use values defined in the subclass constructor. --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 3 --- src/ShapeDisplayManagers/TransformIOManager.cpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 652d45f..ea76f2a 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -36,9 +36,6 @@ SerialShapeIOManager::SerialShapeIOManager() { pinStuckSinceTime[x][y] = timeOfLastConfigsRefresh; } } - - // connect to shape display - connectToDisplay(); } SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 3077b29..4657379 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -23,6 +23,9 @@ TransformIOManager::TransformIOManager() { deadZone = 2; maxSpeed = 200; + // Connect to shape display. + connectToDisplay(); + configureBoards(); } From 588229c20b4a8267fc190d49000828908f809080 Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 17:42:58 -0400 Subject: [PATCH 07/60] refactor serial connection string handling --- src/Constants/constants.h | 18 +----------------- .../SerialShapeIOManager.cpp | 2 +- .../SerialShapeIOManager.hpp | 3 +++ .../TransformIOManager.cpp | 9 +++++++++ 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Constants/constants.h b/src/Constants/constants.h index e85a49e..3d2802d 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -40,23 +40,7 @@ using namespace std; #define NUM_PINS_ARDUINO 6 #define NUM_SERIAL_CONNECTIONS 6 -#define SERIAL_PORT_0 "/dev/tty.usbserial-A702YMNV" -#define SERIAL_PORT_1 "/dev/tty.usbserial-A702YLM2" -#define SERIAL_PORT_2 "/dev/tty.usbserial-A702YMNT" -#define SERIAL_PORT_3 "/dev/tty.usbserial-A702YLM6" -#define SERIAL_PORT_4 "/dev/tty.usbserial-A702YLM9" -#define SERIAL_PORT_5 "/dev/tty.usbserial-A30011Hp" - - - -const string SERIAL_PORTS[NUM_SERIAL_CONNECTIONS] = { - SERIAL_PORT_0, - SERIAL_PORT_1, - SERIAL_PORT_2, - SERIAL_PORT_3, - SERIAL_PORT_4, - SERIAL_PORT_5 -}; + // Shape display table // ------------------- diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index ea76f2a..4547650 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -106,7 +106,7 @@ void SerialShapeIOManager::disconnectFromDisplay(bool clearHeights) { // destroyed. void SerialShapeIOManager::openSerialConnections() { for (int i = 0; i < NUM_SERIAL_CONNECTIONS; i++) { - serialConnections[i] = new SerialShapeIO(SERIAL_PORTS[i], SERIAL_BAUD_RATE, heightsFromShapeDisplayAvailable); + serialConnections[i] = new SerialShapeIO(serialPorts[i], SERIAL_BAUD_RATE, heightsFromShapeDisplayAvailable); } } diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 38a098e..2efad38 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -145,6 +145,9 @@ class SerialShapeIOManager : public ShapeIOManager { int deadZone; int maxSpeed; + // Serial connection id strings + std::vector serialPorts; + }; #endif /* SerialShapeIOManager_hpp */ diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 4657379..2c7abd9 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -22,6 +22,15 @@ TransformIOManager::TransformIOManager() { maxI = 25; deadZone = 2; maxSpeed = 200; + + // Add serial connection strings to the vector of serial connections. + serialPorts.push_back("/dev/tty.usbserial-A702YMNV"); + serialPorts.push_back("/dev/tty.usbserial-A702YLM2"); + serialPorts.push_back("/dev/tty.usbserial-A702YMNT"); + serialPorts.push_back("/dev/tty.usbserial-A702YLM6"); + serialPorts.push_back("/dev/tty.usbserial-A702YLM9"); + serialPorts.push_back("/dev/tty.usbserial-A30011Hp"); + // Connect to shape display. connectToDisplay(); From 29ae65c0ae5d337f2a8f25391f399fe589c12beb Mon Sep 17 00:00:00 2001 From: jdub Date: Sun, 12 May 2024 18:00:44 -0400 Subject: [PATCH 08/60] never used, and have been replaced --- src/Constants/constants.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Constants/constants.h b/src/Constants/constants.h index 3d2802d..2f5743a 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -49,15 +49,6 @@ using namespace std; #define SHAPE_DISPLAY_CAN_TALK_BACK 1 -#define PINBLOCK_0_X_OFFSET 13 -#define PINBLOCK_0_WIDTH 16 - -#define PINBLOCK_1_X_OFFSET 43 -#define PINBLOCK_1_WIDTH 16 - -#define PINBLOCK_2_X_OFFSET 73 -#define PINBLOCK_2_WIDTH 16 - // shape display derived dimensions, for convenience #define SHAPE_DISPLAY_SIZE_2D (SHAPE_DISPLAY_SIZE_X * SHAPE_DISPLAY_SIZE_Y) From 3db70072338e33a256acf579984ff02e8432eb20 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Tue, 4 Jun 2024 23:07:00 -0400 Subject: [PATCH 09/60] don't subclass SerialShapeIOManager It's the only subclass and the abstraction isn't helping --- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 6 ++++-- src/ShapeDisplayManagers/ShapeIOManager.hpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 2efad38..d0e2440 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -29,8 +29,7 @@ class SerialPinBoard { int serialConnection; // what serial connection is it on? }; - -class SerialShapeIOManager : public ShapeIOManager { +class SerialShapeIOManager { public: SerialShapeIOManager(); SerialShapeIOManager(KinectManager* kinectRef); @@ -67,6 +66,9 @@ class SerialShapeIOManager : public ShapeIOManager { int getDeadZone() const { return deadZone; } int getMaxSpeed() const { return maxSpeed; } + // can heights be read from the display? + const bool heightsFromShapeDisplayAvailable = SHAPE_DISPLAY_CAN_TALK_BACK; + protected: // manage the connection to the shape display diff --git a/src/ShapeDisplayManagers/ShapeIOManager.hpp b/src/ShapeDisplayManagers/ShapeIOManager.hpp index aa78314..209478f 100644 --- a/src/ShapeDisplayManagers/ShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/ShapeIOManager.hpp @@ -13,6 +13,8 @@ #include "constants.h" #include "PinConfigs.h" +// This has been dereferenced from the SerialShapeIOManager.hpp file, so maybe think about removing someday. + class ShapeIOManager { public: // virtual destructor allows delegation to derived class destructors when used polymorphically From 685ce8017493e43a30c30933051473b7fe46f5c0 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Tue, 4 Jun 2024 23:09:19 -0400 Subject: [PATCH 10/60] change array to vector and add a constructor that can initialize the size --- src/AppManager.cpp | 4 ++++ src/AppManager.hpp | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index c63bf6a..0ad82c2 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -7,6 +7,10 @@ #include "AppManager.hpp" +AppManager::AppManager() { + heightsForShapeDisplay = std::vector>(SHAPE_DISPLAY_SIZE_X, std::vector(SHAPE_DISPLAY_SIZE_Y)); +} + void AppManager::setup(){ ofSetFrameRate(30); diff --git a/src/AppManager.hpp b/src/AppManager.hpp index 459aea8..d2107ef 100644 --- a/src/AppManager.hpp +++ b/src/AppManager.hpp @@ -45,6 +45,8 @@ class AppManager : public ofBaseApp { public: + AppManager(); + void setup(); void update(); void draw(); @@ -104,7 +106,7 @@ class AppManager : public ofBaseApp { // I/O data buffers // maybe rename to serialHeightOutput() - unsigned char heightsForShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> heightsForShapeDisplay; // maybe rename to serialHeightInput() unsigned char heightsFromShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; ofPixels heightPixelsForShapeDisplay; From 0aa0387dffbfe6e815773f206655a49a7c0d7d69 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Tue, 4 Jun 2024 23:12:19 -0400 Subject: [PATCH 11/60] change the array to a vector and size it correctly in the constructor. Also don't write zeros to it because it is initialized with zeros --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 10 ++++++++-- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 4547650..76020a6 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -26,10 +26,13 @@ SerialShapeIOManager::SerialShapeIOManager() { // from the shape display telling us whether pins are stuck enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; + // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values + heightsForShapeDisplay.resize(SHAPE_DISPLAY_SIZE_X, std::vector(SHAPE_DISPLAY_SIZE_Y, 0)); + // initialize per-pin data arrays for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - heightsForShapeDisplay[x][y] = 0; + //heightsForShapeDisplay[x][y] = 0; heightsFromShapeDisplay[x][y] = 0; pinDiscrepancy[x][y] = 0; pinEnabled[x][y] = true; @@ -45,11 +48,14 @@ SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { // stuck pin safety toggling can only be implemented if we have height data // from the shape display telling us whether pins are stuck enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; + + // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values + heightsForShapeDisplay.resize(SHAPE_DISPLAY_SIZE_X, std::vector(SHAPE_DISPLAY_SIZE_Y, 0)); // initialize per-pin data arrays for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - heightsForShapeDisplay[x][y] = 0; + //heightsForShapeDisplay[x][y] = 0; heightsFromShapeDisplay[x][y] = 0; pinDiscrepancy[x][y] = 0; pinEnabled[x][y] = true; diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index d0e2440..6fcec3e 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -36,7 +36,7 @@ class SerialShapeIOManager { ~SerialShapeIOManager(); // send and receive height values - void sendHeightsToShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]); + void sendHeightsToShapeDisplay(const std::vector>& heights); void getHeightsFromShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]); void clearShapeDisplayHeights(int value=0); @@ -106,7 +106,7 @@ class SerialShapeIOManager { SerialPinBoard pinBoards[NUM_ARDUINOS]; // shape display height values (both intended and actual values) - unsigned char heightsForShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> heightsForShapeDisplay; unsigned char heightsFromShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; // pin behavior configurations From 7d2ffba66f7da165aba119ad1fcf448788a45924 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Tue, 4 Jun 2024 23:13:05 -0400 Subject: [PATCH 12/60] don't use copy, just set the one equal to the other it seems to work --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 76020a6..4536892 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -142,9 +142,8 @@ void SerialShapeIOManager::printBoardConfiguration() { //-------------------------------------------------------------- // Set the desired heights for the shape display -void SerialShapeIOManager::sendHeightsToShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) { - unsigned char *src = (unsigned char *) heights; - copy(src, src + SHAPE_DISPLAY_SIZE_2D, (unsigned char *) heightsForShapeDisplay); +void SerialShapeIOManager::sendHeightsToShapeDisplay( const std::vector>& heights ) { + heightsForShapeDisplay = heights; // update display update(); From b0429ab9866a2802189c71322991615b6d744fe6 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 15:28:33 -0400 Subject: [PATCH 13/60] remove the app manager constructor turns out we don't need it after all --- src/AppManager.cpp | 4 ---- src/AppManager.hpp | 1 - 2 files changed, 5 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 0ad82c2..c63bf6a 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -7,10 +7,6 @@ #include "AppManager.hpp" -AppManager::AppManager() { - heightsForShapeDisplay = std::vector>(SHAPE_DISPLAY_SIZE_X, std::vector(SHAPE_DISPLAY_SIZE_Y)); -} - void AppManager::setup(){ ofSetFrameRate(30); diff --git a/src/AppManager.hpp b/src/AppManager.hpp index d2107ef..a9c90f3 100644 --- a/src/AppManager.hpp +++ b/src/AppManager.hpp @@ -45,7 +45,6 @@ class AppManager : public ofBaseApp { public: - AppManager(); void setup(); void update(); From 3a6700158b70ec580340a4795a0255c326871cce Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 15:33:30 -0400 Subject: [PATCH 14/60] heightsForShapeDisplay sized in subclass according to the constants set in the subclass, in this case the TransformIOManager. This way each specific hardware subclass can size the heights array independently --- src/AppManager.cpp | 3 +++ src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 3 --- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 4 ++++ src/ShapeDisplayManagers/TransformIOManager.cpp | 8 ++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index c63bf6a..0574222 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -76,6 +76,9 @@ void AppManager::setupShapeDisplayManagement() { printf("Setting up Shape Display Management\n"); + //m_serialShapeIOManager->shapeDisplaySizeX + // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values + heightsForShapeDisplay = std::vector>(m_serialShapeIOManager->shapeDisplaySizeX, std::vector(m_serialShapeIOManager->shapeDisplaySizeY)); // initialize shape display pin configs PinConfigs pinConfigs; diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 4536892..c6f1f74 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -25,9 +25,6 @@ SerialShapeIOManager::SerialShapeIOManager() { // stuck pin safety toggling can only be implemented if we have height data // from the shape display telling us whether pins are stuck enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; - - // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values - heightsForShapeDisplay.resize(SHAPE_DISPLAY_SIZE_X, std::vector(SHAPE_DISPLAY_SIZE_Y, 0)); // initialize per-pin data arrays for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 6fcec3e..ad044ae 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -69,6 +69,10 @@ class SerialShapeIOManager { // can heights be read from the display? const bool heightsFromShapeDisplayAvailable = SHAPE_DISPLAY_CAN_TALK_BACK; + // Shape display hardware constants, to be initialized by the relevant sub-class. + int shapeDisplaySizeX; + int shapeDisplaySizeY; + protected: // manage the connection to the shape display diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 2c7abd9..aa8b366 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -12,6 +12,14 @@ TransformIOManager::TransformIOManager() { // Set the Transform specific hardware parameters here. + shapeDisplaySizeX = 48; + shapeDisplaySizeY = 24; + + // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. + // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. + heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + + pinHeightMin = 50; pinHeightMax = 210; pinHeightRange = pinHeightMax - pinHeightMin; From f19a4f5c9e7535189c053f9d37a4e3ea2c15cf24 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 15:41:45 -0400 Subject: [PATCH 15/60] heightsForShapeDisplay is setup with zeros so it doesn't need zeroing out. It doesn't have an effect. --- src/AppManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 0574222..376db43 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -94,7 +94,6 @@ void AppManager::setupShapeDisplayManagement() { // clear height and pin config buffers for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - heightsForShapeDisplay[x][y] = 0; heightsFromShapeDisplay[x][y] = 0; pinConfigsForShapeDisplay[x][y] = pinConfigs; } From a16b4a0af69e7db9879c8b3fbf77ed2c71c62528 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 16:01:35 -0400 Subject: [PATCH 16/60] remove commented out code and spacing --- src/AppManager.cpp | 1 - src/AppManager.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 376db43..369c669 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -76,7 +76,6 @@ void AppManager::setupShapeDisplayManagement() { printf("Setting up Shape Display Management\n"); - //m_serialShapeIOManager->shapeDisplaySizeX // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values heightsForShapeDisplay = std::vector>(m_serialShapeIOManager->shapeDisplaySizeX, std::vector(m_serialShapeIOManager->shapeDisplaySizeY)); diff --git a/src/AppManager.hpp b/src/AppManager.hpp index a9c90f3..af51e73 100644 --- a/src/AppManager.hpp +++ b/src/AppManager.hpp @@ -45,7 +45,6 @@ class AppManager : public ofBaseApp { public: - void setup(); void update(); void draw(); From 4dc323e0cc727bc30fac75506d1a7bb557b2498c Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 16:42:27 -0400 Subject: [PATCH 17/60] switch heightFromShapeDisplay to 2d vector from static 2d array --- src/AppManager.cpp | 2 +- src/AppManager.hpp | 2 +- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 9 ++++----- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 4 ++-- src/ShapeDisplayManagers/TransformIOManager.cpp | 3 ++- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 369c669..6bf1a6d 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -78,6 +78,7 @@ void AppManager::setupShapeDisplayManagement() { // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values heightsForShapeDisplay = std::vector>(m_serialShapeIOManager->shapeDisplaySizeX, std::vector(m_serialShapeIOManager->shapeDisplaySizeY)); + heightsFromShapeDisplay = std::vector>(m_serialShapeIOManager->shapeDisplaySizeX, std::vector(m_serialShapeIOManager->shapeDisplaySizeY)); // initialize shape display pin configs PinConfigs pinConfigs; @@ -93,7 +94,6 @@ void AppManager::setupShapeDisplayManagement() { // clear height and pin config buffers for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - heightsFromShapeDisplay[x][y] = 0; pinConfigsForShapeDisplay[x][y] = pinConfigs; } } diff --git a/src/AppManager.hpp b/src/AppManager.hpp index af51e73..af11d8e 100644 --- a/src/AppManager.hpp +++ b/src/AppManager.hpp @@ -106,7 +106,7 @@ class AppManager : public ofBaseApp { // maybe rename to serialHeightOutput() std::vector> heightsForShapeDisplay; // maybe rename to serialHeightInput() - unsigned char heightsFromShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> heightsFromShapeDisplay; ofPixels heightPixelsForShapeDisplay; ofPixels heightPixelsFromShapeDisplay; PinConfigs pinConfigsForShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index c6f1f74..1273d13 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -30,7 +30,7 @@ SerialShapeIOManager::SerialShapeIOManager() { for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { //heightsForShapeDisplay[x][y] = 0; - heightsFromShapeDisplay[x][y] = 0; + //heightsFromShapeDisplay[x][y] = 0; pinDiscrepancy[x][y] = 0; pinEnabled[x][y] = true; pinStuckSinceTime[x][y] = timeOfLastConfigsRefresh; @@ -53,7 +53,7 @@ SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { //heightsForShapeDisplay[x][y] = 0; - heightsFromShapeDisplay[x][y] = 0; + //heightsFromShapeDisplay[x][y] = 0; pinDiscrepancy[x][y] = 0; pinEnabled[x][y] = true; pinStuckSinceTime[x][y] = timeOfLastConfigsRefresh; @@ -148,13 +148,12 @@ void SerialShapeIOManager::sendHeightsToShapeDisplay( const std::vector>& heights) { if (!heightsFromShapeDisplayAvailable) { throw ("height data from shape display is not available on " + shapeDisplayName); } - unsigned char *src = (unsigned char *) heightsFromShapeDisplay; - copy(src, src + SHAPE_DISPLAY_SIZE_2D, (unsigned char *) heights); + heightsFromShapeDisplay = heights; } // Set a single height for the display. diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index ad044ae..188c4c3 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -37,7 +37,7 @@ class SerialShapeIOManager { // send and receive height values void sendHeightsToShapeDisplay(const std::vector>& heights); - void getHeightsFromShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]); + void getHeightsFromShapeDisplay(const std::vector>& heights); void clearShapeDisplayHeights(int value=0); // setters for pin config values @@ -111,7 +111,7 @@ class SerialShapeIOManager { // shape display height values (both intended and actual values) std::vector> heightsForShapeDisplay; - unsigned char heightsFromShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> heightsFromShapeDisplay; // pin behavior configurations PinConfigs pinConfigs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index aa8b366..b8dec5d 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -18,7 +18,8 @@ TransformIOManager::TransformIOManager() { // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); - + // Also size the array that receives height values from the shape display. + heightsFromShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); pinHeightMin = 50; pinHeightMax = 210; From 914182312f5ff2d4d4917c40e3790bcf87001593 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 16:42:58 -0400 Subject: [PATCH 18/60] remove unnecessary --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 1273d13..4e64f84 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -45,9 +45,6 @@ SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { // stuck pin safety toggling can only be implemented if we have height data // from the shape display telling us whether pins are stuck enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; - - // Size the pin arrays correctly based on the hardware specific dimension, and initialize them with zero values - heightsForShapeDisplay.resize(SHAPE_DISPLAY_SIZE_X, std::vector(SHAPE_DISPLAY_SIZE_Y, 0)); // initialize per-pin data arrays for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { From 22f22afb1c442b2e149ed476d6973df35b1ae686 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 8 Jun 2024 16:46:31 -0400 Subject: [PATCH 19/60] allocate pixels based on serialShapeIO values --- src/AppManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 6bf1a6d..9f0c539 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -99,9 +99,9 @@ void AppManager::setupShapeDisplayManagement() { } // allocate height pixels objects and clear contents - heightPixelsForShapeDisplay.allocate(SHAPE_DISPLAY_SIZE_X, SHAPE_DISPLAY_SIZE_Y, 1); + heightPixelsForShapeDisplay.allocate(m_serialShapeIOManager->shapeDisplaySizeX, m_serialShapeIOManager->shapeDisplaySizeY, 1); heightPixelsForShapeDisplay.set(0); - heightPixelsFromShapeDisplay.allocate(SHAPE_DISPLAY_SIZE_X, SHAPE_DISPLAY_SIZE_Y, 1); + heightPixelsFromShapeDisplay.allocate(m_serialShapeIOManager->shapeDisplaySizeX, m_serialShapeIOManager->shapeDisplaySizeY, 1); heightPixelsFromShapeDisplay.set(0); // allocate shape display graphics container and clear contents From 8f77452aab1426eed2fa83c16218798cf181038a Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 16:09:00 -0400 Subject: [PATCH 20/60] transmute pinConfigsForShapeDisplay to vector from static array. Also removes a potential point of confusion where the property was named pinConfigs, which only differs from the struct name PinConfigs by case. To clear this up, it was renamed to pinConfigsForShapeDisplay using the same naming convention as other properties in the SerialShapeIOManager class. --- src/AppManager.cpp | 9 +++------ src/AppManager.hpp | 2 +- src/Applications/Application.cpp | 5 ++--- src/Applications/Application.hpp | 4 ++-- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 10 +++++----- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 4 ++-- src/ShapeDisplayManagers/ShapeIOManager.hpp | 2 +- src/ShapeDisplayManagers/TransformIOManager.cpp | 14 ++++++++++++++ src/ShapeDisplayManagers/TransformIOManager.hpp | 2 ++ 9 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 9f0c539..14a4183 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -91,12 +91,9 @@ void AppManager::setupShapeDisplayManagement() { m_serialShapeIOManager->setGlobalPinConfigs(pinConfigs); timeOfLastPinConfigsUpdate = elapsedTimeInSeconds(); - // clear height and pin config buffers - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - pinConfigsForShapeDisplay[x][y] = pinConfigs; - } - } + + // Set the dimensions of the pinConfigs + pinConfigsForShapeDisplay.resize(m_serialShapeIOManager->shapeDisplaySizeX, std::vector(m_serialShapeIOManager->shapeDisplaySizeY, pinConfigs)); // allocate height pixels objects and clear contents heightPixelsForShapeDisplay.allocate(m_serialShapeIOManager->shapeDisplaySizeX, m_serialShapeIOManager->shapeDisplaySizeY, 1); diff --git a/src/AppManager.hpp b/src/AppManager.hpp index af11d8e..6e1cfb0 100644 --- a/src/AppManager.hpp +++ b/src/AppManager.hpp @@ -109,7 +109,7 @@ class AppManager : public ofBaseApp { std::vector> heightsFromShapeDisplay; ofPixels heightPixelsForShapeDisplay; ofPixels heightPixelsFromShapeDisplay; - PinConfigs pinConfigsForShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> pinConfigsForShapeDisplay; ofFbo graphicsForShapeDisplay; ofPixels colorPixels; ofPixels depthPixels; diff --git a/src/Applications/Application.cpp b/src/Applications/Application.cpp index 07b29ad..ecd5d73 100644 --- a/src/Applications/Application.cpp +++ b/src/Applications/Application.cpp @@ -30,9 +30,8 @@ void Application::getHeightsForShapeDisplay(ofPixels &heights) { heights = heightsForShapeDisplay; }; -void Application::getPinConfigsForShapeDisplay(PinConfigs configs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) { - PinConfigs *src = (PinConfigs *) pinConfigsForShapeDisplay; - copy(src, src + SHAPE_DISPLAY_SIZE_2D, (PinConfigs *) configs); +void Application::getPinConfigsForShapeDisplay(std::vector>& configs) { + pinConfigsForShapeDisplay = configs; }; void Application::setHeightsFromShapeDisplayRef(const ofPixels *heights) { diff --git a/src/Applications/Application.hpp b/src/Applications/Application.hpp index ac58b91..8f992b3 100644 --- a/src/Applications/Application.hpp +++ b/src/Applications/Application.hpp @@ -23,7 +23,7 @@ class Application { Application(SerialShapeIOManager *theCustomShapeDisplayManager); void getHeightsForShapeDisplay(ofPixels &heights); - void getPinConfigsForShapeDisplay(PinConfigs configs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]); + void getPinConfigsForShapeDisplay(std::vector>& configs); void setHeightsFromShapeDisplayRef(const ofPixels *heights); void setPixelsFromKinectRefs(const ofPixels *colorPixels, const ofPixels *depthPixels); @@ -48,7 +48,7 @@ class Application { protected: ofPixels heightsForShapeDisplay; - PinConfigs pinConfigsForShapeDisplay[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> pinConfigsForShapeDisplay; const ofPixels *heightsFromShapeDisplay; bool hasHeightsFromShapeDisplay = false; diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 4e64f84..d126c5b 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -173,10 +173,10 @@ void SerialShapeIOManager::clearShapeDisplayHeights(int value) { // //-------------------------------------------------------------- -void SerialShapeIOManager::setPinConfigs(PinConfigs configs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) { +void SerialShapeIOManager::setPinConfigs(std::vector>& configs) { for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - pinConfigs[x][y] = configs[x][y]; + pinConfigsForShapeDisplay[x][y] = configs[x][y]; } } } @@ -184,7 +184,7 @@ void SerialShapeIOManager::setPinConfigs(PinConfigs configs[SHAPE_DISPLAY_SIZE_X void SerialShapeIOManager::setGlobalPinConfigs(PinConfigs configs) { for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - pinConfigs[x][y] = configs; + pinConfigsForShapeDisplay[x][y] = configs; } } } @@ -259,8 +259,8 @@ void SerialShapeIOManager::readyDataForArduinos() { pinBoards[i].heights[j] = heightsForShapeDisplay[x][y]; // if they've been updated, copy the pin configs to the board - if (pinBoards[i].configs[j].timeOfUpdate < pinConfigs[x][y].timeOfUpdate) { - pinBoards[i].configs[j] = pinConfigs[x][y]; + if (pinBoards[i].configs[j].timeOfUpdate < pinConfigsForShapeDisplay[x][y].timeOfUpdate) { + pinBoards[i].configs[j] = pinConfigsForShapeDisplay[x][y]; pinBoards[i].timeOfLastConfigsUpdate = elapsedTimeInSeconds(); } diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 188c4c3..d076e53 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -41,7 +41,7 @@ class SerialShapeIOManager { void clearShapeDisplayHeights(int value=0); // setters for pin config values - void setPinConfigs(PinConfigs configs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]); + void setPinConfigs(std::vector>& configs); void setGlobalPinConfigs(PinConfigs configs); // should pins that appear stuck be turned off at regular intervals? @@ -114,7 +114,7 @@ class SerialShapeIOManager { std::vector> heightsFromShapeDisplay; // pin behavior configurations - PinConfigs pinConfigs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> pinConfigsForShapeDisplay; // initialization flags bool boardsAreConfigured = false; diff --git a/src/ShapeDisplayManagers/ShapeIOManager.hpp b/src/ShapeDisplayManagers/ShapeIOManager.hpp index 209478f..3db4a23 100644 --- a/src/ShapeDisplayManagers/ShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/ShapeIOManager.hpp @@ -26,7 +26,7 @@ class ShapeIOManager { virtual void clearShapeDisplayHeights(int value=0) = 0; // setters for pin config values - virtual void setPinConfigs(PinConfigs configs[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) = 0; + virtual void setPinConfigs(std::vector>& configs) = 0; virtual void setGlobalPinConfigs(PinConfigs configs) = 0; //virtual ofPixels getPinPixelsOnly(ofPixels fullPixels); diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index b8dec5d..43b7a77 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -32,6 +32,20 @@ TransformIOManager::TransformIOManager() { deadZone = 2; maxSpeed = 200; + // Make a new PinConfigs struct instance with the default values. + PinConfigs defaultPinConfigs; + defaultPinConfigs.timeOfUpdate = 0; + defaultPinConfigs.gainP = gainP; + defaultPinConfigs.gainI = gainI; + defaultPinConfigs.maxI = maxI; + defaultPinConfigs.deadZone = deadZone; + defaultPinConfigs.maxSpeed = maxSpeed; + + + + // Set the dimensions of the pinConfigs + pinConfigsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, defaultPinConfigs)); + // Add serial connection strings to the vector of serial connections. serialPorts.push_back("/dev/tty.usbserial-A702YMNV"); serialPorts.push_back("/dev/tty.usbserial-A702YLM2"); diff --git a/src/ShapeDisplayManagers/TransformIOManager.hpp b/src/ShapeDisplayManagers/TransformIOManager.hpp index 7662eb6..36e07e8 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.hpp +++ b/src/ShapeDisplayManagers/TransformIOManager.hpp @@ -13,6 +13,8 @@ #include "constants.h" #include "SerialShapeIOManager.hpp" +#include "PinConfigs.h" + class TransformIOManager : public SerialShapeIOManager { public: TransformIOManager(); From 09d0ca33924cf54e99fcf215fc55f6c1583a383a Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 10 Jun 2024 18:08:49 -0400 Subject: [PATCH 21/60] allocate heights and drawing buffer --- src/Applications/Application.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Applications/Application.cpp b/src/Applications/Application.cpp index ecd5d73..8f9507a 100644 --- a/src/Applications/Application.cpp +++ b/src/Applications/Application.cpp @@ -14,11 +14,13 @@ Application::Application() { }; Application::Application(SerialShapeIOManager *theCustomShapeDisplayManager){ - heightsForShapeDisplay.allocate(SHAPE_DISPLAY_SIZE_X, SHAPE_DISPLAY_SIZE_Y, OF_IMAGE_GRAYSCALE); - heightsForShapeDisplay.set(0); - heightsDrawingBuffer.allocate(SHAPE_DISPLAY_SIZE_X, SHAPE_DISPLAY_SIZE_Y); m_CustomShapeDisplayManager = theCustomShapeDisplayManager; + + heightsForShapeDisplay.allocate(theCustomShapeDisplayManager->shapeDisplaySizeX, theCustomShapeDisplayManager->shapeDisplaySizeY, OF_IMAGE_GRAYSCALE); + heightsForShapeDisplay.set(0); + heightsDrawingBuffer.allocate(theCustomShapeDisplayManager->shapeDisplaySizeX, theCustomShapeDisplayManager->shapeDisplaySizeY); + } void Application::setRefForShapeIOManager(SerialShapeIOManager* customIOManager){ From 7fe0698cacfdac0fbe3113109b6ab1e10fc8d03c Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 16:46:26 -0400 Subject: [PATCH 22/60] use constructor to pass custom shape display object to the VideoPlayer app. This makes a separate method to set the reference to the custom shape display object unecessary. --- src/AppManager.cpp | 3 +-- src/Applications/VideoPlayerApp.cpp | 4 ++++ src/Applications/VideoPlayerApp.hpp | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 14a4183..561aa02 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -32,8 +32,7 @@ void AppManager::setup(){ mqttApp->setRefForShapeIOManager(m_serialShapeIOManager); applications["mqttTransmission"] = mqttApp; - videoPlayerApp = new VideoPlayerApp(); - videoPlayerApp->setRefForShapeIOManager(m_serialShapeIOManager); + videoPlayerApp = new VideoPlayerApp(m_serialShapeIOManager); applications["videoPlayer"] = videoPlayerApp; videoPlayerApp->setup(); diff --git a/src/Applications/VideoPlayerApp.cpp b/src/Applications/VideoPlayerApp.cpp index b2fa431..c09442f 100755 --- a/src/Applications/VideoPlayerApp.cpp +++ b/src/Applications/VideoPlayerApp.cpp @@ -7,6 +7,10 @@ #include "VideoPlayerApp.hpp" +VideoPlayerApp::VideoPlayerApp(SerialShapeIOManager *theCustomShapeDisplayManager) : Application(theCustomShapeDisplayManager) { + cout << "VideoPlayerApp constructor\n"; +} + void VideoPlayerApp::setup() { //setupTransformedPixelMap(); video.load("escher-5-slow.mov"); diff --git a/src/Applications/VideoPlayerApp.hpp b/src/Applications/VideoPlayerApp.hpp index c22287c..94871a6 100755 --- a/src/Applications/VideoPlayerApp.hpp +++ b/src/Applications/VideoPlayerApp.hpp @@ -13,6 +13,7 @@ class VideoPlayerApp : public Application { public: + VideoPlayerApp(SerialShapeIOManager *theCustomShapeDisplayManager); void setup(); void update(float dt); void drawGraphicsForShapeDisplay(int x, int y, int width, int height); From 24c6cdb113c53fc2bd1adef3e7025cdd525e151c Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 17:04:12 -0400 Subject: [PATCH 23/60] switch AxisCheckerApp to constructor based shape display setup --- src/AppManager.cpp | 3 +-- src/Applications/DebuggingApps/AxisCheckerApp.cpp | 3 +++ src/Applications/DebuggingApps/AxisCheckerApp.hpp | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 561aa02..a7e5be0 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -38,8 +38,7 @@ void AppManager::setup(){ // set up debugging application // and the debugging apps, too - axisCheckerApp = new AxisCheckerApp(); - axisCheckerApp->setRefForShapeIOManager(m_serialShapeIOManager); + axisCheckerApp = new AxisCheckerApp(m_serialShapeIOManager); applications["axisChecker"] = axisCheckerApp; kinectDebugApp = new KinectDebugApp(kinectManager); diff --git a/src/Applications/DebuggingApps/AxisCheckerApp.cpp b/src/Applications/DebuggingApps/AxisCheckerApp.cpp index 9bf8ef1..7ad34d6 100644 --- a/src/Applications/DebuggingApps/AxisCheckerApp.cpp +++ b/src/Applications/DebuggingApps/AxisCheckerApp.cpp @@ -7,6 +7,9 @@ #include "AxisCheckerApp.hpp" +AxisCheckerApp::AxisCheckerApp(SerialShapeIOManager *theSerialShapeIOManager) : Application(theSerialShapeIOManager) { + cout << "AxisCheckerApp constructor" << endl; +} void AxisCheckerApp::update(float dt) { normalizedPhase += dt * 0.5; diff --git a/src/Applications/DebuggingApps/AxisCheckerApp.hpp b/src/Applications/DebuggingApps/AxisCheckerApp.hpp index a05863b..c768149 100644 --- a/src/Applications/DebuggingApps/AxisCheckerApp.hpp +++ b/src/Applications/DebuggingApps/AxisCheckerApp.hpp @@ -15,6 +15,7 @@ class AxisCheckerApp : public Application { public: + AxisCheckerApp(SerialShapeIOManager *theCustomShapeDisplayManager); void update(float dt); void drawGraphicsForShapeDisplay(int x, int y, int width, int height); string appInstructionsText(); From 1a0167e954461e43ab3970962042016785b59304 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 17:06:14 -0400 Subject: [PATCH 24/60] switch axis checker app to use new dimensions from the custom shape display manager --- .../DebuggingApps/AxisCheckerApp.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Applications/DebuggingApps/AxisCheckerApp.cpp b/src/Applications/DebuggingApps/AxisCheckerApp.cpp index 7ad34d6..73e4f8b 100644 --- a/src/Applications/DebuggingApps/AxisCheckerApp.cpp +++ b/src/Applications/DebuggingApps/AxisCheckerApp.cpp @@ -14,20 +14,20 @@ AxisCheckerApp::AxisCheckerApp(SerialShapeIOManager *theSerialShapeIOManager) : void AxisCheckerApp::update(float dt) { normalizedPhase += dt * 0.5; tally++; - tally %= SHAPE_DISPLAY_SIZE_X + SHAPE_DISPLAY_SIZE_Y; + tally %= m_CustomShapeDisplayManager->shapeDisplaySizeX + m_CustomShapeDisplayManager->shapeDisplaySizeY; updateHeights(); } void AxisCheckerApp::updateHeights() { if (checkerboard) { - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { int height; - if (x < SHAPE_DISPLAY_SIZE_X / 2 && y < SHAPE_DISPLAY_SIZE_Y / 2) { + if (x < m_CustomShapeDisplayManager->shapeDisplaySizeX / 2 && y < m_CustomShapeDisplayManager->shapeDisplaySizeY / 2) { height = 40; - } else if (x < SHAPE_DISPLAY_SIZE_X / 2) { + } else if (x < m_CustomShapeDisplayManager->shapeDisplaySizeX / 2) { height = 250; - } else if (y < SHAPE_DISPLAY_SIZE_Y / 2) { + } else if (y < m_CustomShapeDisplayManager->shapeDisplaySizeY / 2) { height = 110; } else { height = 180; @@ -37,13 +37,13 @@ void AxisCheckerApp::updateHeights() { } } } else { - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { int height; - if (tally < SHAPE_DISPLAY_SIZE_X) { + if (tally < m_CustomShapeDisplayManager->shapeDisplaySizeX) { height = x == tally ? 255 : 0; } else { - height = SHAPE_DISPLAY_SIZE_X + y == tally ? 255 : 0; + height = m_CustomShapeDisplayManager->shapeDisplaySizeX + y == tally ? 255 : 0; } int xy = heightsForShapeDisplay.getPixelIndex(x, y); heightsForShapeDisplay[xy] = height; From 65521991a10ece78cfcdaeb6608e98dde03073de Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 17:08:31 -0400 Subject: [PATCH 25/60] switch mqtt app to constructor based shape display initialization --- src/AppManager.cpp | 3 +-- src/Applications/MqttTransmissionApp.cpp | 3 +++ src/Applications/MqttTransmissionApp.hpp | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index a7e5be0..ace8a87 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -28,8 +28,7 @@ void AppManager::setup(){ timeOfLastUpdate = elapsedTimeInSeconds(); // set up applications - mqttApp = new MqttTransmissionApp(); - mqttApp->setRefForShapeIOManager(m_serialShapeIOManager); + mqttApp = new MqttTransmissionApp(m_serialShapeIOManager); applications["mqttTransmission"] = mqttApp; videoPlayerApp = new VideoPlayerApp(m_serialShapeIOManager); diff --git a/src/Applications/MqttTransmissionApp.cpp b/src/Applications/MqttTransmissionApp.cpp index 68023c0..704f126 100644 --- a/src/Applications/MqttTransmissionApp.cpp +++ b/src/Applications/MqttTransmissionApp.cpp @@ -13,6 +13,9 @@ #include #include +MqttTransmissionApp::MqttTransmissionApp(SerialShapeIOManager *theSerialShapeIOManager) : Application(theSerialShapeIOManager) { + cout << "MqttTransmissionApp constructor\n"; +} // zero matrix for reset std::string doob = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; diff --git a/src/Applications/MqttTransmissionApp.hpp b/src/Applications/MqttTransmissionApp.hpp index 566d30f..fe5ac71 100644 --- a/src/Applications/MqttTransmissionApp.hpp +++ b/src/Applications/MqttTransmissionApp.hpp @@ -14,6 +14,7 @@ class MqttTransmissionApp : public Application { public: + MqttTransmissionApp(SerialShapeIOManager *theCustomShapeDisplayManager); void update(float dt); void drawGraphicsForShapeDisplay(int x, int y, int width, int height); string appInstructionsText(); From 5e95dcb9b82292d6bf2e09d965abc28076323091 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 17:11:09 -0400 Subject: [PATCH 26/60] :pencil: adjust comment --- src/ShapeDisplayManagers/TransformIOManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 43b7a77..a6f42c2 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -43,7 +43,7 @@ TransformIOManager::TransformIOManager() { - // Set the dimensions of the pinConfigs + // Set the dimensions of the pinConfigs, and set all the elements to the defaultPinConfigs struct. pinConfigsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, defaultPinConfigs)); // Add serial connection strings to the vector of serial connections. From dcf6ded320ef27e28c6c4997cf2046937988fcca Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 17:56:48 -0400 Subject: [PATCH 27/60] use custom display dimensions --- src/Applications/KinectHandWavy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/KinectHandWavy.cpp b/src/Applications/KinectHandWavy.cpp index ba2d3cd..6779b8f 100644 --- a/src/Applications/KinectHandWavy.cpp +++ b/src/Applications/KinectHandWavy.cpp @@ -120,9 +120,9 @@ void KinectHandWavy::updateHeights() { ofPixels livePixels = m_CustomShapeDisplayManager->cropToActiveSurface( blurredDepthImg.getPixels() ); // Process the inputs and updates the 'heightsForShapeDisplay' property accordingly. - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { // This takes the 2 dimensional coordinates and turns them into a one dimensional index for the flattened array. int flattenedIndex = heightsForShapeDisplay.getPixelIndex(x, y); From 5eddb6d80c3d58426d4abe92532b2358d32df7e3 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 18:15:21 -0400 Subject: [PATCH 28/60] fix destructor --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 4 ---- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index d126c5b..7619ec1 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -64,10 +64,6 @@ SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { m_kinectManagerRef = kinectRef; } -// Destructor -SerialShapeIOManager::~SerialShapeIOManager() { - disconnectFromDisplay(); -} // Connect to the display void SerialShapeIOManager::connectToDisplay() { diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index d076e53..f857e7d 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -33,7 +33,10 @@ class SerialShapeIOManager { public: SerialShapeIOManager(); SerialShapeIOManager(KinectManager* kinectRef); - ~SerialShapeIOManager(); + // Destructor + virtual ~SerialShapeIOManager(){ + disconnectFromDisplay(); + }; // send and receive height values void sendHeightsToShapeDisplay(const std::vector>& heights); From 4eae6411abea07809cb8640df7a3290ab8a14139 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 18:18:56 -0400 Subject: [PATCH 29/60] use dimensions from custom shape display --- src/Applications/VideoPlayerApp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Applications/VideoPlayerApp.cpp b/src/Applications/VideoPlayerApp.cpp index c09442f..1370a48 100755 --- a/src/Applications/VideoPlayerApp.cpp +++ b/src/Applications/VideoPlayerApp.cpp @@ -33,9 +33,9 @@ void VideoPlayerApp::updateHeights() { // Pass the current video frame to the shape display manager to get the actuated pixels. ofPixels livePixels = m_CustomShapeDisplayManager->cropToActiveSurface(m_videoPixels); - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { // This takes the 2 dimensional coordinates and turns them into a one dimensional index for the flattened array. int flattenedIndex = heightsForShapeDisplay.getPixelIndex(x, y); From ec15b0a779634bc0d84a7756efc234a666fddb19 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 20:17:10 -0400 Subject: [PATCH 30/60] use constructor to setup shape manager --- src/AppManager.cpp | 3 +-- src/Applications/DebuggingApps/KinectDebugApp.cpp | 7 +++++++ src/Applications/DebuggingApps/KinectDebugApp.hpp | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index ace8a87..9d39432 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -40,8 +40,7 @@ void AppManager::setup(){ axisCheckerApp = new AxisCheckerApp(m_serialShapeIOManager); applications["axisChecker"] = axisCheckerApp; - kinectDebugApp = new KinectDebugApp(kinectManager); - kinectDebugApp->setRefForShapeIOManager(m_serialShapeIOManager); + kinectDebugApp = new KinectDebugApp(m_serialShapeIOManager, kinectManager); applications["kinectDebug"] = kinectDebugApp; depthDebugApp = new DepthDebugApp(); diff --git a/src/Applications/DebuggingApps/KinectDebugApp.cpp b/src/Applications/DebuggingApps/KinectDebugApp.cpp index 3314f71..b8c90c7 100644 --- a/src/Applications/DebuggingApps/KinectDebugApp.cpp +++ b/src/Applications/DebuggingApps/KinectDebugApp.cpp @@ -21,6 +21,13 @@ KinectDebugApp::KinectDebugApp(KinectManager* kinectManager){ } +KinectDebugApp::KinectDebugApp(SerialShapeIOManager *theCustomShapeDisplayManager, KinectManager *theKinectManager) : Application( theCustomShapeDisplayManager ) { + m_kinectManager = theKinectManager; + + setupDepthFloorMap(); + +} + void KinectDebugApp::setup() { setupDepthFloorMap(); } diff --git a/src/Applications/DebuggingApps/KinectDebugApp.hpp b/src/Applications/DebuggingApps/KinectDebugApp.hpp index e1c0307..858f81b 100644 --- a/src/Applications/DebuggingApps/KinectDebugApp.hpp +++ b/src/Applications/DebuggingApps/KinectDebugApp.hpp @@ -20,6 +20,7 @@ class KinectDebugApp : public Application{ public: KinectDebugApp(KinectManager* kinectManager); + KinectDebugApp(SerialShapeIOManager *theCustomShapeDisplayManager, KinectManager *theKinectManager); void setup(); void update(float dt); From 97ea797764bbadf3d9a0d8ab548d4ec39f29c608 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 20:47:21 -0400 Subject: [PATCH 31/60] use constructor to setup shape display --- src/AppManager.cpp | 3 +-- src/Applications/DebuggingApps/DepthDebugApp.cpp | 3 +++ src/Applications/DebuggingApps/DepthDebugApp.hpp | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 9d39432..f058ade 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -43,8 +43,7 @@ void AppManager::setup(){ kinectDebugApp = new KinectDebugApp(m_serialShapeIOManager, kinectManager); applications["kinectDebug"] = kinectDebugApp; - depthDebugApp = new DepthDebugApp(); - depthDebugApp->setRefForShapeIOManager(m_serialShapeIOManager); + depthDebugApp = new DepthDebugApp(m_serialShapeIOManager); applications["depthDebug"] = depthDebugApp; kinectHandWavy = new KinectHandWavy(m_serialShapeIOManager,kinectManager); diff --git a/src/Applications/DebuggingApps/DepthDebugApp.cpp b/src/Applications/DebuggingApps/DepthDebugApp.cpp index 196ecb3..e2d0cba 100644 --- a/src/Applications/DebuggingApps/DepthDebugApp.cpp +++ b/src/Applications/DebuggingApps/DepthDebugApp.cpp @@ -7,6 +7,9 @@ #include "DepthDebugApp.hpp" +DepthDebugApp::DepthDebugApp(SerialShapeIOManager *theCustomShapeDisplayManager) : Application(theCustomShapeDisplayManager) { + cout << "DepthDebugApp constructor" << endl; +} void DepthDebugApp::update(float dt) { cout << "hello there debug depth"; diff --git a/src/Applications/DebuggingApps/DepthDebugApp.hpp b/src/Applications/DebuggingApps/DepthDebugApp.hpp index e013a51..eb3fa38 100644 --- a/src/Applications/DebuggingApps/DepthDebugApp.hpp +++ b/src/Applications/DebuggingApps/DepthDebugApp.hpp @@ -15,6 +15,8 @@ class DepthDebugApp : public Application { public: + DepthDebugApp(SerialShapeIOManager *theCustomShapeDisplayManager); + void update(float dt); void drawGraphicsForShapeDisplay(int x, int y, int width, int height); string appInstructionsText(); From 5b0c427998f8fbbb70abf1e968f0555c8bb2e2d1 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 20:57:05 -0400 Subject: [PATCH 32/60] remove allocation with static constants this has been moved to the constructor that takes a shape display manager as a parameter. That way the allocations can be made with the dimension of the passed shape display manager --- src/Applications/Application.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Applications/Application.cpp b/src/Applications/Application.cpp index 8f9507a..222590e 100644 --- a/src/Applications/Application.cpp +++ b/src/Applications/Application.cpp @@ -8,9 +8,7 @@ #include "Application.hpp" Application::Application() { - heightsForShapeDisplay.allocate(SHAPE_DISPLAY_SIZE_X, SHAPE_DISPLAY_SIZE_Y, OF_IMAGE_GRAYSCALE); - heightsForShapeDisplay.set(0); - heightsDrawingBuffer.allocate(SHAPE_DISPLAY_SIZE_X, SHAPE_DISPLAY_SIZE_Y); + // Default constructor }; Application::Application(SerialShapeIOManager *theCustomShapeDisplayManager){ From aa3762a927bb68569dd780d5344202e371cdd77c Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 21:26:09 -0400 Subject: [PATCH 33/60] replace globals with local properties --- src/ShapeDisplayManagers/TransformIOManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index a6f42c2..3a20a6a 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -110,8 +110,8 @@ void TransformIOManager::configureBoards() { for (int j = 0; j < NUM_PINS_ARDUINO; j++) { unsigned char j0 = pinBoards[i].pinCoordinates[j][0]; unsigned char j1 = pinBoards[i].pinCoordinates[j][1]; - pinBoards[i].pinCoordinates[j][0] = SHAPE_DISPLAY_SIZE_X - 1 - j0; - pinBoards[i].pinCoordinates[j][1] = SHAPE_DISPLAY_SIZE_Y - 1 - j1; + pinBoards[i].pinCoordinates[j][0] = shapeDisplaySizeX - 1 - j0; + pinBoards[i].pinCoordinates[j][1] = shapeDisplaySizeY - 1 - j1; } } From f037881cea736ea444cc0eb5ebbcb79fa708fb42 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 9 Jun 2024 21:28:04 -0400 Subject: [PATCH 34/60] use dimensions from shape IO instead of hardcoded globals --- src/AppManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index f058ade..8fbf6bd 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -119,8 +119,8 @@ void AppManager::update(){ // note: manually looping over all pixels is important! the underlying // ofPixels char array is stored as unsigned char[y][x], while the // shape display heights are stored as unsigned char[x][y] - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < m_serialShapeIOManager->shapeDisplaySizeX; x++) { + for (int y = 0; y < m_serialShapeIOManager->shapeDisplaySizeY; y++) { int xy = heightPixelsFromShapeDisplay.getPixelIndex(x, y); heightPixelsFromShapeDisplay[xy] = heightsFromShapeDisplay[x][y]; } @@ -136,8 +136,8 @@ void AppManager::update(){ // note: manually looping over all pixels is important! the underlying // ofPixels char array is stored as unsigned char[y][x], while the // shape display heights are stored as unsigned char[x][y] - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < m_serialShapeIOManager->shapeDisplaySizeX; x++) { + for (int y = 0; y < m_serialShapeIOManager->shapeDisplaySizeY; y++) { int xy = heightPixelsForShapeDisplay.getPixelIndex(x, y); heightsForShapeDisplay[x][y] = heightPixelsForShapeDisplay[xy]; } From 767a33da1b5caa58e5a2c26e3d6bb403a0b13fae Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:18:14 -0400 Subject: [PATCH 35/60] get the shape display dimension from the class instance not from globals --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 7619ec1..532d685 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -177,9 +177,11 @@ void SerialShapeIOManager::setPinConfigs(std::vector>& c } } +// Set all of the values of pinConfigsForShapeDisplay to the same value, passed as the configs parameter. +// I can't really say why this is necessary, but the boards don't get the right configs without it. void SerialShapeIOManager::setGlobalPinConfigs(PinConfigs configs) { - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < shapeDisplaySizeX; x++) { + for (int y = 0; y < shapeDisplaySizeY; y++) { pinConfigsForShapeDisplay[x][y] = configs; } } From e12a41e98133a9d566c22195098d9d7e4e8ae912 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:24:25 -0400 Subject: [PATCH 36/60] patch potentially unnecessary code --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 532d685..5aea4b4 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -169,9 +169,10 @@ void SerialShapeIOManager::clearShapeDisplayHeights(int value) { // //-------------------------------------------------------------- +// This may be unecessary, it's no different from setGlobalPinConfigs and it never seems to be called. void SerialShapeIOManager::setPinConfigs(std::vector>& configs) { - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < shapeDisplaySizeX; x++) { + for (int y = 0; y < shapeDisplaySizeY; y++) { pinConfigsForShapeDisplay[x][y] = configs[x][y]; } } From 92224221f9d742b6af708e23a0fc260f8fce3829 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:35:21 -0400 Subject: [PATCH 37/60] convert pin detail arrays to vectors that are resized with default values --- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 7 ++++--- src/ShapeDisplayManagers/TransformIOManager.cpp | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index f857e7d..d4c7696 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -128,9 +128,10 @@ class SerialShapeIOManager { double timeOfLastConfigsRefresh; // properties for detecting stuck pins to toggle - int pinDiscrepancy[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; - bool pinEnabled[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; - double pinStuckSinceTime[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]; + std::vector> pinDiscrepancy; + std::vector> pinEnabled; + std::vector> pinStuckSinceTime; + const int pinDiscrepancyToggleThreshold = 100; const float secondsUntilPinToggledOff = 1.0; const float secondsUntilPinToggledOn = 3.0; diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 3a20a6a..6acb224 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -46,6 +46,11 @@ TransformIOManager::TransformIOManager() { // Set the dimensions of the pinConfigs, and set all the elements to the defaultPinConfigs struct. pinConfigsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, defaultPinConfigs)); + // Initialize pin tracking vectors. + pinDiscrepancy.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + pinEnabled.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, true)); + pinStuckSinceTime.resize( shapeDisplaySizeX, std::vector(shapeDisplaySizeY, elapsedTimeInSeconds() )); + // Add serial connection strings to the vector of serial connections. serialPorts.push_back("/dev/tty.usbserial-A702YMNV"); serialPorts.push_back("/dev/tty.usbserial-A702YLM2"); From 6e352a5cf7ee645131831ef34a9d5ae3ae3bf25d Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:35:57 -0400 Subject: [PATCH 38/60] remove initializer because the vectors have default values and don't need to be initialized again --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 5aea4b4..26e33a1 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -25,17 +25,6 @@ SerialShapeIOManager::SerialShapeIOManager() { // stuck pin safety toggling can only be implemented if we have height data // from the shape display telling us whether pins are stuck enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; - - // initialize per-pin data arrays - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - //heightsForShapeDisplay[x][y] = 0; - //heightsFromShapeDisplay[x][y] = 0; - pinDiscrepancy[x][y] = 0; - pinEnabled[x][y] = true; - pinStuckSinceTime[x][y] = timeOfLastConfigsRefresh; - } - } } SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { From 3aaf9f80f19b8048fde2275b9043cbb86e2fca42 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:45:17 -0400 Subject: [PATCH 39/60] :fire: remove unnecessary initializer and add comment that the whole constructor function appears to not be necessary, it doesn't get called. --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 26e33a1..17c181b 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -27,6 +27,7 @@ SerialShapeIOManager::SerialShapeIOManager() { enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; } +// This constructor may not be necessary, it doesn't get called. SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { timeOfLastConfigsUpdate = elapsedTimeInSeconds(); timeOfLastConfigsRefresh = elapsedTimeInSeconds(); @@ -35,17 +36,6 @@ SerialShapeIOManager::SerialShapeIOManager(KinectManager* kinectRef) { // from the shape display telling us whether pins are stuck enableStuckPinSafetyToggle = enableStuckPinSafetyToggle && heightsFromShapeDisplayAvailable; - // initialize per-pin data arrays - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { - //heightsForShapeDisplay[x][y] = 0; - //heightsFromShapeDisplay[x][y] = 0; - pinDiscrepancy[x][y] = 0; - pinEnabled[x][y] = true; - pinStuckSinceTime[x][y] = timeOfLastConfigsRefresh; - } - } - // connect to shape display connectToDisplay(); From 5ccbd537368c4905cae17d2253ab25450ca5a26f Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:54:07 -0400 Subject: [PATCH 40/60] patch clipping function to use dimensions from the instantiated subclass --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 17c181b..45a94d8 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -210,8 +210,8 @@ void SerialShapeIOManager::toggleStuckPins() { // Clip all values to fit within the allowed range void SerialShapeIOManager::clipAllHeightValuesToBeWithinRange() { float thresholdScalar = 1.0 * pinHeightRange / 255; - for (int i = 0; i < SHAPE_DISPLAY_SIZE_X; i++) { - for (int j = 0; j < SHAPE_DISPLAY_SIZE_Y; j++) { + for (int i = 0; i < shapeDisplaySizeX; i++) { + for (int j = 0; j < shapeDisplaySizeY; j++) { // to rescale the values instead of clipping them, use this line: //heightsForShapeDisplay[i][j] = heightsForShapeDisplay[i][j] * thresholdScalar + pinHeightMin; From c4ff0efc3e65f918ce31027d07eb210bb66d4dbb Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 17:59:49 -0400 Subject: [PATCH 41/60] use class member values --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 45a94d8..b71de6e 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -133,8 +133,8 @@ void SerialShapeIOManager::getHeightsFromShapeDisplay( const std::vector Date: Sat, 29 Jun 2024 18:12:51 -0400 Subject: [PATCH 42/60] use dimensions from custom shape display --- src/Applications/DebuggingApps/KinectDebugApp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Applications/DebuggingApps/KinectDebugApp.cpp b/src/Applications/DebuggingApps/KinectDebugApp.cpp index b8c90c7..92eb8fb 100644 --- a/src/Applications/DebuggingApps/KinectDebugApp.cpp +++ b/src/Applications/DebuggingApps/KinectDebugApp.cpp @@ -34,9 +34,9 @@ void KinectDebugApp::setup() { void KinectDebugApp::setupDepthFloorMap() { //set all pins to 0 - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { // This takes the 2 dimensional coordinates and turns them into a one dimensional index for the flattened array. int flattenedIndex = heightsForShapeDisplay.getPixelIndex(x, y); @@ -242,9 +242,9 @@ void KinectDebugApp::updateHeights() { float tempSum = 0; - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { // This takes the 2 dimensional coordinates and turns them into a one dimensional index for the flattened array. int flattenedIndex = heightsForShapeDisplay.getPixelIndex(x, y); From ce73a868383a9491dafabf472ecb96b8a3b1de37 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 20:43:13 -0400 Subject: [PATCH 43/60] rough port of mqtt app for vectorization --- src/Applications/MqttTransmissionApp.cpp | 36 +++++++++++++++++------- src/Applications/MqttTransmissionApp.hpp | 2 ++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Applications/MqttTransmissionApp.cpp b/src/Applications/MqttTransmissionApp.cpp index 704f126..2c1ef1f 100644 --- a/src/Applications/MqttTransmissionApp.cpp +++ b/src/Applications/MqttTransmissionApp.cpp @@ -15,6 +15,10 @@ MqttTransmissionApp::MqttTransmissionApp(SerialShapeIOManager *theSerialShapeIOManager) : Application(theSerialShapeIOManager) { cout << "MqttTransmissionApp constructor\n"; + m_CustomShapeDisplayManager = theSerialShapeIOManager; + + theNewHeights.resize( m_CustomShapeDisplayManager->shapeDisplaySizeX * m_CustomShapeDisplayManager->shapeDisplaySizeY ); + } // zero matrix for reset @@ -22,9 +26,9 @@ std::string doob = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 // Helper functions for array piece -int theHeights[SHAPE_DISPLAY_SIZE_X*SHAPE_DISPLAY_SIZE_Y]; +//int theHeights[SHAPE_DISPLAY_SIZE_X*SHAPE_DISPLAY_SIZE_Y]; std::string theStr; -string stringArray[SHAPE_DISPLAY_SIZE_X*SHAPE_DISPLAY_SIZE_Y]; +//string stringArray[SHAPE_DISPLAY_SIZE_X*SHAPE_DISPLAY_SIZE_Y]; string int_array_to_string(int int_array[], int size_of_array) { theStr = ""; @@ -42,13 +46,14 @@ std::vector string_to_int_array(std::string text){ return tokens; } - +/* void updateINTHEIGHTS(std::vector puma){ for (int i=0; i<1152; i++){ //printf("%s",puma.at(i).c_str()); theHeights[i] = stoi(puma.at(i)); } } + */ void MqttTransmissionApp::updateHeights() { //depression = touchDetector->significantDepressionAmidstStabilityPixels(); @@ -67,26 +72,37 @@ void MqttTransmissionApp::updateHeights() { if (string_to_int_array(doob).size() != 1152){ printf ("ERROR!"); printf("%i\n",string_to_int_array(doob).size()); - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { int xy = heightsForShapeDisplay.getPixelIndex(x, y); heightsForShapeDisplay[xy] = 30; } } }else{ - updateINTHEIGHTS(string_to_int_array(doob)); - for (int x = 0; x < SHAPE_DISPLAY_SIZE_X; x++) { - for (int y = 0; y < SHAPE_DISPLAY_SIZE_Y; y++) { + //updateINTHEIGHTS(string_to_int_array(doob)); + std::vector puma = string_to_int_array(doob); + + int flatLength = m_CustomShapeDisplayManager->shapeDisplaySizeX * m_CustomShapeDisplayManager->shapeDisplaySizeY; + + for (int i=0; i< flatLength; i++){ + //printf("%s",puma.at(i).c_str()); + //theHeights[i] = stoi(puma.at(i)); + theNewHeights[i] = stoi(puma.at(i)); + } + + + for (int x = 0; x < m_CustomShapeDisplayManager->shapeDisplaySizeX; x++) { + for (int y = 0; y < m_CustomShapeDisplayManager->shapeDisplaySizeY; y++) { int xy = heightsForShapeDisplay.getPixelIndex(x, y); // if (theHeights[xy] > 193){ // theHeights[xy] = 170; // } - heightsForShapeDisplay[xy] = theHeights[xy]+30;//heightScalar * height + heightOffset; + //heightsForShapeDisplay[xy] = theHeights[xy]+30;//heightScalar * height + heightOffset; - + heightsForShapeDisplay[xy] = theNewHeights[xy]+30; //if {//(heightsForShapeDisplay[xy] != theHeights[xy]){//(depression.getColor(x, y).r != 0) { //heightsForShapeDisplay[xy] = HEIGHT_MAX; diff --git a/src/Applications/MqttTransmissionApp.hpp b/src/Applications/MqttTransmissionApp.hpp index fe5ac71..95b9fdf 100644 --- a/src/Applications/MqttTransmissionApp.hpp +++ b/src/Applications/MqttTransmissionApp.hpp @@ -43,6 +43,8 @@ class MqttTransmissionApp : public Application { int are_we_setup = 0; + std::vector theNewHeights; + //some convenience params std::string m_doob = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; From b6955636db85c6277b3804d7a5e4ed6b6bda11dc Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 20:45:22 -0400 Subject: [PATCH 44/60] remove dimensions from constants --- src/Constants/constants.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/Constants/constants.h b/src/Constants/constants.h index 2f5743a..9eab6d7 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -41,16 +41,7 @@ using namespace std; #define NUM_SERIAL_CONNECTIONS 6 - -// Shape display table -// ------------------- -#define SHAPE_DISPLAY_SIZE_X 48 -#define SHAPE_DISPLAY_SIZE_Y 24 - #define SHAPE_DISPLAY_CAN_TALK_BACK 1 -// shape display derived dimensions, for convenience -#define SHAPE_DISPLAY_SIZE_2D (SHAPE_DISPLAY_SIZE_X * SHAPE_DISPLAY_SIZE_Y) - #endif /* constants_h */ From fd1f76b7d584b4fc7baaadeab60a6faba618bfd1 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 21:58:31 -0400 Subject: [PATCH 45/60] use vector for serialConnections --- .../SerialShapeIOManager.cpp | 17 +++++++---------- .../SerialShapeIOManager.hpp | 4 ++-- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index b71de6e..19584bb 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -74,22 +74,19 @@ void SerialShapeIOManager::disconnectFromDisplay(bool clearHeights) { // close connections isConnected = false; - closeSerialConnections(); + + // No longer necessary, the unique_ptrs will automatically deallocate the objects when the vector is cleared or goes out of scope. + //closeSerialConnections(); } // Open serial connections to the display. Connections close automatically when // destroyed. void SerialShapeIOManager::openSerialConnections() { - for (int i = 0; i < NUM_SERIAL_CONNECTIONS; i++) { - serialConnections[i] = new SerialShapeIO(serialPorts[i], SERIAL_BAUD_RATE, heightsFromShapeDisplayAvailable); - } -} - -// Close all serial connections to the display -void SerialShapeIOManager::closeSerialConnections() { - for (int i = 0; i < NUM_SERIAL_CONNECTIONS; i++) { - delete serialConnections[i]; + for (const auto& port : serialPorts) { + serialConnections.push_back(std::make_unique(port, SERIAL_BAUD_RATE, heightsFromShapeDisplayAvailable)); } + // No need for a closeSerialConnections function, as the unique_ptrs will automatically + // deallocate the objects when the vector is cleared or goes out of scope. } // Print board configuration settings to console for debugging diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index d4c7696..9085475 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -82,7 +82,6 @@ class SerialShapeIOManager { void connectToDisplay(); void disconnectFromDisplay(bool clearHeights=false); void openSerialConnections(); - void closeSerialConnections(); // setup hardware-specific board configuration virtual void configureBoards() = 0; @@ -109,7 +108,8 @@ class SerialShapeIOManager { void readHeightsFromBoards(); // serial communications objects - SerialShapeIO *serialConnections[NUM_SERIAL_CONNECTIONS]; + std::vector> serialConnections; + SerialPinBoard pinBoards[NUM_ARDUINOS]; // shape display height values (both intended and actual values) From fc6e1deea346306ca1dbf3a8a3a9678a46930d66 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 22:11:33 -0400 Subject: [PATCH 46/60] comment out oudated references in a dereferenced file --- src/ShapeDisplayManagers/ShapeIOManager.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/ShapeIOManager.hpp b/src/ShapeDisplayManagers/ShapeIOManager.hpp index 3db4a23..6339320 100644 --- a/src/ShapeDisplayManagers/ShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/ShapeIOManager.hpp @@ -21,8 +21,8 @@ class ShapeIOManager { virtual ~ShapeIOManager() {}; // send and receive height values - virtual void sendHeightsToShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) = 0; - virtual void getHeightsFromShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) = 0; + //virtual void sendHeightsToShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) = 0; + //virtual void getHeightsFromShapeDisplay(unsigned char heights[SHAPE_DISPLAY_SIZE_X][SHAPE_DISPLAY_SIZE_Y]) = 0; virtual void clearShapeDisplayHeights(int value=0) = 0; // setters for pin config values From 491abec7cf4b64a694adfd608ac37bd0db1632b2 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 22:12:50 -0400 Subject: [PATCH 47/60] switch to an iterator since serialConnections is a vector now --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 19584bb..7f22ac7 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -313,8 +313,9 @@ void SerialShapeIOManager::sendValueToAllBoards(unsigned char termId, unsigned c messageContents[i + 2] = (unsigned char) value; } - for (int i = 0; i < NUM_SERIAL_CONNECTIONS; i++) { - serialConnections[i]->writeMessage(messageContents); + // Iterate through all serial connections and send the message to each one. + for (auto& connection : serialConnections) { + connection->writeMessage(messageContents); } } From 0f7cbd6328bcfd96dcbac6c6b52a50ed792d1981 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 22:21:21 -0400 Subject: [PATCH 48/60] dynamically set the iterations based on the size of the serialConnections vector --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 7f22ac7..56d81fb 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -412,7 +412,7 @@ void SerialShapeIOManager::sendAllConfigValues() { // Read actual heights from the boards void SerialShapeIOManager::readHeightsFromBoards() { // receive the current heights on the shape display - for (int i = 0; i < NUM_SERIAL_CONNECTIONS; i++) { + for (size_t i = 0; i < serialConnections.size(); i++) { while (serialConnections[i]->hasNewMessage()) { unsigned char messageContent[MSG_SIZE_RECEIVE]; serialConnections[i]->readMessage(messageContent); From 655254090217b22d8a809e6982db889ebd350439 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 22:24:37 -0400 Subject: [PATCH 49/60] :fire: remove constant for the number of serial connections --- src/Constants/constants.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Constants/constants.h b/src/Constants/constants.h index 9eab6d7..83cf32e 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -39,8 +39,6 @@ using namespace std; #define NUM_ARDUINOS 192 #define NUM_PINS_ARDUINO 6 -#define NUM_SERIAL_CONNECTIONS 6 - #define SHAPE_DISPLAY_CAN_TALK_BACK 1 #endif /* constants_h */ From 755b2632a4f038c5f15f626a038d6a7282b73f0b Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 22:42:26 -0400 Subject: [PATCH 50/60] switch to class based numberOfArduinos --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 14 +++++++------- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 2 ++ src/ShapeDisplayManagers/TransformIOManager.cpp | 4 +++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 56d81fb..60f03eb 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -91,7 +91,7 @@ void SerialShapeIOManager::openSerialConnections() { // Print board configuration settings to console for debugging void SerialShapeIOManager::printBoardConfiguration() { - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { printf("board: %d: ", i); for (int j = 0; j < NUM_PINS_ARDUINO; j++) { printf("%d,%d(%d); ", pinBoards[i].pinCoordinates[j][0], pinBoards[i].pinCoordinates[j][1], pinBoards[i].invertHeight); @@ -225,7 +225,7 @@ void SerialShapeIOManager::clipAllHeightValuesToBeWithinRange() { // Copy data from storage in the 2D array to the corresponding arduino board // structures. Flip height values where needed to match the board's orientation. void SerialShapeIOManager::readyDataForArduinos() { - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { for (int j = 0; j < NUM_PINS_ARDUINO; j++) { int x = pinBoards[i].pinCoordinates[j][0]; int y = pinBoards[i].pinCoordinates[j][1]; @@ -274,12 +274,12 @@ void SerialShapeIOManager::update() { // send height data. if the display talks back, ask it what it's doing if (heightsFromShapeDisplayAvailable) { - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { sendHeightsToBoardAndRequestFeedback(i + 1, pinBoards[i].heights, pinBoards[i].serialConnection); } readHeightsFromBoards(); // gets actual heights from arduino boards } else { - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { sendHeightsToBoard(i + 1, pinBoards[i].heights, pinBoards[i].serialConnection); } } @@ -388,7 +388,7 @@ void SerialShapeIOManager::sendConfigsToBoard(unsigned char boardId, PinConfigs // Send configuration values that have been updated to the display void SerialShapeIOManager::sendUpdatedConfigValues() { - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { if (timeOfLastConfigsUpdate < pinBoards[i].timeOfLastConfigsUpdate) { sendConfigsToBoard(i + 1, pinBoards[i].configs, pinBoards[i].serialConnection); } @@ -402,7 +402,7 @@ void SerialShapeIOManager::sendUpdatedConfigValues() { // that appear broken; invalid values can crop up over time from firmware issues // and connection noise. void SerialShapeIOManager::sendAllConfigValues() { - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { sendConfigsToBoard(i + 1, pinBoards[i].configs, pinBoards[i].serialConnection); } timeOfLastConfigsUpdate = elapsedTimeInSeconds(); @@ -418,7 +418,7 @@ void SerialShapeIOManager::readHeightsFromBoards() { serialConnections[i]->readMessage(messageContent); if (messageContent[0] == TERM_ID_HEIGHT_RECEIVE) { int boardAddress = messageContent[1] - 1; - if (boardAddress >= 0 && boardAddress <= NUM_ARDUINOS) { + if (boardAddress >= 0 && boardAddress <= numberOfArduinos) { for (int j = 0; j < 6; j++) { int height = messageContent[j + 2]; if (pinBoards[boardAddress].invertHeight) { diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 9085475..fc61495 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -76,6 +76,8 @@ class SerialShapeIOManager { int shapeDisplaySizeX; int shapeDisplaySizeY; + int numberOfArduinos; + protected: // manage the connection to the shape display diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 6acb224..318c2d5 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -15,6 +15,8 @@ TransformIOManager::TransformIOManager() { shapeDisplaySizeX = 48; shapeDisplaySizeY = 24; + numberOfArduinos = 192; + // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); @@ -74,7 +76,7 @@ TransformIOManager::TransformIOManager(KinectManager* kinectRef) : TransformIOMa // setup transFORM-specific board configuration void TransformIOManager::configureBoards() { // set up coordinates for - for (int i = 0; i < NUM_ARDUINOS; i++) { + for (int i = 0; i < numberOfArduinos; i++) { // determine which serial connection each board is on: // every 3rd and 4th board is on the second if (i < 64) { From 59b6a74cb58292f9b6c122519f453677f79fc6d5 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 23:07:04 -0400 Subject: [PATCH 51/60] switch pinBoards to vector --- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 2 +- src/ShapeDisplayManagers/TransformIOManager.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index fc61495..9f7dc37 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -112,7 +112,7 @@ class SerialShapeIOManager { // serial communications objects std::vector> serialConnections; - SerialPinBoard pinBoards[NUM_ARDUINOS]; + std::vector pinBoards; // shape display height values (both intended and actual values) std::vector> heightsForShapeDisplay; diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index 318c2d5..a439553 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -17,6 +17,9 @@ TransformIOManager::TransformIOManager() { numberOfArduinos = 192; + // Size the pinBoards vector appropriately. + pinBoards.resize(numberOfArduinos); + // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); From 9e6386fc9fdf84848ade770b33965d845018ea82 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sat, 29 Jun 2024 23:15:50 -0400 Subject: [PATCH 52/60] :fire: remove constant for number of arduinos --- src/Constants/constants.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Constants/constants.h b/src/Constants/constants.h index 83cf32e..892034e 100644 --- a/src/Constants/constants.h +++ b/src/Constants/constants.h @@ -36,7 +36,6 @@ using namespace std; // Transform specific constants -#define NUM_ARDUINOS 192 #define NUM_PINS_ARDUINO 6 #define SHAPE_DISPLAY_CAN_TALK_BACK 1 From 847a51e9d98f0c034f06634e3be9b185a2bf9ccc Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Sun, 30 Jun 2024 19:30:58 -0400 Subject: [PATCH 53/60] use class properties instead of hardcoding the dimensions --- src/ShapeDisplayManagers/TransformIOManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ShapeDisplayManagers/TransformIOManager.cpp b/src/ShapeDisplayManagers/TransformIOManager.cpp index a439553..ec8140e 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.cpp +++ b/src/ShapeDisplayManagers/TransformIOManager.cpp @@ -155,7 +155,7 @@ ofPixels TransformIOManager::cropToActiveSurface( ofPixels fullSurface ) { ofPixels combinedActiveZones = combineActiveZones(fullSurface, sections); // Scale and rotate the combined active zones - combinedActiveZones.resize(48, 24); + combinedActiveZones.resize(shapeDisplaySizeX, shapeDisplaySizeY); combinedActiveZones.rotate90(2); // Return the cropped and transformed image From 88127228f5fecd8afb811172d2075b0d4768a424 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 1 Jul 2024 11:00:15 -0400 Subject: [PATCH 54/60] change shape display name to a virtual getter method. Turns out it is much easier to deal with inheritance in C++ for a method than it is for a property --- src/ShapeDisplayManagers/SerialShapeIOManager.cpp | 2 +- src/ShapeDisplayManagers/SerialShapeIOManager.hpp | 3 +-- src/ShapeDisplayManagers/TransformIOManager.hpp | 11 ++++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp index 60f03eb..35b734c 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.cpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.cpp @@ -119,7 +119,7 @@ void SerialShapeIOManager::sendHeightsToShapeDisplay( const std::vector>& heights) { if (!heightsFromShapeDisplayAvailable) { - throw ("height data from shape display is not available on " + shapeDisplayName); + throw ("height data from shape display is not available on " + getShapeDisplayName()); } heightsFromShapeDisplay = heights; diff --git a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp index 9f7dc37..d932323 100644 --- a/src/ShapeDisplayManagers/SerialShapeIOManager.hpp +++ b/src/ShapeDisplayManagers/SerialShapeIOManager.hpp @@ -50,8 +50,7 @@ class SerialShapeIOManager { // should pins that appear stuck be turned off at regular intervals? bool enableStuckPinSafetyToggle = false; - // the name of this shape display - string shapeDisplayName = "Serial Shape Display"; + virtual string getShapeDisplayName() { return "Shape Display Name"; } // Dan and Jonathan Custom API-like commands virtual ofPixels getKinectStream(){return feebsTEMP;} diff --git a/src/ShapeDisplayManagers/TransformIOManager.hpp b/src/ShapeDisplayManagers/TransformIOManager.hpp index 36e07e8..609d611 100644 --- a/src/ShapeDisplayManagers/TransformIOManager.hpp +++ b/src/ShapeDisplayManagers/TransformIOManager.hpp @@ -21,13 +21,14 @@ class TransformIOManager : public SerialShapeIOManager { TransformIOManager(KinectManager* kinectRef); - // should pins that appear stuck be turned off at regular intervals? - bool enableStuckPinSafetyToggle = false; - // the name of this shape display - string shapeDisplayName = "transFORM"; + string getShapeDisplayName() { + // This is a method instead of a property only to simplify the inheritance by making the superclass declaration virtual. + return "TRANSFORM"; + } - void sendHeightsToShapeDisplay(); + // should pins that appear stuck be turned off at regular intervals? + bool enableStuckPinSafetyToggle = false; ofPixels getKinectStream(); From 7e735078afa9072ae71ee7ae29e26f10b562178d Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 1 Jul 2024 11:02:31 -0400 Subject: [PATCH 55/60] make a conditional choice of serialShapeIOManagers based on a simple static string. This gives us a straightforward was to designate which shape display hardware we are working with --- src/AppManager.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 8fbf6bd..6d619b5 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -67,7 +67,15 @@ void AppManager::setup(){ void AppManager::setupShapeDisplayManagement() { // initialize communication with the shape display // This is where the particulars of the shape display are set (i.e. TRANSFORM, inFORM, or any other physical layout). - m_serialShapeIOManager = new TransformIOManager(kinectManager); + string shapeDisplayToUse = "TRANSFORM"; + + if (shapeDisplayToUse == "TRANSFORM") { + m_serialShapeIOManager = new TransformIOManager(kinectManager); + } else if (shapeDisplayToUse == "inFORM") { + m_serialShapeIOManager = new InFormIOManager(kinectManager); + } else { + throw "unknown shape display type: " + shapeDisplayToUse; + } printf("Setting up Shape Display Management\n"); From 9b605b4f80edc3089623c4a6705d7b211aee582f Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 1 Jul 2024 12:20:19 -0400 Subject: [PATCH 56/60] add inFORM shape display manager and make it the preset for now --- src/AppManager.cpp | 2 +- src/Applications/Application.hpp | 1 + src/ShapeDisplayManagers/InFormIOManager.cpp | 140 +++++++++++++++++++ src/ShapeDisplayManagers/InFormIOManager.hpp | 40 ++++++ 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 src/ShapeDisplayManagers/InFormIOManager.cpp create mode 100644 src/ShapeDisplayManagers/InFormIOManager.hpp diff --git a/src/AppManager.cpp b/src/AppManager.cpp index 6d619b5..16efba8 100644 --- a/src/AppManager.cpp +++ b/src/AppManager.cpp @@ -67,7 +67,7 @@ void AppManager::setup(){ void AppManager::setupShapeDisplayManagement() { // initialize communication with the shape display // This is where the particulars of the shape display are set (i.e. TRANSFORM, inFORM, or any other physical layout). - string shapeDisplayToUse = "TRANSFORM"; + string shapeDisplayToUse = "inFORM"; if (shapeDisplayToUse == "TRANSFORM") { m_serialShapeIOManager = new TransformIOManager(kinectManager); diff --git a/src/Applications/Application.hpp b/src/Applications/Application.hpp index 8f992b3..09c2477 100644 --- a/src/Applications/Application.hpp +++ b/src/Applications/Application.hpp @@ -15,6 +15,7 @@ #include "PinConfigs.h" #include "../ShapeDisplayManagers/ShapeIOManager.hpp" #include "../ShapeDisplayManagers/TransformIOManager.hpp" +#include "../ShapeDisplayManagers/InFormIOManager.hpp" class Application { public: diff --git a/src/ShapeDisplayManagers/InFormIOManager.cpp b/src/ShapeDisplayManagers/InFormIOManager.cpp new file mode 100644 index 0000000..7c2a9cd --- /dev/null +++ b/src/ShapeDisplayManagers/InFormIOManager.cpp @@ -0,0 +1,140 @@ +// +// InFormIOManager.cpp +// neoForm +// +// Created by Jonathan Williams on 6/29/24. +// + +#include "InFormIOManager.hpp" + + +InFormIOManager::InFormIOManager() { + // Set the InForm specific hardware parameters here. + //shapeDisplayName = "InForm"; + + shapeDisplaySizeX = 24; + shapeDisplaySizeY = 24; + + numberOfArduinos = 96; + + // Size the pinBoards vector appropriately. + pinBoards.resize(numberOfArduinos); + + // Size the 2d heights array appropriately for the specific shape display hardware, and initialize it with zero values. + // This needs to happen in the subclass constructor because the superclass constructor fires first, and won't yet have the subclass specific constants. + heightsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + // Also size the array that receives height values from the shape display. + heightsFromShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + + pinHeightMin = 50; + pinHeightMax = 210; + pinHeightRange = pinHeightMax - pinHeightMin; + + // Pin config values, might be abstracted into a single array. + gainP = 1.5; + gainI = 0.045; + maxI = 25; + deadZone = 2; + maxSpeed = 200; + + // Make a new PinConfigs struct instance with the default values. + PinConfigs defaultPinConfigs; + defaultPinConfigs.timeOfUpdate = 0; + defaultPinConfigs.gainP = gainP; + defaultPinConfigs.gainI = gainI; + defaultPinConfigs.maxI = maxI; + defaultPinConfigs.deadZone = deadZone; + defaultPinConfigs.maxSpeed = maxSpeed; + + + + // Set the dimensions of the pinConfigs, and set all the elements to the defaultPinConfigs struct. + pinConfigsForShapeDisplay.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, defaultPinConfigs)); + + // Initialize pin tracking vectors. + pinDiscrepancy.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, 0)); + pinEnabled.resize(shapeDisplaySizeX, std::vector(shapeDisplaySizeY, true)); + pinStuckSinceTime.resize( shapeDisplaySizeX, std::vector(shapeDisplaySizeY, elapsedTimeInSeconds() )); + + + // Add serial connection strings to the vector of serial connections. + serialPorts.push_back("/dev/tty.usbserial-A30010PW"); + serialPorts.push_back("/dev/tty.usbserial-A702YLM3"); + serialPorts.push_back("/dev/tty.usbserial-A702YMNY"); + + // Connect to shape display. + connectToDisplay(); + + configureBoards(); +} + +// Secondary Constructor delegates to the primary constructor and adds the kinect reference. +InFormIOManager::InFormIOManager(KinectManager* kinectRef) : InFormIOManager() { + m_kinectManagerRef = kinectRef; +} + +void InFormIOManager::configureBoards() { + // set up coordinates for + for (int i = 0; i < numberOfArduinos; i++) { + // determine which serial connection each board is on: + // every 3rd and 4th board is on the second + if (i < 36) { //64 + pinBoards[i].serialConnection = 0; //((i / 2) % 2 == 0) ? 0 : 1 + } else if (i < 60) { //128 + pinBoards[i].serialConnection = 1; //((i / 2) % 2 == 0) ? 2 : 3 + } else { + pinBoards[i].serialConnection = 2; //((i / 2) % 2 == 0) ? 4 : 5 + } + // every 5th to 8th board is mounted upside down, so invert the height + if (i % 12 == 4 || i % 12 == 5 || i % 12 == 6 || i % 12 == 7) { + //printf(“%d\n”, i % 12 == 8 || i % 12 == 9 || i % 12 == 10 || i % 12 == 11); + pinBoards[i].invertHeight = true; + } else{ + printf("%d\n", i % 12 == 8 || i % 12 == 9 || i % 12 == 10 || i % 12 == 11); + pinBoards[i].invertHeight = false; + } + //pinBoards[i].invertHeight = ((i / 4) % 2 == 0) ? false : true; + for (int j = 0; j < NUM_PINS_ARDUINO; j++) { + int currentRow = (int)(i / 4); + int currentColumn = 5 - j + (i % 4 * 6); + pinBoards[i].heights[j] = 0; + pinBoards[i].pinCoordinates[j][0] = currentRow; + pinBoards[i].pinCoordinates[j][1] = currentColumn; + } + // if ((i / 2) % 2 == 0) { // + // int pinCoordinateRows[NUM_PINS_ARDUINO]; + // + // //invert pin order if the boards are mounted rotated + // for (int count = 0; count < NUM_PINS_ARDUINO; count++) { + // pinCoordinateRows[NUM_PINS_ARDUINO - count - 1] = pinBoards[i].pinCoordinates[count][1]; + // } + // for (int count = 0; count < NUM_PINS_ARDUINO; count++) { + // pinBoards[i].pinCoordinates[count][1] = pinCoordinateRows[count]; + // } + // + // // also invert the pin height again if they are: + // pinBoards[i].invertHeight = !pinBoards[i].invertHeight; + // } + // last, orient the x-y coordinate axes to the desired external axes + for (int j = 0; j < NUM_PINS_ARDUINO; j++) { + unsigned char j0 = pinBoards[i].pinCoordinates[j][0]; + unsigned char j1 = pinBoards[i].pinCoordinates[j][1]; + pinBoards[i].pinCoordinates[j][0] = shapeDisplaySizeX - 1 - j0; + pinBoards[i].pinCoordinates[j][1] = shapeDisplaySizeY - 1 - j1; + } + } + + printBoardConfiguration(); + // flag configuration as complete + boardsAreConfigured = true; +} + +ofPixels InFormIOManager::cropToActiveSurface(ofPixels fullSurface) { + // Inform needs no cropping, but it does need to be resized to pin dimensions of the active surface. + // NOTE video mode doesn't need resizing, so check to see if the dimensions differ before resizing. + if (fullSurface.getWidth() != shapeDisplaySizeX || fullSurface.getHeight() != shapeDisplaySizeY) { + fullSurface.resize(shapeDisplaySizeX, shapeDisplaySizeY); + } + + return fullSurface; +} diff --git a/src/ShapeDisplayManagers/InFormIOManager.hpp b/src/ShapeDisplayManagers/InFormIOManager.hpp new file mode 100644 index 0000000..e1c98cf --- /dev/null +++ b/src/ShapeDisplayManagers/InFormIOManager.hpp @@ -0,0 +1,40 @@ +// +// InFormIOManager.hpp +// neoForm +// +// Created by Jonathan Williams on 6/29/24. +// + +#ifndef InFormIOManager_hpp +#define InFormIOManager_hpp + +#include +#include "ofMain.h" +#include "constants.h" +#include "SerialShapeIOManager.hpp" + +#include "PinConfigs.h" + +class InFormIOManager : public SerialShapeIOManager { +public: + InFormIOManager(); + + InFormIOManager(KinectManager* kinectRef); + + // Name to identify the shape display. + string getShapeDisplayName() { + // This is a method instead of a property only to simplify the inheritance by making the superclass declaration virtual. + return "inFORM"; + } + + // should pins that appear stuck be turned off at regular intervals? + bool enableStuckPinSafetyToggle = false; + + ofPixels cropToActiveSurface(ofPixels fullSurface); + +protected: + // setup hardware-specific board configuration + void configureBoards(); +}; + +#endif /* InFormIOManager_hpp */ From c50c0a4bd7da2cf32d12a1107ccc7a6fcea8ffcb Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 1 Jul 2024 12:23:40 -0400 Subject: [PATCH 57/60] adapt kinect hand wavy for inForm --- src/Applications/KinectHandWavy.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Applications/KinectHandWavy.cpp b/src/Applications/KinectHandWavy.cpp index 6779b8f..7329067 100644 --- a/src/Applications/KinectHandWavy.cpp +++ b/src/Applications/KinectHandWavy.cpp @@ -57,9 +57,11 @@ void KinectHandWavy::drawGraphicsForShapeDisplay(int x, int y, int width, int he //*** Contours are disabled, but maybe they will be useful in the future. //m_kinectManager->drawContours(); - - //*** Draw preview of the actuated pixel regions (sections). - drawPreviewActuatedSections(); + + if ( m_CustomShapeDisplayManager->getShapeDisplayName() == "TRANSFORM" ) { + //*** Draw preview of the actuated pixel regions (sections). + drawPreviewActuatedSections(); + } } // Draw a rectangle around the shape display pixels based on the mask info from settings.xml @@ -82,7 +84,7 @@ void KinectHandWavy::drawPreviewMaskRectangle() { ofFill(); } -// Draw a semi-transparent rectangle over each of the three the actuated sections. +// Draw a semi-transparent rectangle over each of the three the actuated sections. This should only be called when the shape display is a transFORM. void KinectHandWavy::drawPreviewActuatedSections() { // Get the width in inches of the the full transform surface (need to cast shape display manager object first). From cf085495ff83275b953f7d4a565050035a7cc30b Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 1 Jul 2024 12:24:47 -0400 Subject: [PATCH 58/60] add an inFORM specific video file for Escher mode --- bin/data/inFORM-escher-mode.mp4 | Bin 0 -> 61669 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 bin/data/inFORM-escher-mode.mp4 diff --git a/bin/data/inFORM-escher-mode.mp4 b/bin/data/inFORM-escher-mode.mp4 new file mode 100755 index 0000000000000000000000000000000000000000..839ecd19a18767da03adbc7ca9279f5f31098488 GIT binary patch literal 61669 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�&hkjNF*NEH172a5h#hcToHY?=(#E?%C<*b*{yD{ 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 Date: Mon, 1 Jul 2024 12:25:43 -0400 Subject: [PATCH 59/60] adapt video player for inFORM by putting TRANSFORM specific code in conditionals --- src/Applications/VideoPlayerApp.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Applications/VideoPlayerApp.cpp b/src/Applications/VideoPlayerApp.cpp index 1370a48..d9a82d5 100755 --- a/src/Applications/VideoPlayerApp.cpp +++ b/src/Applications/VideoPlayerApp.cpp @@ -13,7 +13,14 @@ VideoPlayerApp::VideoPlayerApp(SerialShapeIOManager *theCustomShapeDisplayManage void VideoPlayerApp::setup() { //setupTransformedPixelMap(); - video.load("escher-5-slow.mov"); + + // Select a video appropriate for the shape display. + if (m_CustomShapeDisplayManager->getShapeDisplayName() == "TRANSFORM") { + video.load("escher-5-slow.mov"); + } else { + video.load("inFORM-escher-mode.mp4"); + } + video.play(); } @@ -51,7 +58,9 @@ void VideoPlayerApp::drawGraphicsForShapeDisplay(int x, int y, int width, int he video.draw(30, 300, 544, 128); // Draw the preview of the actuated pixels sections. - drawSectionPreviewFrameBuffer(30, 300, 544, 128); + if (m_CustomShapeDisplayManager->getShapeDisplayName() == "TRANSFORM") { + drawSectionPreviewFrameBuffer(30, 300, 544, 128); + } } void VideoPlayerApp::drawSectionPreviewFrameBuffer(int x, int y, int width, int height) { From 7fb55b3e21b8759ecf3d26670c6bc7db3cf3016e Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 1 Jul 2024 13:00:32 -0400 Subject: [PATCH 60/60] update pbxproject --- neoForm.xcodeproj/project.pbxproj | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/neoForm.xcodeproj/project.pbxproj b/neoForm.xcodeproj/project.pbxproj index cf198d8..2c55691 100644 --- a/neoForm.xcodeproj/project.pbxproj +++ b/neoForm.xcodeproj/project.pbxproj @@ -56,6 +56,7 @@ A7A38C1DAA6949FC9F8B48C0 /* will_mosq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98278F7AD1AA612A8F4DDA10 /* will_mosq.c */; }; ACE7DC9A3223ED5EE1B80074 /* cameras.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DBD37876A11E46E4D7069B3 /* cameras.c */; }; B006626C26FF99AB717C7CD4 /* utf8_mosq.c in Sources */ = {isa = PBXBuildFile; fileRef = D1822FF66A31138F103D3C2F /* utf8_mosq.c */; }; + B94766EA2C3105CC00877064 /* InFormIOManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B94766E82C3105CC00877064 /* InFormIOManager.cpp */; }; B9A9F318297DF82000ACC2F8 /* KinectManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B9A9F2F5297DF82000ACC2F8 /* KinectManager.cpp */; }; B9A9F319297DF82000ACC2F8 /* SerialIOManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B9A9F2FA297DF82000ACC2F8 /* SerialIOManager.cpp */; }; B9A9F31A297DF82000ACC2F8 /* ShapeIOManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B9A9F2FD297DF82000ACC2F8 /* ShapeIOManager.cpp */; }; @@ -511,6 +512,8 @@ B88A80AA34B79BD6DA9253DE /* sse_utils.hpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = sse_utils.hpp; path = ../../../addons/ofxOpenCv/libs/opencv/include/opencv4/opencv2/core/sse_utils.hpp; sourceTree = SOURCE_ROOT; }; B8A2CBF3E24E6E5026B13A90 /* ofxBase3DVideo.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = ofxBase3DVideo.h; path = ../../../addons/ofxKinect/src/ofxBase3DVideo.h; sourceTree = SOURCE_ROOT; }; B8F39F6EBA0607ECB7D18D89 /* handle_disconnect.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 4; name = handle_disconnect.c; path = "../../../addons/ofxMQTT-1.5.0/libs/mosquitto/src/handle_disconnect.c"; sourceTree = SOURCE_ROOT; }; + B94766E82C3105CC00877064 /* InFormIOManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InFormIOManager.cpp; sourceTree = ""; }; + B94766E92C3105CC00877064 /* InFormIOManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InFormIOManager.hpp; sourceTree = ""; }; B9A9F2F5297DF82000ACC2F8 /* KinectManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KinectManager.cpp; sourceTree = ""; }; B9A9F2F6297DF82000ACC2F8 /* KinectManager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = KinectManager.hpp; sourceTree = ""; }; B9A9F2F8297DF82000ACC2F8 /* PinConfigs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PinConfigs.h; sourceTree = ""; }; @@ -1980,15 +1983,17 @@ isa = PBXGroup; children = ( B9A9F2F8297DF82000ACC2F8 /* PinConfigs.h */, - B9A9F2F9297DF82000ACC2F8 /* TransformIOManager.hpp */, + B94766E82C3105CC00877064 /* InFormIOManager.cpp */, + B94766E92C3105CC00877064 /* InFormIOManager.hpp */, + B9A9F2FE297DF82000ACC2F8 /* SerialIOManager.hpp */, B9A9F2FA297DF82000ACC2F8 /* SerialIOManager.cpp */, B9A9F2FB297DF82000ACC2F8 /* SerialShapeIO.hpp */, - B9A9F2FC297DF82000ACC2F8 /* SerialShapeIOManager.hpp */, - B9A9F2FD297DF82000ACC2F8 /* ShapeIOManager.cpp */, - B9A9F2FE297DF82000ACC2F8 /* SerialIOManager.hpp */, B9A9F2FF297DF82000ACC2F8 /* SerialShapeIO.cpp */, + B9A9F2FC297DF82000ACC2F8 /* SerialShapeIOManager.hpp */, B9A9F300297DF82000ACC2F8 /* SerialShapeIOManager.cpp */, B9A9F301297DF82000ACC2F8 /* ShapeIOManager.hpp */, + B9A9F2FD297DF82000ACC2F8 /* ShapeIOManager.cpp */, + B9A9F2F9297DF82000ACC2F8 /* TransformIOManager.hpp */, B9A9F302297DF82000ACC2F8 /* TransformIOManager.cpp */, ); path = ShapeDisplayManagers; @@ -2007,15 +2012,15 @@ isa = PBXGroup; children = ( B9A9F308297DF82000ACC2F8 /* Application.hpp */, + B9A9F30E297DF82000ACC2F8 /* Application.cpp */, + B9A9F30F297DF82000ACC2F8 /* AxisChecker.hpp */, B9A9F309297DF82000ACC2F8 /* AxisChecker.cpp */, - B9A9F30A297DF82000ACC2F8 /* MqttTransmissionApp.cpp */, - B9A9F30B297DF82000ACC2F8 /* VideoPlayerApp.cpp */, B9A9F30C297DF82000ACC2F8 /* MqttTransmissionApp.hpp */, + B9A9F30A297DF82000ACC2F8 /* MqttTransmissionApp.cpp */, B9A9F30D297DF82000ACC2F8 /* VideoPlayerApp.hpp */, - B9A9F30E297DF82000ACC2F8 /* Application.cpp */, - B9A9F30F297DF82000ACC2F8 /* AxisChecker.hpp */, - 84B1DCFE2B792D8500DE7B7B /* KinectHandWavy.cpp */, + B9A9F30B297DF82000ACC2F8 /* VideoPlayerApp.cpp */, 84B1DCFF2B792D8500DE7B7B /* KinectHandWavy.hpp */, + 84B1DCFE2B792D8500DE7B7B /* KinectHandWavy.cpp */, B9A9F310297DF82000ACC2F8 /* DebuggingApps */, ); path = Applications; @@ -2024,12 +2029,12 @@ B9A9F310297DF82000ACC2F8 /* DebuggingApps */ = { isa = PBXGroup; children = ( - B9A9F311297DF82000ACC2F8 /* KinectDebugApp.cpp */, B9A9F312297DF82000ACC2F8 /* AxisCheckerApp.hpp */, - B9A9F313297DF82000ACC2F8 /* KinectDebugApp.hpp */, B9A9F314297DF82000ACC2F8 /* AxisCheckerApp.cpp */, - 84AEEE272A926C7700D26E7C /* DepthDebugApp.cpp */, 84AEEE282A926C7700D26E7C /* DepthDebugApp.hpp */, + 84AEEE272A926C7700D26E7C /* DepthDebugApp.cpp */, + B9A9F311297DF82000ACC2F8 /* KinectDebugApp.cpp */, + B9A9F313297DF82000ACC2F8 /* KinectDebugApp.hpp */, ); path = DebuggingApps; sourceTree = ""; @@ -2638,7 +2643,7 @@ attributes = { LastUpgradeCheck = 1420; }; - buildConfigurationList = E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "neoFORM" */; + buildConfigurationList = E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "neoForm" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; @@ -2713,6 +2718,7 @@ F4135EEFC911E9ED211FB6F9 /* core.c in Sources */, E55DEEF784A10419E444669E /* flags.c in Sources */, B9A9F31F297DF82000ACC2F8 /* AxisChecker.cpp in Sources */, + B94766EA2C3105CC00877064 /* InFormIOManager.cpp in Sources */, FCC16AB16073FF0581F50ED7 /* loader.c in Sources */, D31F5C1B140C59B2AF1533A8 /* registration.c in Sources */, 49BEEB2DFA5319D55AA6899F /* tilt.c in Sources */, @@ -3647,7 +3653,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "neoFORM" */ = { + E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "neoForm" */ = { isa = XCConfigurationList; buildConfigurations = ( E4B69B4E0A3A1720003C02F2 /* Debug */,