clean and refactoring

This commit is contained in:
Bogdan Pilyugin 2023-07-26 15:40:59 +02:00
parent c76fe416e0
commit a9192feb22
6 changed files with 100 additions and 450 deletions

View File

@ -39,7 +39,6 @@ idf_component_register(
"src/ETHTransport.c" "src/ETHTransport.c"
"src/SNTP.c" "src/SNTP.c"
"src/MQTT.c" "src/MQTT.c"
"src/MQTTSysHandler.c"
src/OTA.c src/OTA.c
src/RestApiHandler.c src/RestApiHandler.c
src/SysComm.c src/SysComm.c

View File

@ -63,9 +63,16 @@ typedef struct
{ {
int key1; int key1;
int key2; int key2;
} payload_type_50; } payload_type_50;
typedef struct
{
int key1;
int key2;
} payload_type_10;
#define DATA_MESSAGE_TYPE_COMMAND (1) #define DATA_MESSAGE_TYPE_COMMAND (1)
#define DATA_MESSAGE_TYPE_REQUEST (2) #define DATA_MESSAGE_TYPE_REQUEST (2)
@ -91,6 +98,7 @@ typedef struct
} data_message_t; } data_message_t;
esp_err_t SysServiceDataHandler(data_message_t *MSG); esp_err_t SysServiceDataHandler(data_message_t *MSG);
sys_error_code SysVarsPayloadHandler(data_message_t *MSG);
void GetSysErrorDetales(sys_error_code err, const char **br, const char **ds); void GetSysErrorDetales(sys_error_code err, const char **br, const char **ds);
#endif /* COMPONENTS_WEBGUIAPP_INCLUDE_SYSTEMAPPLICATION_H_ */ #endif /* COMPONENTS_WEBGUIAPP_INCLUDE_SYSTEMAPPLICATION_H_ */

View File

@ -132,6 +132,51 @@ esp_err_t SysServiceMQTTSend(char *data, int len, int idx)
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
#define MAX_ERROR_JSON 256
mqtt_app_err_t PublicTestMQTT(int idx)
{
char tmp[10];
char resp[256];
char JSONMess[512];
jwOpen(JSONMess, MAX_ERROR_JSON, JW_OBJECT, JW_PRETTY);
time_t now;
time(&now);
jwObj_int("time", (unsigned int) now);
jwObj_string("event", "MQTT_TEST_MESSAGE)");
strcpy(resp, "mqtt://");
strcat(resp, GetSysConf()->mqttStation[idx].ServerAddr);
itoa(GetSysConf()->mqttStation[idx].ServerPort, tmp, 10);
strcat(resp, ":");
strcat(resp, tmp);
jwObj_string("url", resp);
ComposeTopic(resp, idx, "SYSTEM", "UPLINK");
jwObj_string("tx_topic", resp);
ComposeTopic(resp, idx, "SYSTEM", "DWLINK");
jwObj_string("rx_topic", resp);
jwEnd();
jwClose();
char *buf = (char*) malloc(strlen(JSONMess) + 1);
if (buf)
{
memcpy(buf, JSONMess, strlen(JSONMess));
MQTT_DATA_SEND_STRUCT DSS;
ComposeTopic(DSS.topic, idx, "SYSTEM", "UPLINK");
DSS.raw_data_ptr = buf;
DSS.data_length = strlen(JSONMess);
if (xQueueSend(GetMQTTHandlesPool(idx)->mqtt_queue, &DSS, pdMS_TO_TICKS(1000)) == pdPASS)
return API_OK;
else
{
free(buf);
return API_INTERNAL_ERR;
}
}
else
{ // ERR internal error on publish error
return API_INTERNAL_ERR;
}
}
static void mqtt_system_event_handler(int idx, void *handler_args, esp_event_base_t base, int32_t event_id, static void mqtt_system_event_handler(int idx, void *handler_args, esp_event_base_t base, int32_t event_id,
void *event_data) void *event_data)

View File

