Compare commits

...

56 Commits

Author SHA1 Message Date
bogd
147c2b9cdd reset transaction on file delete error 2024-07-17 15:03:03 +02:00
bogd
8a1027a408 Merge remote-tracking branch 'gitlab/main' into main 2024-07-16 08:59:01 +02:00
b7ec9c8c35 fixed delete file after transid 2024-07-15 14:03:48 +02:00
bogd
a95e66c4b5 disabled debug block transfer 2024-07-08 11:12:20 +02:00
9b10a7f23d disabled debug of system log file operations 2024-07-07 14:39:02 +02:00
bc0660ef35 system log settings added to global configuration 2024-07-07 14:33:21 +02:00
26e104afe5 implemented system log with file rotation 2024-07-07 13:22:46 +02:00
bogd
0edc230a47 running GSM start task on core 1 to prevent uart irq allocate fail 2024-07-03 14:25:29 +02:00
bogd
d58ce6af9c file block transfer mechanism lock for first client, timeout of transfer
implemented
2024-07-02 12:40:25 +02:00
bogd
a1f7694bdb added transition id into block transfer module 2024-07-02 10:55:45 +02:00
bogd
3fe41b0f2e Merge remote-tracking branch 'gitlab/main' into main 2024-07-01 15:31:03 +02:00
bogd
44d7c8d539 fix infinit wait for get IP in GSM modem 2024-07-01 15:25:32 +02:00
b706e5ab26 resolved coflict with 'exec' variables handler 2024-06-25 13:38:26 +02:00
bogd
b8f649b371 conditional build of eeprom driver 2024-06-25 13:29:37 +02:00
7058e86538 implemented extended errors return for 'exec' variable 2024-06-24 21:29:58 +02:00
bogd
775635019c check eeprom ready before read, disabled debug messages in eeprom driver 2024-06-24 14:36:16 +02:00
bogd
f48880e78a eeprom block write debug 2024-06-21 16:31:02 +02:00
9276d4a6c1 implemented EEPROM write operation with data overlapped page size margin 2024-06-20 21:12:52 +02:00
bogd
6cb5bc0e9c start implementation i2c eeprom driver 2024-06-20 16:22:05 +02:00
0edd07fbd2 second MQTT always off for reduce memory consumption 2024-06-10 19:39:08 +02:00
bogd
0a21101817 fixed default interface variable output 2024-05-30 12:56:41 +02:00
bogd
8b8ea9a57f added CHAR type to the variables 2024-05-29 15:58:30 +02:00
bogd
a7417df420 gsm interface speed back to 115200, increased gsm commands attempts 2024-05-27 13:40:03 +02:00
394a798a98 fixed crash on modem restart during info retrieve over web ui 2024-05-23 09:54:36 +02:00
9f20a1b08b MQTT services definitions moved to mqtt header 2024-05-16 21:12:49 +02:00
92a1cc3cc7 astro timers implemented 2024-05-16 14:23:35 +02:00
513c9f6b89 astro timer combined with cron 2024-05-15 15:49:55 +02:00
3609a28892 astro data return after save 2024-05-15 08:21:06 +02:00
7346de2bdf astro data backend implemented 2024-05-14 17:07:26 +02:00
96a7238065 astro handle added 2024-05-14 10:54:05 +02:00
298c2e6534 astronomical calculations moved from double to float 2024-05-14 10:50:17 +02:00
a64de4a0c5 Astro timer moved to CRON scheduler 2024-05-14 10:28:59 +02:00
9d54a977fc added build config for astro timer 2024-05-13 15:57:25 +02:00
a9b4f515d5 added astro calculation core code 2024-05-13 15:36:19 +02:00
f0a773b53f added manual time set, fixed SNTP client disable 2024-05-13 12:47:40 +02:00
cda4bc7722 Merge branch 'main_sdcard' into 'main'
Main sdcard

See merge request userbogd/webguiapp!6
2024-05-08 14:43:23 +00:00
cef4def7f5 fixed basic auth header 2024-05-08 15:26:36 +02:00
c9beeaa39c SD card, if selected in build config, replacing internal storage 2024-05-08 10:24:42 +02:00
8e2490bef0 Merge branch 'main_sdcard' into 'main'
added SD card support

See merge request userbogd/webguiapp!5
2024-05-07 12:14:36 +00:00
4eaaff65fd added SD card support 2024-05-07 14:12:46 +02:00
94ff29e312 MQTT ID now is fully user defined 2024-04-30 09:46:58 +02:00
428bb65c7b time sync sequence improved 2024-04-27 12:21:41 +02:00
27cbfffb5b custom modem interaction baudrate set to 230 kbit/s 2024-04-24 14:59:26 +02:00
78dbc8e917 added SetSystemTime() function 2024-04-24 12:45:37 +02:00
3a7bf2a635 fixed GSM modem initialization sequence 2024-04-23 11:27:26 +02:00
3858722cca GSM external reset function delay 2024-04-11 16:02:30 +02:00
4fdec54608 timestamp format changed to ISO8601 2024-04-05 12:53:10 +02:00
db5452fe8b rollback mqtt reconnect time, added debug for receive mqtt data 2024-04-04 14:48:20 +02:00
2d8e4ee592 fixed lora visibility variable, tune mqtt timeouts, removes file topic 2024-04-03 14:26:25 +02:00
b473c8f198 fixed size of file block checking 2024-03-29 10:00:19 +02:00
25feb4f9fb export block_transaction_t object and it's parse function 2024-03-28 12:34:57 +02:00
83ab4dcba2 file api interface refactored 2024-03-28 12:08:49 +02:00
ec5069c096 reworked file api handler 2024-03-28 11:41:34 +02:00
84257e8276 documented raw memory access structure 2024-03-25 08:54:41 +02:00
9b11542f1a implemented file API in general protocol 2024-03-24 20:10:58 +02:00
5aaa2004c3 file read write API implemented 2024-03-13 19:51:11 +02:00
25 changed files with 1508 additions and 751 deletions

View File

@ -16,8 +16,6 @@ idf_component_register(
"src/HTTPServer.c"
"src/FileServer.c"
"src/HTTPAPISystem.c"
# "src/HTTPPrintSystem.c"
# "src/HTTPPostSystem.c"
"src/CommandProcSys.c"
"src/Helpers.c"
"src/NetTransport.c"
@ -27,11 +25,13 @@ idf_component_register(
"src/MQTT.c"
"src/CronTimers.c"
"src/SerialPort.c"
src/RawMemAPI.c
src/sdcard.c
src/FileBlockHandler.c
src/OTA.c
src/RestApiHandler.c
src/SysComm.c
src/SysErr.c
src/EEPROM.c
${lora_SRCS}
${gprs_SRCS}
${jreadwrite_SRCS}
@ -47,6 +47,7 @@ idf_component_register(
REQUIRES nvs_flash
spiffs
fatfs
esp_http_server
mbedtls
lwip

65
Kconfig
View File

@ -261,6 +261,57 @@ menu "WebGUIApp"
endmenu
menu "SDCARD settings"
config SDCARD_ENABLE
bool "Enabled SDCARD interface"
default n
help
Set enabled SDCARD
if SDCARD_ENABLE
config SDCARD_SPI_HOST
int "SPI Host Number"
range 0 2
default 2
help
Set the SPI host used.
config SDCARD_SPI_CS_GPIO
int "SDCARD SPI CS GPIO number"
range GPIO_RANGE_MIN GPIO_RANGE_MAX
default 0 if IDF_TARGET_ESP32
default 0 if IDF_TARGET_ESP32S3
help
Set the GPIO number used by SPI SCLK.
config SDCARD_SPI_SCLK_GPIO
int "SDCARD SPI SCLK GPIO number"
range GPIO_RANGE_MIN GPIO_RANGE_MAX
default 9 if IDF_TARGET_ESP32
default 9 if IDF_TARGET_ESP32S3
help
Set the GPIO number used by SPI SCLK.
config SDCARD_SPI_MOSI_GPIO
int "SDCARD SPI MOSI GPIO number"
range GPIO_RANGE_MIN GPIO_RANGE_MAX
default 34 if IDF_TARGET_ESP32
default 44 if IDF_TARGET_ESP32S3
help
Set the GPIO number used by SPI MOSI.
config SDCARD_SPI_MISO_GPIO
int "SDCARD SPI MISO GPIO number"
range GPIO_RANGE_MIN GPIO_RANGE_MAX
default 33 if IDF_TARGET_ESP32
default 43 if IDF_TARGET_ESP32S3
help
Set the GPIO number used by SPI MISO.
endif
endmenu
menu "WiFi settings"
config WEBGUIAPP_WIFI_ENABLE
@ -865,8 +916,6 @@ menu "WebGUIApp"
endif
endmenu
menu "MQTT settings"
config WEBGUIAPP_MQTT_ENABLE
bool "Enabled MQTT transport"
@ -930,6 +979,18 @@ menu "WebGUIApp"
endif
endmenu
menu "System log"
config WEBGUIAPP_SYSLOG_MAX_CHUNKS
int "Number of syslog parts"
range 1 10
default 4
config WEBGUIAPP_SYSLOG_CHUNK_SIZE
int "Size of one part in kilobytes"
range 1 256
default 50
endmenu
if WEBGUIAPP_WIFI_ENABLE || WEBGUIAPP_ETHERNET_ENABLE || WEBGUIAPP_GPRS_ENABLE
menu "DNS settings"

View File

@ -50,13 +50,14 @@ typedef struct
bool del; /*!< Flag of non valid record, free for future overwrite */
bool enab; /*!< Enable scheduler */
bool prev; /*!< Enable to execute nearest in the past sheduled action */
int type; /*!< Type: manual, sunrise, sunset, more types... */
float sun_angle;/*!<Sun angle unconditional event issue*/
char name[TIMER_NAME_LENGTH]; /*!< Human readable name of scheduler */
char cron[TIMER_CRONSTRING_LENGTH]; /*!< Cron expression */
char exec[TIMER_EXECSTRING_LENGTH]; /*!< Cron command string */
} cron_timer_t;
esp_err_t InitCronSheduler();
esp_err_t ReloadCronSheduler();
char* GetCronError();
void DebugTimer();
@ -67,12 +68,15 @@ char* GetCronActionName(int idx);
char* GetCronActAvail(int idx);
void TimeObtainHandler(struct timeval *tm);
void CronRecordsInterface(char *argres, int rw);
void AstroRecordsInterface(char *argres, int rw);
/**
* \brief Handle all actions under all objects
* \param obj Index of the object
* \param act Index of the action
*/
void custom_cron_execute(int obj, int act);
void SetSunTimes(uint32_t t);
void MidnightTimer();
#endif /* COMPONENTS_WEBGUIAPP_INCLUDE_CRONTIMERS_H_ */

View File

@ -45,8 +45,8 @@
/* Max length a file path can have on storage */
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN)
#define MAX_FILE_SIZE (1000*1024) // 200 KB
#define MAX_FILE_SIZE_STR "1MB"
#define MAX_FILE_SIZE (100*1000*1024) // 200 KB
#define MAX_FILE_SIZE_STR "100MB"
/* Scratch buffer size */
#define SCRATCH_BUFSIZE EXPECTED_MAX_DATA_SIZE
@ -84,6 +84,23 @@ typedef struct
void (*HandlerRoutine)(char *VarData, void *arg);
} dyn_var_handler_t;
#define BLOCK_OPERATION_TIMEOUT 30
#define MEM_OBLECT_MAX_LENGTH 32
typedef struct
{
int transid;
int opertype;
int operphase;
int part;
int parts;
int size;
char mem_object[MEM_OBLECT_MAX_LENGTH];
char filepath[FILE_PATH_MAX];
struct stat file_stat;
FILE *f;
int open_file_timeout;
} cb_blockdata_transfer_t;
esp_err_t start_file_server(void);
HTTP_IO_RESULT HTTPPostApp(httpd_req_t *req, const char *filename, char *PostData);
int HTTPPrint(httpd_req_t *req, char* buf, char* var);
@ -93,5 +110,9 @@ esp_err_t download_get_handler(httpd_req_t *req);
esp_err_t upload_post_handler(httpd_req_t *req);
esp_err_t delete_post_handler(httpd_req_t *req);
esp_err_t ParseBlockDataObject(char *argres, cb_blockdata_transfer_t *ft);
void FileBlockHandler(char *argres, int rw, const char* path);
void FileListHandler(char *argres, int rw, const char* path);
void FileBlockTimeoutCounter();
#endif /* COMPONENTS_WEB_GUI_APPLICATION_INCLUDE_HTTPSERVER_H_ */

View File

