/*****
File: _P202007MS02_Dosiersystem_2020123001.cpp
Project: P202007 Dosiersystem Tinkerforge
Author: UW
Zum Projekt
Objective (Ziel): Dosiersystem mit drei Peristaltik-Pumpen auf der Basis von TF-Modulen
Purpose, Scope (Zweck): Automatisierte kontinuierliche Dosierung von 3 Flüssigkeiten für Versuchsreihen

Date: 2020-12-30
Aktueller Stand: Prototyp für drei Dosierpumpen fertig.

    Hardware ist komplett montiert, verdrahtet und mit dem Brick Viewer getestet.

    Hardware Configuration:
    1 RED-Brick
    3 Stepper Bricks
    1 LCD128x64-LCD Bricklet
    3 Encoder-Bricklets
    RED-Brick ist über USB mit PC verbunden.
    Stromversorgung erfolgt über ein im Gehäuse integriertes 12-V-Schaltnetzteil (75 W).
    Das Gehäuse hat eine USB-B-Buchse.
    Das Gehäuse hat eine Netzanschlussbuchse mit integriertem Schalter und Sicherungshalter.

    Software
    - keine Compiler-Fehler
    - Neun Warnings
    - Pumpen lassen sich ein- und ausschalten.
    - Die Parameter der Pumpen lassen sich einstellen.

    Funktionskontrolle
    - "Button pressed" ist noch nicht belegt.
    - Die Rotationsgeschwindigkeit der Pumpen erhöht sich, wenn man den Flow verändert.
    - Der Fluss ist noch nicht kalibriert.
    - Die Intervallsteuerung ist noch nicht implementiert.
    - Die User-Eingaben werden noch nicht mit den Grenzwerten der Parameter abgeglichen.

*****/
/*****
Bekannte Mängel
    - Der Code ist nicht sauber kommentiert.
    - Der Code enthält noch Bildschirm-Meldungen zur Kontrolle des Programmablaufs - sie müssen entfernt werden.
    - Der Code enthält noch auskommentierte Altlasten.
    - Die im Code verwendeten Variablen sind nicht sauber dokumentiert.
    - Der Code ist nicht sauber strukturiert.
    - Der Code ist nicht modularisiert.
    - Der Code ist nicht konsequent in C++ geschrieben.
*****/

/*****
Fehler
keine Compiler-Fehler
*****/

/*****
Aktueller Stand:
1. Display-Steuerung - erledigt.
2. Fehleingaben - erledigt.
3. kontinuierliche Dosierung funktioniert mit "void PumpMotorStart(PeristalticPump *DummyPump)" - erledigt.
3a. Flush-Funktion - Erledigt.
4. Intervall-Betrieb funktioniert noch nicht - Timing Problem beim LCD??.
5. IQ = Eingaben und Dosiermengen, "Motorengeräusche", "Abwärme" (Motoren, Stepper, Stepdown, Gesamtwärme im Gehäuse), Manual Entwurf erstellt
6. OQ = IQ + Betrieb 2 x 8 h mit korrekten Dosiermengen (± x%, x noch definieren)
7. PQ = Badreise ohne funktionelle Fehler, Verbrauchsmaterial kann gewechselt werden, Dokumentation für Hard- und Software erstellt.
*****/
/*****
Fehlerbild:
1. Die Motor-Funktionen machen eigentlich das was sie sollen.
2. Bei Intervall-Betrieb ist das Display unreproduzierbar aber sehr häufig blockiert und zeigt die Buttons nicht mehr an.
3. Beim Intervallbetrieb lässt sich der Motor nicht mehr stoppen ob dies mit dem blockierten Display zusammenhängt ist nicht klar.
*****/
/*****
Nächster Schritt:
1.  Intervall-Dosierung implementieren (Del != 0).

Anmerkung: Ammoniak verdünnen zwecks Lebensdauer des Schlauches.
*****/



#include <iostream>
#include <string>

//#include <sstream>

#define IPCON_EXPOSE_MILLISLEEP
#include "ip_connection.h"

#include "bricklet_lcd_128x64.h"

#include "brick_stepper.h"
#include "bricklet_rotary_encoder_v2.h"

#define HOST "localhost"
#define PORT 4223
#define UID_LCD128x64 "R3L"

#define UID_rotEnc01 "KdZ"
#define UID_rotEnc02 "KcF"
#define UID_rotEnc03 "KcD"

#define UID_STEPPER01 "67PnyE"
#define UID_STEPPER02 "67NFob"
#define UID_STEPPER03 "68wDP7"

#define STEPPER_MAX_VELOCITY 3000
#define STEPPER_ACCELERATION 2000
#define STEPPER_DEACCELERATION 3000
#define STEPPER_CURRENT 400
#define STEPPER_MAX_Umin 120 //Ueberfluessig?

#define PUMP_FLOW_MLPERHOUR 600
#define PUMP_CALFACTOR_PERCENT 100
#define PUMP_DOSINTERVAL_TIME_MINUTE 10
#define PUMP_DELAYINTERVAL_TIME_MINUTE 0
#define PUMP_ROUNDS_PER_100ML 500
#define PUMP_FULL_STEPS_PER_ROUND 200

#define NUMBER_OF_PUMPS 3
#define PUMP01_ID 0
#define PUMP02_ID 1
#define PUMP03_ID 2

#define PUMP01_NAME "P01"
#define PUMP02_NAME "P02"
#define PUMP03_NAME "P03"

#define PUMP01_LIQUIDNAME "RG1"
#define PUMP02_LIQUIDNAME "RG2"
#define PUMP03_LIQUIDNAME "NH3"

#define PUMPDOSINGMODE_INTERVALL true
#define PUMPDOSINGMODE_CONTINUOUS false

#define TABHOME 0
#define PUMP01_TABINDEX 1
#define PUMP02_TABINDEX 2
#define PUMP03_TABINDEX 3

#define LCD128x64_ButtonStart 1
#define LCD128x64_ButtonStop 2
#define LCD128x64_ButtonFlush 3
#define LCD128x64_ButtonFlow 4
#define LCD128x64_ButtonCalFactor 5
#define LCD128x64_ButtonDosingInterval 6
#define LCD128x64_ButtonDelayInterval 7