@ -1,447 +0,0 @@
/*! Copyright 2022 Bogdan Pilyugin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* \file MQTTSysHandler.c
* \version 1.0
* \date 2022-08-19
* \author Bogdan Pilyugin
* \brief
* \details
* \copyright Apache License, Version 2.0
*/
/*!
* Structure of JSON data for system MQTT API
* {
* "messid":12345, //uint32_t message id for request/response context
* "api":"2.0", //string of current API version
* "request":"GET", //string request type - "GET" or "POST" allowed
* "url":"status.json", //string url of resource (generally a file name)
* "postdata":"param1=value&param2=value", //string of POST data payload (required if request is POST)
* "reload":"true" //string "true" or "false" is needed reload page after POST request (required if request is POST)
* }
*/
/*
{
"messid":12345,
"api":"2.0",
"request":"GET",
"url":"api/status.json",
"postdata":"param1=value&param2=value",
"reload":"true"
}
*/
#include "MQTT.h"
#include "jWrite.h"
#include "jRead.h"
#include "esp_log.h"
#include "romfs.h"
#include "HTTPServer.h"
extern espfs_fs_t *fs;
#define PANEL_MESSAGE_LENGTH 32 //base message length, mainly depended by radio requirements
#define MAX_JSON_MESSAGE 256 //max size of mqtt message to publish
#define MAX_FILE_PUBLISH 4096 //bufer for mqtt data publish
#define MAX_DYNVAR_LENTH 64
#define MAX_FILENAME_LENTH 32
#define MAX_ERROR_MESSAGE 32
#define MAX_ERROR_JSON 256
#define MAX_MESSAGE_ID 15
#define MAX_POST_DATA_LENTH 512
#define TAG "MQTTSysHandler"
const char apiver[] = "2.0";
const char tagGet[] = "GET";
const char tagPost[] = "POST";
const char *mqtt_app_err_descr[] = {
"Operation OK",
"Internal error",
"Wrong json format",
"Key 'idmess' not found",
"Key 'idmess' value too long",
"Key 'api' not found",
"API version not supported",
"Key 'request' not found",
"Unsupported HTTP method",
"Key 'url' not found",
"Key 'url' value too long",
"URL not found",
"Key 'postdata' not found",
"Key 'postdata' too long",
"File size too big",
"File is empty",
"Unknown error"
};
const char *mqtt_app_err_breef[] = {
"OK",
"INTERNAL_ERR",
"WRONG_JSON_ERR",
"NO_ID_ERR",
"ID_OVERSIZE_ERR",
"NO_API_ERR",
"VERSION_ERR",
"NO_REQUEST_ERR",
"UNSUPPORTED_METHOD_ERR",
"NO_URL_ERR",
"URL_OVERSIZE_ERR",
"URL_NOT_FOUND_ERR",
"NO_POSTDATA_ERR",
"POSTDATA_OVERSIZE_ERR",
"FILE_OVERSIZE_ERR",
"FILE_EMPTY_ERR",
"UNKNOWN_ERR"
};
typedef enum
{
UNSUPPORTED = 0,
GET,
POST
} mqtt_api_request_t;
static mqtt_app_err_t ResponceWithError(int idx,
espfs_file_t *file,
char *id,
char *url,
mqtt_app_err_t api_err)
{
espfs_fclose(file);
char JSONErrorMess[MAX_ERROR_JSON];
jwOpen(JSONErrorMess, MAX_ERROR_JSON, JW_OBJECT, JW_PRETTY);
if (id[0])
jwObj_string("messid", (char*) id);
else
jwObj_string("messid", "ERROR");
jwObj_string("api", (char*) apiver);
jwObj_string("responce", (char*) mqtt_app_err_breef[api_err]);
jwObj_string("descript", (char*) mqtt_app_err_descr[api_err]);
if (url[0])
jwObj_string("url", (char*) url);
else
jwObj_string("url", "ERROR");
jwEnd();
jwClose();
char *buf = (char*) malloc(strlen(JSONErrorMess) + 1);
if (buf)
{
memcpy(buf, JSONErrorMess, strlen(JSONErrorMess));
MQTT_DATA_SEND_STRUCT DSS;
ComposeTopic(DSS.topic, idx, "SYSTEM", "UPLINK");
DSS.raw_data_ptr = buf;
DSS.data_length = strlen(JSONErrorMess);
if (xQueueSend(GetMQTTHandlesPool(idx)->mqtt_queue, &DSS, pdMS_TO_TICKS(1000)) == pdPASS)
return API_OK;
else
{
free(buf);
return API_INTERNAL_ERR;
}
}
else
{ // ERR internal error on publish error
return API_INTERNAL_ERR;
}
}
static mqtt_app_err_t ResponceWithFile(int idx, espfs_file_t *file,
char *id,
char *url)
{
struct espfs_stat_t stat;
char *filebuf = NULL;
char *outbuf = NULL;
uint32_t fileLenth, filePtr, readBytes;
espfs_fstat(file, &stat);
fileLenth = stat.size;
mqtt_app_err_t api_err = API_UNKNOWN_ERR;
if (fileLenth > MAX_FILE_PUBLISH)
{
ESP_LOGE(TAG, "File is too big");
api_err = API_FILE_OVERSIZE_ERR;
goto file_send_err;
}
outbuf = (char*) malloc(MAX_FILE_PUBLISH + 256);
filebuf = (char*) malloc(fileLenth);
if (!outbuf || !filebuf)
{
ESP_LOGE(TAG, "Failed to allocate memory");
api_err = API_INTERNAL_ERR;
goto file_send_err;
}
if (espfs_fread(file, filebuf, fileLenth) == 0)
{
ESP_LOGE(TAG, "Read no bytes from file");
api_err = API_FILE_EMPTY_ERR;
goto file_send_err;
}
espfs_fclose(file);
jwOpen(outbuf, MAX_FILE_PUBLISH, JW_OBJECT, JW_PRETTY);
jwObj_string("messid", (char*) id);
jwObj_string("api", (char*) apiver);
jwObj_string("responce", (char*) mqtt_app_err_breef[API_OK]);
jwObj_string("descript", (char*) mqtt_app_err_descr[API_OK]);
jwObj_string("url", (char*) url);
jwObj_string("body", "bodydata");
jwEnd();
jwClose();
char *fdata = memmem(outbuf, MAX_FILE_PUBLISH, "\"bodydata\"", strlen("\"bodydata\""));
filePtr = 0;
readBytes = 0;
while (filePtr < fileLenth && readBytes < (MAX_FILE_PUBLISH - MAX_DYNVAR_LENTH))
{
if (filebuf[filePtr] == '~')
{
int k = 0;
char DynVarName[16];
while (filePtr < fileLenth && k < 16 && (filebuf[++filePtr] != '~'))
DynVarName[k++] = filebuf[filePtr];
if (filebuf[filePtr] == '~')
{ //got valid dynamic variable name
DynVarName[k] = 0x00;
readBytes += HTTPPrint(NULL, &fdata[readBytes], DynVarName);
filePtr++;
}
}
else
fdata[readBytes++] = filebuf[filePtr++];
}
const char tail[] = "}";
strcat((fdata + readBytes), tail);
free(filebuf);
MQTT_DATA_SEND_STRUCT DSS;
ComposeTopic(DSS.topic, idx, "SYSTEM", "UPLINK");
DSS.raw_data_ptr = outbuf;
DSS.data_length = (fdata - outbuf) + readBytes + strlen(tail);
if (xQueueSend(GetMQTTHandlesPool(idx)->mqtt_queue, &DSS, pdMS_TO_TICKS(1000)) == pdPASS)
return API_OK;
else
{
ESP_LOGE(TAG, "Failed to write mqtt queue");
api_err = API_INTERNAL_ERR;
goto file_send_err;
}
file_send_err:
free(outbuf);
free(filebuf);
return api_err;
}
void SystemDataHandler(char *data, uint32_t len, int idx)
{
struct jReadElement result;
char URL[MAX_FILENAME_LENTH + 1];
char ID[MAX_MESSAGE_ID + 1];
char POST_DATA[MAX_POST_DATA_LENTH + 1];
mqtt_api_request_t req = UNSUPPORTED;
mqtt_app_err_t api_err = API_UNKNOWN_ERR;
ID[0] = 0x00;
URL[0] = 0x00;
espfs_file_t *file = NULL;
jRead(data, "", &result);
if (result.dataType == JREAD_OBJECT)
{
/*Checking and get ID message*/
jRead(data, "{'messid'", &result);
if (result.elements == 1)
{
if (result.bytelen > MAX_MESSAGE_ID)
{
api_err = API_ID_OVERSIZE_ERR;
goto api_json_err;
}
memcpy(ID, result.pValue, result.bytelen);
ID[result.bytelen] = 0x00;
}
else
{
api_err = API_NO_ID_ERR;
goto api_json_err;
}
/*Checking and get API version*/
jRead(data, "{'api'", &result);
if (result.elements == 1)
{
if (memcmp(apiver, result.pValue, result.bytelen))
{
api_err = API_VERSION_ERR;
goto api_json_err;
}
}
else
{
api_err = API_NO_API_ERR;
goto api_json_err;
}
/*Checking and get request type POST, GET or UNSUPPORTED*/
jRead(data, "{'request'", &result);
if (result.elements == 1)
{
if (!memcmp(tagGet, result.pValue, result.bytelen))
req = GET;
else if (!memcmp(tagPost, result.pValue, result.bytelen))
req = POST;
}
else
{
api_err = API_NO_REQUEST_ERR;
goto api_json_err;
}
/*Checking and get url*/
jRead(data, "{'url'", &result);
if (result.elements == 1)
{
if (result.bytelen > MAX_FILENAME_LENTH)
{
api_err = API_URL_OVERSIZE_ERR;
goto api_json_err;
}
memcpy(URL, result.pValue, result.bytelen);
URL[result.bytelen] = 0x00;
file = espfs_fopen(fs, URL);
if (!file)
{
api_err = API_URL_NOT_FOUND_ERR;
goto api_json_err;
}
}
else
{
api_err = API_NO_URL_ERR;
goto api_json_err;
}
if (req == POST)
{
/*Checking and get POST DATA*/
jRead(data, "{'postdata'", &result);
if (result.elements == 1)
{
if (result.bytelen > MAX_POST_DATA_LENTH)
{
api_err = API_POSTDATA_OVERSIZE_ERR;
goto api_json_err;
}
memcpy(POST_DATA, result.pValue, result.bytelen);
POST_DATA[result.bytelen] = 0x00;
}
else
{
api_err = API_NO_POSTDATA_ERR;
goto api_json_err;
}
ESP_LOGW(TAG, "URL=%s, DATA=%s", URL, POST_DATA);
HTTPPostApp(NULL, URL, POST_DATA);
jRead(data, "{'reload'", &result);
if (result.elements == 1 && !memcmp("true", result.pValue, result.bytelen))
{
if (ResponceWithFile(idx, file, ID, URL) == API_OK)
return;
else
goto api_json_err;
}
else
{
if (ResponceWithError(idx, file, ID, URL, API_OK) != API_OK)
ESP_LOGE(TAG, "Failed to allocate memory for file MQTT message");
}
return;
}
else if (req == GET)
{
//Here GET handler, send file wrapped into json
if (ResponceWithFile(idx, file, ID, URL) == API_OK)
return;
else
goto api_json_err;
}
else
{
api_err = API_UNSUPPORTED_METHOD_ERR;
goto api_json_err;
}
}
else
{ //ERR no json format
api_err = API_WRONG_JSON_ERR;
goto api_json_err;
}
api_json_err:
ESP_LOGE(TAG, "ERROR:%s:%s", mqtt_app_err_breef[api_err], mqtt_app_err_descr[api_err]);
if (ResponceWithError(idx, file, ID, URL, api_err) != API_OK)
ESP_LOGE(TAG, "Failed to allocate memory for file MQTT message");
}
mqtt_app_err_t PublicTestMQTT(int idx)
{
char tmp[10];
char resp[256];
char JSONMess[512];
jwOpen(JSONMess, MAX_ERROR_JSON, JW_OBJECT, JW_PRETTY);
time_t now;
time(&now);
jwObj_int("time", (unsigned int) now);
jwObj_string("event", "MQTT_TEST_MESSAGE)");
strcpy(resp, "mqtt://");
strcat(resp, GetSysConf()->mqttStation[idx].ServerAddr);
itoa(GetSysConf()->mqttStation[idx].ServerPort, tmp, 10);
strcat(resp, ":");
strcat(resp, tmp);
jwObj_string("url", resp);
ComposeTopic(resp, idx, "SYSTEM", "UPLINK");
jwObj_string("tx_topic", resp);
ComposeTopic(resp, idx, "SYSTEM", "DWLINK");
jwObj_string("rx_topic", resp);
jwEnd();
jwClose();
char *buf = (char*) malloc(strlen(JSONMess) + 1);
if (buf)
{
memcpy(buf, JSONMess, strlen(JSONMess));
MQTT_DATA_SEND_STRUCT DSS;
ComposeTopic(DSS.topic, idx, "SYSTEM", "UPLINK");
DSS.raw_data_ptr = buf;
DSS.data_length = strlen(JSONMess);
if (xQueueSend(GetMQTTHandlesPool(idx)->mqtt_queue, &DSS, pdMS_TO_TICKS(1000)) == pdPASS)
return API_OK;
else
{
free(buf);
return API_INTERNAL_ERR;
}
}
else
{ // ERR internal error on publish error
return API_INTERNAL_ERR;
}
}