@ -47,6 +47,10 @@ typedef int mqtt_app_err_t;
#define API_FILE_EMPTY_ERR 15
#define API_UNKNOWN_ERR 16
#define EXTERNAL_SERVICE_NAME "RS485"
#define UPLINK_SUBTOPIC "UPLINK" // Device publish to this topic
#define DOWNLINK_SUBTOPIC "DWLINK" // Device listen from this topic
typedef struct
{
char topic[CONFIG_WEBGUIAPP_MQTT_MAX_TOPIC_LENGTH];

View File

@ -117,6 +117,8 @@ void GotEthIF(void);
void GetRFC3339Time(char *t);
void GetISO8601Time(char *t);
void StartTimeGet(void);
void SetSystemTime(struct tm *time, const char* source);
void SetSystemTimeVal(struct timeval *tv, const char* source);
esp_err_t StartOTA(bool isManual);
char* GetAvailVersion();

View File

@ -1,36 +0,0 @@
/* Copyright 2024 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 name: RawMemAPI.h
* Project: WebguiappTemplate
* Created on: 2024-03-11
* Author: bogd
* Description:
*/
#ifndef COMPONENTS_WEBGUIAPP_INCLUDE_RAWMEMAPI_H_
#define COMPONENTS_WEBGUIAPP_INCLUDE_RAWMEMAPI_H_
#include "webguiapp.h"
typedef struct
{
bool isActive;
int operType;
int dataLengthTotal;
int dataLengthReady;
} mqtt_files_cb;
void RawDataHandler(char *argres, int rw);
#endif /* COMPONENTS_WEBGUIAPP_INCLUDE_RAWMEMAPI_H_ */

View File

@ -43,7 +43,8 @@ typedef enum{
VAR_STRING,
VAR_PASS,
VAR_IPADDR,
VAR_FUNCT
VAR_FUNCT,
VAR_CHAR
} rest_var_types;
@ -103,6 +104,9 @@ typedef struct
{
bool bIsGlobalEnabled;
} Flags1;
float lat;
float lon;
} sntpClient;
#if CONFIG_WEBGUIAPP_MQTT_ENABLE

View File

@ -111,6 +111,7 @@ typedef struct
}UART_DATA_SEND_STRUCT;
void InitSerialPort(void);
void InitSysSDCard();
esp_err_t TransmitSerialPort(char *data, int ln);
esp_err_t GetConfVar(char* name, char* val, rest_var_types *tp);
@ -120,4 +121,9 @@ esp_err_t ServiceDataHandler(data_message_t *MSG);
sys_error_code SysVarsPayloadHandler(data_message_t *MSG);
void GetSysErrorDetales(sys_error_code err, const char **br, const char **ds);
#ifdef CONFIG_WEBGUIAPP_I2C_ENABLE
esp_err_t eepr_i2c_read(uint16_t addr, uint8_t *data, int length);
esp_err_t eepr_i2c_write(uint16_t addr, uint8_t *data, int length);
#endif
#endif /* COMPONENTS_WEBGUIAPP_INCLUDE_SYSTEMAPPLICATION_H_ */

View File

@ -42,5 +42,6 @@ void SetAppVars( rest_var_t* appvars, int size);
bool GetUserAppNeedReset(void);
void SetUserAppNeedReset(bool res);
void LogFile(char *fname, char *format, ...);
void SysLog(char *format, ...);
#endif /* COMPONENTS_WEBGUIAPPCOMPONENT_INCLUDE_WEBGUIAPP_H_ */

View File

@ -147,7 +147,7 @@ static int ExecCommandParse(char *cmd)
//int err = 0;
int commlen = strlen(cmd);
if (commlen > CONFIG_WEBGUIAPP_MAX_COMMAND_STRING_LENGTH)
return 1;
return 1; //ERROR_TOO_LONG_COMMAND
char comm[CONFIG_WEBGUIAPP_MAX_COMMAND_STRING_LENGTH + 1];
strcpy(comm, cmd);
@ -155,9 +155,9 @@ static int ExecCommandParse(char *cmd)
com = strtok(NULL, ",");
arg = strtok(NULL, "\0");
if (!obj)
return 2;
return 2; //ERROR_OBJECT_NOT_PARSED
if (!com)
return 3;
return 3; //ERROR_ACTION_NOT_PARSED
for (int idx = 0; idx < CONFIG_WEBGUIAPP_MAX_OBJECTS_NUM; idx++)
{
@ -170,13 +170,13 @@ static int ExecCommandParse(char *cmd)
if (com_obj_arr[idx].command_handlers[i] != NULL)
{
com_obj_arr[idx].command_handlers[i](obj, com, arg);
return 0;
return 0; //EXECUTED_OK
}
else
return 6;
return 6; //ERROR_HANDLER_NOT_IMPLEMENTED
}
}
return 5;
return 5; //ERROR_ACTION_NOT_FOUND
}
}
@ -191,15 +191,15 @@ static int ExecCommandParse(char *cmd)
if (custom_com_obj_arr[idx].command_handlers[i] != NULL)
{
custom_com_obj_arr[idx].command_handlers[i](obj, com, arg);
return 0;
return 0; //EXECUTED_OK
}
else
return 6;
return 6; //ERROR_HANDLER_NOT_IMPLEMENTED
}
}
return 5;
return 5; //ERROR_ACTION_NOT_FOUND
}
}
return 4;
return 4; //ERROR_OBJECT_NOT_FOUND
}

View File

@ -23,12 +23,18 @@
#include "esp_log.h"
#include "webguiapp.h"
#include "string.h"
#include <math.h>
#include <stdlib.h>
#include <freertos/task.h>
#define TAG "CRON_TIMER"
static cron_job *JobsList[CONFIG_WEBGUIAPP_CRON_NUMBER];
static char cron_express_error[CRON_EXPRESS_MAX_LENGTH];
static int GetSunEvent(uint8_t event, uint32_t unixt, float ang);
static int RecalcAstro(uint32_t tt);
char* GetCronError()
{
return cron_express_error;
@ -39,12 +45,6 @@ void custom_cron_job_callback(cron_job *job)
ExecCommand(((cron_timer_t*) job->data)->exec);
}
esp_err_t InitCronSheduler()
{
esp_err_t res = ESP_OK;
return res;
}
const char* check_expr(const char *expr)
{
const char *err = NULL;
@ -105,6 +105,7 @@ static void ExecuteLastAction(obj_struct_t *objarr)
void TimeObtainHandler(struct timeval *tm)
{
ESP_LOGI(TAG, "Current time updated with value %d", (unsigned int )tm->tv_sec);
RecalcAstro(tm->tv_sec);
ReloadCronSheduler();
ExecuteLastAction(GetSystemObjects());
ExecuteLastAction(GetCustomObjects());
@ -150,3 +151,239 @@ esp_err_t ReloadCronSheduler()
return ESP_OK;
}
void CronRecordsInterface(char *argres, int rw)
{
if (rw)
{
struct jReadElement result;
cron_timer_t T = { 0 };
jRead(argres, "", &result);
if (result.dataType == JREAD_ARRAY)
{
int i;
for (i = 0; i < result.elements; i++)
{
T.num = jRead_int(argres, "[*{'num'", &i);
T.del = jRead_int(argres, "[*{'del'", &i);
T.enab = jRead_int(argres, "[*{'enab'", &i);
T.prev = jRead_int(argres, "[*{'prev'", &i);
T.type = jRead_int(argres, "[*{'type'", &i);
T.sun_angle = (float) jRead_double(argres, "[*{'sun_angle'", &i);
jRead_string(argres, "[*{'name'", T.name, sizeof(T.name), &i);
jRead_string(argres, "[*{'cron'", T.cron, sizeof(T.cron), &i);
jRead_string(argres, "[*{'exec'", T.exec, sizeof(T.exec), &i);
if (T.type > 0)
{
time_t now;
time(&now);
int min = GetSunEvent((T.type == 1) ? 0 : 1, now, T.sun_angle);
sprintf(T.cron, "0 %d %d * * *", min % 60, min / 60);
}
memcpy(&GetSysConf()->Timers[T.num - 1], &T, sizeof(cron_timer_t));
}
ReloadCronSheduler();
}
}
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_ARRAY, JW_COMPACT);
for (int idx = 0; idx < CRON_TIMERS_NUMBER; idx++)
{
cron_timer_t T;
memcpy(&T, &GetSysConf()->Timers[idx], sizeof(cron_timer_t));
jwArr_object(&jwc);
jwObj_int(&jwc, "num", (unsigned int) T.num);
jwObj_int(&jwc, "del", (T.del) ? 1 : 0);
jwObj_int(&jwc, "enab", (T.enab) ? 1 : 0);
jwObj_int(&jwc, "prev", (T.prev) ? 1 : 0);
jwObj_int(&jwc, "type", (unsigned int) T.type);
jwObj_double(&jwc, "sun_angle", (double) T.sun_angle);
jwObj_string(&jwc, "name", T.name);
jwObj_string(&jwc, "cron", T.cron);
jwObj_string(&jwc, "exec", T.exec);
jwEnd(&jwc);
}
jwClose(&jwc);
}
/************************ ASTRO *******************************/
#define C (3.14159265/180.0)
#define B (180.0/3.14159265)
#define zenith 90.8335f
#define LAT 54.73
#define LON 20.51
#define SUN_ANG 0
static uint16_t srTime = 0;
static uint16_t ssTime = 0;
static float Lat, Lon, Ang;
static int GetSunEvent(uint8_t event, uint32_t unixt, float ang);
uint16_t NumberDayFromUnix(uint32_t t)
{
time_t clock;
struct tm *tp;
clock = t;
tp = gmtime(&clock);
return ((uint16_t) tp->tm_yday) + 1;
}
void SetSunConditions(double lat, double lon, double ang)
{
Lat = lat;
Lon = lon;
Ang = ang;
}
void SetSunTimes(uint32_t t)
{
double tt;
tt = GetSunEvent(0, t, SUN_ANG);
if (tt > 0)
srTime = tt;
else
srTime = 0xffff; //no valid sinrise time
tt = GetSunEvent(1, t, SUN_ANG);
if (tt > 0)
ssTime = tt;
else
ssTime = 0xffff; //no valid sunset time
ESP_LOGI("ASTRO", "Day number %d", NumberDayFromUnix(t));
ESP_LOGI("ASTRO", "Sanrise %dh %dm", srTime / 60 + 2, srTime - (srTime / 60 * 60));
ESP_LOGI("ASTRO", "Sanset %dh %dm", ssTime / 60 + 2, ssTime - (ssTime / 60 * 60));
}
uint16_t GetSunrise(void)
{
return srTime;
}
uint16_t GetSunset(void)
{
return ssTime;
}
static int GetSunEvent(uint8_t event, uint32_t unixt, float ang)
{
float lngHour, t, M, L, RA, sinDec, cosDec, cosH, H, T, UT;
float Lquadrant, RAquadrant;
float zen;
int day = NumberDayFromUnix(unixt);
if (ang == 0)
zen = zenith + (float) ang; //sunrise/set
else
zen = 90.0 + (float) ang; //twilight
lngHour = GetSysConf()->sntpClient.lon / 15;
if (event == 0)
t = day + ((6 - lngHour) / 24);
else
t = day + ((18 - lngHour) / 24);
M = (0.9856 * t) - 3.289;
L = M + (1.916 * sin(M * C)) + (0.020 * sin(2 * M * C)) + 282.634;
if (L > 360)
{
L = L - 360;
}
else if (L < 0)
{
L = L + 360;
}
RA = B * atan(0.91764 * tan(L * C));
if (RA > 360)
{
RA = RA - 360;
}
else if (RA < 0)
{
RA = RA + 360;
}
Lquadrant = (floor(L / 90)) * 90;
RAquadrant = (floor(RA / 90)) * 90;
RA = RA + (Lquadrant - RAquadrant);
RA = RA / 15;
sinDec = 0.39782 * sin(L * C);
cosDec = cos(asin(sinDec));
cosH = (cos(zen * C) - (sinDec * sin(GetSysConf()->sntpClient.lat * C)))
/ (cosDec * cos(GetSysConf()->sntpClient.lat * C));
if (event == 0)
{ //rise
if (cosH > 1)
return -1;
H = 360 - B * (acos(cosH));
}
else
{ //set
if (cosH < -1)
return -1;
H = B * (acos(cosH));
}
H = H / 15;
T = H + RA - (0.06571 * t) - 6.622;
UT = T - lngHour;
if (UT >= 24)
{
UT = UT - 24;
}
else if (UT < 0)
{
UT = UT + 24;
}
return (int) floor(UT * 60.0);
}
static int RecalcAstro(uint32_t tt)
{
struct timeval tv_now;
gettimeofday(&tv_now, NULL);
int timers_to_update = 0;
ESP_LOGI(TAG, "Recalculation astronomical events");
for (int i = 0; i < CRON_TIMERS_NUMBER; i++)
{
cron_timer_t *T = &GetSysConf()->Timers[i];
if (T->type == 0 || T->del)
continue;
int min = GetSunEvent((T->type == 1) ? 0 : 1, tt, T->sun_angle);
sprintf(T->cron, "0 %d %d * * *", min % 60, min / 60);
//ESP_LOGI(TAG, "Recalculated astro for rec %d new cron %s", T->num, T->cron);
++timers_to_update;
}
ESP_LOGI(TAG, "Recalculated %d astro timers", timers_to_update);
return timers_to_update;
}
#define MIDNIGHT_CHECK_INTERVAL 10
#define MIDNIGHT_DETECT_WINDOW 60
void MidnightTimer()
{
static int cnt = MIDNIGHT_CHECK_INTERVAL;
if (cnt-- <= 0)
{
cnt = MIDNIGHT_CHECK_INTERVAL;
struct timeval tv_now;
gettimeofday(&tv_now, NULL);
//ESP_LOGI(TAG, "Seconds remains to midnight %d", (int )tv_now.tv_sec % 86400);
if (tv_now.tv_sec % 86400 < MIDNIGHT_DETECT_WINDOW)
{
if (RecalcAstro(tv_now.tv_sec))
ReloadCronSheduler();
cnt = MIDNIGHT_CHECK_INTERVAL + MIDNIGHT_DETECT_WINDOW;
}
}
}