IPConnection ipcon;

Stepper pStepper[NUMBER_OF_PUMPS];
RotaryEncoderV2 pEncoder[NUMBER_OF_PUMPS];
LCD128x64 pLCD128x64;

bool pLCD128x64_created;
int8_t LCDTabIndex = TABHOME;
int8_t LCDTabCurrentIndex = TABHOME;
uint8_t LCDButtonIndex = LCD128x64_ButtonFlow;
uint8_t LCDButtonCurrentIndex;
int32_t count[NUMBER_OF_PUMPS];


char text01[22];
char text02[22];
char text03[22]; // Für Display-Anzeigen, nicht aktiv
char text04[22]; // Für Display-Anzeigen, nicht aktiv
std::string printScreen;

struct PeristalticPump
{
    uint16_t PumpID;
    int8_t PumpTabIndex;
    uint8_t PumpButtonIndex;
    char PumpName[4];
    char LiquidName[6];
    char FlowMLPerHour_Name[11];
    int16_t FlowMLPerHour_Value;
    char DosingIntervalTimeMinute_Name[11];
    uint16_t DosingIntervalTimeMinute_Value;
    char DelayIntervalTimeMinute_Name[11];
    uint16_t DelayIntervalTimeMinute_Value;
    char CalibrationFactorPercent_Name[11];
    uint16_t CalibrationFactorPercent_Value;
    uint16_t RoundsPer100mL;
    int32_t EncoderCount;
    bool PumpDosingMode;
    RotaryEncoderV2 *pEncoder;
    Stepper *pStepper;
    LCD128x64 *pLCD128x64;

};
PeristalticPump pump[NUMBER_OF_PUMPS];
PeristalticPump ActivePump;

void cb_ispressed01(PeristalticPump *ActivePump);
void cb_gui_button_pressed01(uint8_t index, bool pressed, int8_t *LCDTabIndex);
void cb_gui_tab_selected(int8_t index, PeristalticPump *ActivePump);
void cb_InputEncoder(int32_t count, PeristalticPump *ActivePump);
void cb_StepperPositionReached(PeristalticPump *ActivePump);
int16_t InitializePumpParameter1(PeristalticPump *ActivePump, uint16_t PumpID, char PumpName, char LiquidName, int8_t TabIndex, uint8_t ButtonIndex);
int16_t InitializePumpParameter2(PeristalticPump *ActivePump, Stepper *pStepper, RotaryEncoderV2 *pEncoder, LCD128x64 *pLCD128x64);
void LCD128x64_HomeScreen();
void LCD128x64_Tab01(PeristalticPump *ActivePump);
void LCD128x64_Tab02(PeristalticPump *ActivePump);
void LCD128x64_Tab03(PeristalticPump *ActivePump);
void Motor(PeristalticPump *ActivePump);
void PumpMotorFlush(PeristalticPump *ActivePump);
void PumpMotorStartIntervalMode(PeristalticPump *ActivePump);
void PumpMotorStartContinuousMode(PeristalticPump *ActivePump);
void PumpMotorStop(PeristalticPump *ActivePump);
void StructUebergabeIndices(PeristalticPump *ActivePump);
void StructUebergabeValues(PeristalticPump *ActivePump);



void PumpMotorFlush(PeristalticPump *DummyPump)
{
    uint16_t MotorSpeedStepsPerSecond = 3000;
    uint8_t mode = STEPPER_STEP_MODE_HALF_STEP;

	stepper_set_motor_current(DummyPump->pStepper, STEPPER_CURRENT);
	stepper_set_step_mode(DummyPump->pStepper, mode);

	stepper_set_speed_ramping(DummyPump->pStepper, STEPPER_ACCELERATION, STEPPER_DEACCELERATION);
    if(MotorSpeedStepsPerSecond > STEPPER_MAX_VELOCITY)
    {
        MotorSpeedStepsPerSecond = STEPPER_MAX_VELOCITY;
        printf("Too fast!!!!");
    }
	stepper_set_max_velocity(DummyPump->pStepper, MotorSpeedStepsPerSecond);
	stepper_enable(DummyPump->pStepper);
    stepper_drive_forward(DummyPump->pStepper);
}


