Kommunikation hat funktioniert
This commit is contained in:
5
.gitignore
vendored
Executable file
5
.gitignore
vendored
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
# ignore all files in bin folder
|
||||||
|
bin/
|
||||||
|
|
||||||
|
._*
|
||||||
|
.DS_Store
|
||||||
179
can/can_client.c
Executable file
179
can/can_client.c
Executable file
@@ -0,0 +1,179 @@
|
|||||||
|
|
||||||
|
#include <can/can_client.h>
|
||||||
|
#include <io/io.h>
|
||||||
|
#include <mqtt/mqtt_client.h>
|
||||||
|
|
||||||
|
struct MOTOR_CONTROL_DATA motctrl[MOTOR_COUNT];
|
||||||
|
struct CAN_INTERFACE_DATA intf_data[MOTOR_COUNT];
|
||||||
|
|
||||||
|
/// @brief Open socket of CAN interface for the given motor
|
||||||
|
/// @param iMotorIndex
|
||||||
|
/// @param ifacename
|
||||||
|
/// @return
|
||||||
|
int Can_OpenInterface(int iMotorIndex, const char * ifacename)
|
||||||
|
{
|
||||||
|
strcpy(intf_data[iMotorIndex].iface_name, ifacename);
|
||||||
|
Can_SetMotorGear(iMotorIndex, 0);
|
||||||
|
Can_SetMotorPower(iMotorIndex, 0);
|
||||||
|
|
||||||
|
// first we have to create a socket
|
||||||
|
if ((intf_data[iMotorIndex].socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
|
||||||
|
{
|
||||||
|
printf("Could not create socket for motor %d!\n", iMotorIndex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve the interface index
|
||||||
|
strcpy(intf_data[iMotorIndex].ifr.ifr_name, intf_data[iMotorIndex].iface_name);
|
||||||
|
if (ioctl(intf_data[iMotorIndex].socket, SIOCGIFINDEX, &intf_data[iMotorIndex].ifr) < 0)
|
||||||
|
{
|
||||||
|
printf("Could not get interface index for motor %d!\n", iMotorIndex);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind the socket to the CAN interface
|
||||||
|
memset(&intf_data[iMotorIndex].addr, 0, sizeof(intf_data[iMotorIndex].addr));
|
||||||
|
intf_data[iMotorIndex].addr.can_family = AF_CAN;
|
||||||
|
intf_data[iMotorIndex].addr.can_ifindex = intf_data[iMotorIndex].ifr.ifr_ifindex;
|
||||||
|
if (bind(intf_data[iMotorIndex].socket, (struct sockaddr *)&intf_data[iMotorIndex].addr, sizeof(intf_data[iMotorIndex].addr)) < 0)
|
||||||
|
{
|
||||||
|
printf("Could not bind socket to inteface for motor %d!\n", iMotorIndex);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Interface %s (motor %d) opened!\n", ifacename, iMotorIndex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Close socket of CAN interface for the given motor
|
||||||
|
/// @param iMotorIndex
|
||||||
|
void Can_CloseInterface(int iMotorIndex)
|
||||||
|
{
|
||||||
|
if (close(intf_data[iMotorIndex].socket) < 0)
|
||||||
|
{
|
||||||
|
printf("Could not close socket of motor %d!\n", iMotorIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Interface %s (motor %d) closed.\n", intf_data[iMotorIndex].iface_name, iMotorIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Set gear for the given motor
|
||||||
|
/// @param iMotorIndex
|
||||||
|
/// @param iGear (-1=reverse, 0=neutral, 1=forward)
|
||||||
|
void Can_SetMotorGear(int iMotorIndex, int iGear)
|
||||||
|
{
|
||||||
|
if (iGear > 0)
|
||||||
|
{
|
||||||
|
if (motctrl[iMotorIndex].iMotorGear != MOTOR_GEAR_FORWARD)
|
||||||
|
{
|
||||||
|
MqttClient_Publish_MotorGear(iMotorIndex, iGear);
|
||||||
|
motctrl[iMotorIndex].iMotorGear = MOTOR_GEAR_FORWARD;
|
||||||
|
}
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, HIGH);
|
||||||
|
printf("Motor[%d]: Set gear forward.\n", iMotorIndex);
|
||||||
|
}
|
||||||
|
else if (iGear < 0)
|
||||||
|
{
|
||||||
|
if (motctrl[iMotorIndex].iMotorGear != MOTOR_GEAR_REVERSE)
|
||||||
|
{
|
||||||
|
MqttClient_Publish_MotorGear(iMotorIndex, iGear);
|
||||||
|
motctrl[iMotorIndex].iMotorGear = MOTOR_GEAR_REVERSE;
|
||||||
|
}
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, HIGH);
|
||||||
|
printf("Motor[%d]: Set gear reverse.\n", iMotorIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (motctrl[iMotorIndex].iMotorGear != MOTOR_GEAR_NEUTRAL)
|
||||||
|
{
|
||||||
|
MqttClient_Publish_MotorGear(iMotorIndex, iGear);
|
||||||
|
motctrl[iMotorIndex].iMotorGear = MOTOR_GEAR_NEUTRAL;
|
||||||
|
}
|
||||||
|
Can_SetMotorPower(iMotorIndex, MOTOR_PWR_MIN_PCT);
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, LOW);
|
||||||
|
printf("Motor[%d]: Set gear neutral.\n", iMotorIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Set power for the given motor
|
||||||
|
/// @param iMotorIndex
|
||||||
|
/// @param iPower (Range: 0..100)
|
||||||
|
void Can_SetMotorPower(int iMotorIndex, int iPower)
|
||||||
|
{
|
||||||
|
if (iPower <= MOTOR_PWR_MIN_PCT)
|
||||||
|
{
|
||||||
|
motctrl[iMotorIndex].iMotorPowerPct = MOTOR_PWR_MIN_PCT;
|
||||||
|
}
|
||||||
|
else if (iPower >= MOTOR_PWR_MAX_PCT)
|
||||||
|
{
|
||||||
|
motctrl[iMotorIndex].iMotorPowerPct = MOTOR_PWR_MAX_PCT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
motctrl[iMotorIndex].iMotorPowerPct = iPower;
|
||||||
|
}
|
||||||
|
MqttClient_Publish_MotorPower(iMotorIndex, motctrl[iMotorIndex].iMotorPowerPct);
|
||||||
|
|
||||||
|
motctrl[iMotorIndex].iMotorPower = 250 * motctrl[iMotorIndex].iMotorPowerPct / 100;
|
||||||
|
|
||||||
|
printf("Motor[%d]: Set power to %d%% -> %d\n",
|
||||||
|
iMotorIndex, motctrl[iMotorIndex].iMotorPowerPct, motctrl[iMotorIndex].iMotorPower);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Send CAN protocol for motor gear for the given motor
|
||||||
|
/// @param iMotorIndex
|
||||||
|
void Can_TransmitMotorGear(int iMotorIndex)
|
||||||
|
{
|
||||||
|
// Transmission rate: 100ms
|
||||||
|
struct can_frame frame;
|
||||||
|
|
||||||
|
frame.can_id = 0x18F005D0;
|
||||||
|
frame.can_id |= CAN_EFF_FLAG;
|
||||||
|
frame.can_dlc = 8;
|
||||||
|
frame.data[0] = motctrl[iMotorIndex].iMotorGear;
|
||||||
|
frame.data[1] = 0xFF;
|
||||||
|
frame.data[2] = 0xFF;
|
||||||
|
frame.data[3] = 0xFF;
|
||||||
|
frame.data[4] = 0xFF;
|
||||||
|
frame.data[5] = 0xFF;
|
||||||
|
frame.data[6] = 0xFF;
|
||||||
|
frame.data[7] = 0xFF;
|
||||||
|
|
||||||
|
if (write(intf_data[iMotorIndex].socket, &frame, sizeof(frame)) != sizeof(frame))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Send CAN protocol for motor power for the given motor
|
||||||
|
/// @param iMotorIndex
|
||||||
|
void Can_TransmitMotorPower(int iMotorIndex)
|
||||||
|
{
|
||||||
|
// Transmission rate: 50ms
|
||||||
|
struct can_frame frame;
|
||||||
|
|
||||||
|
frame.can_id = 0x0CF003D0;
|
||||||
|
frame.can_id |= CAN_EFF_FLAG;
|
||||||
|
frame.can_dlc = 8;
|
||||||
|
frame.data[0] = 0xFF;
|
||||||
|
frame.data[1] = motctrl[iMotorIndex].iMotorPower; // motor power 0 = 0%, 250 = 100%
|
||||||
|
frame.data[2] = 0xFF;
|
||||||
|
frame.data[3] = 0xFF;
|
||||||
|
frame.data[4] = 0xFF;
|
||||||
|
frame.data[5] = 0xFF;
|
||||||
|
frame.data[6] = 0xFF;
|
||||||
|
frame.data[7] = 0xFF;
|
||||||
|
|
||||||
|
if (write(intf_data[iMotorIndex].socket, &frame, sizeof(frame)) != sizeof(frame))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
52
can/can_client.h
Executable file
52
can/can_client.h
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#if !defined(__CAN_CLIENT_H__)
|
||||||
|
#define __CAN_CLIENT_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <linux/can.h>
|
||||||
|
#include <linux/can/raw.h>
|
||||||
|
|
||||||
|
#define MOTOR_COUNT 2
|
||||||
|
|
||||||
|
// motor gear: 0x7C=reverse, 0x7D=neutral, 0x7E=forward
|
||||||
|
#define MOTOR_GEAR_REVERSE 0x7C
|
||||||
|
#define MOTOR_GEAR_NEUTRAL 0x7D
|
||||||
|
#define MOTOR_GEAR_FORWARD 0x7E
|
||||||
|
|
||||||
|
#define MOTOR_PWR_MIN_PCT 5
|
||||||
|
#define MOTOR_PWR_MAX_PCT 100
|
||||||
|
#define MOTOR_PWR_STEP 14
|
||||||
|
|
||||||
|
struct MOTOR_CONTROL_DATA
|
||||||
|
{
|
||||||
|
int iMotorGear;
|
||||||
|
int iMotorPower;
|
||||||
|
int iMotorPowerPct;
|
||||||
|
};
|
||||||
|
extern struct MOTOR_CONTROL_DATA motctrl[MOTOR_COUNT];
|
||||||
|
|
||||||
|
struct CAN_INTERFACE_DATA
|
||||||
|
{
|
||||||
|
int socket;
|
||||||
|
char iface_name[20];
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct sockaddr_can addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
int Can_OpenInterface(int iMotorIndex, const char * ifacename);
|
||||||
|
void Can_CloseInterface(int iMotorIndex);
|
||||||
|
|
||||||
|
void Can_SetMotorGear(int iMotorIndex, int iGear);
|
||||||
|
void Can_SetMotorPower(int iMotorIndex, int iPower);
|
||||||
|
|
||||||
|
void Can_TransmitMotorGear(int iMotorIndex);
|
||||||
|
void Can_TransmitMotorPower(int iMotorIndex);
|
||||||
|
|
||||||
|
#endif
|
||||||
211
io/io.c
Executable file
211
io/io.c
Executable file
@@ -0,0 +1,211 @@
|
|||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include <can/can_client.h>
|
||||||
|
|
||||||
|
struct GPIO_KEY_DATA gpioKeyStop;
|
||||||
|
struct GPIO_KEY_DATA gpioKeyPwrUp;
|
||||||
|
struct GPIO_KEY_DATA gpioKeyPwrDown;
|
||||||
|
|
||||||
|
int IO_Init()
|
||||||
|
{
|
||||||
|
if (wiringPiSetupPinType(WPI_PIN_BCM))
|
||||||
|
{
|
||||||
|
printf("IO: Set up wiringPi failed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IO-Pins für Tasten konfigurieren
|
||||||
|
SetupKeyPin(&gpioKeyStop, GPIO_KEY_STOP);
|
||||||
|
SetupKeyPin(&gpioKeyPwrUp, GPIO_KEY_PWRUP);
|
||||||
|
SetupKeyPin(&gpioKeyPwrDown, GPIO_KEY_PWRDOWN);
|
||||||
|
|
||||||
|
// IO-Pins für Ausgänge konfigurieren
|
||||||
|
SetupOutputPin(GPIO_LED_MOTRUN);
|
||||||
|
|
||||||
|
// Einschaltsequenz
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, HIGH);
|
||||||
|
delay(500);
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, LOW);
|
||||||
|
delay(500);
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, HIGH);
|
||||||
|
delay(500);
|
||||||
|
WriteOutputPin(GPIO_LED_MOTRUN, LOW);
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
printf("IO initialized successfull!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetupKeyPin(struct GPIO_KEY_DATA *pdata, int iKeyPin)
|
||||||
|
{
|
||||||
|
pdata->iKeyPin = iKeyPin;
|
||||||
|
pdata->iKeyValue = 0;
|
||||||
|
pdata->iKeyRisingEdge = 0;
|
||||||
|
pdata->iKeyFallingEdge = 0;
|
||||||
|
pdata->nHighCycleCounter = 0;
|
||||||
|
pdata->nLowCycleCounter = 0;
|
||||||
|
pdata->iKeyPressedCycleCounter = 0;
|
||||||
|
pdata->iKeyRepeatCycleCounter = 0;
|
||||||
|
|
||||||
|
// Wenn Eingang verwendet wird
|
||||||
|
if (pdata->iKeyPin > 0)
|
||||||
|
{
|
||||||
|
pinMode(pdata->iKeyPin, INPUT);
|
||||||
|
pullUpDnControl(pdata->iKeyPin, PUD_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ReadKey(struct GPIO_KEY_DATA *pdata)
|
||||||
|
{
|
||||||
|
if (pdata->iKeyPin > 0)
|
||||||
|
{
|
||||||
|
int newval = pdata->iKeyValue;
|
||||||
|
|
||||||
|
if (digitalRead(pdata->iKeyPin) == LOW) // invertierte Logik weil wir PullUp-Widerstand bei Betätigung auf low ziehen
|
||||||
|
{
|
||||||
|
// Signal liegt an
|
||||||
|
if (pdata->nLowCycleCounter > 0)
|
||||||
|
{
|
||||||
|
pdata->nLowCycleCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdata->nHighCycleCounter < KEY_RISING_FILTERCYCLES)
|
||||||
|
{
|
||||||
|
pdata->nHighCycleCounter++;
|
||||||
|
if (pdata->nHighCycleCounter >= KEY_RISING_FILTERCYCLES)
|
||||||
|
{
|
||||||
|
// gewünschte Anzahl Zyklen stabil
|
||||||
|
newval = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Signal liegt nicht an
|
||||||
|
if (pdata->nHighCycleCounter > 0)
|
||||||
|
{
|
||||||
|
pdata->nHighCycleCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdata->nLowCycleCounter < KEY_FALLING_FILTERCYCLES)
|
||||||
|
{
|
||||||
|
pdata->nLowCycleCounter++;
|
||||||
|
if (pdata->nLowCycleCounter >= KEY_FALLING_FILTERCYCLES)
|
||||||
|
{
|
||||||
|
// gewünschte Anzahl Zyklen stabil
|
||||||
|
newval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newval && !pdata->iKeyValue)
|
||||||
|
{
|
||||||
|
// Taster wurde betätigt
|
||||||
|
pdata->iKeyRisingEdge = 1;
|
||||||
|
pdata->iKeyValue = newval;
|
||||||
|
pdata->iKeyPressedCycleCounter = 0;
|
||||||
|
pdata->iKeyRepeatCycleCounter = 0;
|
||||||
|
}
|
||||||
|
else if (pdata->iKeyValue && !newval)
|
||||||
|
{
|
||||||
|
// Taster wurde losgelassen
|
||||||
|
pdata->iKeyFallingEdge = 1;
|
||||||
|
pdata->iKeyValue = newval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Keine Änderung
|
||||||
|
pdata->iKeyRisingEdge = 0;
|
||||||
|
pdata->iKeyFallingEdge = 0;
|
||||||
|
|
||||||
|
if (pdata->iKeyValue)
|
||||||
|
{
|
||||||
|
// Wenn Taste gedrückt ist
|
||||||
|
if (pdata->iKeyPressedCycleCounter < KEY_START_REPEAT_CYCLECOUNT)
|
||||||
|
{
|
||||||
|
// Zyklen zählen
|
||||||
|
pdata->iKeyPressedCycleCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdata->iKeyPressedCycleCounter >= KEY_START_REPEAT_CYCLECOUNT)
|
||||||
|
{
|
||||||
|
// Wenn Taste länger als KEY_START_REPEAT_CYCLECOUNT gedrückt ist
|
||||||
|
pdata->iKeyRepeatCycleCounter++;
|
||||||
|
if (pdata->iKeyRepeatCycleCounter >= KEY_REPEAT_CYCLECOUNT)
|
||||||
|
{
|
||||||
|
// alle KEY_REPEAT_CYCLECOUNT Zyklen Tastendruck signalisieren
|
||||||
|
pdata->iKeyRisingEdge = 1;
|
||||||
|
pdata->iKeyRepeatCycleCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetupOutputPin(int iOutPin)
|
||||||
|
{
|
||||||
|
if (iOutPin > 0)
|
||||||
|
{
|
||||||
|
pinMode(iOutPin, OUTPUT);
|
||||||
|
digitalWrite(iOutPin, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteOutputPin(int iOutPin, int iValue)
|
||||||
|
{
|
||||||
|
if (iOutPin > 0)
|
||||||
|
{
|
||||||
|
digitalWrite(iOutPin, iValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IO_DoCyclic()
|
||||||
|
{
|
||||||
|
ReadKey(&gpioKeyStop);
|
||||||
|
ReadKey(&gpioKeyPwrUp);
|
||||||
|
ReadKey(&gpioKeyPwrDown);
|
||||||
|
|
||||||
|
if (gpioKeyStop.iKeyValue)
|
||||||
|
{
|
||||||
|
// Stop-Taste betätigt -> hat Vorrang vor den anderen Tasten
|
||||||
|
if (gpioKeyStop.iKeyRisingEdge)
|
||||||
|
{
|
||||||
|
Can_SetMotorGear(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (gpioKeyPwrUp.iKeyRisingEdge)
|
||||||
|
{
|
||||||
|
// Leistung erhöhen
|
||||||
|
if (motctrl[0].iMotorGear == MOTOR_GEAR_NEUTRAL)
|
||||||
|
{
|
||||||
|
Can_SetMotorGear(0, 1);
|
||||||
|
Can_SetMotorPower(0, MOTOR_PWR_MIN_PCT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Can_SetMotorPower(0, motctrl[0].iMotorPowerPct + MOTOR_PWR_STEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpioKeyPwrDown.iKeyRisingEdge)
|
||||||
|
{
|
||||||
|
// Leistung verringern
|
||||||
|
if (motctrl[0].iMotorPowerPct > MOTOR_PWR_MIN_PCT)
|
||||||
|
{
|
||||||
|
Can_SetMotorPower(0, motctrl[0].iMotorPowerPct - MOTOR_PWR_STEP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Can_SetMotorGear(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
io/io.h
Executable file
37
io/io.h
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
#if !defined(__IO_H__)
|
||||||
|
#define __IO_H__
|
||||||
|
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define GPIO_LED_MOTRUN 17 // GPIO Pin fuer LED Motor läuft
|
||||||
|
|
||||||
|
#define GPIO_KEY_STOP 26 // GPIO Pin fuer Taster Stop
|
||||||
|
#define GPIO_KEY_PWRUP 5 // GPIO Pin fuer Taster Leistung-Erhöhen
|
||||||
|
#define GPIO_KEY_PWRDOWN 6 // GPIO Pin fuer Taster Leistung-Verringern
|
||||||
|
|
||||||
|
#define KEY_RISING_FILTERCYCLES 5 // Filterwert für Eingänge steigende Flanke
|
||||||
|
#define KEY_FALLING_FILTERCYCLES 15 // Filterwert für Eingänge (Zyklen-Zähler)
|
||||||
|
#define KEY_START_REPEAT_CYCLECOUNT 50 // Anzahl Zyklen, nach denen Wiederholungen beginnen
|
||||||
|
#define KEY_REPEAT_CYCLECOUNT 50 // Anzahl Zyklen, nach den wiederholt wird
|
||||||
|
|
||||||
|
// Datenstruktur für einen Taster
|
||||||
|
struct GPIO_KEY_DATA
|
||||||
|
{
|
||||||
|
int iKeyPin;
|
||||||
|
int iKeyValue;
|
||||||
|
int iKeyRisingEdge;
|
||||||
|
int iKeyFallingEdge;
|
||||||
|
unsigned int nHighCycleCounter;
|
||||||
|
unsigned int nLowCycleCounter;
|
||||||
|
int iKeyPressedCycleCounter;
|
||||||
|
int iKeyRepeatCycleCounter;
|
||||||
|
};
|
||||||
|
|
||||||
|
int IO_Init();
|
||||||
|
void IO_DoCyclic();
|
||||||
|
void SetupKeyPin(struct GPIO_KEY_DATA *pdata, int iKeyPin);
|
||||||
|
void SetupOutputPin(int iOutPin);
|
||||||
|
void WriteOutputPin(int iOutPin, int iValue);
|
||||||
|
|
||||||
|
#endif
|
||||||
253
main.c
Executable file
253
main.c
Executable file
@@ -0,0 +1,253 @@
|
|||||||
|
|
||||||
|
#include <main.h>
|
||||||
|
#include <mqtt/mqtt_client.h>
|
||||||
|
#include <can/can_client.h>
|
||||||
|
#include <io/io.h>
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
/// @brief Initialize period_info with period_ms for cyclic task
|
||||||
|
/// @param period_ms
|
||||||
|
/// @param pinfo
|
||||||
|
static void periodic_task_init(long period_ms, struct period_info *pinfo)
|
||||||
|
{
|
||||||
|
/* for simplicity, hardcoding a 1ms period */
|
||||||
|
pinfo->period_ns = period_ms * 1000000;
|
||||||
|
pinfo->cyclecounter = 0;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &(pinfo->next_period));
|
||||||
|
pinfo->fStartTime = (float)pinfo->next_period.tv_sec + ((float)pinfo->next_period.tv_nsec / 1000000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Wait in cyclic task the rest of time until the next cycle
|
||||||
|
/// @param pinfo
|
||||||
|
static void wait_rest_of_period(struct period_info *pinfo)
|
||||||
|
{
|
||||||
|
pinfo->next_period.tv_nsec += pinfo->period_ns;
|
||||||
|
|
||||||
|
while (pinfo->next_period.tv_nsec >= 1000000000) {
|
||||||
|
/* timespec nsec overflow */
|
||||||
|
pinfo->next_period.tv_sec++;
|
||||||
|
pinfo->next_period.tv_nsec -= 1000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for simplicity, ignoring possibilities of signal wakes */
|
||||||
|
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pinfo->next_period, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Get monotonic time in sec as float
|
||||||
|
/// @return
|
||||||
|
float clock_gettime_s()
|
||||||
|
{
|
||||||
|
struct timespec tm;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &tm);
|
||||||
|
return (float)tm.tv_sec + ((float)tm.tv_nsec / 1000000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Cyclic task, is called from thread_func every ms
|
||||||
|
/// @param pinfo
|
||||||
|
static void do_cyclic_1ms(struct period_info *pinfo)
|
||||||
|
{
|
||||||
|
uint16_t nCalled = 0;
|
||||||
|
|
||||||
|
if ((pinfo->cyclecounter % 10) == 0)
|
||||||
|
{
|
||||||
|
// called every 10ms
|
||||||
|
nCalled |= 0x1000;
|
||||||
|
IO_DoCyclic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pinfo->cyclecounter % 50) == 0)
|
||||||
|
{
|
||||||
|
// called every 50ms
|
||||||
|
nCalled |= 0x0001;
|
||||||
|
Can_TransmitMotorPower(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((pinfo->cyclecounter + 10) % 100) == 0)
|
||||||
|
{
|
||||||
|
// called every 100ms
|
||||||
|
nCalled |= 0x0010;
|
||||||
|
Can_TransmitMotorGear(0);
|
||||||
|
//printf("%.3f: 100ms-Cycle %ld...\n", clock_gettime_s() - pinfo->fStartTime, pinfo->cyclecounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((pinfo->cyclecounter + 20) % 100) == 0)
|
||||||
|
{
|
||||||
|
// called every 100ms
|
||||||
|
nCalled |= 0x0100;
|
||||||
|
MqttClient_Refresher();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((pinfo->cyclecounter + 30) % 500) == 0)
|
||||||
|
{
|
||||||
|
// called every 250ms
|
||||||
|
MqttClient_Publisher();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nCalled > 0)
|
||||||
|
{
|
||||||
|
//printf("%.3f: Called 0x%.4X at cycle %ld...\n", clock_gettime_s() - pinfo->fStartTime, nCalled, pinfo->cyclecounter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Our one and only realtime task
|
||||||
|
/// @param data
|
||||||
|
/// @return
|
||||||
|
void *thread_func(void *data)
|
||||||
|
{
|
||||||
|
// Open CAN interface first motor
|
||||||
|
if (Can_OpenInterface(0, "can0"))
|
||||||
|
{
|
||||||
|
printf("Can_OpenInterface() failed!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to mqtt broker
|
||||||
|
while (MqttClient_Connect() && (iThreadControl == 0))
|
||||||
|
{
|
||||||
|
printf("MqttClient_Connect() failed!\n");
|
||||||
|
sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize IO Ports
|
||||||
|
if (IO_Init())
|
||||||
|
{
|
||||||
|
printf("IO_Init() failed!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize cyclic task
|
||||||
|
periodic_task_init(1, &pinfo);
|
||||||
|
|
||||||
|
// cyclic call of do_cyclic_1ms()
|
||||||
|
while (iThreadControl == 0)
|
||||||
|
{
|
||||||
|
pinfo.cyclecounter++;
|
||||||
|
if (pinfo.cyclecounter >= 86400000)
|
||||||
|
{
|
||||||
|
// Reset cycle counter every 24h
|
||||||
|
pinfo.cyclecounter = 0;
|
||||||
|
}
|
||||||
|
do_cyclic_1ms(&pinfo);
|
||||||
|
wait_rest_of_period(&pinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect from mqtt broker
|
||||||
|
MqttClient_Close();
|
||||||
|
|
||||||
|
// Close CAN interface
|
||||||
|
Can_CloseInterface(0);
|
||||||
|
|
||||||
|
iThreadControl = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief catch signals and set flag to terminate for the realtime thread
|
||||||
|
/// @param signo
|
||||||
|
void sig_handler(int signo)
|
||||||
|
{
|
||||||
|
if ((signo == SIGINT) || (signo == SIGTERM))
|
||||||
|
{
|
||||||
|
printf("Received signal %d\n", signo);
|
||||||
|
iThreadControl = -1; // signal realtime thread to exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Hauptfunktion Echtzeit-Task erstellen und starten
|
||||||
|
/// @param argc
|
||||||
|
/// @param argv
|
||||||
|
/// @return
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
struct sched_param param;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_t thread;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// catch signals
|
||||||
|
if (signal(SIGTERM, sig_handler) == SIG_ERR)
|
||||||
|
{
|
||||||
|
printf("Can't catch SIGTERM\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (signal(SIGINT, sig_handler) == SIG_ERR)
|
||||||
|
{
|
||||||
|
printf("Can't catch SIGINT\n");
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock memory */
|
||||||
|
if(mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
|
||||||
|
{
|
||||||
|
printf("mlockall failed: %m\n");
|
||||||
|
exit(-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize pthread attributes (default values) */
|
||||||
|
ret = pthread_attr_init(&attr);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("init pthread attributes failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a specific stack size */
|
||||||
|
ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("pthread setstacksize failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set scheduler policy and priority of pthread */
|
||||||
|
ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("pthread setschedpolicy failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
param.sched_priority = 99; // Priority between 1 (low) and 99() high)
|
||||||
|
ret = pthread_attr_setschedparam(&attr, ¶m);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("pthread setschedparam failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Use scheduling parameters of attr */
|
||||||
|
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("pthread setinheritsched failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a pthread with specified attributes */
|
||||||
|
iThreadControl = 0;
|
||||||
|
ret = pthread_create(&thread, &attr, thread_func, NULL);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("create pthread failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// join the thread and wait for it to exit
|
||||||
|
ret = pthread_join(thread, NULL);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
printf("faild to join thread!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
26
main.h
Executable file
26
main.h
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#if !defined(__MAIN_H__)
|
||||||
|
#define __MAIN_H__
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct period_info
|
||||||
|
{
|
||||||
|
struct timespec next_period;
|
||||||
|
long period_ns;
|
||||||
|
unsigned long cyclecounter;
|
||||||
|
float fStartTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct period_info pinfo;
|
||||||
|
|
||||||
|
#endif
|
||||||
26
makefile
Executable file
26
makefile
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
# UNAME = $(shell uname -o)
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wextra -Wall -std=gnu99 -I. -Wno-unused-parameter -Wno-unused-variable -Wno-duplicate-decl-specifier
|
||||||
|
|
||||||
|
|
||||||
|
MQTT_SOURCES = mqtt/mqtt_client.c
|
||||||
|
CAN_SOURCES = can/can_client.c
|
||||||
|
IO_SOURCES = io/io.c
|
||||||
|
PROG = bin/CanRtDriver
|
||||||
|
BINDIR = bin
|
||||||
|
|
||||||
|
|
||||||
|
all: $(BINDIR) $(PROG)
|
||||||
|
|
||||||
|
bin/CanRtDriver: main.c $(CAN_SOURCES) $(MQTT_SOURCES) $(IO_SOURCES)
|
||||||
|
$(CC) $(CFLAGS) $^ -lpthread -lmosquitto -lwiringPi -o $@
|
||||||
|
|
||||||
|
$(BINDIR):
|
||||||
|
mkdir -p $(BINDIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BINDIR)
|
||||||
|
|
||||||
|
check: all
|
||||||
|
./$(MQTT_C_UNITTESTS)
|
||||||
281
mqtt/mqtt_client.c
Executable file
281
mqtt/mqtt_client.c
Executable file
@@ -0,0 +1,281 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
alternativer Client: libmosquitto-dev:
|
||||||
|
https://mosquitto.org/api/files/mosquitto-h.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <main.h>
|
||||||
|
#include <mqtt/mqtt_client.h>
|
||||||
|
#include <can/can_client.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mosquitto.h>
|
||||||
|
|
||||||
|
|
||||||
|
const char* mqtt_topic_status_cyclecounter = "Pool/Status/CycleCounter";
|
||||||
|
|
||||||
|
const char* mqtt_topic_motor1_gear = "Pool/Motor1/Gear";
|
||||||
|
int iMqttMotor1Gear = 0;
|
||||||
|
const char* mqtt_topic_motor1_power = "Pool/Motor1/Power";
|
||||||
|
int iMqttMotor1Power = 0;
|
||||||
|
const char* mqtt_topic_motor2_gear = "Pool/Motor2/Gear";
|
||||||
|
int iMqttMotor2Gear = 0;
|
||||||
|
const char* mqtt_topic_motor2_power = "Pool/Motor2/Power";
|
||||||
|
int iMqttMotor2Power = 0;
|
||||||
|
|
||||||
|
const char* mqtt_broker_addr = "127.0.0.1";
|
||||||
|
const int mqtt_broker_port = 1883;
|
||||||
|
struct mosquitto *mosq; /**< Libmosquito MQTT client instance. */
|
||||||
|
|
||||||
|
int iHadConnectError = 0;
|
||||||
|
|
||||||
|
void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
|
||||||
|
{
|
||||||
|
char* topic_value = (char *)malloc(message->payloadlen + 1);
|
||||||
|
memcpy(topic_value, message->payload, message->payloadlen);
|
||||||
|
topic_value[message->payloadlen] = '\0';
|
||||||
|
|
||||||
|
if (strcmp(message->topic, mqtt_topic_motor1_gear) == 0)
|
||||||
|
{
|
||||||
|
int val = 9999;
|
||||||
|
if (sscanf(topic_value, "%d", &val))
|
||||||
|
{
|
||||||
|
printf("%ld: Received value for mqtt_topic_motor1_gear: %d\n", pinfo.cyclecounter, val);
|
||||||
|
iMqttMotor1Gear = val;
|
||||||
|
Can_SetMotorGear(0, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%ld: Received mqtt_topic_motor1_gear: %s\n", pinfo.cyclecounter, topic_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(message->topic, mqtt_topic_motor1_power) == 0)
|
||||||
|
{
|
||||||
|
int val = 9999;
|
||||||
|
if (sscanf(topic_value, "%d", &val))
|
||||||
|
{
|
||||||
|
printf("%ld: Received value for mqtt_topic_motor1_power: %d\n", pinfo.cyclecounter, val);
|
||||||
|
iMqttMotor1Power = val;
|
||||||
|
Can_SetMotorPower(0, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%ld: Received mqtt_topic_motor1_power: %s\n", pinfo.cyclecounter, topic_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(message->topic, mqtt_topic_motor2_gear) == 0)
|
||||||
|
{
|
||||||
|
int val = 9999;
|
||||||
|
if (sscanf(topic_value, "%d", &val))
|
||||||
|
{
|
||||||
|
printf("%ld: Received value for mqtt_topic_motor2_gear: %d\n", pinfo.cyclecounter, val);
|
||||||
|
iMqttMotor2Gear = val;
|
||||||
|
Can_SetMotorGear(1, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%ld: Received mqtt_topic_motor2_gear: %s\n", pinfo.cyclecounter, topic_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(message->topic, mqtt_topic_motor2_power) == 0)
|
||||||
|
{
|
||||||
|
int val = 9999;
|
||||||
|
if (sscanf(topic_value, "%d", &val))
|
||||||
|
{
|
||||||
|
printf("%ld: Received value for mqtt_topic_motor2_power: %d\n", pinfo.cyclecounter, val);
|
||||||
|
iMqttMotor2Power = val;
|
||||||
|
Can_SetMotorPower(1, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%ld: Received mqtt_topic_motor2_power: %s\n", pinfo.cyclecounter, topic_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%ld: Received publish('%s'): %s\n", pinfo.cyclecounter, message->topic, topic_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(topic_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MqttClient_Connect()
|
||||||
|
{
|
||||||
|
int major, minor, revision;
|
||||||
|
|
||||||
|
mosquitto_lib_version(&major, &minor, &revision);
|
||||||
|
printf("Libmosquitto version: %d.%d.%d\n", major, minor, revision);
|
||||||
|
|
||||||
|
// libmosquitto initialization
|
||||||
|
mosquitto_lib_init();
|
||||||
|
|
||||||
|
// create an instance of a mosquitto lib object
|
||||||
|
mosq = mosquitto_new(NULL, true, NULL);
|
||||||
|
if (mosq == NULL)
|
||||||
|
{
|
||||||
|
printf("Failed to create mosquitto client!/n");
|
||||||
|
iHadConnectError++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a function which will be called by libmosquitto client every time when there is a new MQTT message
|
||||||
|
mosquitto_message_callback_set(mosq, my_message_callback);
|
||||||
|
|
||||||
|
// Connect to MQTT broker
|
||||||
|
if (mosquitto_connect(mosq, mqtt_broker_addr, mqtt_broker_port, 60) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("Error: connecting to MQTT broker failed\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iHadConnectError)
|
||||||
|
{
|
||||||
|
/* Wenn wir Verbindungsfehler hatten, dann befinden wir uns wohl in Boot-Prozess und der Mosquitto ist
|
||||||
|
gerade erst gestartet. Wir müssen hier etwas warten, sonst funktioniert das Subscriben nicht */
|
||||||
|
sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish all topics we want to subscribe
|
||||||
|
char message[10];
|
||||||
|
snprintf(message, sizeof(message), "0");
|
||||||
|
if (mosquitto_publish(mosq, NULL, mqtt_topic_motor1_gear, strlen(message), &message, 0, false) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_publish(mqtt_topic_motor1_gear) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
if (mosquitto_publish(mosq, NULL, mqtt_topic_motor1_power, strlen(message), &message, 0, false) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_publish(mqtt_topic_motor1_power) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
if (mosquitto_publish(mosq, NULL, mqtt_topic_motor2_gear, strlen(message), &message, 0, false) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_publish(mqtt_topic_motor2_gear) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
if (mosquitto_publish(mosq, NULL, mqtt_topic_motor2_power, strlen(message), &message, 0, false) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_publish(mqtt_topic_motor2_power) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribe all needed topics
|
||||||
|
if (mosquitto_subscribe(mosq, NULL, mqtt_topic_motor1_gear, 0) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_subscribe(mqtt_topic_motor1_gear) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
if (mosquitto_subscribe(mosq, NULL, mqtt_topic_motor1_power, 0) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_subscribe(mqtt_topic_motor1_power) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 21;
|
||||||
|
}
|
||||||
|
if (mosquitto_subscribe(mosq, NULL, mqtt_topic_motor2_gear, 0) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_subscribe(mqtt_topic_motor2_gear) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 22;
|
||||||
|
}
|
||||||
|
if (mosquitto_subscribe(mosq, NULL, mqtt_topic_motor2_power, 0) != MOSQ_ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("mosquitto_subscribe(mqtt_topic_motor2_power) fehlgeschlagen!\n");
|
||||||
|
MqttClient_Close();
|
||||||
|
iHadConnectError++;
|
||||||
|
return 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("MQTT: Connected successfull!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MqttClient_Close()
|
||||||
|
{
|
||||||
|
//Clean up/destroy objects created by libmosquitto
|
||||||
|
mosquitto_destroy(mosq);
|
||||||
|
mosquitto_lib_cleanup();
|
||||||
|
|
||||||
|
printf("MQTT: Disconnected!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MqttClient_Refresher()
|
||||||
|
{
|
||||||
|
mosquitto_loop(mosq, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MqttClient_Publisher()
|
||||||
|
{
|
||||||
|
char message[100];
|
||||||
|
|
||||||
|
snprintf(message, sizeof(message), "%ld", pinfo.cyclecounter);
|
||||||
|
mosquitto_publish(mosq, NULL, mqtt_topic_status_cyclecounter, strlen(message), message, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MqttClient_Publish_MotorGear(int iMotorIndex, int iGear)
|
||||||
|
{
|
||||||
|
if (iMotorIndex == 0)
|
||||||
|
{
|
||||||
|
if (iGear != iMqttMotor1Gear)
|
||||||
|
{
|
||||||
|
iMqttMotor1Gear = iGear;
|
||||||
|
char message[100];
|
||||||
|
snprintf(message, sizeof(message), "%d", iGear);
|
||||||
|
mosquitto_publish(mosq, NULL, mqtt_topic_motor1_gear, strlen(message), message, 0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iMotorIndex == 1)
|
||||||
|
{
|
||||||
|
if (iGear != iMqttMotor2Gear)
|
||||||
|
{
|
||||||
|
iMqttMotor2Gear = iGear;
|
||||||
|
char message[100];
|
||||||
|
snprintf(message, sizeof(message), "%d", iGear);
|
||||||
|
mosquitto_publish(mosq, NULL, mqtt_topic_motor2_gear, strlen(message), message, 0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MqttClient_Publish_MotorPower(int iMotorIndex, int iPower)
|
||||||
|
{
|
||||||
|
if (iMotorIndex == 0)
|
||||||
|
{
|
||||||
|
if (iPower != iMqttMotor1Power)
|
||||||
|
{
|
||||||
|
iMqttMotor1Power = iPower;
|
||||||
|
char message[100];
|
||||||
|
snprintf(message, sizeof(message), "%d", iPower);
|
||||||
|
mosquitto_publish(mosq, NULL, mqtt_topic_motor1_power, strlen(message), message, 0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iMotorIndex == 1)
|
||||||
|
{
|
||||||
|
if (iPower != iMqttMotor2Power)
|
||||||
|
{
|
||||||
|
iMqttMotor2Power = iPower;
|
||||||
|
char message[100];
|
||||||
|
snprintf(message, sizeof(message), "%d", iPower);
|
||||||
|
mosquitto_publish(mosq, NULL, mqtt_topic_motor2_power, strlen(message), message, 0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
mqtt/mqtt_client.h
Executable file
13
mqtt/mqtt_client.h
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#if !defined(__MQTT_CLIENT_H__)
|
||||||
|
#define __MQTT_CLIENT_H__
|
||||||
|
|
||||||
|
#define USE_MOSQUITTO_LIB
|
||||||
|
|
||||||
|
int MqttClient_Connect();
|
||||||
|
void MqttClient_Close();
|
||||||
|
void MqttClient_Refresher();
|
||||||
|
void MqttClient_Publisher();
|
||||||
|
void MqttClient_Publish_MotorGear(int iMotorIndex, int iGear);
|
||||||
|
void MqttClient_Publish_MotorPower(int iMotorIndex, int iPower);
|
||||||
|
|
||||||
|
#endif
|
||||||
23
scripts/CanRtDriver.service
Executable file
23
scripts/CanRtDriver.service
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
## Service Definition
|
||||||
|
## Datei gehört in /etc/systemd/system
|
||||||
|
## aktivieren dann mit:
|
||||||
|
## - sudo systemctl daemon-reload
|
||||||
|
## - sudo systemctl enable CanRtDriver.service
|
||||||
|
## - sudo systemctl start CanRtDriver.service
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=CAN-Bus Treiber für Gegenstromanlage
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/home/veltmann/Documents/CanRtDriver/bin/CanRtDriver
|
||||||
|
# Oder: ExecStart=/usr/bin/python3 /home/pi/meinprogramm.py
|
||||||
|
WorkingDirectory=/home/veltmann/Documents/CanRtDriver/bin
|
||||||
|
StandardOutput=inherit
|
||||||
|
StandardError=inherit
|
||||||
|
Restart=always
|
||||||
|
#User=veltmann
|
||||||
|
# Optional: Group=meinbenutzergruppe
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
7
scripts/can_link_up.sh
Executable file
7
scripts/can_link_up.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ip link set can0 up type can bitrate 250000
|
||||||
|
ip link set can1 up type can bitrate 250000
|
||||||
|
ifconfig can0 txqueuelen 65536
|
||||||
|
ifconfig can1 txqueuelen 65536
|
||||||
|
|
||||||
2
scripts/candump.sh
Executable file
2
scripts/candump.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
candump can1
|
||||||
|
|
||||||
Reference in New Issue
Block a user