From 912eea58dd03a967ec6e48d62c2c669fc5442555 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Mon, 15 Jul 2024 13:08:53 +0300 Subject: [PATCH] Version 1.0.0 Initial version. --- .gitignore | 6 +-- CMakeLists.txt | 2 +- README.md | 121 +++++++++++++++++++++++++++++++++++++++++++- include/main.h | 0 include/zh_syslog.h | 114 +++++++++++++++++++++++++++++++++++++++++ main.c | 0 version.txt | 1 + zh_syslog.c | 72 ++++++++++++++++++++++++++ 8 files changed, 308 insertions(+), 8 deletions(-) delete mode 100644 include/main.h create mode 100644 include/zh_syslog.h delete mode 100644 main.c create mode 100644 zh_syslog.c diff --git a/.gitignore b/.gitignore index 65225d8..496ee2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1 @@ -.DS_Store -.vscode -build -sdkconfig -sdkconfig.old \ No newline at end of file +.DS_Store \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ab5c51..289a70d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1 +1 @@ -idf_component_register(SRCS "main.c" INCLUDE_DIRS "include") \ No newline at end of file +idf_component_register(SRCS "zh_syslog.c" INCLUDE_DIRS "include") \ No newline at end of file diff --git a/README.md b/README.md index 3df3e4d..a49006e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,120 @@ -# esp_component_template +# ESP32 ESP-IDF and ESP8266 RTOS SDK component for Syslog server UDP client -esp_component_template \ No newline at end of file +## Tested on + +1. ESP8266 RTOS_SDK v3.4 +2. ESP32 ESP-IDF v5.2 + +## Using + +In an existing project, run the following command to install the component: + +```text +cd ../your_project/components +git clone https://github.com/aZholtikov/zh_syslog.git +``` + +In the application, add the component: + +```c +#include "zh_syslog.h" +``` + +## Example + +Sending messages: + +```c +#include "nvs_flash.h" +#include "esp_netif.h" +#include "esp_wifi.h" +#include "esp_timer.h" +#include "esp_event.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "zh_syslog.h" + +#define WIFI_SSID "ssid" +#define WIFI_PASS "password" +#define WIFI_MAXIMUM_RETRY 5 +#define WIFI_RECONNECT_TIME 5 +#define WIFI_CONNECT_SUCCESS BIT0 + +#define SYSLOG_IP "192.168.1.2" + +esp_timer_handle_t wifi_reconnect_timer = {0}; +uint8_t wifi_reconnect_retry_num = 0; +EventGroupHandle_t event_group_handle = {0}; + +void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); + +void app_main(void) +{ + nvs_flash_init(); + esp_netif_init(); + esp_event_loop_create_default(); +#ifdef CONFIG_IDF_TARGET_ESP8266 + tcpip_adapter_init(); +#else + esp_netif_create_default_wifi_sta(); +#endif + wifi_init_config_t wifi_init_sta_config = WIFI_INIT_CONFIG_DEFAULT(); + esp_wifi_init(&wifi_init_sta_config); + wifi_config_t wifi_config = { + .sta.ssid = WIFI_SSID, + .sta.password = WIFI_PASS}; + esp_wifi_set_mode(WIFI_MODE_STA); + esp_wifi_set_config(WIFI_IF_STA, &wifi_config); +#ifdef CONFIG_IDF_TARGET_ESP8266 + esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL); + esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL); +#else + esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL); + esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL); +#endif + esp_wifi_start(); + event_group_handle = xEventGroupCreate(); + xEventGroupWaitBits(event_group_handle, WIFI_CONNECT_SUCCESS, pdTRUE, pdTRUE, portMAX_DELAY); + zh_syslog_init_config_t syslog_init_config = ZH_SYSLOG_INIT_CONFIG_DEFAULT(); + memcpy(syslog_init_config.syslog_ip, SYSLOG_IP, strlen(SYSLOG_IP)); + zh_syslog_init(&syslog_init_config); + for (;;) + { + zh_syslog_send(ZH_USER, ZH_INFO, "my_device", "my_application", "Message"); + vTaskDelay(5000 / portTICK_PERIOD_MS); + } +} + +void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + switch (event_id) + { + case WIFI_EVENT_STA_START: + esp_wifi_connect(); + break; + case WIFI_EVENT_STA_DISCONNECTED: + if (wifi_reconnect_retry_num < WIFI_MAXIMUM_RETRY) + { + esp_wifi_connect(); + ++wifi_reconnect_retry_num; + } + else + { + wifi_reconnect_retry_num = 0; + esp_timer_create_args_t wifi_reconnect_timer_args = { + .callback = (void *)esp_wifi_connect}; + esp_timer_create(&wifi_reconnect_timer_args, &wifi_reconnect_timer); + esp_timer_start_once(wifi_reconnect_timer, WIFI_RECONNECT_TIME * 1000); + } + break; + case IP_EVENT_STA_GOT_IP: + wifi_reconnect_retry_num = 0; + xEventGroupSetBits(event_group_handle, WIFI_CONNECT_SUCCESS); + break; + default: + break; + } +} +``` + +Any [feedback](mailto:github@azholtikov.ru) will be gladly accepted. diff --git a/include/main.h b/include/main.h deleted file mode 100644 index e69de29..0000000 diff --git a/include/zh_syslog.h b/include/zh_syslog.h new file mode 100644 index 0000000..33baaa7 --- /dev/null +++ b/include/zh_syslog.h @@ -0,0 +1,114 @@ +#pragma once + +#include "stdbool.h" +#include "esp_err.h" +#include "esp_log.h" +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" + +#define ZH_SYSLOG_INIT_CONFIG_DEFAULT() \ + { \ + .syslog_ip = "192.168.0.1", \ + .syslog_port = 514 \ + } + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef enum // Enumeration of possible syslog facility codes. + { + ZH_KERN, // Kernel messages. + ZH_USER, // User-level messages. + ZH_MAIL, // Mail system. + ZH_DAEMON, // System daemons. + ZH_AUTH, // Security/authorization messages. + ZH_SYSLOG, // Messages generated internally by syslogd. + ZH_LPR, // Line printer subsystem. + ZH_NEWS, // Network news subsystem. + ZH_UUCP, // UUCP subsystem. + ZH_CRON, // Cron subsystem. + ZH_AUTHPRIV, // Security/authorization messages. + ZH_FTP, // FTP daemon. + ZH_NTP, // NTP subsystem. + ZH_SECURITY, // Log audit. + ZH_CONSOLE, // Log alert. + ZH_SOLARIS_CRON, // Scheduling daemon. + ZH_LOCAL0, // Local use 0. + ZH_LOCAL1, // Local use 1. + ZH_LOCAL2, // Local use 2. + ZH_LOCAL3, // Local use 3. + ZH_LOCAL4, // Local use 4. + ZH_LOCAL5, // Local use 5. + ZH_LOCAL6, // Local use 6. + ZH_LOCAL7, // Local use 7. + } zh_syslog_facility_code_t; + + typedef enum // Enumeration of possible syslog severity codes. + { + ZH_EMERG, // System is unusable. + ZH_ALERT, // Action must be taken immediately. + ZH_CRIT, // Critical conditions. + ZH_ERR, // Error conditions. + ZH_WARNING, // Warning conditions. + ZH_NOTICE, // Normal but significant condition. + ZH_INFO, // Informational messages. + ZH_DEBUG // Debug-level messages. + } zh_syslog_severity_code_t; + + typedef struct // Structure for initial initialization of syslog client. + { + char syslog_ip[16]; // Syslog server IP address. + uint32_t syslog_port; // Syslog server port. + } zh_syslog_init_config_t; + + /** + * @brief Initialize syslog client. + * + * @param[in] config Pointer to syslog client initialized configuration structure. Can point to a temporary variable. + * + * @attention Connection to the network must be established first. + * + * @note Before initialize the syslog client recommend initialize zh_syslog_init_config_t structure with default values. + * + * @code zh_syslog_init_config_t config = ZH_SYSLOG_INIT_CONFIG_DEFAULT() @endcode + * + * @return + * - ESP_OK if initialization was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_FAIL if socker error + */ + esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config); + + /** + * @brief Deinitialize syslog client. + * + * @return + * - ESP_OK if deinitialization was success + * - ESP_ERR_NOT_FOUND if syslog client is not initialized + */ + esp_err_t zh_syslog_deinit(void); + + /** + * @brief Send message to syslog server. + * + * @param[in] facility Syslog facility code. + * @param[in] severity Syslog severity code. + * @param[in] hostname Pointer to device that generated the message. Only alphanumeric characters without spaces. + * @param[in] app_name Pointer to application that generated the message. Only alphanumeric characters without spaces. + * @param[in] message Pointer to message for send. + * + * @return + * - ESP_OK if send was success + * - ESP_ERR_INVALID_ARG if parameter error + * - ESP_ERR_NOT_FOUND if syslog client is not initialized + * - ESP_FAIL if socker error + */ + esp_err_t zh_syslog_send(const zh_syslog_facility_code_t facility, const zh_syslog_severity_code_t severity, const char *hostname, const char *app_name, const char *message); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/main.c b/main.c deleted file mode 100644 index e69de29..0000000 diff --git a/version.txt b/version.txt index e69de29..afaf360 100644 --- a/version.txt +++ b/version.txt @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/zh_syslog.c b/zh_syslog.c new file mode 100644 index 0000000..fe95811 --- /dev/null +++ b/zh_syslog.c @@ -0,0 +1,72 @@ +#include "zh_syslog.h" + +static zh_syslog_init_config_t _init_config = {0}; +static struct sockaddr_in _syslog_server = {0}; +static int _socket = 0; +static bool _is_initialized = false; + +static const char *TAG = "zh_syslog"; + +esp_err_t zh_syslog_init(const zh_syslog_init_config_t *config) +{ + ESP_LOGI(TAG, "Syslog client initialization begin."); + if (config == NULL) + { + ESP_LOGE(TAG, "Syslog client initialization fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + _init_config = *config; + _syslog_server.sin_addr.s_addr = inet_addr(_init_config.syslog_ip); + _syslog_server.sin_family = AF_INET; + _syslog_server.sin_port = htons(_init_config.syslog_port); + _socket = socket(AF_INET, SOCK_DGRAM, 0); + if (_socket < 0) + { + ESP_LOGE(TAG, "Syslog client initialization fail. Create socket error."); + return ESP_FAIL; + } + ESP_LOGI(TAG, "Syslog client initialization success."); + _is_initialized = true; + return ESP_OK; +} + +esp_err_t zh_syslog_deinit(void) +{ + ESP_LOGI(TAG, "Syslog client deinitialization begin."); + if (_is_initialized == false) + { + ESP_LOGE(TAG, "Syslog client deinitialization fail. Syslog client not initialized."); + return ESP_ERR_NOT_FOUND; + } + shutdown(_socket, 0); + close(_socket); + ESP_LOGI(TAG, "Syslog client deinitialization success."); + return ESP_OK; +} + +esp_err_t zh_syslog_send(const zh_syslog_facility_code_t facility, const zh_syslog_severity_code_t severity, const char *hostname, const char *app_name, const char *message) +{ + ESP_LOGI(TAG, "Syslog client send begin."); + if (hostname == NULL || app_name == NULL || message == NULL) + { + ESP_LOGE(TAG, "Syslog client send fail. Invalid argument."); + return ESP_ERR_INVALID_ARG; + } + if (_is_initialized == false) + { + ESP_LOGE(TAG, "Syslog client send fail. Syslog client not initialized."); + return ESP_ERR_NOT_FOUND; + } + char *payload = (char *)heap_caps_malloc(1024, MALLOC_CAP_8BIT); + memset(payload, 0, 1024); + sprintf(payload, "<%d>1 - %s %s - - - %s", (facility * 8) + severity, hostname, app_name, message); + if (sendto(_socket, payload, strlen(payload), 0, (struct sockaddr *)&_syslog_server, sizeof(_syslog_server)) < 0) + { + ESP_LOGE(TAG, "Syslog client send fail. Socker error."); + heap_caps_free(payload); + return ESP_FAIL; + } + heap_caps_free(payload); + ESP_LOGI(TAG, "Syslog client send success."); + return ESP_OK; +} \ No newline at end of file