155
src/EEPROM.c Normal file
View File

@ -0,0 +1,155 @@
/* Copyright 2024 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 name: EEPROM.c
* Project: EVCHS_Stick
* Created on: 2024-06-20
* Author: bogd
* Description:
*/
#include "webguiapp.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "esp_err.h"
#ifdef CONFIG_WEBGUIAPP_I2C_ENABLE
#define TAG "EEPROMDriver"
#define I2C_MASTER_TIMEOUT_MS 1000
#define I2C_MASTER_NUM CONFIG_I2C_HOST /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_SDA_GPIO CONFIG_I2C_SDA_GPIO /*!< I2C master i2c SDA pin*/
#define I2C_MASTER_SCL_GPIO CONFIG_I2C_SCL_GPIO /*!< I2C master i2c SCL pin*/
#define EEPR24CXX_ADDR 0xA0 /*!< Slave address of 24Cxx devices*/
#define EEPROM_WRITE_PAGE_SIZE 32
#define EEPROM_WRITE_MAX_ATTEMPTS 20
typedef struct
{
i2c_port_t port; // I2C port number
uint8_t addr; // I2C address
uint32_t clk_speed; // I2C clock frequency for master mode
} i2c_dev_t;
i2c_dev_t eepr_24c32 = {
.port = I2C_MASTER_NUM,
.addr = EEPR24CXX_ADDR >> 1,
.clk_speed = CONFIG_I2C_CLOCK
};
static esp_err_t i2c_dev_read(const i2c_dev_t *dev, const void *out_data, size_t out_size, void *in_data,
size_t in_size)
{
if (!dev || !in_data || !in_size)
return ESP_ERR_INVALID_ARG;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
if (out_data && out_size)
{
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, (void*) out_data, out_size, true);
}
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->addr << 1) | 1, true);
i2c_master_read(cmd, in_data, in_size, I2C_MASTER_LAST_NACK);
i2c_master_stop(cmd);
esp_err_t res = i2c_master_cmd_begin(dev->port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
/*
if (res != ESP_OK)
ESP_LOGE(TAG, "Could not read from device [0x%02x at %d]: %d", dev->addr, dev->port, res);
*/
i2c_cmd_link_delete(cmd);
return res;
}
static esp_err_t i2c_dev_write(const i2c_dev_t *dev, const void *out_reg, size_t out_reg_size, const void *out_data,
size_t out_size)
{
if (!dev || !out_data || !out_size)
return ESP_ERR_INVALID_ARG;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true);
if (out_reg && out_reg_size)
i2c_master_write(cmd, (void*) out_reg, out_reg_size, true);
i2c_master_write(cmd, (void*) out_data, out_size, true);
i2c_master_stop(cmd);
esp_err_t res = i2c_master_cmd_begin(dev->port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
/*
if (res != ESP_OK)
ESP_LOGE(TAG, "Could not write to device [0x%02x at %d]: %d", dev->addr, dev->port, res);
*/
i2c_cmd_link_delete(cmd);
return res;
}
esp_err_t eepr_i2c_read(uint16_t addr, uint8_t *data, int length)
{
int attempts = 0;
esp_err_t err;
uint8_t adr[] = { (uint8_t)(addr >> 8), (uint8_t)(addr & 0xff) };
while ((err = i2c_dev_read(&eepr_24c32, adr, 2, data, length)) != ESP_OK)
{
//ESP_LOGW(TAG, "EEPROM not ready attempt %d", attempts);
if (++attempts >= EEPROM_WRITE_MAX_ATTEMPTS) //Critical error
{
ESP_LOGE(TAG, "EEPROM read critical error!");
return err;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
return ESP_OK;
}
esp_err_t eepr_i2c_write(uint16_t addr, uint8_t *data, int length)
{
int written = 0, attempts = 0;
uint16_t block_addr = addr;
esp_err_t err;
while ((length - written) > 0)
{
int block_len = MIN(length - written, EEPROM_WRITE_PAGE_SIZE);
uint8_t adr[] = { (uint8_t)(block_addr >> 8), (uint8_t)(block_addr & 0xff) };
while ((err = i2c_dev_write(&eepr_24c32, adr, 2, data + written, block_len)) != ESP_OK)
{
//ESP_LOGW(TAG, "EEPROM not ready attempt %d", attempts);
if (++attempts >= EEPROM_WRITE_MAX_ATTEMPTS) //Critical error
{
ESP_LOGE(TAG, "EEPROM write critical error!");
return err;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
attempts = 0;
written += block_len;
//ESP_LOGI(TAG, "written %d byte from addr %d", written, block_addr);
block_addr += EEPROM_WRITE_PAGE_SIZE;
}
return ESP_OK;
}
#endif

391
src/FileBlockHandler.c Normal file
View File

@ -0,0 +1,391 @@
/* Copyright 2024 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 name: FileBlockHandler.c
* Project: WebguiappTemplate
* Created on: 2024-03-11
* Author: bogd
* Description:
*/
#include "SystemApplication.h"
#include <SysConfiguration.h>
#include <webguiapp.h>
#include "esp_vfs.h"
#include "mbedtls/base64.h"
#define TAG "RAW_MEM_API"
/*
{
"transid": 623787878,
"opertype" : 1, [1-READ, 2-DELETE, 3-WRITE]
"part": 0, []
"parts": 3, []
"mem_object": "testfile.txt", [Resource name string]
"size : 4096, [Data block size in bytes]
"dat" : "" , [Data block BASE64 encoded]
}
*/
#define READ_ORERATION 1
#define DELETE_ORERATION 2
#define WRITE_ORERATION 3
static cb_blockdata_transfer_t FileTransaction = {
.opertype = 0
};
esp_err_t ParseBlockDataObject(char *argres, cb_blockdata_transfer_t *ft)
{
struct jReadElement result;
jRead(argres, "", &result);
if (result.dataType != JREAD_OBJECT)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:not an object\"");
return ESP_ERR_INVALID_ARG;
}
jRead(argres, "{'transid'", &result);
if (result.elements == 1)
{
int trans = atoi((char*) result.pValue);
if (ft->open_file_timeout != 0)
{
if (trans != ft->transid)
{
ESP_LOGW(TAG, "Attempt second client access while first is not finished");
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"Device is busy, please try later\"");
return ESP_ERR_NOT_FINISHED;
}
}
else
{
ft->transid = trans;
//ESP_LOGI(TAG, "New transaction with id %d", ft->transid);
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'transid' not found, frontend update needed\"");
return ESP_ERR_INVALID_ARG;
}
jRead(argres, "{'opertype'", &result);
if (result.elements == 1)
{
ft->opertype = atoi((char*) result.pValue);
if (ft->opertype < 1 || ft->opertype > 3)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'operation' value not in [1...3]\"");
return ESP_ERR_INVALID_ARG;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'operation' not found\"");
return ESP_ERR_INVALID_ARG;
}
jRead(argres, "{'parts'", &result);
if (result.elements == 1)
{
ft->parts = atoi((char*) result.pValue);
if (ft->parts < 0 || ft->parts > 20000)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'parts' value not in [0...20000]\"");
return ESP_ERR_INVALID_ARG;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'parts' not found\"");
return ESP_ERR_INVALID_ARG;
}
jRead(argres, "{'part'", &result);
if (result.elements == 1)
{
ft->part = atoi((char*) result.pValue);
if (ft->parts < 0 || ft->part > ft->parts - 1)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'part' value not in [0...(parts-1)]\"");
return ESP_ERR_INVALID_ARG;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'part' not found\"");
return ESP_ERR_INVALID_ARG;
}
jRead(argres, "{'mem_object'", &result);
if (result.elements == 1)
{
if (result.bytelen > 0 && result.bytelen < MEM_OBLECT_MAX_LENGTH)
{
memcpy(ft->mem_object, (char*) result.pValue, result.bytelen);
ft->mem_object[result.bytelen] = 0x00;
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'mem_object' length out of range\"");
return ESP_ERR_INVALID_ARG;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'mem_object' not found\"");
return ESP_ERR_INVALID_ARG;
}
jRead(argres, "{'size'", &result);
if (result.elements == 1)
{
ft->size = atoi((char*) result.pValue);
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'size' not found\"");
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
void FileBlockHandler(char *argres, int rw, const char *path)
{
if (ParseBlockDataObject(argres, &FileTransaction) != ESP_OK)
return;
FileTransaction.open_file_timeout = BLOCK_OPERATION_TIMEOUT; //restart timeout on every block
//Phase of file operation calculate
FileTransaction.operphase = 0; //Simple read or write
if (FileTransaction.parts == 1)
FileTransaction.operphase = 3; //Only one block handle (open and close in one iteration)
else if (FileTransaction.part == 0)
FileTransaction.operphase = 1; //First block of multipart data (open file)
else if (FileTransaction.part == (FileTransaction.parts - 1))
FileTransaction.operphase = 2; //Last block of multipart data (close file)
strcpy(FileTransaction.filepath, path);
strcat(FileTransaction.filepath, FileTransaction.mem_object);
if (FileTransaction.operphase == 1 || FileTransaction.operphase == 3)
{
if (FileTransaction.opertype == READ_ORERATION || FileTransaction.opertype == DELETE_ORERATION)
{
if (stat(FileTransaction.filepath, &FileTransaction.file_stat) == -1)
{
ESP_LOGE("FILE_API", "File does not exist : %s", FileTransaction.mem_object);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
FileTransaction.open_file_timeout = 0;
return;
}
}
else if (FileTransaction.opertype == WRITE_ORERATION)
{
if (stat(FileTransaction.filepath, &FileTransaction.file_stat) == 0)
{
if (unlink(FileTransaction.filepath) != 0)
{
ESP_LOGE("FILE_API", "Delete file ERROR : %s", FileTransaction.mem_object);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:File is already exists and can't be deleted\"");
}
}
}
}
if (FileTransaction.opertype == DELETE_ORERATION)
{
unlink(FileTransaction.filepath);
FileTransaction.open_file_timeout = 0;
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"DELETED OK\"");
return;
}
else if (FileTransaction.opertype == READ_ORERATION)
{
if (FileTransaction.operphase == 1 || FileTransaction.operphase == 3)
{
FileTransaction.f = fopen(FileTransaction.filepath, "r");
ESP_LOGI("FILE_API", "Open file for read : %s", FileTransaction.mem_object);
}
unsigned char *scr, *dst;
size_t dlen, olen, slen;
if (FileTransaction.f == NULL)
{
ESP_LOGE(TAG, "Failed to open file %s for writing", FileTransaction.mem_object);
return;
}
scr = (unsigned char*) malloc(FileTransaction.size + 1);
if (scr == NULL)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR: no memory to handle request\"");
return;
}
int read = fread(scr, 1, FileTransaction.size, FileTransaction.f);
scr[read] = 0x00;
slen = read;
if (FileTransaction.operphase == 2 || FileTransaction.operphase == 3)
{
fclose(FileTransaction.f);
FileTransaction.f = NULL;
FileTransaction.open_file_timeout = 0;
ESP_LOGI("FILE_API", "Close file for read : %s", FileTransaction.mem_object);
}
dlen = 0;
mbedtls_base64_encode(NULL, dlen, &olen, scr, slen);
dst = (unsigned char*) malloc(olen);
dlen = olen;
mbedtls_base64_encode(dst, dlen, &olen, scr, slen);
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_OBJECT, JW_COMPACT);
jwObj_int(&jwc, "transid", FileTransaction.transid);
jwObj_int(&jwc, "opertype", FileTransaction.opertype);
jwObj_int(&jwc, "parts", FileTransaction.parts);
jwObj_int(&jwc, "part", FileTransaction.part);
jwObj_string(&jwc, "mem_object", FileTransaction.mem_object);
jwObj_int(&jwc, "size", read);
jwObj_string(&jwc, "dat", (char*) dst);
jwClose(&jwc);
free(scr);
free(dst);
}
else if (FileTransaction.opertype == WRITE_ORERATION)
{
struct jReadElement result;
jRead(argres, "{'dat'", &result);
if (result.elements == 1)
{
if (result.bytelen > 0)
{
unsigned char *dst;
size_t dlen, olen;
if (FileTransaction.operphase == 1 || FileTransaction.operphase == 3)
{
FileTransaction.f = fopen(FileTransaction.filepath, "a");
ESP_LOGI("FILE_API", "Open file for write : %s", FileTransaction.mem_object);
}
if (FileTransaction.f == NULL)
{
ESP_LOGE(TAG, "Failed to open file %s for writing", FileTransaction.mem_object);
return;
}
dlen = 0;
mbedtls_base64_decode(NULL, dlen, &olen, (unsigned char*) result.pValue, (size_t) result.bytelen);
dst = (unsigned char*) malloc(olen);
dlen = olen;
mbedtls_base64_decode(dst, dlen, &olen, (unsigned char*) result.pValue, (size_t) result.bytelen);
//ESP_LOGI("FILE_API", "File write operation BEGIN");
int write = fwrite((char*) dst, olen, 1, FileTransaction.f);
//ESP_LOGI("FILE_API", "File write operation END");
if (FileTransaction.operphase == 2 || FileTransaction.operphase == 3)
{
fclose(FileTransaction.f);
FileTransaction.f = NULL;
FileTransaction.open_file_timeout = 0;
ESP_LOGI("FILE_API", "Close file for write : %s", FileTransaction.mem_object);
}
free(dst);
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_OBJECT, JW_COMPACT);
jwObj_int(&jwc, "transid", FileTransaction.transid);
jwObj_int(&jwc, "opertype", FileTransaction.opertype);
jwObj_int(&jwc, "parts", FileTransaction.parts);
jwObj_int(&jwc, "part", FileTransaction.part);
jwObj_string(&jwc, "mem_object", FileTransaction.mem_object);
jwObj_int(&jwc, "size", write);
jwClose(&jwc);
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'dat' length out of range\"");
return;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'dat' not found\"");
return;
}
}
}
void FileBlockTimeoutCounter()
{
if (FileTransaction.open_file_timeout)
{
if (--FileTransaction.open_file_timeout == 0)
{
if (FileTransaction.f != NULL)
fclose(FileTransaction.f);
}
}
//ESP_LOGI(TAG, "Block timeout %d", FileTransaction.open_file_timeout);
}
void FileListHandler(char *argres, int rw, const char *path)
{
char entrypath[FILE_PATH_MAX];
char entrysize[16];
const char *entrytype = "file";
struct dirent *entry;
struct stat entry_stat;
DIR *dir = opendir(path);
const size_t dirpath_len = strlen(path);
strlcpy(entrypath, path, sizeof(entrypath));
if (!dir)
{
ESP_LOGE("FILE_API", "Failed to stat dir : %s", path);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_ARRAY, JW_COMPACT);
while ((entry = readdir(dir)) != NULL)
{
strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len);
entrytype = (entry->d_type == DT_DIR ? "directory" : "file");
if (stat(entrypath, &entry_stat) == -1)
{
ESP_LOGE("FILE_API", "Failed to stat %s : %s", entrytype, entry->d_name);
continue;
}
jwArr_object(&jwc);
jwObj_raw(&jwc, "sel", "false");
jwObj_string(&jwc, "name", (char*) entry->d_name);
jwObj_int(&jwc, "size", entry_stat.st_size);
jwEnd(&jwc);
}
jwClose(&jwc);
}