/**
* Die folgende Funktion startet die Pumpe und macht die Anzahl Schritte, die übergeben wurde.
* Die Motorsteps per second werden ebenfalls zuvor berechnet und übergeben.
* Über die Callbackfunktion wird sie nach einer gewissen Zeit (Delay-Time) wieder aufgerufen.
*
*/
void PumpMotorStartIntervalMode(PeristalticPump *DummyPump)
{
/* Anfang  - Variablen lediglich zur Kontrolle und nicht für Betrieb */
    uint16_t currVel;
    int32_t currPos;
    int32_t remainSteps;
    uint16_t stackVolt;
    uint16_t externVolt;
    uint16_t currConsumpt;
    char retPos;
/* Ende Variablen zur Kontrolle */

    uint16_t DosingFactor = 1;
    uint16_t MotorSpeedmLPerHour;
    uint16_t MotorSpeedStepsPerSecond;
    uint32_t NumberOfStepsPerHour;
    uint32_t NumberOfStepsPerDosingPeriod;
    uint8_t mode = STEPPER_STEP_MODE_EIGHTH_STEP;

    DosingFactor = (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / DummyPump->DosingIntervalTimeMinute_Value;
    NumberOfStepsPerHour =  PUMP_FULL_STEPS_PER_ROUND * mode * DummyPump->RoundsPer100mL / 100 * DummyPump->FlowMLPerHour_Value * DummyPump->CalibrationFactorPercent_Value / 100;

    NumberOfStepsPerDosingPeriod = NumberOfStepsPerHour * (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / 60;
    MotorSpeedStepsPerSecond = NumberOfStepsPerHour / 3600 * DosingFactor;


    stepper_set_motor_current(DummyPump->pStepper, STEPPER_CURRENT);
	stepper_set_step_mode(DummyPump->pStepper, mode);
    stepper_set_max_velocity(DummyPump->pStepper, MotorSpeedStepsPerSecond);

	stepper_enable(DummyPump->pStepper);
    for (uint16_t i = 1; i < DosingFactor; ++i)
    {


    stepper_set_current_position(DummyPump->pStepper, 0);
//    stepper_drive_forward(DummyPump->pStepper);
    stepper_set_steps(DummyPump->pStepper, NumberOfStepsPerDosingPeriod);
    millisleep(DummyPump->DelayIntervalTimeMinute_Value * 6000);
    }
//    stepper_set_steps(DummyPump->pStepper, 5000);
/** Kontrollausgabe zur Überprüfung am Bildschirm */
    std::cout<< std::endl << "PumpMotorStartIntervalMode(PeristalticPump *DummyPump)\n";
    sprintf(text03, "Dos: %2d\tDel: %2d\t DF: %2d\t Steps/h: %d\t Steps/Period: %d\t, Step/sec: %d", DummyPump->DosingIntervalTimeMinute_Value,
            DummyPump->DelayIntervalTimeMinute_Value, DosingFactor, NumberOfStepsPerHour, NumberOfStepsPerDosingPeriod, MotorSpeedStepsPerSecond);
    std::cout << "text03: " << text03 << std::endl;
/* Ende Kontrollausgabe*/

}


void PumpMotorStartContinuousMode(PeristalticPump *DummyPump)
{
    uint16_t DosingFactor = 1;
    uint16_t MotorSpeedmLPerHour;
    uint16_t MotorSpeedStepsPerSecond;
    uint8_t mode = STEPPER_STEP_MODE_EIGHTH_STEP;

    DosingFactor = (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / DummyPump->DosingIntervalTimeMinute_Value;
    MotorSpeedmLPerHour = DummyPump->FlowMLPerHour_Value * DummyPump->CalibrationFactorPercent_Value / 100 * DosingFactor;
    MotorSpeedStepsPerSecond = MotorSpeedmLPerHour * PUMP_FULL_STEPS_PER_ROUND * DummyPump->RoundsPer100mL/100 * mode / 3600;

	stepper_set_motor_current(DummyPump->pStepper, STEPPER_CURRENT);
	stepper_set_step_mode(DummyPump->pStepper, mode);
    stepper_get_step_mode(DummyPump->pStepper, &mode);
	stepper_set_speed_ramping(DummyPump->pStepper, STEPPER_ACCELERATION, STEPPER_DEACCELERATION);

    if(MotorSpeedStepsPerSecond > STEPPER_MAX_VELOCITY)
    {
        MotorSpeedStepsPerSecond = STEPPER_MAX_VELOCITY;
        printf("Too fast!!!!");
    }

	stepper_set_max_velocity(DummyPump->pStepper, MotorSpeedStepsPerSecond);
	stepper_enable(DummyPump->pStepper);
    stepper_drive_forward(DummyPump->pStepper);
}


void PumpMotorStop(PeristalticPump *DummyPump)
{
    int32_t x;
    stepper_stop(DummyPump->pStepper);
    stepper_get_steps(DummyPump->pStepper, &x);
    std::cout << std::endl << "get_steps: " << x << std::endl;
}

void Motor(PeristalticPump *DummyPump)
{

	stepper_set_motor_current(DummyPump->pStepper, STEPPER_CURRENT);
	stepper_set_step_mode(DummyPump->pStepper, STEPPER_STEP_MODE_EIGHTH_STEP);
	stepper_set_max_velocity(DummyPump->pStepper, 2000);
	stepper_set_speed_ramping(DummyPump->pStepper, STEPPER_ACCELERATION, STEPPER_DEACCELERATION);
	stepper_enable(DummyPump->pStepper);
	stepper_set_steps(DummyPump->pStepper,4000);

}

void cb_StepperPositionReached(PeristalticPump *DummyPump)
{
    PumpMotorStop(DummyPump);
}


void cb_InputEncoder(int32_t DummyCount, PeristalticPump *DummyPump)
{
    std::cout << std::endl << "void cb_InputEncoder(int32_t DummyCount, PeristalticPump *DummyPump)";
    DummyPump->EncoderCount = DummyCount;
    LCDTabIndex = DummyPump->PumpTabIndex;
    lcd_128x64_set_gui_tab_selected(&pLCD128x64, LCDTabIndex);

    sprintf(text01, "P%2d Enc: %4d", DummyPump->PumpID, DummyPump->EncoderCount);
    lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);

//    StructUebergabeValues(DummyPump);

}

void cb_ispressed01(PeristalticPump *DummyPump)
{
    std::cout << "cb_ispressed01(PeristalticPump &DummyPump) \n";

}

void cb_gui_button_pressed01(uint8_t ButtonIndex, bool pressed, int8_t *TabIndex)
{
/*
Funktion durchläuft switch/case und liefert den richtigen Button.
Die Funktion wird aus unerfindlichen Gründen immer zweimal aufgerufen.
Der Index des entsprechenden buttons wird korrekt in pump[TabIndex].ButtonButtonIndex abgelegt.
Die Werte werden übernommen.

*/
    std::cout << std::endl << "void cb_gui_button_pressed01(uint8_t ButtonIndex, bool pressed, PeristalticPump *DummyPump)" << std::endl;

    int8_t LocalPumpID;
    LCDButtonIndex = ButtonIndex;
    LocalPumpID = *TabIndex - 1;
    if(!pressed)
    {

    switch (LCDButtonIndex)
    {
    case LCD128x64_ButtonFlow:
        {
            pump[LocalPumpID].FlowMLPerHour_Value = pump[LocalPumpID].EncoderCount;
            printf("Pumpe: %s Flow: %d\n", pump[LocalPumpID].PumpName, pump[LocalPumpID].FlowMLPerHour_Value);
            sprintf(pump[LocalPumpID].FlowMLPerHour_Name, "%d mL/h", pump[LocalPumpID].FlowMLPerHour_Value);
            lcd_128x64_set_gui_button(pump[LocalPumpID].pLCD128x64, LCD128x64_ButtonFlow, 0, 13, 62, 12, pump[LocalPumpID].FlowMLPerHour_Name);
            break;
        }
    case LCD128x64_ButtonDosingInterval:
        {
            if(pump[LocalPumpID].EncoderCount < 1 || pump[LocalPumpID].EncoderCount > 60)
            {
                pump[LocalPumpID].DosingIntervalTimeMinute_Value = 60;
            }
            else
            {
                pump[LocalPumpID].DosingIntervalTimeMinute_Value = pump[LocalPumpID].EncoderCount;
            }
            sprintf(pump[LocalPumpID].DosingIntervalTimeMinute_Name, "%d min", pump[LocalPumpID].DosingIntervalTimeMinute_Value);
            lcd_128x64_set_gui_button(pump[LocalPumpID].pLCD128x64, LCD128x64_ButtonDosingInterval, 0, 28, 62, 12, pump[LocalPumpID].DosingIntervalTimeMinute_Name);
            break;
        }
    case LCD128x64_ButtonDelayInterval:
        {
            if(pump[LocalPumpID].EncoderCount <= 0 || pump[LocalPumpID].EncoderCount > 59)
            {
                pump[LocalPumpID].DelayIntervalTimeMinute_Value = 0;
                pump[LocalPumpID].PumpDosingMode = PUMPDOSINGMODE_CONTINUOUS;
            }
            else
            {
                pump[LocalPumpID].DelayIntervalTimeMinute_Value = pump[LocalPumpID].EncoderCount;
                pump[LocalPumpID].PumpDosingMode = PUMPDOSINGMODE_INTERVALL;
                lcd_128x64_write_line(&pLCD128x64, 0, 16, "Interv");
            }
            sprintf(pump[LocalPumpID].DelayIntervalTimeMinute_Name, "%d min", pump[LocalPumpID].DelayIntervalTimeMinute_Value);
            lcd_128x64_set_gui_button(pump[LocalPumpID].pLCD128x64, LCD128x64_ButtonDelayInterval, 65, 28, 62, 12, pump[LocalPumpID].DelayIntervalTimeMinute_Name);
            break;
        }
    case LCD128x64_ButtonCalFactor:
        {
            if(pump[LocalPumpID].EncoderCount <= 50 || pump[LocalPumpID].EncoderCount > 150)
            {
                pump[LocalPumpID].CalibrationFactorPercent_Value = 100;
            }
            else
            {
                pump[LocalPumpID].CalibrationFactorPercent_Value = pump[LocalPumpID].EncoderCount;
            }
            sprintf(pump[LocalPumpID].CalibrationFactorPercent_Name, "%d %%", pump[LocalPumpID].CalibrationFactorPercent_Value);
            lcd_128x64_set_gui_button(pump[LocalPumpID].pLCD128x64, LCD128x64_ButtonCalFactor, 65, 13, 62, 12, pump[LocalPumpID].CalibrationFactorPercent_Name);
            break;
        }
    case LCD128x64_ButtonStart:
        {
            printf("Start pressed\n");
            PumpMotorStartContinuousMode(&pump[LocalPumpID]);
            break;
        }
    case LCD128x64_ButtonStop:
        {
            printf("Stop pressed\n");
            PumpMotorStop(&pump[LocalPumpID]);
            break;
        }
    case LCD128x64_ButtonFlush:
        {
            printf("Aus pressed");
//            PumpMotorFlush(&pump[LocalPumpID]);
            PumpMotorStartIntervalMode(&pump[LocalPumpID]);
            break;
        }
    default:
        {
            break;
        }
    }
    }
    else
    {
        printf("pressed");
    }

    std::cout << "Ende von cb_gui_button_pressed01(uint8_t index, bool pressed, PeristalticPump &DummyPump)\n";
}

void cb_gui_tab_selected(int8_t index, PeristalticPump *DummyPump)
{
/*********

Diese Funktion wird aufgerufen wenn ein Tab auf dem LCD gedrückt wird.
    uint8_t index entält den Index des entsprechenden Tabs.
    *DummyPump enthält die Adresse des globalen struct DummyPump.
    DummyPump enthält diesen Adresswert.
    &DummyPump liefert die Adresse der lokalen struct DummyPump?????
Wird ein Tab gedrückt, dann:
    Wird der Index des gedrückten Tabs in DummyPump->PumpTabIndex gespeichert.
    Wird über select/case die entsprechende Funktion zum Aufbau der Bildschirmseite aufgerufen.
    Wird die DummyPump die Adresse der entsprechenden Pumpe übergeben.
    Wird der Encoder-Wert von Peristaltic-Pump ausgegeben - nicht der aktuelle Encoder-Wert.
*********/

//**** Ausgabe zum testen der Parameter/Werte
//std::cout << std::endl << "void cb_gui_tab_selected(int8_t index, PeristalticPump *DummyPump)";
//    std::cout << "void cb_InputEncoder(int32_t Dummycount, PeristalticPump *DummyPump)" << std::endl;
//    std::cout << "LCDButtonIndex: " << LCDButtonIndex << std::endl;
//    StructUebergabeValues(DummyPump);

    DummyPump->PumpTabIndex = index;
    LCDTabIndex = index;
//    std::cout << "cb_gui_Tab_Selected - DummyPump->PumpTabIndex: " << DummyPump->PumpTabIndex << std::endl;
//    StructUebergabeValues(DummyPump);

//***** Ende Test

    switch (index)
    {
        case TABHOME:
        {
            LCD128x64_HomeScreen();
            break;
        }
        case PUMP01_TABINDEX:
        {
            DummyPump = &pump[0];
            LCD128x64_Tab01(&pump[0]);
            sprintf(text01, "P%d-Enc: %4d", DummyPump->PumpID, DummyPump->EncoderCount);
            lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);
            break;
        }
        case PUMP02_TABINDEX:
        {
            DummyPump = &pump[1];
            LCD128x64_Tab02(&pump[1]);
            sprintf(text01, "P%d-Enc: %4d", DummyPump->PumpID, DummyPump->EncoderCount);
            lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);
            break;

        }
        case PUMP03_TABINDEX:
        {
            DummyPump = &pump[2];
            LCD128x64_Tab03(&pump[2]);
            sprintf(text01, "P%d-Enc: %4d", DummyPump->PumpID, DummyPump->EncoderCount);
            lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);
            break;
        }
        default:
        {
            break;
        }
    }
}
int16_t InitializePumpParameter1(PeristalticPump *DummyPump, uint16_t PumpID, char PumpName[4], char LiquidName[6], int8_t TabIndex, uint8_t ButtonIndex)
{
std::cout << "*********************** Initialize *********************" << std::endl;
// std::cout << "DummyPump->PumpID vorher: " << &DummyPump->PumpID << "\t" << DummyPump->PumpID << std::endl;

    DummyPump->PumpID = PumpID;

//std::cout << "DummyPump->PumpID nachher: " << &DummyPump->PumpID << "\t" << DummyPump->PumpID << std::endl;
//std::cout << "PumpID: " << &PumpID << "\t" << PumpID << std::endl;
//sprintf(text02, "TabIndex %4c\t Adresse: %p", TabIndex, &TabIndex);
//sprintf(text03, "TI %2d\t A %p", TabIndex, &TabIndex);
//sprintf(text04, "BI %2d\t A %p", ButtonIndex, &ButtonIndex);
//std::cout << text03 << std::endl;
//std::cout << text04 << std::endl;
//std::cout << "PumpName: " << PumpName << std::endl;

//    DummyPump->PumpName = PumpName;
//    DummyPump->LiquidName = LiquidName;
    strcpy(DummyPump->PumpName, PumpName);
    strcpy(DummyPump->LiquidName, LiquidName);
    DummyPump->PumpTabIndex = TabIndex;
    DummyPump->PumpButtonIndex = ButtonIndex;

    DummyPump->PumpButtonIndex = LCDButtonIndex;
    DummyPump->RoundsPer100mL = PUMP_ROUNDS_PER_100ML;
    DummyPump->CalibrationFactorPercent_Value = PUMP_CALFACTOR_PERCENT;
    DummyPump->DelayIntervalTimeMinute_Value = PUMP_DELAYINTERVAL_TIME_MINUTE;
    DummyPump->DosingIntervalTimeMinute_Value = PUMP_DOSINTERVAL_TIME_MINUTE;
    DummyPump->FlowMLPerHour_Value = PUMP_FLOW_MLPERHOUR;

    return(0);
}
int16_t InitializePumpParameter2(PeristalticPump *DummyPump, Stepper *pStepper, RotaryEncoderV2 *pEncoder, LCD128x64 *pLCD128x64)
{
    DummyPump->pStepper = pStepper;
    DummyPump->pEncoder = pEncoder;
    DummyPump->pLCD128x64 = pLCD128x64;
    return(0);
}
void LCD128x64_HomeScreen()
{
    std::cout << "LCD128x64_HomeScreeeeeeen()\n";
    lcd_128x64_clear_display(&pLCD128x64);
	lcd_128x64_remove_all_gui(&pLCD128x64);
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 0, "Ho");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 1, "R1");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 2, "R2");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 3, "NH3");
    lcd_128x64_set_gui_tab_selected(&pLCD128x64, TABHOME);
	lcd_128x64_set_gui_tab_configuration(&pLCD128x64, LCD_128X64_CHANGE_TAB_ON_CLICK_AND_SWIPE, true);
	lcd_128x64_write_line(&pLCD128x64, 0, 0, "** Dosing Unit V00 **");
}