View File

@ -21,6 +21,7 @@
* \copyright Apache License, Version 2.0 * \copyright Apache License, Version 2.0
*/ */
#include "SystemApplication.h"
#include <SysConfiguration.h> #include <SysConfiguration.h>
#include <webguiapp.h> #include <webguiapp.h>
@ -86,3 +87,43 @@ esp_err_t GetConfVar(char* valias, rest_var_types* vtype, void* val)
} }
sys_error_code SysVarsPayloadHandler(data_message_t *MSG)
{
struct jReadElement result;
payload_type_50 *payload;
payload = ((payload_type_50*) (MSG->parsedData.payload));
if (MSG->parsedData.msgType == DATA_MESSAGE_TYPE_COMMAND)
{
//Extract 'key1' or throw exception
jRead(MSG->inputDataBuffer, "{'data'{'payload'{'key1'", &result);
if (result.elements == 1)
{
}
else
return SYS_ERROR_PARSE_KEY1;
//Extract 'key1' or throw exception
jRead(MSG->inputDataBuffer, "{'data'{'payload'{'key2'", &result);
if (result.elements == 1)
{
}
else
return SYS_ERROR_PARSE_KEY2;
//return StartTransactionPayloadType1(MSG);
}
else if (MSG->parsedData.msgType == DATA_MESSAGE_TYPE_REQUEST)
{
PrepareResponsePayloadType50(MSG);
return SYS_OK_DATA;
}
else
return SYS_ERROR_PARSE_MSGTYPE;
return SYS_OK;
}