View File

@ -22,16 +22,16 @@
#include <string.h>
#include "../include/SysConfiguration.h"
#include "NetTransport.h"
#include "driver/gpio.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_modem_api.h"
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_netif_ppp.h"
#include "esp_event.h"
#include "esp_modem_api.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "NetTransport.h"
#if CONFIG_WEBGUIAPP_GPRS_ENABLE
static EventGroupHandle_t event_group = NULL;
@ -41,46 +41,40 @@ static int ResetType = 0;
static bool isPPPinitializing = false;
#endif
#define CUSTOM_MODEM_BAUDRATE 115200
#define MAX_COMMAND_REPEATE_NUMBER 15
#define WATCHDOG_INTERVAL 30
#define WAIT_FOR_GET_IP 30
static bool isPPPConn = false;
static int attimeout = 1000;
TaskHandle_t initTaskhandle;
#define PPP_MODEM_TIMEOUT 40
MODEM_INFO mod_info = { "-", "-", "-", "-" };
MODEM_INFO mod_info = {"-", "-", "-", "-"};
esp_netif_t *ppp_netif;
esp_modem_dce_t *dce;
TaskHandle_t trasporttask;
static void (*gsm_reset)(uint8_t level) = NULL;
void RegGSMReset(void (*gsm_rst)(uint8_t level))
{
gsm_reset = gsm_rst;
}
void RegGSMReset(void (*gsm_rst)(uint8_t level)) { gsm_reset = gsm_rst; }
esp_netif_t* GetPPPNetifAdapter(void)
{
esp_netif_t *GetPPPNetifAdapter(void) {
if (isPPPConn)
return ppp_netif;
else
return NULL;
}
MODEM_INFO* GetPPPModemInfo(void)
{
return &mod_info;
}
MODEM_INFO *GetPPPModemInfo(void) { return &mod_info; }
bool isPPPConnected(void)
{
return isPPPConn;
}
bool isPPPConnected(void) { return isPPPConn; }
#if CONFIG_WEBGUIAPP_GPRS_ENABLE
static void on_ppp_changed(void *arg, esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
ESP_LOGI(TAG, "PPP state changed event %u", (unsigned int )event_id);
if (event_id == NETIF_PPP_ERRORUSER)
{
int32_t event_id, void *event_data) {
ESP_LOGI(TAG, "PPP state changed event %u", (unsigned int)event_id);
if (event_id == NETIF_PPP_ERRORUSER) {
/* User interrupted event from esp-netif */
esp_netif_t *netif = event_data;
ESP_LOGI(TAG, "User interrupted event from netif:%p", netif);
@ -88,21 +82,21 @@ static void on_ppp_changed(void *arg, esp_event_base_t event_base,
}
static void on_ip_event(void *arg, esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
ESP_LOGD(TAG, "IP event! %u", (unsigned int )event_id);
if (event_id == IP_EVENT_PPP_GOT_IP)
{
int32_t event_id, void *event_data) {
ESP_LOGD(TAG, "IP event! %u", (unsigned int)event_id);
if (event_id == IP_EVENT_PPP_GOT_IP) {
esp_netif_dns_info_t dns_info;
ip_event_got_ip_t *event = (ip_event_got_ip_t*) event_data;
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
esp_netif_t *netif = event->esp_netif;
#if CONFIG_WEBGUIAPP_GPRS_ENABLE
memcpy(&GetSysConf()->gsmSettings.IPAddr, &event->ip_info.ip, sizeof(event->ip_info.ip));
memcpy(&GetSysConf()->gsmSettings.Mask, &event->ip_info.netmask, sizeof(event->ip_info.netmask));
memcpy(&GetSysConf()->gsmSettings.Gateway, &event->ip_info.gw, sizeof(event->ip_info.gw));
memcpy(&GetSysConf()->gsmSettings.IPAddr, &event->ip_info.ip,
sizeof(event->ip_info.ip));
memcpy(&GetSysConf()->gsmSettings.Mask, &event->ip_info.netmask,
sizeof(event->ip_info.netmask));
memcpy(&GetSysConf()->gsmSettings.Gateway, &event->ip_info.gw,
sizeof(event->ip_info.gw));
#endif
ESP_LOGI(TAG, "Modem Connect to PPP Server");
@ -118,67 +112,57 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
xEventGroupSetBits(event_group, CONNECT_BIT);
isPPPConn = true;
ESP_LOGI(TAG, "GOT ip event!!!");
}
else if (event_id == IP_EVENT_PPP_LOST_IP)
{
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
isPPPConn = false;
}
else if (event_id == IP_EVENT_GOT_IP6)
{
} else if (event_id == IP_EVENT_GOT_IP6) {
ESP_LOGI(TAG, "GOT IPv6 event!");
ip_event_got_ip6_t *event = (ip_event_got_ip6_t*) event_data;
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(event->ip6_info.ip));
}
}
void ModemNotReady(void)
{
void ModemNotReady(void) {}
}
static void GSMInitTask(void *pvParameter)
{
static void GSMInitTask(void *pvParameter) {
isPPPinitializing = true;
int starttype = *((int*) pvParameter);
int starttype = *((int *)pvParameter);
esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event);
esp_event_handler_unregister(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed);
esp_event_handler_unregister(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID,
&on_ppp_changed);
if (dce)
{
if (dce) {
esp_modem_destroy(dce);
}
if (ppp_netif != NULL)
{
if (ppp_netif != NULL) {
esp_netif_destroy(ppp_netif);
}
if (starttype == 0)
{
if (starttype == 0) {
ESP_LOGE(TAG, "GSM module power down and up reset");
#if CONFIG_MODEM_DEVICE_POWER_CONTROL_PIN >= 0
gpio_set_level(CONFIG_MODEM_DEVICE_POWER_CONTROL_PIN, 0);
vTaskDelay(pdMS_TO_TICKS(1000));
vTaskDelay(pdMS_TO_TICKS(5000));
gpio_set_level(CONFIG_MODEM_DEVICE_POWER_CONTROL_PIN, 1);
vTaskDelay(pdMS_TO_TICKS(5000));
#else
if (gsm_reset)
{
if (gsm_reset) {
gsm_reset(0);
vTaskDelay(pdMS_TO_TICKS(1000));
vTaskDelay(pdMS_TO_TICKS(5000));
gsm_reset(1);
}
else
{
ESP_LOGE(TAG, "ethernet chip reset pin not defined");
vTaskDelay(pdMS_TO_TICKS(5000));
} else {
ESP_LOGE(TAG, "GSM module reset procedure not defined");
ESP_ERROR_CHECK(1);
}
#endif
}
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &on_ip_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID,
&on_ip_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID,
&on_ppp_changed, NULL));
event_group = xEventGroupCreate();
/* Configure the DTE */
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
@ -195,7 +179,8 @@ static void GSMInitTask(void *pvParameter)
dte_config.task_priority = CONFIG_MODEM_UART_EVENT_TASK_PRIORITY;
dte_config.dte_buffer_size = CONFIG_MODEM_UART_RX_BUFFER_SIZE / 2;
/* Configure the DCE */
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(GetSysConf()->gsmSettings.APN);
esp_modem_dce_config_t dce_config =
ESP_MODEM_DCE_DEFAULT_CONFIG(GetSysConf()->gsmSettings.APN);
/* Configure the PPP netif */
esp_netif_inherent_config_t esp_netif_conf = ESP_NETIF_INHERENT_DEFAULT_PPP();
@ -207,116 +192,133 @@ static void GSMInitTask(void *pvParameter)
/* Init netif object */
ppp_netif = esp_netif_new(&netif_ppp_config);
assert(ppp_netif);
dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM800, &dte_config, &dce_config, ppp_netif);
dce = esp_modem_new_dev(ESP_MODEM_DCE_SIM800, &dte_config, &dce_config,
ppp_netif);
assert(dce);
if (esp_modem_set_baud(dce, CUSTOM_MODEM_BAUDRATE) == ESP_OK)
uart_set_baudrate(0, CUSTOM_MODEM_BAUDRATE);
mod_info.model[0] = 0x00;
int GSMConnectTimeout = 0;
while (esp_modem_get_module_name(dce, mod_info.model) != ESP_OK)
{
if (++GSMConnectTimeout >= PPP_MODEM_TIMEOUT)
int OperationRepeate = 0;
// MODULE NAME
while (esp_modem_get_module_name(dce, mod_info.model) != ESP_OK) {
if (OperationRepeate++ >= MAX_COMMAND_REPEATE_NUMBER) {
ESP_LOGE(TAG, "Error get module name");
goto modem_init_fail;
}
ESP_LOGW(TAG, "Retry get module name");
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGI(TAG, "Module type:%s", mod_info.model);
// IMSI
OperationRepeate = 0;
mod_info.imsi[0] = 0x00;
while (esp_modem_get_imsi(dce, mod_info.imsi) != ESP_OK)
{
if (++GSMConnectTimeout >= PPP_MODEM_TIMEOUT)
while (esp_modem_get_imsi(dce, mod_info.imsi) != ESP_OK) {
if (OperationRepeate++ >= MAX_COMMAND_REPEATE_NUMBER) {
ESP_LOGE(TAG, "Error get IMSI");
goto modem_init_fail;
}
ESP_LOGW(TAG, "Retry get IMSI");
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGI(TAG, "IMSI:%s", mod_info.imsi);
// OPERATOR NAME
OperationRepeate = 0;
mod_info.oper[0] = 0x00;
int tech = 0;
while (esp_modem_get_operator_name(dce, mod_info.oper, &tech) != ESP_OK)
{
if (++GSMConnectTimeout >= PPP_MODEM_TIMEOUT)
vTaskDelay(pdMS_TO_TICKS(10000));
while (esp_modem_get_operator_name(dce, mod_info.oper, &tech) != ESP_OK) {
if (OperationRepeate++ >= MAX_COMMAND_REPEATE_NUMBER) {
ESP_LOGE(TAG, "Error get operator name");
goto modem_init_fail;
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGW(TAG, "Retry get operator name");
vTaskDelay(pdMS_TO_TICKS(10000));
}
ESP_LOGI(TAG, "Operator:%s", mod_info.oper);
// IMEI
mod_info.imei[0] = 0x00;
while (esp_modem_get_imei(dce, mod_info.imei) != ESP_OK)
{
if (++GSMConnectTimeout >= PPP_MODEM_TIMEOUT)
OperationRepeate = 0;
while (esp_modem_get_imei(dce, mod_info.imei) != ESP_OK) {
if (OperationRepeate++ >= MAX_COMMAND_REPEATE_NUMBER) {
ESP_LOGE(TAG, "Error get IMEI");
goto modem_init_fail;
}
ESP_LOGW(TAG, "Retry get IMEI");
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGI(TAG, "IMEI:%s", mod_info.imei);
while (esp_modem_set_mode(dce, ESP_MODEM_MODE_CMUX) != ESP_OK)
{
if (++GSMConnectTimeout >= PPP_MODEM_TIMEOUT)
// SWITCH TO CMUX
OperationRepeate = 0;
while (esp_modem_set_mode(dce, ESP_MODEM_MODE_CMUX) != ESP_OK) {
if (OperationRepeate++ >= MAX_COMMAND_REPEATE_NUMBER) {
ESP_LOGE(TAG, "Error switch module to CMUX");
goto modem_init_fail;
}
ESP_LOGW(TAG, "Retry switch module to CMUX");
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_LOGI(TAG, "PPP data mode OK");
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, portMAX_DELAY);
xEventGroupWaitBits(event_group, CONNECT_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(WAIT_FOR_GET_IP * 1000));
isPPPinitializing = false;
vTaskDelete(NULL);
return;
modem_init_fail:
ESP_LOGE(TAG, "PPP modem init error");
ESP_LOGE(TAG, "PPP modem initialization fail");
isPPPinitializing = false;
vTaskDelete(NULL);
}
void PPPModemColdStart(void)
{
void PPPModemColdStart(void) {
ResetType = 0;
xTaskCreate(GSMInitTask, "GSMInitTask", 1024 * 6, &ResetType, 3, &initTaskhandle);
xTaskCreatePinnedToCore(GSMInitTask, "GSMInitTask", 1024 * 6, &ResetType, 3,
&initTaskhandle, 1);
ESP_LOGI(TAG, "Start GSM cold initialization task");
}
void PPPModemSoftRestart(void)
{
void PPPModemSoftRestart(void) {
ResetType = 1;
xTaskCreate(GSMInitTask, "GSMInitTask", 1024 * 6, &ResetType, 3, &initTaskhandle);
xTaskCreate(GSMInitTask, "GSMInitTask", 1024 * 6, &ResetType, 3,
&initTaskhandle);
ESP_LOGI(TAG, "Start GSM soft initialization task");
}
static void GSMRunTask(void *pvParameter)
{
while (1)
{
if (!isPPPConn && !isPPPinitializing)
{ //try to reconnect modem
ESP_LOGI(TAG, "PPP modem restart");
static void GSMRunTask(void *pvParameter) {
while (1) {
if (!isPPPConn && !isPPPinitializing) { // try to reconnect modem
ESP_LOGW(TAG, "Module restart by watchdog");
PPPModemColdStart();
}
vTaskDelay(pdMS_TO_TICKS(30000));
vTaskDelay(pdMS_TO_TICKS(WATCHDOG_INTERVAL * 1000));
}
}
void PPPModemStart(void)
{
xTaskCreate(GSMRunTask, "GSMRunTask", 1024 * 4, &ResetType, 3, NULL);
void PPPModemStart(void) {
xTaskCreatePinnedToCore(GSMRunTask, "GSMRunTask", 1024 * 4, &ResetType, 3, NULL, 1);
}
int PPPModemGetRSSI(void)
{
int PPPModemGetRSSI(void) {
int rssi = -1, ber;
if (isPPPConn)
esp_modem_get_signal_quality(dce, &rssi, &ber);
return rssi;
}
void ModemSetATTimeout(int timeout)
{
attimeout = timeout;
}
void ModemSetATTimeout(int timeout) { attimeout = timeout; }
void ModemSendAT(char *cmd, char *resp, int timeout)
{
void ModemSendAT(char *cmd, char *resp, int timeout) {
ESP_LOGI(TAG, "Command:%s", cmd);
int res = esp_modem_at(dce, cmd, resp, attimeout);
switch(res)
{
switch (res) {
case 0:
ESP_LOGI(TAG, "OK");
break;
@ -331,16 +333,11 @@ void ModemSendAT(char *cmd, char *resp, int timeout)
ESP_LOGI(TAG, "Response:%s", resp);
}
esp_err_t cmd_cb(uint8_t* data, int len)
{
esp_err_t cmd_cb(uint8_t *data, int len) {
ESP_LOGI(TAG, "Response:%*s", len, data);
return ESP_OK;
}
void ModemSendSMS(void)
{
esp_modem_command(dce, "atd", &cmd_cb, 3000);
}
void ModemSendSMS(void) { esp_modem_command(dce, "atd", &cmd_cb, 3000); }
#endif

View File

@ -57,19 +57,24 @@ void regHTTPUserAppHandlers(char *url,
}
#define BASIC_LOGIN_LENGTH 31
#define BASIC_PASS_LENGTH 31
#define BASIC_DECODED_LENGTH (BASIC_LOGIN_LENGTH + BASIC_PASS_LENGTH + 1 + 1)
#define BASIC_ENCODED_LENGTH (BASIC_DECODED_LENGTH * 4 / 3)
static esp_err_t CheckAuth(httpd_req_t *req)
{
unsigned char pass[18] = { 0 }; //max length of login:password decoded string
unsigned char inp[31]; //max length of login:password coded string plus Basic
unsigned char pass[BASIC_DECODED_LENGTH] = { 0 }; //max length of login:password decoded string
unsigned char inp[BASIC_ENCODED_LENGTH]; //max length of login:password coded string plus Basic
const char keyword1[] = "Basic ";
const int keyword1len = sizeof(keyword1) - 1;
if (httpd_req_get_hdr_value_len(req, "Authorization") > 31)
if (httpd_req_get_hdr_value_len(req, "Authorization") > BASIC_ENCODED_LENGTH)
{
httpd_resp_set_hdr(req, "Connection", "close");
httpd_resp_send_err(req, HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE, "Authorization field value is too large");
return ESP_FAIL;
}
httpd_req_get_hdr_value_str(req, "Authorization", (char*) inp, 31);
httpd_req_get_hdr_value_str(req, "Authorization", (char*) inp, BASIC_ENCODED_LENGTH);
unsigned char *pt = memmem(inp, sizeof(inp), keyword1, keyword1len);
if (pt)
{
@ -460,7 +465,11 @@ esp_err_t start_file_server(void)
return ESP_ERR_NO_MEM;
}
strlcpy(server_data->base_path, "/", sizeof("/"));
#if CONFIG_SDCARD_ENABLE
strlcpy(server_data->base_path2, "/sdcard", sizeof("/sdcard"));
#else
strlcpy(server_data->base_path2, "/data", sizeof("/data"));
#endif
server = start_webserver();
return ESP_OK;
}

View File

@ -28,17 +28,13 @@
#define TAG "MQTT"
#define SERVICE_NAME "SYSTEM" // Dedicated service name
#define FILE_SERVICE_NAME "FILE"
#define EXTERNAL_SERVICE_NAME "RS485"
#define UPLINK_SUBTOPIC "UPLINK" // Device publish to this topic
#define DOWNLINK_SUBTOPIC "DWLINK" // Device listen from this topic
#define MQTT_DEBUG_MODE CONFIG_WEBGUIAPP_MQTT_DEBUG_LEVEL
#define MQTT_MESSAGE_BUFER_LENTH 10 //size of mqtt queue
#define MQTT_RECONNECT_CHANGE_ADAPTER 3
#define MQTT_RECONNECT_TIMEOUT 20
#define MQTT_RECONNECT_TIMEOUT 10
#if CONFIG_WEBGUIAPP_MQTT_ENABLE
@ -107,8 +103,8 @@ void ComposeTopic(char *topic, int idx, char *service_name, char *direct)
strcat((char*) topic, GetSysConf()->mqttStation[idx].GroupName); // Global system name
strcat((char*) topic, "/");
strcat((char*) topic, GetSysConf()->mqttStation[idx].ClientID); // Device client name (for multiclient devices)
strcat((char*) topic, "-");
strcat((char*) topic, GetSysConf()->ID); //
//strcat((char*) topic, "-");
//strcat((char*) topic, GetSysConf()->ID); //
strcat((char*) topic, "/");
strcat((char*) topic, (const char*) service_name); // Device service name
strcat((char*) topic, "/");
@ -127,6 +123,7 @@ esp_err_t SysServiceMQTTSend(char *data, int len, int idx)
ComposeTopic(DSS.topic, idx, SERVICE_NAME, UPLINK_SUBTOPIC);
DSS.raw_data_ptr = buf;
DSS.data_length = len;
DSS.keep_memory_onfinish = false;
if (xQueueSend(GetMQTTHandlesPool(idx)->mqtt_queue, &DSS, pdMS_TO_TICKS(0)) == pdPASS)
return ESP_OK;
else
@ -221,13 +218,6 @@ static void mqtt_system_event_handler(int idx, void *handler_args, esp_event_bas
ESP_LOGI(TAG, "Subscribe to %s", topic);
#endif
ComposeTopic(topic, idx, FILE_SERVICE_NAME, DOWNLINK_SUBTOPIC);
msg_id = esp_mqtt_client_subscribe(client, (char*) topic, 0);
#if MQTT_DEBUG_MODE > 0
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
ESP_LOGI(TAG, "Subscribe to %s", topic);
#endif
#ifdef CONFIG_WEBGUIAPP_UART_TRANSPORT_ENABLE
if (GetSysConf()->serialSettings.Flags.IsBridgeEnabled)
{
@ -273,7 +263,9 @@ static void mqtt_system_event_handler(int idx, void *handler_args, esp_event_bas
case MQTT_EVENT_DATA:
#if MQTT_DEBUG_MODE > 1
ESP_LOGI(TAG, "MQTT_EVENT_DATA, client %d", idx);
ESP_LOGI(TAG, "MQTT_EVENT_DATA, client:%d, data-length:%d, offset:%d ", idx, event->data_len, event->current_data_offset);
ESP_LOGI(TAG, "MQTT client %d data received:%.*s", idx, event->data_len, event->data);
#endif
if (event->data_len == 0 || event->current_data_offset > 0) //possible fragments of long data
goto end_of_system_handler;
@ -302,13 +294,6 @@ static void mqtt_system_event_handler(int idx, void *handler_args, esp_event_bas
ESP_LOGE(TAG, "Out of free RAM for MQTT API handle");
}
ComposeTopic(topic, idx, FILE_SERVICE_NAME, DOWNLINK_SUBTOPIC);
if (!memcmp(topic, event->topic, event->topic_len))
{
ESP_LOGI(TAG, "Got data for FILE_SYSTEM_SERVICE:%s", event->data);
//Here handler of file system operations
}
#ifdef CONFIG_WEBGUIAPP_UART_TRANSPORT_ENABLE
if (GetSysConf()->serialSettings.Flags.IsBridgeEnabled)
{
@ -406,7 +391,7 @@ void MQTTTaskTransmit(void *pvParameter)
{
#if MQTT_DEBUG_MODE > 1
ESP_LOGI(TAG, "MQTT client %d data send:%.*s", idx, DSS.data_length, DSS.raw_data_ptr);
ESP_LOGW(TAG, "MQTT client %d data send:%.*s", idx, DSS.data_length, DSS.raw_data_ptr);
#endif
esp_mqtt_client_publish(mqtt[idx].mqtt,
(const char*) DSS.topic,
@ -467,7 +452,7 @@ static void start_mqtt()
esp_mqtt_client_register_event(mqtt[i].mqtt, ESP_EVENT_ANY_ID, mqtt[i].user_event_handler, &mqtt[i]);
esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &reconnect_MQTT_handler, &mqtt[i].mqtt);
esp_mqtt_client_start(mqtt[i].mqtt);
xTaskCreate(MQTTTaskTransmit, "MQTTTaskTransmit", 1024 * 2, (void*) &mqtt[i].mqtt_index, 3, NULL);
xTaskCreate(MQTTTaskTransmit, "MQTTTaskTransmit", 1024 * 4, (void*) &mqtt[i].mqtt_index, 3, NULL);
}
}
}

View File

@ -1,214 +0,0 @@
/* Copyright 2024 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 name: RawMemAPI.c
* Project: WebguiappTemplate
* Created on: 2024-03-11
* Author: bogd
* Description:
*/
#include "RawMemAPI.h"
#include "SystemApplication.h"
#include <SysConfiguration.h>
#include <webguiapp.h>
#include "esp_vfs.h"
#include "mbedtls/base64.h"
#define TAG "RAW_MEM_API"
/*
{
"operation" : 1,
"mem_object": "testfile.txt",
"offset" : 2000,
"size : 4096,
"data" : "" ,
}
*/
#define READ_ORERATION 1
#define DELETE_ORERATION 2
#define APPEND_ORERATION 3
#define REPLACE_ORERATION 4
static const char *dirpath = "/data/";
#define MEM_OBLECT_MAX_LENGTH 32
void RawDataHandler(char *argres, int rw)
{
int operation = 0;
int offset;
int size;
char mem_object[MEM_OBLECT_MAX_LENGTH];
char filepath[FILE_PATH_MAX];
struct stat file_stat;
struct jReadElement result;
jRead(argres, "", &result);
if (result.dataType != JREAD_OBJECT)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:not an object\"");
return;
}
jRead(argres, "{'operation'", &result);
if (result.elements == 1)
{
operation = atoi((char*) result.pValue);
if (operation < 1 || operation > 2)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'operation' value not in [1...2]\"");
return;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'operation' not found\"");
return;
}
jRead(argres, "{'mem_object'", &result);
if (result.elements == 1)
{
if (result.bytelen > 0 && result.bytelen < MEM_OBLECT_MAX_LENGTH)
{
memcpy(mem_object, (char*) result.pValue, result.bytelen);
mem_object[result.bytelen] = 0x00;
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'mem_object' length out of range\"");
return;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'mem_object' not found\"");
return;
}
jRead(argres, "{'offset'", &result);
if (result.elements == 1)
{
offset = atoi((char*) result.pValue);
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'offset' not found\"");
return;
}
jRead(argres, "{'size'", &result);
if (result.elements == 1)
{
size = atoi((char*) result.pValue);
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'size' not found\"");
return;
}
//ESP_LOGI(TAG, "Got memory object %s, with offest %d and size %d", mem_object, offset, size);
strcpy(filepath, dirpath);
strcat(filepath, mem_object);
if (stat(filepath, &file_stat) == -1)
{
ESP_LOGE("FILE_API", "File does not exist : %s", mem_object);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
if (operation == DELETE_ORERATION)
{
unlink(filepath);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"DELETED OK\"");
return;
}
else if (operation == READ_ORERATION)
{
FILE *f = fopen(filepath, "r");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file %s for writing", mem_object);
return;
}
char *dat = (char*) malloc(size + 1);
if (dat == NULL)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR: no memory to handle request\"");
return;
}
fseek(f, offset, SEEK_SET);
int read = fread(dat, 1, size, f);
dat[read] = 0x00;
fclose(f);
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_OBJECT, JW_COMPACT);
jwObj_int(&jwc, "operation", operation);
jwObj_string(&jwc, "mem_object", mem_object);
jwObj_int(&jwc, "offset", offset);
jwObj_int(&jwc, "size", read);
jwObj_string(&jwc, "dat", dat);
jwClose(&jwc);
free(dat);
}
else if (operation == APPEND_ORERATION || operation == REPLACE_ORERATION)
{
jRead(argres, "{'dat'", &result);
if (result.elements == 1)
{
if (result.bytelen > 0 && result.bytelen <= size)
{
//memcpy(mem_object, (char*) result.pValue, result.bytelen);
//mem_object[result.bytelen] = 0x00;
if (operation == REPLACE_ORERATION)
FILE *f = fopen(filepath, "w");
else if (operation == APPEND_ORERATION)
FILE *f = fopen(filepath, "a");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file %s for writing", mem_object);
return;
}
fseek(f, offset, SEEK_SET);
int write = fwrite((char*) result.pValue, result.bytelen, 1, f);
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_OBJECT, JW_COMPACT);
jwObj_int(&jwc, "operation", operation);
jwObj_string(&jwc, "mem_object", mem_object);
jwObj_int(&jwc, "offset", offset);
jwObj_int(&jwc, "size", write);
jwClose(&jwc);
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:'dat' length out of range\"");
return;
}
}
else
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:key 'dat' not found\"");
return;
}
}
}

View File

@ -31,7 +31,6 @@
#include "esp_idf_version.h"
#include "NetTransport.h"
#include "esp_vfs.h"
#include "RawMemAPI.h"
extern SYS_CONFIG SysConfig;
@ -97,7 +96,9 @@ static void funct_mqtt_2_test(char *argres, int rw)
static void funct_def_interface(char *argres, int rw)
{
GetDefaultNetIFName(argres);
char interface[3];
GetDefaultNetIFName(interface);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"%s\"", interface);
}
static void funct_time(char *argres, int rw)
@ -107,6 +108,20 @@ static void funct_time(char *argres, int rw)
snprintf(argres, VAR_MAX_VALUE_LENGTH, "%d", (int) now);
}
static void funct_time_set(char *argres, int rw)
{
time_t unix = atoi(argres);
if (unix == 0)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "%s", "\"ERROR_UNIX_TIME_NULL\"");
return;
}
struct timeval tv;
tv.tv_sec = unix;
SetSystemTimeVal(&tv, "Time set from user API");
snprintf(argres, VAR_MAX_VALUE_LENGTH, "%s", "\"TIME_SET_OK\"");
}
static void funct_uptime(char *argres, int rw)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "%d", (int) GetUpTime());
@ -216,7 +231,6 @@ static void funct_wifiscanres(char *argres, int rw)
strcpy(argres, "\"SYS_ERROR_UNKNOWN\"");
}
#if CONFIG_WEBGUIAPP_GPRS_ENABLE
void funct_gsm_module(char *argres, int rw)
{
@ -255,7 +269,6 @@ void funct_gsm_rssi(char *argres, int rw)
}
#endif
#ifdef CONFIG_WEBGUIAPP_LORAWAN_ENABLE
void funct_lora_stat(char *argres, int rw)
{
@ -283,7 +296,6 @@ void funct_lora_appkey(char *argres, int rw)
}
#endif
static void funct_ota_state(char *argres, int rw)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"%s\"", GetUpdateStatus());
@ -301,50 +313,8 @@ static void funct_ota_newver(char *argres, int rw)
//CRON implementation BEGIN
static void funct_cronrecs(char *argres, int rw)
{
if (rw)
{
struct jReadElement result;
cron_timer_t T = { 0 };
jRead(argres, "", &result);
if (result.dataType == JREAD_ARRAY)
{
int i;
for (i = 0; i < result.elements; i++)
{
T.num = jRead_int(argres, "[*{'num'", &i);
T.del = jRead_int(argres, "[*{'del'", &i);
T.enab = jRead_int(argres, "[*{'enab'", &i);
T.prev = jRead_int(argres, "[*{'prev'", &i);
jRead_string(argres, "[*{'name'", T.name, sizeof(T.name), &i);
jRead_string(argres, "[*{'cron'", T.cron, sizeof(T.cron), &i);
jRead_string(argres, "[*{'exec'", T.exec, sizeof(T.exec), &i);
memcpy(&GetSysConf()->Timers[T.num - 1], &T, sizeof(cron_timer_t));
}
ReloadCronSheduler();
}
}
else
{
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_ARRAY, JW_COMPACT);
for (int idx = 0; idx < CRON_TIMERS_NUMBER; idx++)
{
cron_timer_t T;
memcpy(&T, &GetSysConf()->Timers[idx], sizeof(cron_timer_t));
jwArr_object(&jwc);
jwObj_int(&jwc, "num", (unsigned int) T.num);
jwObj_int(&jwc, "del", (T.del) ? 1 : 0);
jwObj_int(&jwc, "enab", (T.enab) ? 1 : 0);
jwObj_int(&jwc, "prev", (T.prev) ? 1 : 0);
jwObj_string(&jwc, "name", T.name);
jwObj_string(&jwc, "cron", T.cron);
jwObj_string(&jwc, "exec", T.exec);
jwEnd(&jwc);
}
jwClose(&jwc);
}
CronRecordsInterface(argres, rw);
}
//CRON implementation END
static void funct_serial_mode(char *argres, int rw)
@ -358,139 +328,73 @@ static void funct_serial_mode(char *argres, int rw)
}
static void funct_objsinfo(char *argres, int rw)
{
GetObjectsInfo(argres);
}
const char *EXEC_ERROR[] = {
"EXECUTED_OK",
"ERROR_TOO_LONG_COMMAND",
"ERROR_OBJECT_NOT_PARSED",
"ERROR_ACTION_NOT_PARSED",
"ERROR_OBJECT_NOT_FOUND",
"ERROR_ACTION_NOT_FOUND",
"ERROR_HANDLER_NOT_IMPLEMENTED",
};
static void funct_exec(char *argres, int rw)
{
if (rw)
ExecCommand(argres);
else
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"EXECUTED\"");
int res = ExecCommand(argres);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"%s\"", EXEC_ERROR[res]);
}
static const char *dirpath = "/data/";
static void funct_file_list(char *argres, int rw)
{
char entrypath[FILE_PATH_MAX];
char entrysize[16];
const char *entrytype = "file";
struct dirent *entry;
struct stat entry_stat;
DIR *dir = opendir(dirpath);
const size_t dirpath_len = strlen(dirpath);
strlcpy(entrypath, dirpath, sizeof(entrypath));
if (!dir)
{
ESP_LOGE("FILE_API", "Failed to stat dir : %s", dirpath);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
struct jWriteControl jwc;
jwOpen(&jwc, argres, VAR_MAX_VALUE_LENGTH, JW_ARRAY, JW_COMPACT);
while ((entry = readdir(dir)) != NULL)
{
strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len);
entrytype = (entry->d_type == DT_DIR ? "directory" : "file");
if (stat(entrypath, &entry_stat) == -1)
{
ESP_LOGE("FILE_API", "Failed to stat %s : %s", entrytype, entry->d_name);
continue;
}
jwArr_object(&jwc);
jwObj_string(&jwc, "name", (char*) entry->d_name);
jwObj_string(&jwc, "type", entrytype);
jwObj_int(&jwc, "size", entry_stat.st_size);
jwEnd(&jwc);
}
jwClose(&jwc);
#if CONFIG_SDCARD_ENABLE
FileListHandler(argres, rw, "/sdcard/");
#else
FileListHandler(argres, rw, "/data/");
#endif
}
static void funct_file_delete(char *argres, int rw)
static void funct_file_block(char *argres, int rw)
{
char filepath[FILE_PATH_MAX];
struct stat file_stat;
const char *filename = argres;
if (!filename)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
if (filename[strlen(filename) - 1] == '/')
{
ESP_LOGE("FILE_API", "Invalid filename : %s", filename);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
strcpy(filepath, dirpath);
strcat(filepath, filename);
ESP_LOGI("FILE_API", " filepath to delete : %s", filepath);
if (stat(filepath, &file_stat) == -1)
{
ESP_LOGE("FILE_API", "File does not exist : %s", filename);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
/* Respond with 400 Bad Request */
return;
}
unlink(filepath);
#if CONFIG_SDCARD_ENABLE
FileBlockHandler(argres, rw, "/sdcard/");
#else
FileBlockHandler(argres, rw, "/data/");
#endif
}
static void funct_file_get(char *argres, int rw)
#if CONFIG_SDCARD_ENABLE
static void funct_sd_list(char *argres, int rw)
{
char filepath[FILE_PATH_MAX];
struct stat file_stat;
const char *filename = argres;
if (!filename)
{
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
if (filename[strlen(filename) - 1] == '/')
{
ESP_LOGE("FILE_API", "Invalid filename : %s", filename);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
return;
}
strcpy(filepath, dirpath);
strcat(filepath, filename);
ESP_LOGI("FILE_API", " filepath to delete : %s", filepath);
if (stat(filepath, &file_stat) == -1)
{
ESP_LOGE("FILE_API", "File does not exist : %s", filename);
snprintf(argres, VAR_MAX_VALUE_LENGTH, "\"ERROR:DIR_NOT_FOUND\"");
/* Respond with 400 Bad Request */
return;
}
FileListHandler(argres, rw, "/sdcard/");
}
static void funct_file_put(char *argres, int rw)
static void funct_sd_block(char *argres, int rw)
{
FileBlockHandler(argres, rw, "/sdcard/");
}
#endif
static void funct_lat(char *argres, int rw)
{
if (rw)
{
GetSysConf()->sntpClient.lat = atof(argres);
}
snprintf(argres, VAR_MAX_VALUE_LENGTH, "%f", GetSysConf()->sntpClient.lat);
}
static void funct_raw_data(char *argres, int rw)
static void funct_lon(char *argres, int rw)
{
RawDataHandler(argres, rw);
if (rw)
{
GetSysConf()->sntpClient.lon = atof(argres);
}
snprintf(argres, VAR_MAX_VALUE_LENGTH, "%f", GetSysConf()->sntpClient.lon);
}
const int hw_rev = CONFIG_BOARD_HARDWARE_REVISION;
@ -502,6 +406,7 @@ const rest_var_t SystemVariables[] =
{ 0, "exec", &funct_exec, VAR_FUNCT, RW, 0, 0 },
{ 0, "time", &funct_time, VAR_FUNCT, R, 0, 0 },
{ 0, "time_set", &funct_time_set, VAR_FUNCT, RW, 0, 0 },
{ 0, "uptime", &funct_uptime, VAR_FUNCT, R, 0, 0 },
{ 0, "free_ram", &funct_fram, VAR_FUNCT, R, 0, 0 },
{ 0, "free_ram_min", &funct_fram_min, VAR_FUNCT, R, 0, 0 },
@ -514,14 +419,12 @@ const rest_var_t SystemVariables[] =
{ 0, "hw_rev", ((int*) &hw_rev), VAR_INT, R, 1, 1024 },
//{ 0, "hw_opt", CONFIG_BOARD_HARDWARE_OPTION, VAR_STRING, R, 1, 256 },
{ 0, "net_bios_name", &SysConfig.NetBIOSName, VAR_STRING, RW, 3, 31 },
{ 0, "sys_name", &SysConfig.SysName, VAR_STRING, RW, 3, 31 },
{ 0, "sys_pass", &SysConfig.SysPass, VAR_PASS, RW, 3, 31 },
{ 0, "primary_color", CONFIG_WEBGUIAPP_ACCENT_COLOR, VAR_STRING, RW, 3, 31 },
{ 0, "dark_theme", (bool*) (&VAR_TRUE), VAR_BOOL, R, 0, 1 },
{ 0, "ota_url", &SysConfig.OTAURL, VAR_STRING, RW, 3, 128 },
{ 0, "ota_auto_int", &SysConfig.OTAAutoInt, VAR_INT, RW, 0, 65535 },
{ 0, "ota_state", &funct_ota_state, VAR_FUNCT, R, 0, 0 },
@ -544,6 +447,9 @@ const rest_var_t SystemVariables[] =
{ 0, "sntp_serv3", &SysConfig.sntpClient.SntpServer3Adr, VAR_STRING, RW, 3, 32 },
{ 0, "sntp_enab", &SysConfig.sntpClient.Flags1.bIsGlobalEnabled, VAR_BOOL, RW, 0, 1 },
{ 0, "lat", &funct_lat, VAR_FUNCT, RW, 0, 0 },
{ 0, "lon", &funct_lon, VAR_FUNCT, RW, 0, 0 },
#if CONFIG_WEBGUIAPP_MQTT_ENABLE
{ 0, "mqtt_1_enab", &SysConfig.mqttStation[0].Flags1.bIsGlobalEnabled, VAR_BOOL, RW, 0, 1 },
{ 0, "mqtt_1_serv", &SysConfig.mqttStation[0].ServerAddr, VAR_STRING, RW, 3, 63 },
@ -612,7 +518,7 @@ const rest_var_t SystemVariables[] =
{ 0, "wifi_scan_res", &funct_wifiscanres, VAR_FUNCT, R, 0, 0 },
{ 0, "wifi_level", &funct_wifi_level, VAR_FUNCT, R, 0, 0 },
#endif
#endif
#if CONFIG_WEBGUIAPP_GPRS_ENABLE
{ 0, "gsm_enab", &SysConfig.gsmSettings.Flags1.bIsGSMEnabled, VAR_BOOL, RW, 0, 1 },
@ -630,7 +536,7 @@ const rest_var_t SystemVariables[] =
{ 0, "gsm_dns2", &SysConfig.gsmSettings.DNSAddr2, VAR_IPADDR, RW, 0, 0 },
{ 0, "gsm_dns3", &SysConfig.gsmSettings.DNSAddr3, VAR_IPADDR, RW, 0, 0 },
{ 0, "gsm_stat", &funct_gsm_stat, VAR_FUNCT, R, 0, 0 },
#ifdef CONFIG_WEBGUIAPP_MODEM_AT_ACCESS
#ifdef CONFIG_WEBGUIAPP_MODEM_AT_ACCESS
{ 0, "gsm_at_timeout", &funct_gsm_at_timeout, VAR_FUNCT, R, 0, 0 },
{ 0, "gsm_at", &funct_gsm_at, VAR_FUNCT, R, 0, 0 },
#endif
@ -638,7 +544,7 @@ const rest_var_t SystemVariables[] =
{ 0, "gsm_visible", (bool*) (&VAR_TRUE), VAR_BOOL, R, 0, 1 },
#else
{ 0, "gsm_visible", (bool*) (&VAR_FALSE), VAR_BOOL, R, 0, 1 },
#endif
#endif
#ifdef CONFIG_WEBGUIAPP_UART_TRANSPORT_ENABLE
{ 0, "serial_enab", &SysConfig.serialSettings.Flags.IsSerialEnabled, VAR_BOOL, RW, 0, 1 },
@ -647,14 +553,13 @@ const rest_var_t SystemVariables[] =
{ 0, "serial_baud", &SysConfig.serialSettings.BaudRate, VAR_INT, RW, 1200, 4096000 },
{ 0, "serial_break", &SysConfig.serialSettings.InputBrake, VAR_INT, RW, 1, 50 },
{ 0, "serial_visible", (bool*) (&VAR_TRUE), VAR_BOOL, R, 0, 1 },
#else
#else
{ 0, "serial_visible", (bool*) (&VAR_FALSE), VAR_BOOL, R, 0, 1 },
#endif
#endif
#ifdef CONFIG_WEBGUIAPP_LORAWAN_ENABLE
{ 0, "lora_enab", &SysConfig.lorawanSettings.Flags1.bIsLoRaWANEnabled, VAR_BOOL, RW, 0, 1 },
{ 0, "lora_visible", (bool*) (&VAR_TRUE), VAR_BOOL, RW, 0, 1 },
{ 0, "lora_visible", (bool*) (&VAR_TRUE), VAR_BOOL, R, 0, 1 },
{ 0, "lora_devid", &funct_lora_devid, VAR_FUNCT, RW, 0, 0 },
{ 0, "lora_appid", &funct_lora_appid, VAR_FUNCT, RW, 0, 0 },
{ 0, "lora_appkey", &funct_lora_appkey, VAR_FUNCT, R, 0, 0 },
@ -662,12 +567,7 @@ const rest_var_t SystemVariables[] =
#else
{ 0, "lora_visible", (bool*) (&VAR_FALSE), VAR_BOOL, R, 0, 1 },
#endif
#endif
#ifdef CONFIG_WEBGUIAPP_MBTCP_ENABLED
{ 0, "mbtcp_enab", &SysConfig.modbusSettings.IsModbusTCPEnabled, VAR_BOOL, RW, 0, 1 },
@ -675,20 +575,22 @@ const rest_var_t SystemVariables[] =
{ 0, "mbtcp_visible", (bool*) (&VAR_TRUE), VAR_BOOL, R, 0, 1 },
#else
{ 0, "mbtcp_visible", (bool*) (&VAR_FALSE), VAR_BOOL, R, 0, 1 },
#endif
#endif
{ 0, "cronrecs", &funct_cronrecs, VAR_FUNCT, RW, 0, 0 },
{ 0, "objsinfo", &funct_objsinfo, VAR_FUNCT, R, 0, 0 },
{ 0, "file_list", &funct_file_list, VAR_FUNCT, R, 0, 0 },
{ 0, "file_delete", &funct_file_delete, VAR_FUNCT, R, 0, 0 },
{ 0, "file_get", &funct_file_get, VAR_FUNCT, R, 0, 0 },
{ 0, "file_put", &funct_file_put, VAR_FUNCT, R, 0, 0 },
{ 0, "raw_data", &funct_raw_data, VAR_FUNCT, R, 0, 0 },
{ 0, "file_block", &funct_file_block, VAR_FUNCT, R, 0, 0 },
#if CONFIG_SDCARD_ENABLE
{ 0, "sd_list", &funct_sd_list, VAR_FUNCT, R, 0, 0 },
{ 0, "sd_block", &funct_sd_block, VAR_FUNCT, R, 0, 0 },
{ 0, "sd_visible", (bool*) (&VAR_TRUE), VAR_BOOL, R, 0, 1 }
#else
{ 0, "sd_visible", (bool*) (&VAR_FALSE), VAR_BOOL, R, 0, 1 },
#endif
};
esp_err_t SetConfVar(char *name, char *val, rest_var_types *tp)
{
rest_var_t *V = NULL;
@ -730,6 +632,12 @@ esp_err_t SetConfVar(char *name, char *val, rest_var_types *tp)
else
return ESP_ERR_INVALID_ARG;
break;
case VAR_CHAR:
constr = atoi(val);
if (constr < V->minlen || constr > V->maxlen)
return ESP_ERR_INVALID_ARG;
*((uint8_t*) V->ref) = constr;
break;
case VAR_INT:
constr = atoi(val);
if (constr < V->minlen || constr > V->maxlen)
@ -799,6 +707,9 @@ esp_err_t GetConfVar(char *name, char *val, rest_var_types *tp)
case VAR_INT:
itoa(*((int*) V->ref), val, 10);
break;
case VAR_CHAR:
itoa(*((uint8_t*) V->ref), val, 10);
break;
case VAR_STRING:
strcpy(val, (char*) V->ref);
break;

View File

@ -134,9 +134,27 @@ void StartSystemTimer(void)
ESP_ERROR_CHECK(esp_timer_start_periodic(system_seconds_timer, 1000000));
}
void SetSystemTime(struct tm *time, const char* source)
{
time_t t = mktime(time);
ESP_LOGI("SNTP","Setting time: %s from the source %s", asctime(time), source);
struct timeval now = { .tv_sec = t };
settimeofday(&now, NULL);
TimeObtainHandler(&now);
}
void SetSystemTimeVal(struct timeval *tv, const char* source)
{
ESP_LOGI("SNTP","Setting time: %d from the source %s", (int)(tv->tv_sec), source);
settimeofday(tv, NULL);
TimeObtainHandler(tv);
}
void SecondTickSystem(void *param)
{
++UpTime;
MidnightTimer();
FileBlockTimeoutCounter();
}
uint32_t GetUpTime(void)

View File

@ -131,8 +131,8 @@ void serial_RX_task(void *arg)
if (GetSysConf()->serialSettings.Flags.IsBridgeEnabled)
{
ExternalServiceMQTTSend(rxbuf, buffered_size, 0);
ExternalServiceMQTTSend(rxbuf, buffered_size, 1);
ExternalServiceMQTTSend(EXTERNAL_SERVICE_NAME, rxbuf, buffered_size, 0);
ExternalServiceMQTTSend(EXTERNAL_SERVICE_NAME, rxbuf, buffered_size, 1);
}
else
ReceiveHandlerAPI();

View File

@ -54,8 +54,8 @@ static sys_error_code PayloadDefaultTypeHandler(data_message_t *MSG)
jwObj_int(&jwc, "msgid", MSG->parsedData.msgID);
jwObj_string(&jwc, "srcid", GetSysConf()->ID);
jwObj_string(&jwc, "dstid", MSG->parsedData.srcID);
char time[RFC3339_TIMESTAMP_LENGTH];
GetRFC3339Time(time);
char time[ISO8601_TIMESTAMP_LENGTH];
GetISO8601Time(time);
jwObj_string(&jwc, "time", time);
jwObj_int(&jwc, "msgtype", DATA_MESSAGE_TYPE_RESPONSE);
jwObj_int(&jwc, "payloadtype", MSG->parsedData.payloadType);
@ -330,8 +330,8 @@ esp_err_t ServiceDataHandler(data_message_t *MSG)
jwObj_int(&jwc, "msgid", MSG->parsedData.msgID);
jwObj_string(&jwc, "srcid", GetSysConf()->ID);
jwObj_string(&jwc, "dstid", MSG->parsedData.srcID);
char time[RFC3339_TIMESTAMP_LENGTH];
GetRFC3339Time(time);
char time[ISO8601_TIMESTAMP_LENGTH];
GetISO8601Time(time);
jwObj_string(&jwc, "time", time);
jwObj_int(&jwc, "messtype", DATA_MESSAGE_TYPE_RESPONSE);
const char *err_br;

View File

@ -99,6 +99,9 @@ esp_err_t WebGuiAppInit(void)
#if CONFIG_WEBGUIAPP_I2C_ENABLE
InitSysI2C();
#endif
#if CONFIG_SDCARD_ENABLE
InitSysSDCard();
#endif
esp_err_t err = nvs_flash_init();
ESP_ERROR_CHECK(esp_netif_init());
@ -157,6 +160,7 @@ esp_err_t WebGuiAppInit(void)
/*Start services depends on client connection*/
#if CONFIG_WEBGUIAPP_GPRS_ENABLE || CONFIG_WEBGUIAPP_ETHERNET_ENABLE || CONFIG_WEBGUIAPP_WIFI_ENABLE
ESP_ERROR_CHECK(start_file_server());
if (GetSysConf()->sntpClient.Flags1.bIsGlobalEnabled)
StartTimeGet();
//regTimeSyncCallback(&TimeObtainHandler);
//mDNSServiceStart();
@ -174,7 +178,6 @@ esp_err_t WebGuiAppInit(void)
InitSerialPort();
#endif
return ESP_OK;
}
@ -249,7 +252,7 @@ static void ResetSysConfig(SYS_CONFIG *Conf)
UINT32_VAL d;
GetChipId((uint8_t*) d.v);
snprintf(Conf->SN, 11, "%010u", (unsigned int)swap(d.Val));
snprintf(Conf->SN, 11, "%010u", (unsigned int) swap(d.Val));
Conf->ColorSheme = CONFIG_WEBGUIAPP_DEFAULT_COLOR_SCHEME;
@ -361,23 +364,29 @@ esp_netif_str_to_ip4(CONFIG_WEBGUIAPP_DNS3_ADDRESS_DEFAULT, (esp_ip4_addr_t*) &C
sizeof(CONFIG_WEBGUIAPP_MQTT_SYSTEM_NAME));
memcpy(Conf->mqttStation[0].GroupName, CONFIG_WEBGUIAPP_MQTT_GROUP_NAME,
sizeof(CONFIG_WEBGUIAPP_MQTT_GROUP_NAME));
memcpy(Conf->mqttStation[0].ClientID, CONFIG_WEBGUIAPP_MQTT_CLIENT_ID_1,
sizeof(CONFIG_WEBGUIAPP_MQTT_CLIENT_ID_1));
Conf->mqttStation[0].ClientID[0] = 0x00;
strcat(Conf->mqttStation[0].ClientID, CONFIG_WEBGUIAPP_MQTT_CLIENT_ID_1);
strcat(Conf->mqttStation[0].ClientID, "-");
strcat(Conf->mqttStation[0].ClientID, Conf->ID);
memcpy(Conf->mqttStation[0].UserName, CONFIG_WEBGUIAPP_MQTT_USERNAME,
sizeof(CONFIG_WEBGUIAPP_MQTT_USERNAME));
memcpy(Conf->mqttStation[0].UserPass, CONFIG_WEBGUIAPP_MQTT_PASSWORD,
sizeof(CONFIG_WEBGUIAPP_MQTT_PASSWORD));
#if CONFIG_WEBGUIAPP_MQTT_CLIENTS_NUM == 2
Conf->mqttStation[1].Flags1.bIsGlobalEnabled = false;
#if CONFIG_WEBGUIAPP_MQTT_ON
Conf->mqttStation[1].Flags1.bIsGlobalEnabled = true;
#endif
memcpy(Conf->mqttStation[1].ServerAddr, CONFIG_WEBGUIAPP_MQTT_SERVER_URL, sizeof(CONFIG_WEBGUIAPP_MQTT_SERVER_URL));
Conf->mqttStation[1].ServerPort = CONFIG_WEBGUIAPP_MQTT_SERVER_PORT;
memcpy(Conf->mqttStation[1].SystemName, CONFIG_WEBGUIAPP_MQTT_SYSTEM_NAME,
sizeof(CONFIG_WEBGUIAPP_MQTT_SYSTEM_NAME));
memcpy(Conf->mqttStation[1].GroupName, CONFIG_WEBGUIAPP_MQTT_GROUP_NAME, sizeof(CONFIG_WEBGUIAPP_MQTT_GROUP_NAME));
memcpy(Conf->mqttStation[1].ClientID, CONFIG_WEBGUIAPP_MQTT_CLIENT_ID_2, sizeof(CONFIG_WEBGUIAPP_MQTT_CLIENT_ID_2));
Conf->mqttStation[1].ClientID[0] = 0x00;
strcat(Conf->mqttStation[1].ClientID, CONFIG_WEBGUIAPP_MQTT_CLIENT_ID_2);
strcat(Conf->mqttStation[1].ClientID, "-");
strcat(Conf->mqttStation[1].ClientID, Conf->ID);
memcpy(Conf->mqttStation[1].UserName, CONFIG_WEBGUIAPP_MQTT_USERNAME, sizeof(CONFIG_WEBGUIAPP_MQTT_USERNAME));
memcpy(Conf->mqttStation[1].UserPass, CONFIG_WEBGUIAPP_MQTT_PASSWORD, sizeof(CONFIG_WEBGUIAPP_MQTT_PASSWORD));
#endif
@ -390,6 +399,8 @@ esp_netif_str_to_ip4(CONFIG_WEBGUIAPP_DNS3_ADDRESS_DEFAULT, (esp_ip4_addr_t*) &C
sizeof(CONFIG_WEBGUIAPP_SNTP_HOST_3));
Conf->sntpClient.Flags1.bIsGlobalEnabled = CONFIG_WEBGUIAPP_SNTP_AUTOUPDATE_ENABLE;
Conf->sntpClient.TimeZone = CONFIG_WEBGUIAPP_SNTP_TIMEZONE;
Conf->sntpClient.lat = 0.0;
Conf->sntpClient.lon = 0.0;
#ifdef CONFIG_WEBGUIAPP_LORAWAN_ENABLE
Conf->lorawanSettings.Flags1.bIsLoRaWANEnabled = true;
@ -424,17 +435,23 @@ esp_netif_str_to_ip4(CONFIG_WEBGUIAPP_DNS3_ADDRESS_DEFAULT, (esp_ip4_addr_t*) &C
#endif
Conf->modbusSettings.ModbusTCPPort = CONFIG_WEBGUIAPP_MBTCP_SERVER_PORT;
#endif
for (int i = 0; i < CONFIG_WEBGUIAPP_CRON_NUMBER; i++ )
for (int i = 0; i < CONFIG_WEBGUIAPP_CRON_NUMBER; i++)
{
Conf->Timers[i].num = i+1;
Conf->Timers[i].num = i + 1;
Conf->Timers[i].del = true;
Conf->Timers[i].enab = false;
Conf->Timers[i].prev = false;
Conf->Timers[i].type = 0;
Conf->Timers[i].sun_angle = 0;
strcpy(Conf->Timers[i].name, "Timer Name");
strcpy(Conf->Timers[i].cron, "* * * * * *");
strcpy(Conf->Timers[i].exec, "OBJECT,ACTION,ARGUMENTS");
}
#ifdef CONFIG_WEBGUIAPP_ASTRO_ENABLE
#endif
}
esp_err_t ReadNVSSysConfig(SYS_CONFIG *SysConf)
@ -575,6 +592,70 @@ void SetUserAppNeedReset(bool res)
isUserAppNeedReset = res;
}
#define LOG_MAX_CHUNK_SIZE CONFIG_WEBGUIAPP_SYSLOG_CHUNK_SIZE
#define LOG_MAX_CHUNKS CONFIG_WEBGUIAPP_SYSLOG_MAX_CHUNKS
#define DEFAULT_LOG_FILE_NAME "syslog"
#define LOG_PARTITION "/data/"
static void ComposeLogFilename(int chunk, char *filename)
{
char chunkstr[2];
strcpy(filename, LOG_PARTITION);
strcat(filename, DEFAULT_LOG_FILE_NAME);
itoa(chunk, chunkstr, 10);
strcat(filename, chunkstr);
strcat(filename, ".log");
}
void SysLog(char *format, ...)
{
char tstamp[ISO8601_TIMESTAMP_LENGTH + 2];
static int cur_chunk = 0, isstart = 1;
char filename[32];
struct stat file_stat;
FILE *f;
ComposeLogFilename(cur_chunk, filename);
//If first call after reboot, try to find not full chunk
if (isstart)
{
while (file_stat.st_size > LOG_MAX_CHUNK_SIZE * 1024 && cur_chunk <= LOG_MAX_CHUNKS - 1)
{
cur_chunk++;
ComposeLogFilename(cur_chunk, filename);
}
isstart = 0;
}
stat(filename, &file_stat);
//next if full, else append to current
if (file_stat.st_size > LOG_MAX_CHUNK_SIZE * 1024)
{
if (++cur_chunk > LOG_MAX_CHUNKS - 1)
cur_chunk = 0;
ComposeLogFilename(cur_chunk, filename);
f = fopen(filename, "w");
}
else
f = fopen(filename, "a");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file %s for writing", filename);
return;
}
va_list arg;
va_start(arg, format);
va_end(arg);
strcpy(tstamp, "\r\n");
char ts[ISO8601_TIMESTAMP_LENGTH];
GetISO8601Time(ts);
strcat(tstamp, ts);
strcat(tstamp, " ");
fwrite(tstamp, 1, strlen(tstamp), f);
vfprintf(f, format, arg);
fclose(f);
}
void LogFile(char *fname, char *format, ...)
{
char filename[32];

119
src/sdcard.c Normal file
View File

@ -0,0 +1,119 @@
/* Copyright 2024 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 name: sdcard.c
* Project: webguiapp
* Created on: 2024-05-07
* Author: bogd
* Description:
*/
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "SysConfiguration.h"
#if CONFIG_SDCARD_ENABLE
static const char *TAG = "sdcard";
#define MOUNT_POINT "/sdcard"
// Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu.
// You can also change the pin assignments here by changing the following 4 lines.
#define PIN_NUM_MISO CONFIG_SDCARD_SPI_MISO_GPIO
#define PIN_NUM_MOSI CONFIG_SDCARD_SPI_MOSI_GPIO
#define PIN_NUM_CLK CONFIG_SDCARD_SPI_SCLK_GPIO
#define PIN_NUM_CS CONFIG_SDCARD_SPI_CS_GPIO
void InitSysSDCard()
{
esp_err_t ret;
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
// Please check its source code and implement error recovery when developing
// production applications.
ESP_LOGI(TAG, "Using SPI peripheral");
// By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz)
// For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = CONFIG_SDCARD_SPI_HOST;
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
}
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = PIN_NUM_CS;
slot_config.host_id = host.slot;
ESP_LOGI(TAG, "Mounting filesystem");
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK)
{
if (ret == ESP_FAIL)
{
ESP_LOGE(
TAG,
"Failed to mount filesystem. "
"If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
}
else
{
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.",
esp_err_to_name(ret));
}
return;
}
ESP_LOGI(TAG, "Filesystem mounted");
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
}
#endif

View File

@ -35,8 +35,8 @@ function upload() {
/* Max size of an individual file. Make sure this
* value is same as that set in file_server.c */
var MAX_FILE_SIZE = 1000*1024;
var MAX_FILE_SIZE_STR = "1MB";
var MAX_FILE_SIZE = 100*1000*1024;
var MAX_FILE_SIZE_STR = "100MB";
if (fileInput.length == 0) {
alert("No file selected!");
@ -46,8 +46,8 @@ function upload() {
alert("File path on server cannot have spaces!");
} else if (filePath[filePath.length-1] == '/') {
alert("File name not specified after path!");
} else if (fileInput[0].size > 1000*1024) {
alert("File size must be less than 1MB!");
} else if (fileInput[0].size > MAX_FILE_SIZE) {
alert("File size must be less than 100MB!");
} else {
document.getElementById("newfile").disabled = true;
document.getElementById("filepath").disabled = true;