void LCD128x64_Tab01(PeristalticPump *DummyPump)
{
    std::cout << "\nvoid LCD128x64_Tab01(PeristalticPump *DummyPump)";
//Werte für DummyPump festlegen
    LCDTabIndex = PUMP01_TABINDEX;
    DummyPump->PumpID = PUMP01_ID;
    sprintf(DummyPump->FlowMLPerHour_Name, "%dmL/h", DummyPump->FlowMLPerHour_Value);
    sprintf(DummyPump->DosingIntervalTimeMinute_Name, "Do %dmin", DummyPump->DosingIntervalTimeMinute_Value);
    sprintf(DummyPump->DelayIntervalTimeMinute_Name, "De %dmin", DummyPump->DelayIntervalTimeMinute_Value);
    sprintf(DummyPump->CalibrationFactorPercent_Name, "Co %d%%", DummyPump->CalibrationFactorPercent_Value);

    lcd_128x64_clear_display(DummyPump->pLCD128x64);
	lcd_128x64_remove_all_gui(DummyPump->pLCD128x64);

    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonStart, 5, 42, 35, 10, "Start");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonStop, 45, 42, 35, 10, "Stop");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonFlush, 85, 42, 35, 10, "Inter");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonFlow, 0, 13, 62, 12, DummyPump->FlowMLPerHour_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonDosingInterval, 0, 28, 62, 12, DummyPump->DosingIntervalTimeMinute_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonDelayInterval, 65, 28, 62, 12, DummyPump->DelayIntervalTimeMinute_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonCalFactor, 65, 13, 62, 12, DummyPump->CalibrationFactorPercent_Name);

    lcd_128x64_set_gui_tab_text(&pLCD128x64, 0, "Ho");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 1, "R1");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 2, "R2");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 3, "NH3");
    lcd_128x64_set_gui_tab_selected(&pLCD128x64, 1);
	lcd_128x64_set_gui_tab_configuration(&pLCD128x64, LCD_128X64_CHANGE_TAB_ON_CLICK_AND_SWIPE, true);