View File

@ -224,7 +224,6 @@ static sys_error_code SysDataParser(data_message_t *MSG)
MSG->parsedData.payloadType = atoi((char*) result.pValue); MSG->parsedData.payloadType = atoi((char*) result.pValue);
if (MSG->parsedData.payloadType < 1 && MSG->parsedData.payloadType > 100) if (MSG->parsedData.payloadType < 1 && MSG->parsedData.payloadType > 100)
return SYS_ERROR_PARSE_PAYLOADTYPE; return SYS_ERROR_PARSE_PAYLOADTYPE;
MSG->parsedData.payload = malloc(sizeof(payload_type_50));
} }
else else
return SYS_ERROR_PARSE_PAYLOADTYPE; return SYS_ERROR_PARSE_PAYLOADTYPE;
@ -232,7 +231,12 @@ static sys_error_code SysDataParser(data_message_t *MSG)
switch (MSG->parsedData.payloadType) switch (MSG->parsedData.payloadType)
{ {
case 50: case 50:
MSG->parsedData.payload = malloc(sizeof(payload_type_50));
return SysPayloadType50Handler(MSG); return SysPayloadType50Handler(MSG);
case 51:
MSG->parsedData.payload = malloc(sizeof(payload_type_10));
return SysVarsPayloadHandler(MSG);
break; break;
} }