123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /*
- * mqtt_client.c
- *
- * Created on: Jun 10, 2024
- * Author: jakubski
- */
- #include <stdio.h>
- #include "FreeRTOS.h"
- #include "task.h"
- #include "main.h"
- #include "cmsis_os.h"
- #include <string.h>
- #include "lwip.h"
- #include "lwip/api.h"
- #include "MQTTClient.h"
- #include "MQTTInterface.h"
- #include "node-red-config.h"
- #include "measurements.h"
- #include "cJSON.h"
- #include "interprocess_data.h"
- #include "uart_tasks.h"
- #define MQTT_BUFSIZE 1024
- char* const subscribeTopicNames[MASTER_BOARD + SLAVES_COUNT] = { "Set/0", "Set/1", "Set/2", "Set/3", "Set/4" };
- #define MAX_COMMANDS_IN_MQTT_PAYLOAD 17
- char* const topicCommands[MAX_COMMANDS_IN_MQTT_PAYLOAD] = { "fanSpeed", "motorXon", "motorYon", "diode", "motorXMaxCurrent", "motorYMaxCurrent", "clearPeakElectricalMeasurements", "mainBoardRelay",
- "setEncoderXValue", "setEncoderYValue", "setVoltageMeasGains", "setVoltageMeasOffsets", "setCurrentMeasGains", "setCurrentMeasOffsets", "resetSystem", "setPositionX", "setPositionY" };
- enum _Topics
- {
- fanSpeedTopic = 0,
- motorXonTopic,
- motorYonTopic,
- diodeTopic,
- motorXMaxCurrentTopic,
- motorYMaxCurrentTopic,
- clearPeakElectricalMeasurementsTopic,
- mainBoardRelayTopic,
- setEncoderXValue,
- setEncoderYValue,
- setVoltageMeasGains,
- setVoltageMeasOffsets,
- setCurrentMeasGains,
- setCurrentMeasOffsets,
- resetSystem,
- setPositionX,
- setPositionY
- };
- enum _BoardNoOverTopic
- {
- main_board = 0,
- board_1,
- board_2,
- board_3,
- board_4,
- unknownBoard
- };
- typedef enum _BoardNoOverTopic BoardNoOverTopic;
- extern struct netif gnetif; //extern gnetif
- extern UartTaskData uart1TaskData; // Board 1
- extern UartTaskData uart3TaskData; // Board 2
- extern UartTaskData uart6TaskData; // Board 3
- extern UartTaskData uart2TaskData; // Board 4
- extern UartTaskData uart8TaskData; // Debug
- extern osTimerId_t relay1TimerHandle;
- extern osTimerId_t relay2TimerHandle;
- extern osTimerId_t relay3TimerHandle;
- extern osTimerId_t relay4TimerHandle;
- const osThreadAttr_t mqttClientSubTaskAttr =
- { .name = "mqttClientSubTask", .stack_size = configMINIMAL_STACK_SIZE * 4,
- .priority = (osPriority_t) osPriorityNormal, };
- const osThreadAttr_t mqttClientPubTaskAttr =
- { .name = "mqttClientPsubTask", .stack_size = configMINIMAL_STACK_SIZE * 4,
- .priority = (osPriority_t) osPriorityNormal, };
- osThreadId mqttClientSubTaskHandle; //mqtt client task handle
- osThreadId mqttClientPubTaskHandle; //mqtt client task handle
- Network net; //mqtt network
- MQTTClient mqttClient; //mqtt client
- uint8_t sndBuffer[MQTT_BUFSIZE]; //mqtt send buffer
- uint8_t rcvBuffer[MQTT_BUFSIZE]; //mqtt receive buffer
- void RelayCtrl(int32_t relayNumber, int32_t relayTimeOn);
- void MqttClientSubTask (void* argument); // mqtt client subscribe task function
- void MqttClientPubTask (void* argument); // mqtt client publish task function
- uint32_t MqttConnectBroker (void); // mqtt broker connect function
- void MqttMessageArrived (MessageData* msg); // mqtt message callback function
- void MqttClientSubTask (void* argument) {
- uint8_t connectionTryCounter = 0;
- while (1) {
- // waiting for valid ip address
- if (gnetif.ip_addr.addr == 0 || gnetif.netmask.addr == 0 || gnetif.gw.addr == 0) // system has no valid ip address
- {
- osDelay (pdMS_TO_TICKS (1000));
- continue;
- } else {
- printf ("DHCP/Static IP O.K.\n");
- break;
- }
- }
- while (1) {
- if (!mqttClient.isconnected) {
- // try to connect to the broker
- if (MqttConnectBroker () != MQTT_SUCCESS) {
- osDelay (pdMS_TO_TICKS (1000));
- connectionTryCounter++;
- if (connectionTryCounter > 10) {
- __disable_irq ();
- NVIC_SystemReset ();
- }
- }
- } else {
- connectionTryCounter = 0;
- MQTTYield (&mqttClient, 500); // handle timer
- osDelay (pdMS_TO_TICKS (100));
- }
- }
- }
- void MqttClientPubTask (void* argument) {
- char messageBuffer[512] = { 0x00 };
- char topicTextBuffer[32] = { 0x00 };
- uint32_t bytesInBuffer = 0;
- uint8_t boardNumber = 0;
- MQTTMessage message;
- while (1) {
- if (mqttClient.isconnected) {
- if (is_link_up ()) {
- for (boardNumber = 0; boardNumber < SLAVES_COUNT; boardNumber++) {
- osMutexAcquire (resMeasurementsMutex, osWaitForever);
- RESMeasurements* resMeas = &resMeasurements[boardNumber];
- sprintf (topicTextBuffer, "RESmeasurments/%d", boardNumber + 1);
- bytesInBuffer = sprintf (messageBuffer, "{\"voltageRMS\":[%.2f, %.2f, %.2f], ", resMeas->voltageRMS[0], resMeas->voltageRMS[1], resMeas->voltageRMS[2]);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"voltagePeak\":[%.2f, %.2f, %.2f], ", resMeas->voltagePeak[0], resMeas->voltagePeak[1], resMeas->voltagePeak[2]);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"currentRMS\":[%.3f, %.3f, %.3f], ", resMeas->currentRMS[0], resMeas->currentRMS[1], resMeas->currentRMS[2]);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"currentPeak\":[%.3f, %.3f, %.3f], ", resMeas->currentPeak[0], resMeas->currentPeak[1], resMeas->currentPeak[2]);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"power\":[%.2f, %.2f, %.2f], ", resMeas->power[0], resMeas->power[1], resMeas->power[2]);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"lastSeen\": %ld}", slaveLastSeen[boardNumber]);
- osMutexRelease (resMeasurementsMutex);
- message.payload = (void*)messageBuffer;
- message.payloadlen = strlen (messageBuffer);
- MQTTPublish (&mqttClient, topicTextBuffer, &message); // publish a message
- }
- for (boardNumber = 0; boardNumber < SLAVES_COUNT + 1; boardNumber++) {
- if (boardNumber > 0) {
- osMutexAcquire (sensorsInfoMutex, osWaitForever);
- SesnorsInfo* sensors = &sensorsInfo[boardNumber - 1];
- sprintf (topicTextBuffer, "Sensors/%d", boardNumber);
- bytesInBuffer = sprintf (messageBuffer, "{\"pvTemperature\":[%.1f, %.1f], ", sensors->pvTemperature[0], sensors->pvTemperature[1]);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"fanVoltage\":%.2f, ", sensors->fanVoltage);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"pvEncoderX\":%.2f, ", sensors->pvEncoderX);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"pvEncoderY\":%.2f, ", sensors->pvEncoderY);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"motorXStatus\":%d, ", sensors->motorXStatus);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"motorYStatus\":%d, ", sensors->motorYStatus);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"motorXAveCurrent\":%.3f, ", sensors->motorXAveCurrent);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"motorYAveCurrent\":%.3f, ", sensors->motorYAveCurrent);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"motorXPeakCurrent\":%.3f, ", sensors->motorXPeakCurrent);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"motorYPeakCurrent\":%.3f, ", sensors->motorYPeakCurrent);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"limitXSwitchUp\":%d, ", sensors->limitXSwitchUp);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"limitXSwitchDown\":%d, ", sensors->limitXSwitchDown);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"limitXSwitchCenter\":%d, ", sensors->limitXSwitchCenter);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"limitYSwitchUp\":%d, ", sensors->limitYSwitchUp);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"limitYSwitchDown\":%d, ", sensors->limitYSwitchDown);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"limitYSwitchCenter\":%d, ", sensors->limitYSwitchCenter);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"currentXPosition\":%.2f, ", sensors->currentXPosition);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"currentYPosition\":%.2f, ", sensors->currentYPosition);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"positionXWeak\":%d, ", sensors->positionXWeak);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"positionYWeak\":%d, ", sensors->positionYWeak);
- bytesInBuffer += sprintf (&messageBuffer[bytesInBuffer], "\"powerSupplyFailMask\":%d}", sensors->powerSupplyFailMask);
- osMutexRelease (sensorsInfoMutex);
- } else {
- sprintf (topicTextBuffer, "Sensors/%d", boardNumber);
- uint8_t mainBoardPowerSupplyFailMask = ~((HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_4) << 1) | HAL_GPIO_ReadPin (GPIOD, GPIO_PIN_2)) & 0x3;
- bytesInBuffer = sprintf (messageBuffer, "{\"powerSupplyFailMask\":%d}", mainBoardPowerSupplyFailMask);
- }
- message.payload = (void*)messageBuffer;
- message.payloadlen = strlen (messageBuffer);
- MQTTPublish (&mqttClient, topicTextBuffer, &message); // publish a message
- }
- }
- }
- osDelay (pdMS_TO_TICKS (1000));
- }
- }
- uint32_t MqttConnectBroker () {
- uint8_t boardNumber = 0;
- int ret;
- NewNetwork (&net);
- ret = ConnectNetwork (&net, BROKER_IP, MQTT_PORT);
- if (ret != MQTT_SUCCESS) {
- printf ("ConnectNetwork failed.\n");
- return -1;
- }
- MQTTClientInit (&mqttClient, &net, 1000, sndBuffer, sizeof (sndBuffer), rcvBuffer, sizeof (rcvBuffer));
- MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
- data.willFlag = 0;
- data.MQTTVersion = 3;
- data.clientID.cstring = "test_user1";
- data.username.cstring = "test_user1";
- data.password.cstring = "1234";
- data.keepAliveInterval = 100;
- data.cleansession = 1;
- ret = MQTTConnect (&mqttClient, &data);
- if (ret != MQTT_SUCCESS) {
- net_disconnect (&net);
- printf ("MQTTConnect failed. Code %d\n", ret);
- return ret;
- }
- for (boardNumber = 0; boardNumber < SLAVES_COUNT; boardNumber++) {
- ret = MQTTSubscribe (&mqttClient, subscribeTopicNames[boardNumber], QOS0, MqttMessageArrived);
- if (ret != MQTT_SUCCESS) {
- net_disconnect (&net);
- printf ("MQTTSubscribe failed.\n");
- return ret;
- }
- }
- printf ("MQTT_ConnectBroker O.K.\n");
- return MQTT_SUCCESS;
- }
- void RelayCtrl (int32_t relayNumber, int32_t relayTimeOn) {
- switch (relayNumber) {
- case 1:
- if (relayTimeOn > 0) {
- osTimerStart (relay1TimerHandle, relayTimeOn * 1000);
- } else {
- osTimerStop (relay1TimerHandle);
- }
- if (relayTimeOn != 0) {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_5, GPIO_PIN_SET);
- } else {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_5, GPIO_PIN_RESET);
- }
- break;
- case 2:
- if (relayTimeOn > 0) {
- osTimerStart (relay2TimerHandle, relayTimeOn * 1000);
- } else {
- osTimerStop (relay2TimerHandle);
- }
- if (relayTimeOn != 0) {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
- } else {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
- }
- break;
- case 3:
- if (relayTimeOn > 0) {
- osTimerStart (relay3TimerHandle, relayTimeOn * 1000);
- } else {
- osTimerStop (relay3TimerHandle);
- }
- if (relayTimeOn != 0) {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_4, GPIO_PIN_SET);
- } else {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_4, GPIO_PIN_RESET);
- }
- break;
- case 4:
- if (relayTimeOn > 0) {
- osTimerStart (relay4TimerHandle, relayTimeOn * 1000);
- } else {
- osTimerStop (relay4TimerHandle);
- }
- if (relayTimeOn != 0) {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_2, GPIO_PIN_SET);
- } else {
- HAL_GPIO_WritePin (GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);
- }
- break;
- default: break;
- }
- }
- void MqttMessageArrived (MessageData* msg) {
- SerialProtocolCommands spCommand = spUnknown;
- BoardNoOverTopic topicForBoard = unknownBoard;
- uint8_t boardNumber = 0;
- MQTTMessage* message = msg->message;
- char topicName[32] = { 0 };
- memcpy (topicName, msg->topicName->lenstring.data, msg->topicName->lenstring.len);
- for (boardNumber = 0; boardNumber < SLAVES_COUNT; boardNumber++) {
- if (strcmp (topicName, subscribeTopicNames[boardNumber]) == 0) {
- topicForBoard = (BoardNoOverTopic)(boardNumber);
- break;
- }
- }
- if (topicForBoard == unknownBoard) {
- return;
- }
- cJSON* json = cJSON_Parse (message->payload);
- const cJSON* objectItem = NULL;
- InterProcessData data = { 0 };
- uint32_t arraySize = 0;
- if (topicForBoard != main_board) {
- for (int topicCmdNumber = 0; topicCmdNumber < MAX_COMMANDS_IN_MQTT_PAYLOAD; topicCmdNumber++) {
- spCommand = spUnknown;
- objectItem = cJSON_GetObjectItemCaseSensitive (json, topicCommands[topicCmdNumber]);
- if (objectItem != NULL) {
- switch (topicCmdNumber) {
- case fanSpeedTopic: spCommand = spSetFanSpeed;
- case motorXonTopic:
- if (spCommand == spUnknown) {
- spCommand = spSetMotorXOn;
- }
- case motorYonTopic:
- if (spCommand == spUnknown) {
- spCommand = spSetMotorYOn;
- }
- if (cJSON_IsArray (objectItem)) {
- data.spCommand = spCommand;
- arraySize = cJSON_GetArraySize (objectItem);
- if (arraySize == 2) {
- for (int i = 0; i < arraySize; i++) {
- cJSON* item = cJSON_GetArrayItem (objectItem, i);
- if (cJSON_IsNumber (item)) {
- data.values.integerValues.value[i] = item->valueint;
- }
- }
- }
- }
- break;
- case diodeTopic:
- if (cJSON_IsNumber (objectItem)) {
- data.spCommand = spSetDiodeOn;
- data.values.integerValues.value[0] = objectItem->valueint;
- }
- break;
- case motorXMaxCurrentTopic: spCommand = spSetmotorXMaxCurrent;
- case motorYMaxCurrentTopic:
- if (cJSON_IsNumber (objectItem)) {
- if (spCommand == spUnknown) {
- spCommand = spSetmotorYMaxCurrent;
- }
- data.spCommand = spCommand;
- data.values.flaotValues.value[0] = objectItem->valuedouble;
- }
- break;
- case clearPeakElectricalMeasurementsTopic:
- if (cJSON_IsNumber (objectItem)) {
- if (objectItem->valueint == 1) {
- data.spCommand = spClearPeakMeasurments;
- }
- }
- break;
- case mainBoardRelayTopic:
- if (cJSON_IsArray (objectItem)) {
- arraySize = cJSON_GetArraySize (objectItem);
- if (arraySize == 2) {
- int32_t relayNumber = -1;
- cJSON* item = cJSON_GetArrayItem (objectItem, 0);
- if (cJSON_IsNumber (item)) {
- relayNumber = item->valueint;
- }
- int32_t relayTimeOn = 0;
- item = cJSON_GetArrayItem (objectItem, 1);
- if (cJSON_IsNumber (item)) {
- relayTimeOn = item->valueint;
- }
- RelayCtrl (relayNumber, relayTimeOn);
- }
- }
- break;
- case setEncoderXValue:
- if (cJSON_IsNumber (objectItem)) {
- data.spCommand = spSetEncoderXValue;
- data.values.flaotValues.value[0] = objectItem->valuedouble;
- }
- break;
- case setEncoderYValue:
- if (cJSON_IsNumber (objectItem)) {
- data.spCommand = spSetEncoderYValue;
- data.values.flaotValues.value[0] = objectItem->valuedouble;
- }
- break;
- case setVoltageMeasGains: spCommand = spSetVoltageMeasGains;
- case setVoltageMeasOffsets:
- if (spCommand == spUnknown) {
- spCommand = spSetVoltageMeasOffsets;
- }
- case setCurrentMeasGains:
- if (spCommand == spUnknown) {
- spCommand = spSetCurrentMeasGains;
- }
- case setCurrentMeasOffsets:
- if (spCommand == spUnknown) {
- spCommand = spSetCurrentMeasOffsets;
- }
- if (cJSON_IsArray (objectItem)) {
- data.spCommand = spCommand;
- arraySize = cJSON_GetArraySize (objectItem);
- if (arraySize == 3) {
- for (int i = 0; i < arraySize; i++) {
- cJSON* item = cJSON_GetArrayItem (objectItem, i);
- if (cJSON_IsNumber (item)) {
- data.values.flaotValues.value[i] = item->valuedouble;
- }
- }
- }
- }
- break;
- case resetSystem:
- if (cJSON_IsNumber (objectItem)) {
- if (objectItem->valueint == 1) {
- data.spCommand = spResetSystem;
- break;
- }
- }
- break;
- case setPositionX:
- if (cJSON_IsNumber (objectItem)) {
- data.spCommand = spSetPositonX;
- data.values.flaotValues.value[0] = objectItem->valuedouble;
- }
- break;
- case setPositionY:
- if (cJSON_IsNumber (objectItem)) {
- data.spCommand = spSetPositonY;
- data.values.flaotValues.value[0] = objectItem->valuedouble;
- }
- break;
- default: break;
- }
- }
- }
- } else {
- for (int topicCmdNumber = 0; topicCmdNumber < MAX_COMMANDS_IN_MQTT_PAYLOAD; topicCmdNumber++) {
- objectItem = cJSON_GetObjectItemCaseSensitive (json, topicCommands[topicCmdNumber]);
- if (objectItem != NULL) {
- if (topicCmdNumber == resetSystem) {
- __disable_irq ();
- NVIC_SystemReset ();
- break;
- }
- }
- }
- }
- switch (topicForBoard) {
- case main_board: break;
- case board_1:
- #ifdef USE_UART8_INSTEAD_UART1
- if (uart8TaskData.sendCmdToSlaveQueue != NULL) {
- osMessageQueuePut (uart8TaskData.sendCmdToSlaveQueue, &data, 0, (TickType_t)100);
- }
- #else
- if (uart1TaskData.sendCmdToSlaveQueue != NULL) {
- osMessageQueuePut (uart1TaskData.sendCmdToSlaveQueue, &data, 0, (TickType_t)100);
- }
- #endif
- printf ("Send cmd to board 1\n");
- break;
- case board_2:
- if (uart3TaskData.sendCmdToSlaveQueue != NULL) {
- osMessageQueuePut (uart3TaskData.sendCmdToSlaveQueue, &data, 0, (TickType_t)100);
- }
- printf ("Send cmd to board 2\n");
- break;
- case board_3:
- if (uart6TaskData.sendCmdToSlaveQueue != NULL) {
- osMessageQueuePut (uart6TaskData.sendCmdToSlaveQueue, &data, 0, (TickType_t)100);
- }
- printf ("Send cmd to board 3\n");
- break;
- case board_4:
- if (uart2TaskData.sendCmdToSlaveQueue != NULL) {
- osMessageQueuePut (uart2TaskData.sendCmdToSlaveQueue, &data, 0, (TickType_t)100);
- }
- printf ("Send cmd to board 4\n");
- break;
- default: break;
- }
- cJSON_Delete (json);
- printf ("MQTT Topic:%s, MSG[%d]:%s\n", topicName, (int)message->payloadlen, (char*)message->payload);
- }
- void mqtt_cli_init (void) {
- mqttClientSubTaskHandle = osThreadNew (MqttClientSubTask, NULL, &mqttClientSubTaskAttr); // subscribe task
- mqttClientPubTaskHandle = osThreadNew (MqttClientPubTask, NULL, &mqttClientPubTaskAttr); // publish task
- }
|