/*
Anfang Ausgabe zum Testen

    std::cout << "LCD128x64_Tab01(PeristalticPump *DummyPump)\n";
    strcpy(text01, DummyPump->PumpName.c_str()); // Umwandlung string in char
    sprintf(text02, "Enc: %4d", DummyPump->EncoderCount);
    std::cout << "text01: " << text01 << std::endl;
	std::cout << "Tab01 Pumpe: " << DummyPump->PumpName <<"\n";

Ende Ausgabe zum Testen
*/

//	lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);
//    lcd_128x64_write_line(&pLCD128x64, 0, 5, text02);
//    StructUebergabeValues(DummyPump);
}
void LCD128x64_Tab02(PeristalticPump *DummyPump)
{
    std::cout << "\nvoid LCD128x64_Tab02(PeristalticPump *DummyPump)";
//    std::cout << "LCD128x64_Tab02(PeristalticPump *DummyPump)\n";
//Werte für DummyPump festlegen
//   sprintf(DummyPump.PumpName, "P02");
    LCDTabIndex = PUMP02_TABINDEX;
    DummyPump->PumpID = LCDTabIndex;
    sprintf(DummyPump->FlowMLPerHour_Name, "%dmL/h", DummyPump->FlowMLPerHour_Value);
    sprintf(DummyPump->DosingIntervalTimeMinute_Name, "Do %dmin", DummyPump->DosingIntervalTimeMinute_Value);
    sprintf(DummyPump->DelayIntervalTimeMinute_Name, "De %dmin", DummyPump->DelayIntervalTimeMinute_Value);
    sprintf(DummyPump->CalibrationFactorPercent_Name, "Co %d%%", DummyPump->CalibrationFactorPercent_Value);
//    DummyPump->RoundsPer100mL = 500;

//	std::cout << "Pumpe: " << DummyPump->PumpName <<"\n";
    lcd_128x64_clear_display(DummyPump->pLCD128x64);
    lcd_128x64_remove_all_gui(DummyPump->pLCD128x64);
//	std::cout << "Tab02 Pumpe: " << DummyPump->PumpName <<"\n";

    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonStart, 5, 42, 35, 10, "Start");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonStop, 45, 42, 35, 10, "Stop");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonFlush, 85, 42, 35, 10, "Inter");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonFlow, 0, 13, 62, 12, DummyPump->FlowMLPerHour_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonDosingInterval, 0, 28, 62, 12, DummyPump->DosingIntervalTimeMinute_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonDelayInterval, 65, 28, 62, 12, DummyPump->DelayIntervalTimeMinute_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonCalFactor, 65, 13, 62, 12, DummyPump->CalibrationFactorPercent_Name);
    lcd_128x64_set_gui_tab_text(&pLCD128x64, 0, "Ho");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 1, "R1");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 2, "R2");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 3, "NH3");
    lcd_128x64_set_gui_tab_selected(&pLCD128x64, 2);
	lcd_128x64_set_gui_tab_configuration(&pLCD128x64, LCD_128X64_CHANGE_TAB_ON_CLICK_AND_SWIPE, true);

