From 450e93982ebb81983a792e481ad4c55bc2280583 Mon Sep 17 00:00:00 2001 From: Bernhard Date: Sat, 24 Jan 2026 18:56:30 +0100 Subject: [PATCH] =?UTF-8?q?Im=20Simu-Mode=20Bedienung=20=C3=BCber=20Tastat?= =?UTF-8?q?ur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- io/io.c | 54 ++++++++++++++++---------- io/io.h | 2 + main.c | 92 ++++++++++++++++++++++++++++++++++++++------- main.h | 7 ++++ mqtt/mqtt_client.c | 13 +++++++ mqtt/mqtt_client.h | 1 + settings/settings.c | 36 +++++++++++++----- settings/settings.h | 4 ++ 8 files changed, 167 insertions(+), 42 deletions(-) diff --git a/io/io.c b/io/io.c index a2db865..e0a8a9f 100755 --- a/io/io.c +++ b/io/io.c @@ -2,17 +2,22 @@ #include "main.h" #include "io.h" #include +#include +#include struct GPIO_KEY_DATA gpioKeyStop; struct GPIO_KEY_DATA gpioKeyPwrUp; struct GPIO_KEY_DATA gpioKeyPwrDown; char nInitialized = 0; +int iPowerSupplyOn = 0; /// @brief Initialize the io pins /// @return int IO_Init() { + iPowerSupplyOn = 0; + if (wiringPiSetupPinType(WPI_PIN_BCM)) { mylog(LOG_ERR, "IO: Set up wiringPi failed!"); @@ -179,46 +184,57 @@ void IO_DoCyclic() ReadKey(&gpioKeyPwrUp); ReadKey(&gpioKeyPwrDown); - if (gpioKeyStop.iKeyValue) + if (gpioKeyStop.iKeyValue || atomic_load(&abKeyStop)) { // stop key is pressed - if (gpioKeyStop.iKeyRisingEdge) + if (gpioKeyStop.iKeyRisingEdge || atomic_load(&abKeyStop)) { mylog(LOG_INFO, "IO: KEY-Stop: Stop motor."); Can_SetMotorGear(0, 0); } } - else if (motctrl[0].nDriveReady) // plus and minus keys only when drive is ready + + if (gpioKeyPwrUp.iKeyRisingEdge || atomic_load(&abKeyPlus)) { - if (gpioKeyPwrUp.iKeyRisingEdge) + if (motctrl[0].nDriveReady) { - // plus key is pressed -> increase power + // when drive is ready to run: plus key is pressed -> increase power if (motctrl[0].iMotorGear == MOTOR_GEAR_NEUTRAL) { mylog(LOG_INFO, "IO: KEY-Plus: Start motor."); Can_SetMotorGear(0, 1); Can_SetMotorPower(0, 1); } - else + else if (motctrl[0].iMotorPowerSteps < settings.iMotorPwrStepCount) { mylog(LOG_INFO, "IO: KEY-Plus: Increase power."); Can_SetMotorPower(0, motctrl[0].iMotorPowerSteps + 1); } } - - if (gpioKeyPwrDown.iKeyRisingEdge) + else if (settings.iShellySupplyCount > 0) { - // minus key is pressed -> decrease power - if (motctrl[0].iMotorPowerSteps > 1) - { - mylog(LOG_INFO, "IO: KEY-Minus: Decrease power."); - Can_SetMotorPower(0, motctrl[0].iMotorPowerSteps - 1); - } - else - { - mylog(LOG_INFO, "IO: KEY-Minus: Stop motor."); - Can_SetMotorGear(0, 0); - } + // when drive is not ready and we have to switch the supply + MqttClient_SwitchPowerSupply(1); + iPowerSupplyOn = 1; } } + + if (gpioKeyPwrDown.iKeyRisingEdge || atomic_load(&abKeyMinus)) + { + // minus key is pressed -> decrease power + if (motctrl[0].iMotorPowerSteps > 1) + { + mylog(LOG_INFO, "IO: KEY-Minus: Decrease power."); + Can_SetMotorPower(0, motctrl[0].iMotorPowerSteps - 1); + } + // else + // { + // mylog(LOG_INFO, "IO: KEY-Minus: Stop motor."); + // Can_SetMotorGear(0, 0); + // } + } + + atomic_store(&abKeyPlus, false); + atomic_store(&abKeyMinus, false); + atomic_store(&abKeyStop, false); } diff --git a/io/io.h b/io/io.h index 9893013..b8fddb2 100755 --- a/io/io.h +++ b/io/io.h @@ -30,6 +30,8 @@ struct GPIO_KEY_DATA int iKeyRepeatCycleCounter; }; +extern int iPowerSupplyOn; + int IO_Init(); void IO_DoCyclic(); void SetupKeyPin(struct GPIO_KEY_DATA *pdata, int iKeyPin); diff --git a/main.c b/main.c index 19c9a45..9e06913 100755 --- a/main.c +++ b/main.c @@ -4,12 +4,17 @@ #include #include #include +#include // Period info of the realtime task struct period_info pinfo; -int iThreadControl = 0; // 0: thread is running, <0: thread shall exit, >0 thread has exited int iLogToConsole = 1; +atomic_short asThreadControl = ATOMIC_VAR_INIT(0); // 0: thread is running, <0: thread shall exit, >0 thread has exited +// values for simulation +atomic_bool abKeyPlus = ATOMIC_VAR_INIT(false); +atomic_bool abKeyMinus = ATOMIC_VAR_INIT(false); +atomic_bool abKeyStop = ATOMIC_VAR_INIT(false); /// @brief send a log message /// @param prio @@ -150,7 +155,7 @@ void *thread_func(void *data) } // Connect to mqtt broker - while (MqttClient_Connect() && (iThreadControl == 0)) + while (MqttClient_Connect() && atomic_load(&asThreadControl) == 0) { mylog(LOG_ERR, "MqttClient_Connect() failed!"); sleep(10); @@ -163,7 +168,7 @@ void *thread_func(void *data) WriteOutputPin(GPIO_OUT_PWRON, HIGH); // cyclic call of do_cyclic_1ms() - while (iThreadControl == 0) + while (atomic_load(&asThreadControl) == 0) { pinfo.cyclecounter++; if (pinfo.cyclecounter > CYCLE_COUNTER_MAX) @@ -185,11 +190,22 @@ void *thread_func(void *data) Can_CloseInterface(0); // signal thread has finnished - iThreadControl = 1; + atomic_store(&asThreadControl, 1); return NULL; } +// Funktion, um das Terminal in den "Raw Mode" zu versetzen +void set_conio_terminal_mode() +{ + struct termios new_termios; + tcgetattr(0, &new_termios); + new_termios.c_lflag &= ~ICANON; // Deaktiviert den zeilenweisen Modus + new_termios.c_lflag &= ~ECHO; // Verhindert, dass die Taste angezeigt wird + tcsetattr(0, TCSANOW, &new_termios); +} + + /// @brief catch signals and set flag to terminate for the realtime thread /// @param signo void sig_handler(int signo) @@ -197,7 +213,7 @@ void sig_handler(int signo) if ((signo == SIGINT) || (signo == SIGTERM)) { mylog(LOG_INFO, "Received signal %d", signo); - iThreadControl = -1; // signal realtime thread to exit + atomic_store(&asThreadControl, -1); // signal realtime thread to exit } } @@ -222,16 +238,24 @@ int main(int argc, char* argv[]) // Read the settings file after opening the log Settings_ReadConfFile(); - // catch signals - if (signal(SIGTERM, sig_handler) == SIG_ERR) + if (settings.iCanSimu) { - mylog(LOG_ERR, "Can't catch SIGTERM"); - exit(-1); + // in simulation mode switch terminal to raw mode + set_conio_terminal_mode(); } - if (signal(SIGINT, sig_handler) == SIG_ERR) + else { - mylog(LOG_ERR, "Can't catch SIGINT"); - exit(-2); + // catch signals + if (signal(SIGTERM, sig_handler) == SIG_ERR) + { + mylog(LOG_ERR, "Can't catch SIGTERM"); + exit(-1); + } + if (signal(SIGINT, sig_handler) == SIG_ERR) + { + mylog(LOG_ERR, "Can't catch SIGINT"); + exit(-2); + } } /* Lock memory */ @@ -281,7 +305,7 @@ int main(int argc, char* argv[]) /* Create a pthread with specified attributes */ - iThreadControl = 0; + atomic_store(&asThreadControl, 0); ret = pthread_create(&thread, &attr, thread_func, NULL); if (ret) { @@ -289,6 +313,48 @@ int main(int argc, char* argv[]) goto out; } + if (settings.iCanSimu) + { + // in simulation mode we use keys to control the motors + mylog(LOG_INFO, "*** CanRtDriver in Simu-Mode ***"); + while (1) + { + char ch = getchar(); + mylog(LOG_INFO, "SIMU: Taste gedrückt: %c", ch); + + if (ch == '+') + { + atomic_store(&abKeyPlus, true); + } + else if (ch == '-') + { + atomic_store(&abKeyMinus, true); + } + else if (ch == 's') + { + atomic_store(&abKeyStop, true); + } + else if (ch == 'p') + { + if (iPowerSupplyOn) + { + MqttClient_SwitchPowerSupply(0); + iPowerSupplyOn = 0; + } + else + { + MqttClient_SwitchPowerSupply(1); + iPowerSupplyOn = 1; + } + } + else if ( ch == 'q') + { + atomic_store(&asThreadControl, -1); // signal realtime thread to exit + break; + } + } + } + // join the thread and wait for it to exit ret = pthread_join(thread, NULL); if (ret) diff --git a/main.h b/main.h index 6df4fa6..ff264a3 100755 --- a/main.h +++ b/main.h @@ -13,6 +13,9 @@ #include #include #include +#include +#include + #define CYCLE_COUNTER_MAX 86400000 @@ -24,6 +27,10 @@ struct period_info float fStartTime; }; +extern atomic_bool abKeyPlus; +extern atomic_bool abKeyMinus; +extern atomic_bool abKeyStop; + extern struct period_info pinfo; extern void mylog(int prio, const char *format, ...); diff --git a/mqtt/mqtt_client.c b/mqtt/mqtt_client.c index 4b6163b..0113ca6 100755 --- a/mqtt/mqtt_client.c +++ b/mqtt/mqtt_client.c @@ -301,4 +301,17 @@ void MqttClient_Publish_MotorActualPowerW(int iMotorIndex, int iMotorPowerW) mosquitto_publish(mosq, NULL, mqtt_topic_motor2_actualpowerw, strlen(message), message, 0, false); } } +} + + +void MqttClient_SwitchPowerSupply(int on) +{ + char *cmd = on ? "on" : "off"; + + for (int i=0; i= 0) @@ -74,12 +80,12 @@ void Settings_ReadConfFile() //const char *filename = "/etc/CanRtDriver.conf"; char filename[MAX_PATH + 50]; - sprintf(filename, "%s.conf", settings.sExePath); + sprintf(filename, "/etc/CanRtDriver.conf"); FILE *file = fopen(filename, "r"); if (file == NULL) { mylog(LOG_INFO, "SETTINGS: File %s noch found", filename); - sprintf(filename, "/etc/CanRtDriver.conf"); + sprintf(filename, "%s.conf", settings.sExePath); file = fopen(filename, "r"); if (file == NULL) { @@ -108,43 +114,53 @@ void Settings_ReadConfFile() if ((key != NULL) && (value != NULL)) { - //mylog(LOG_INFO, "SETTINGS: Found key: '%s' | value: '%s'", key, value); - if (strcmp(key, "DebugLevel") == 0) { + // how many log messages we want to see settings.iDebugLevel = atoi(value); mylog(LOG_DEBUG, "SETTINGS: %s = %d", key, settings.iDebugLevel); } else if (strcmp(key, "CanSimu") == 0) { + // shall we do simulation settings.iCanSimu = atoi(value); mylog(LOG_DEBUG, "SETTINGS: %s = %d", key, settings.iCanSimu); } else if (strcmp(key, "MotorPowerMinRaw") == 0) { + // Minimum power value for the motors settings.iMotorPwrMinRaw = atoi(value); mylog(LOG_DEBUG, "SETTINGS: %s = %d", key, settings.iMotorPwrMinRaw); } else if (strcmp(key, "MotorPowerMaxRaw") == 0) { + // Maximum power value for the motors settings.iMotorPwrMaxRaw = atoi(value); mylog(LOG_DEBUG, "SETTINGS: %s = %d", key, settings.iMotorPwrMaxRaw); } else if (strcmp(key, "MotorPowerStepCount") == 0) { + // How many steps do we want to have switching the power settings.iMotorPwrStepCount = atoi(value); mylog(LOG_DEBUG, "SETTINGS: %s = %d", key, settings.iMotorPwrStepCount); } + else if (strcmp(key, "SupplyShellyMqttTopic") == 0) + { + // MQTT topic for switching power supply + if (settings.iShellySupplyCount < MAX_SHELLIES_COUNT) + { + strcpy(settings.sShellySupplyTopic[settings.iShellySupplyCount], value); + settings.iShellySupplyCount++; + } + else + { + mylog(LOG_WARNING, "SETTINGS: Too many SupplyShellyMqttTopic!"); + } + } else { mylog(LOG_WARNING, "SETTING: Unknown key: %s", key); } - // // Beispiel: Wert verarbeiten - // if (strcmp(key, "port") == 0) - // { - // int port = atoi(value); - // printf(" [System] Port auf %d gesetzt.\n", port); - // } } } diff --git a/settings/settings.h b/settings/settings.h index 0506593..5f74bef 100755 --- a/settings/settings.h +++ b/settings/settings.h @@ -9,6 +9,7 @@ #define MAX_LINE_LENGTH 256 #define MAX_PATH 256 +#define MAX_SHELLIES_COUNT 5 struct APP_SETTINGS { @@ -20,6 +21,9 @@ struct APP_SETTINGS int iMotorPwrMinRaw; // Minimum power value for motor (raw value) int iMotorPwrMaxRaw; // Maximum power value for motor (raw value) int iMotorPwrStepCount; // Number of power steps + + int iShellySupplyCount; // How many Shellies we have to switch the power supply + char sShellySupplyTopic[MAX_SHELLIES_COUNT][MAX_PATH]; }; extern struct APP_SETTINGS settings;