diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f31d08..59a0ee1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,6 @@ idf_component_register( "src/ETHTransport.c" "src/SNTP.c" "src/MQTT.c" - "src/MQTTSysHandler.c" src/OTA.c src/RestApiHandler.c src/SysComm.c diff --git a/include/SystemApplication.h b/include/SystemApplication.h index 64197d2..1b0c82a 100644 --- a/include/SystemApplication.h +++ b/include/SystemApplication.h @@ -63,9 +63,16 @@ typedef struct { int key1; int key2; - } payload_type_50; +typedef struct +{ +int key1; +int key2; +} payload_type_10; + + + #define DATA_MESSAGE_TYPE_COMMAND (1) #define DATA_MESSAGE_TYPE_REQUEST (2) @@ -91,6 +98,7 @@ typedef struct } data_message_t; 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); #endif /* COMPONENTS_WEBGUIAPP_INCLUDE_SYSTEMAPPLICATION_H_ */ diff --git a/src/MQTT.c b/src/MQTT.c index 61e7ac1..d8dc297 100644 --- a/src/MQTT.c +++ b/src/MQTT.c @@ -132,6 +132,51 @@ esp_err_t SysServiceMQTTSend(char *data, int len, int idx) 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, void *event_data) diff --git a/src/MQTTSysHandler.c b/src/MQTTSysHandler.c deleted file mode 100644 index cfedf51..0000000 --- a/src/MQTTSysHandler.c +++ /dev/null @@ -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¶m2=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¶m2=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; - } -} - diff --git a/src/RestApiHandler.c b/src/RestApiHandler.c index 2bad915..fb7fa2e 100644 --- a/src/RestApiHandler.c +++ b/src/RestApiHandler.c @@ -21,6 +21,7 @@ * \copyright Apache License, Version 2.0 */ +#include "SystemApplication.h" #include #include @@ -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; +} + + diff --git a/src/SysComm.c b/src/SysComm.c index cec89a8..930e60f 100644 --- a/src/SysComm.c +++ b/src/SysComm.c @@ -224,7 +224,6 @@ static sys_error_code SysDataParser(data_message_t *MSG) MSG->parsedData.payloadType = atoi((char*) result.pValue); if (MSG->parsedData.payloadType < 1 && MSG->parsedData.payloadType > 100) return SYS_ERROR_PARSE_PAYLOADTYPE; - MSG->parsedData.payload = malloc(sizeof(payload_type_50)); } else return SYS_ERROR_PARSE_PAYLOADTYPE; @@ -232,7 +231,12 @@ static sys_error_code SysDataParser(data_message_t *MSG) switch (MSG->parsedData.payloadType) { case 50: + MSG->parsedData.payload = malloc(sizeof(payload_type_50)); return SysPayloadType50Handler(MSG); + case 51: + MSG->parsedData.payload = malloc(sizeof(payload_type_10)); + return SysVarsPayloadHandler(MSG); + break; }