/* Ausgabe zum Testen
    strcpy(text01, DummyPump->PumpName.c_str()); // Umwandlung string in char
    sprintf(text02, "Enc: %4d", DummyPump->EncoderCount);
    std::cout << "text01: " << text01 << std::endl;
	std::cout << "Tab01 Pumpe: " << DummyPump->PumpName <<"\n";
//    StructUebergabeValues(DummyPump);
Ende Ausgabe zum Testen
*/
//    sprintf(text01, "HaHaHa");
//	lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);
//    lcd_128x64_write_line(&pLCD128x64, 0, 5, text02);

}
void LCD128x64_Tab03(PeristalticPump *DummyPump)
{
    std::cout << "\nLCD128x64_Tab03(PeristalticPump *DummyPump)\n";
//Werte für DummyPump festlegen
//    sprintf(DummyPump.PumpName, "P03");
    LCDTabIndex = PUMP03_TABINDEX;
    DummyPump->PumpID = LCDTabIndex;
    sprintf(DummyPump->FlowMLPerHour_Name, "%dmL/h", DummyPump->FlowMLPerHour_Value);
    sprintf(DummyPump->DosingIntervalTimeMinute_Name, "Do %dmin", DummyPump->DosingIntervalTimeMinute_Value);
    sprintf(DummyPump->DelayIntervalTimeMinute_Name, "De %dmin", DummyPump->DelayIntervalTimeMinute_Value);
    sprintf(DummyPump->CalibrationFactorPercent_Name, "Co %d%%", DummyPump->CalibrationFactorPercent_Value);
//    DummyPump->RoundsPer100mL = 500;

    lcd_128x64_clear_display(DummyPump->pLCD128x64);
	lcd_128x64_remove_all_gui(DummyPump->pLCD128x64);
	//std::cout << "Pumpe: " << DummyPump->PumpName <<"\n";

    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonStart, 5, 42, 35, 10, "Start");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonStop, 45, 42, 35, 10, "Stop");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonFlush, 85, 42, 35, 10, "Inter");
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonFlow, 0, 13, 62, 12, DummyPump->FlowMLPerHour_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonDosingInterval, 0, 28, 62, 12, DummyPump->DosingIntervalTimeMinute_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonDelayInterval, 65, 28, 62, 12, DummyPump->DelayIntervalTimeMinute_Name);
    lcd_128x64_set_gui_button(DummyPump->pLCD128x64, LCD128x64_ButtonCalFactor, 65, 13, 62, 12, DummyPump->CalibrationFactorPercent_Name);
    lcd_128x64_set_gui_tab_text(&pLCD128x64, 0, "Ho");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 1, "R1");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 2, "R2");
	lcd_128x64_set_gui_tab_text(&pLCD128x64, 3, "NH3");
    lcd_128x64_set_gui_tab_selected(&pLCD128x64, 3);
	lcd_128x64_set_gui_tab_configuration(&pLCD128x64, LCD_128X64_CHANGE_TAB_ON_CLICK_AND_SWIPE, true);

/*
Anfang Ausgabe zum Testen
    strcpy(text01, DummyPump->PumpName.c_str()); // Umwandlung string in char
    sprintf(text02, "Enc: %4d", DummyPump->EncoderCount);
    std::cout << "text01: " << text01 << std::endl;
	std::cout << "Tab01 Pumpe: " << DummyPump->PumpName <<"\n";
//    StructUebergabeValues(DummyPump);
Ende Ausgabe zum Testen
*/
//	lcd_128x64_write_line(&pLCD128x64, 0, 0, text01);
//    lcd_128x64_write_line(&pLCD128x64, 0, 5, text02);

}

void StructUebergabeIndices(PeristalticPump *DummyPump)
{
    std::cout << "LCD128x64_ButtonFlow\t " << LCD128x64_ButtonFlow << "\n\n";
    std::cout << "Active Pump, ID: " << DummyPump->PumpID << "\t";
    std::cout << "DummyPump.PumpTabIndex: " << DummyPump->PumpTabIndex << "\t";
    std::cout << "DummyPump.PumpButtonIndex: " << DummyPump->PumpButtonIndex << "\n\n";
    std::cout << "pump[0], ID: " << pump[0].PumpID << "\t";
    std::cout << "pump[0].PumpTabIndex: " << pump[0].PumpTabIndex << "\t";
    std::cout << "pump[0].PumpButtonIndex: " << pump[0].PumpButtonIndex << "\n";
    std::cout << "pump[1], ID: " << pump[1].PumpID << "\t";
    std::cout << "pump[1].PumpTabIndex: " << pump[1].PumpTabIndex << "\t";
    std::cout << "pump[1].PumpButtonIndex: " << pump[1].PumpButtonIndex << "\n";
    std::cout << "pump[2], ID: " << pump[2].PumpID << "\t";
    std::cout << "pump[2].PumpTabIndex: " << pump[2].PumpTabIndex << "\t";
    std::cout << "pump[2].PumpButtonIndex: " << pump[2].PumpButtonIndex << "\n\n\n";
//    std::cout << "pump[0].RoundsPer100mL: " << pump[0].RoundsPer100mL << "\t";
//    std::cout << "pump[0].FlowMLPerHour_Value: " << pump[0].FlowMLPerHour_Value << "\n\n\n";
}
void StructUebergabeValues(PeristalticPump *DPump)
{
    std::cout << "\t\t\t\t";
    std::cout << "Dummy\t\tActive\t\tpump[0]\t\tpump[1]\t\tpump[2]\n";

    std::cout << "ID\t\t\t\t";
    std::cout << DPump->PumpID << "\t\t";
    std::cout << ActivePump.PumpID << "\t\t";
    std::cout << pump[0].PumpID << "\t\t";
    std::cout << pump[1].PumpID << "\t\t";
    std::cout << pump[2].PumpID << "\t\t";
    std::cout << std::endl;

    std::cout << "PumpName\t\t\t";
    std::cout << DPump->PumpName << "\t\t";
    std::cout << ActivePump.PumpName << "\t\t";
    std::cout << pump[0].PumpName << "\t\t";
    std::cout << pump[1].PumpName << "\t\t";
    std::cout << pump[2].PumpName << "\t\t";
    std::cout << std::endl;

    std::cout << "LiquidName\t\t\t";
    std::cout << DPump->LiquidName << "\t\t";
    std::cout << ActivePump.LiquidName << "\t\t";
    std::cout << pump[0].LiquidName<< "\t\t";
    std::cout << pump[1].LiquidName << "\t\t";
    std::cout << pump[2].LiquidName << "\t\t";
    std::cout << std::endl;

    std::cout << "PumpTabIndex\t\t\t";
    sprintf(text01, "%d", DPump->PumpTabIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", ActivePump.PumpTabIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", pump[0].PumpTabIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", pump[1].PumpTabIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", pump[2].PumpTabIndex);
    std::cout << text01 << "\t\t";
    std::cout << std::endl;

    std::cout << "PumpButtonIndex\t\t\t";
    sprintf(text01, "%d", DPump->PumpButtonIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", ActivePump.PumpButtonIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", pump[0].PumpButtonIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", pump[1].PumpButtonIndex);
    std::cout << text01 << "\t\t";
    sprintf(text01, "%d", pump[2].PumpButtonIndex);
    std::cout << text01 << "\t\t";
    std::cout << std::endl;

    std::cout << "RoundsPer100mL\t\t\t";
    std::cout << DPump->RoundsPer100mL << "\t\t";
    std::cout << ActivePump.RoundsPer100mL << "\t\t";
    std::cout << pump[0].RoundsPer100mL << "\t\t";
    std::cout << pump[1].RoundsPer100mL << "\t\t";
    std::cout << pump[2].RoundsPer100mL << "\t\t";
    std::cout << std::endl;

    std::cout << "FlowMLPerHour\t\t\t";
    std::cout << DPump->FlowMLPerHour_Value << "\t\t";
    std::cout << ActivePump.FlowMLPerHour_Value << "\t\t";
    std::cout << pump[0].FlowMLPerHour_Value << "\t\t";
    std::cout << pump[1].FlowMLPerHour_Value << "\t\t";
    std::cout << pump[2].FlowMLPerHour_Value << "\t\t";
    std::cout << std::endl;

    std::cout << "CalibrationFactorPercent\t";
    std::cout << DPump->CalibrationFactorPercent_Value<< "\t\t";
    std::cout << ActivePump.CalibrationFactorPercent_Value<< "\t\t";
    std::cout << pump[0].CalibrationFactorPercent_Value << "\t\t";
    std::cout << pump[1].CalibrationFactorPercent_Value << "\t\t";
    std::cout << pump[2].CalibrationFactorPercent_Value << "\t\t";
    std::cout << std::endl;

    std::cout << "DosingIntervalTimeMinute\t";
    std::cout << DPump->DosingIntervalTimeMinute_Value << "\t\t";
    std::cout << ActivePump.DosingIntervalTimeMinute_Value << "\t\t";
    std::cout << pump[0].DosingIntervalTimeMinute_Value << "\t\t";
    std::cout << pump[1].DosingIntervalTimeMinute_Value << "\t\t";
    std::cout << pump[2].DosingIntervalTimeMinute_Value << "\t\t";
    std::cout << std::endl;

    std::cout << "DelayIntervalTimeMinute\t\t";
    std::cout << DPump->DelayIntervalTimeMinute_Value << "\t\t";
    std::cout << ActivePump.DelayIntervalTimeMinute_Value << "\t\t";
    std::cout << pump[0].DelayIntervalTimeMinute_Value << "\t\t";
    std::cout << pump[1].DelayIntervalTimeMinute_Value << "\t\t";
    std::cout << pump[2].DelayIntervalTimeMinute_Value << "\t\t";
    std::cout << std::endl;

    std::cout << "EncoderCount\t\t\t";
    std::cout << DPump->EncoderCount << "\t\t";
    std::cout << ActivePump.EncoderCount << "\t\t";
    std::cout << pump[0].EncoderCount << "\t\t";
    std::cout << pump[1].EncoderCount << "\t\t";
    std::cout << pump[2].EncoderCount << "\t\t";
    std::cout << std::endl;

    std::cout << "Adress\t\t\t\t";
    std::cout << &DPump << "\t";
    std::cout << &ActivePump << "\t";
    std::cout << &pump[0] << "\t";
    std::cout << &pump[1] << "\t";
    std::cout << &pump[2] << "\t";
    std::cout << std::endl;
}

int main(void)
{
	ipcon_create(&ipcon);
    lcd_128x64_create(&pLCD128x64, UID_LCD128x64, &ipcon);

    LCDButtonIndex = LCD128x64_ButtonFlow;
    LCDTabIndex = TABHOME;

    stepper_create(&pStepper[0], UID_STEPPER01, &ipcon);
	stepper_create(&pStepper[1], UID_STEPPER02, &ipcon);
	stepper_create(&pStepper[2], UID_STEPPER03, &ipcon);

	rotary_encoder_v2_create(&pEncoder[0], UID_rotEnc01, &ipcon);
    rotary_encoder_v2_create(&pEncoder[1], UID_rotEnc02, &ipcon);
    rotary_encoder_v2_create(&pEncoder[2], UID_rotEnc03, &ipcon);

    InitializePumpParameter1(&ActivePump, PUMP01_ID, "AcP", "non", PUMP01_TABINDEX, LCD128x64_ButtonFlow);
    InitializePumpParameter1(&pump[0], PUMP01_ID, "P01", "Rg1", PUMP01_TABINDEX, LCD128x64_ButtonCalFactor);
    InitializePumpParameter1(&pump[1], PUMP02_ID, "P02", "Rg2", PUMP02_TABINDEX, LCD128x64_ButtonFlow);
    InitializePumpParameter1(&pump[2], PUMP03_ID, "P03", "NH3", PUMP03_TABINDEX, LCD128x64_ButtonFlow);


    InitializePumpParameter2(&ActivePump, &pStepper[0], &pEncoder[0], &pLCD128x64);
    InitializePumpParameter2(&pump[0], &pStepper[0], &pEncoder[0], &pLCD128x64);
    InitializePumpParameter2(&pump[1], &pStepper[1], &pEncoder[1], &pLCD128x64);
    InitializePumpParameter2(&pump[2], &pStepper[2], &pEncoder[2], &pLCD128x64);

    millisleep(400);
	if(ipcon_connect(&ipcon, HOST, PORT) < 0)
    {
		fprintf(stderr, "Could not connect\n");
		return 1;
    }
 //   LCD128x64_HomeScreen();
  	lcd_128x64_register_callback(&pLCD128x64,
	                             LCD_128X64_CALLBACK_GUI_TAB_SELECTED,
	                             (void (*)(void))cb_gui_tab_selected, &ActivePump
                                );
    lcd_128x64_register_callback(&pLCD128x64,
                                 LCD_128X64_CALLBACK_GUI_BUTTON_PRESSED,
                                 (void (*)(void))cb_gui_button_pressed01, &LCDTabIndex
                                 );

    rotary_encoder_v2_register_callback(pump[0].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT,
                                        (void (*)(void))cb_InputEncoder, &pump[0]);
    rotary_encoder_v2_register_callback(pump[1].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT,
                                        (void (*)(void))cb_InputEncoder, &pump[1]);
    rotary_encoder_v2_register_callback(pump[2].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT,
                                        (void (*)(void))cb_InputEncoder, &pump[2]);

    rotary_encoder_v2_set_count_callback_configuration(pump[0].pEncoder, 200, true, 'x', 0, 0);
    rotary_encoder_v2_set_count_callback_configuration(pump[1].pEncoder, 200, true, 'x', 0, 0);
    rotary_encoder_v2_set_count_callback_configuration(pump[2].pEncoder, 200, true, 'x', 0, 0);

    lcd_128x64_set_gui_button_pressed_callback_configuration(&pLCD128x64, 300, true);
	lcd_128x64_set_gui_tab_selected_callback_configuration(&pLCD128x64, 300, true);

//	stepper_register_callback(pump[0].pStepper, STEPPER_CALLBACK_POSITION_REACHED, (void (*)(void))cb_StepperPositionReached, &pump[0]);
//	stepper_register_callback(pump[1].pStepper, STEPPER_CALLBACK_POSITION_REACHED, (void (*)(void))cb_StepperPositionReached, &pump[1]);
//	stepper_register_callback(pump[2].pStepper, STEPPER_CALLBACK_POSITION_REACHED, (void (*)(void))cb_StepperPositionReached, &pump[2]);

    LCD128x64_HomeScreen();

    printf("Press key to exit\n");
    getchar();



	stepper_stop(pump[0].pStepper); // Request motor stop
    stepper_stop(pump[1].pStepper); // Request motor stop
    stepper_stop(pump[2].pStepper); // Request motor stop
    stepper_set_speed_ramping(pump[0].pStepper, STEPPER_ACCELERATION, STEPPER_DEACCELERATION);
    stepper_set_speed_ramping(pump[1].pStepper, STEPPER_ACCELERATION, STEPPER_DEACCELERATION);
    stepper_set_speed_ramping(pump[2].pStepper, STEPPER_ACCELERATION, STEPPER_DEACCELERATION);

	millisleep(1000); // Wait for motor to actually stop: max velocity (2000 steps/s) / decceleration (5000 steps/s^2) = 0.4 s
	stepper_disable(pump[0].pStepper); // Disable motor power
	stepper_disable(pump[1].pStepper); // Disable motor power
	stepper_disable(pump[2].pStepper); // Disable motor power

	stepper_destroy(pump[0].pStepper);
	stepper_destroy(pump[1].pStepper);
	stepper_destroy(pump[2].pStepper);

	lcd_128x64_destroy(&pLCD128x64);
	rotary_encoder_v2_destroy(pump[0].pEncoder);
	rotary_encoder_v2_destroy(pump[1].pEncoder);
	rotary_encoder_v2_destroy(pump[2].pEncoder);


	ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally

	return 0;
}
