From 0f342b4aa8c0cee1e8dbc47fd112aeacff3d40b0 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Sat, 27 Jun 2020 18:27:49 +0200
Subject: [PATCH] add: pulse mode add: editorconfig

---
 .editorconfig             |  12 +++++
 CMakeLists.txt            |   2 +-
 controller.ini            |   2 +
 include/config.h          |   1 +
 include/enums.h           |   2 +
 include/models/relay.h    |   4 +-
 include/wiring_debug.h    |  11 ++--
 src/handlers/command.c    | 104 +++++++++++++++++++++++---------------
 src/handlers/loop.c       |  48 +++++++++++++-----
 src/helpers/load_config.c |  10 +++-
 src/main.c                |  17 ++++---
 src/models/relay.c        |   4 +-
 src/models/relay_load.c   |   4 ++
 13 files changed, 151 insertions(+), 70 deletions(-)
 create mode 100644 .editorconfig

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..ab2168d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+# EditorConfig is awesome:
+https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 4
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18e1934..ada0b47 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(controller
-        VERSION 0.2.0
+        VERSION 0.2.1
         LANGUAGES C)
 
 add_executable(controller src/main.c)
diff --git a/controller.ini b/controller.ini
index da0bcae..a1165fd 100644
--- a/controller.ini
+++ b/controller.ini
@@ -54,8 +54,10 @@ inverted = 1
 driver = gpio
 pin = 16
 inverted = 1
+pulse-duration = 3
 
 [relay-9]
 driver = gpio
 pin = 15
 inverted = 1
+pulse-duration = 3
diff --git a/include/config.h b/include/config.h
index 80d7bb1..19ce6de 100644
--- a/include/config.h
+++ b/include/config.h
@@ -11,6 +11,7 @@ typedef struct
     uint8_t pin;
     int inverted;
     relay_driver_t driver;
+    uint8_t pulse_duration;
 } config_relay_t;
 
 typedef struct
diff --git a/include/enums.h b/include/enums.h
index a2c0709..c9288d0 100644
--- a/include/enums.h
+++ b/include/enums.h
@@ -24,6 +24,7 @@ typedef enum
     COMMAND_MAPPING_SCHEDULE_ID = 4,
     COMMAND_MAPPING_PERIODS_COUNT = 5,
     COMMAND_MAPPING_PERIODS_BLOB = 6,
+    COMMAND_MAPPING_PULSE_DURATION = 7,
 } control_mapping_t;
 
 typedef enum
@@ -36,6 +37,7 @@ typedef enum
     COMMAND_CODE_GET_SCHEDULE = 103,
     COMMAND_CODE_SET_RELAY_NAME = 104,
     COMMAND_CODE_GET_RELAY_NAME = 105,
+    COMMAND_CODE_PULSE = 200,
 } command_code_t;
 
 typedef enum
diff --git a/include/models/relay.h b/include/models/relay.h
index 224e7b4..c2efd58 100644
--- a/include/models/relay.h
+++ b/include/models/relay.h
@@ -12,6 +12,8 @@ typedef struct
 {
     uint8_t number;
     int is_on;
+    int is_on_schedule;
+    int pulse_timer;
     int sent_to_broker;
     char name[MAX_NAME_LENGTH + 1];
     schedule_t *schedules[7];
@@ -53,7 +55,7 @@ int
 relay_save(relay_t *relay, MDB_env *mdb_env);
 
 int
-relay_is_active(relay_t *relay, struct tm *time_struct);
+relay_is_on_schedule(relay_t *relay, struct tm *time_struct);
 
 void
 relay_free(relay_t *relay);
diff --git a/include/wiring_debug.h b/include/wiring_debug.h
index ab77be0..d46d918 100644
--- a/include/wiring_debug.h
+++ b/include/wiring_debug.h
@@ -4,12 +4,13 @@
 #include <logger.h>
 
 #ifdef WIRING_PI_DEBUG
-    #define wiringPiSetup() LOG_DEBUG("wiringPi wiringPiSetup()\n")
-    #define wiringPiSetupSys() LOG_DEBUG("wiringPi wiringPiSetupSys()\n")
-    #define pinMode(x,y) LOG_DEBUG("wiringPi pinMode(%d, %d)\n", x, y)
-    #define digitalWrite(x,y) LOG_DEBUG("wiringPi digitalWrite(%d, %d)\n", x, y)
+    #define LOG_WIRING_PI LOG_TRACE
+    #define wiringPiSetup() LOG_WIRING_PI("wiringPi wiringPiSetup()\n")
+    #define wiringPiSetupSys() LOG_WIRING_PI("wiringPi wiringPiSetupSys()\n")
+    #define pinMode(x,y) LOG_WIRING_PI("wiringPi pinMode(%d, %d)\n", x, y)
+    #define digitalWrite(x,y) LOG_WIRING_PI("wiringPi digitalWrite(%d, %d)\n", x, y)
 
-    #define piFaceSetup(x) LOG_DEBUG("wiringPi piFaceSetup(%d)\n", x)
+    #define piFaceSetup(x) LOG_WIRING_PI("wiringPi piFaceSetup(%d)\n", x)
 #endif
 
 #endif /* CONTROLLER_WIRING_DEBUG_H */
diff --git a/src/handlers/command.c b/src/handlers/command.c
index 79fb145..2acb78c 100644
--- a/src/handlers/command.c
+++ b/src/handlers/command.c
@@ -18,6 +18,22 @@
 #include <mpack.h>
 #include <models/schedule.h>
 
+static void
+handler_command_pulse(mpack_node_t map, controller_t *controller)
+{
+    uint8_t relay_num = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_RELAY_NUM));
+
+    relay_t *target_relay = controller->relays[relay_num];
+    (void)target_relay;
+
+    uint8_t duration = mpack_node_u8(mpack_node_map_uint(map, COMMAND_MAPPING_PULSE_DURATION));
+    if(duration == 0)
+    {
+        duration = global_config.relay_configs[relay_num].pulse_duration;
+    }
+    target_relay->pulse_timer = duration;
+}
+
 static void
 handler_command_set_name(mpack_node_t map, controller_t *controller)
 {
@@ -72,56 +88,60 @@ void
 handler_command(struct mg_connection *c, int ev, void *ev_data)
 {
     (void)ev_data;
-    if(ev == MG_EV_RECV)
+    if(ev != MG_EV_RECV)
     {
-        uint32_t payload_length = *((uint32_t*)c->recv_mbuf.buf);
-        LOG_DEBUG("payload_length %d\n", payload_length);
+        return;
+    }
+    uint32_t payload_length = *((uint32_t*)c->recv_mbuf.buf);
+    LOG_DEBUG("payload_length %d\n", payload_length);
 
-        if(c->recv_mbuf.len < payload_length + sizeof(payload_length))
-        {
-            return;
-        }
+    if(c->recv_mbuf.len < payload_length + sizeof(payload_length))
+    {
+        return;
+    }
 
-        char *payload = c->recv_mbuf.buf + sizeof(payload_length);
+    char *payload = c->recv_mbuf.buf + sizeof(payload_length);
 
-        mpack_tree_t tree;
-        mpack_tree_init_data(&tree, payload, payload_length);
-        mpack_tree_parse(&tree);
-        mpack_node_t root = mpack_tree_root(&tree);
+    mpack_tree_t tree;
+    mpack_tree_init_data(&tree, payload, payload_length);
+    mpack_tree_parse(&tree);
+    mpack_node_t root = mpack_tree_root(&tree);
 
-        uint8_t command_code = mpack_node_u8(mpack_node_map_uint(root, COMMAND_MAPPING_CODE));
+    uint8_t command_code = mpack_node_u8(mpack_node_map_uint(root, COMMAND_MAPPING_CODE));
 
-        LOG_INFO("received command %d\n", command_code);
+    LOG_INFO("received command %d\n", command_code);
 
-        switch(command_code)
-        {
-            case COMMAND_CODE_GET_TIME:
-                break;
-            case COMMAND_CODE_GET_ID:
-                break;
-            case COMMAND_CODE_SET_NAME:
-                handler_command_set_name(root, global_controller);
-                break;
-            case COMMAND_CODE_GET_NAME:
-                break;
-            case COMMAND_CODE_SET_SCHEDULE:
-                handler_command_set_schedule(root, global_controller);
-                break;
-            case COMMAND_CODE_GET_SCHEDULE:
-                break;
-            case COMMAND_CODE_SET_RELAY_NAME:
-                handler_command_set_relay_name(root, global_controller);
-                break;
-            case COMMAND_CODE_GET_RELAY_NAME:
-                break;
-            default:
-                LOG_ERROR("received invalid command\n");
-        }
+    switch(command_code)
+    {
+        case COMMAND_CODE_GET_TIME:
+            break;
+        case COMMAND_CODE_GET_ID:
+            break;
+        case COMMAND_CODE_SET_NAME:
+            handler_command_set_name(root, global_controller);
+            break;
+        case COMMAND_CODE_GET_NAME:
+            break;
+        case COMMAND_CODE_SET_SCHEDULE:
+            handler_command_set_schedule(root, global_controller);
+            break;
+        case COMMAND_CODE_GET_SCHEDULE:
+            break;
+        case COMMAND_CODE_SET_RELAY_NAME:
+            handler_command_set_relay_name(root, global_controller);
+            break;
+        case COMMAND_CODE_GET_RELAY_NAME:
+            break;
+        case COMMAND_CODE_PULSE:
+            handler_command_pulse(root, global_controller);
+            break;
+        default:
+            LOG_ERROR("received invalid command\n");
+    }
 
-        if(mpack_tree_destroy(&tree) != mpack_ok)
-        {
-            LOG_WARN("error when destroying mpack tree\n");
-        }
+    if(mpack_tree_destroy(&tree) != mpack_ok)
+    {
+        LOG_WARN("error when destroying mpack tree\n");
     }
     controller_save(global_controller, global_mdb_env);
 }
diff --git a/src/handlers/loop.c b/src/handlers/loop.c
index f0b6324..7c6bcc0 100644
--- a/src/handlers/loop.c
+++ b/src/handlers/loop.c
@@ -21,43 +21,65 @@ handler_loop(struct mg_connection *c_mqtt)
     char controller_uid[UUID_STR_LEN];
     uuid_unparse(global_controller->id, controller_uid);
 
-    time_t timestamp = time(NULL);
-    struct tm *time_struct = localtime(&timestamp);
-    LOG_DEBUG("===== IDLE LOOP START =====\n");
+    struct tm time_last, time_now;
+    time_t timestamp;
+
+    timestamp = time(NULL) - 1;
+    localtime_r(&timestamp, &time_last);
+    timestamp = time(NULL);
+    localtime_r(&timestamp, &time_now);
+    LOG_TRACE("===== IDLE LOOP START =====\n");
     for(uint_fast8_t i = 0; i < global_controller->relay_count; ++i)
     {
         relay_t *relay = global_controller->relays[i];
-        int is_active = 0;
-        if(relay_is_active(relay, time_struct))
+        int is_on = 0;
+        
+        int is_on_schedule = relay_is_on_schedule(relay, &time_now);
+
+        if(relay->is_on_schedule != is_on_schedule && relay->is_on_schedule != -1)
         {
-            LOG_DEBUG("relay %d is active\n", i);
-            is_active = 1;
+            relay->pulse_timer = global_config.relay_configs[i].pulse_duration;
+        }
+        if(is_on_schedule && !global_config.relay_configs[i].pulse_duration)
+        {
+            is_on = 1;
+        }
+        if(relay->pulse_timer > 0)
+        {
+            is_on = 1;
+            --relay->pulse_timer;
         }
 
-        if(relay->is_on != is_active)
+        if(is_on)
+        {
+            LOG_DEBUG("relay %d is active\n", i);
+        }
+
+        if(relay->is_on != is_on)
         {
             relay->sent_to_broker = 0;
         }
         if(!relay->sent_to_broker && c_mqtt)
         {
             sprintf(topic_buf, "controller/%s/relay/%u", controller_uid, i);
-            sprintf(payload_buf, "%u", is_active);
+            sprintf(payload_buf, "%u", is_on);
             mg_mqtt_publish(c_mqtt, topic_buf, 0, MG_MQTT_QOS(0), payload_buf, strlen(payload_buf));
             relay->sent_to_broker = 1;
         }
-        relay->is_on = is_active;
+        relay->is_on = is_on;
+        relay->is_on_schedule = is_on_schedule;
 
         if(global_config.relay_configs[i].inverted)
         {
-            is_active = !is_active;
+            is_on = !is_on;
         }
         switch(global_config.relay_configs[i].driver)
         {
             case RELAY_DRIVER_GPIO:
-                driver_gpio_set(global_config.relay_configs[i].pin, is_active);
+                driver_gpio_set(global_config.relay_configs[i].pin, is_on);
                 break;
             case RELAY_DRIVER_PIFACE:
-                driver_piface_set(global_config.relay_configs[i].pin, is_active);
+                driver_piface_set(global_config.relay_configs[i].pin, is_on);
                 break;
             default:
                 LOG_WARN("relay %d is not using a driver\n", i);
diff --git a/src/helpers/load_config.c b/src/helpers/load_config.c
index 8c4af97..71c0be0 100644
--- a/src/helpers/load_config.c
+++ b/src/helpers/load_config.c
@@ -81,7 +81,10 @@ helper_load_config(IniDispatch *disp, void *config_void)
             config->relay_configs = malloc(sizeof(config_relay_t) * config->relay_count);
             for(uint8_t i = 0; i < config->relay_count; ++i)
             {
-                config->relay_configs[i].driver= RELAY_DRIVER_NONE;
+                config->relay_configs[i].driver = RELAY_DRIVER_NONE;
+                config->relay_configs[i].inverted = 0;
+                config->relay_configs[i].pin = 0;
+                config->relay_configs[i].pulse_duration = 0;
             }
             LOG_TRACE("config relay-count set to %u\n", config->relay_count);
             return 0;
@@ -99,6 +102,11 @@ helper_load_config(IniDispatch *disp, void *config_void)
                 config->relay_configs[i].inverted = atoi(disp->value);
                 return 0;
             }
+            if(CONFINI_IS_KEY(relay_section_name, "pulse-duration"))
+            {
+                config->relay_configs[i].pulse_duration = atoi(disp->value);
+                return 0;
+            }
             if(CONFINI_IS_KEY(relay_section_name, "driver"))
             {
                 if(strcasecmp(disp->value, "gpio") == 0)
diff --git a/src/main.c b/src/main.c
index fc5a249..1c64695 100644
--- a/src/main.c
+++ b/src/main.c
@@ -140,15 +140,20 @@ main(int argc, const char** argv)
 
     /******************** START MAIN LOOP ********************/
 
-    for(;;)
+    time_t timer = time(NULL);
+
+    for (;;)
     {
-        mg_mgr_poll(&mgr, 1000);
-        if(!global_connection_mqtt)
+        mg_mgr_poll(&mgr, 200);
+        if(time(NULL) - timer >= 1)
         {
-            LOG_DEBUG("mqtt connection is not open\n");
-            connection_mqtt_connect(&mgr);
+            if(!global_connection_mqtt)
+            {
+                connection_mqtt_connect(&mgr);
+            }
+            handler_loop(global_connection_mqtt);
+            timer = time(NULL);
         }
-        handler_loop(global_connection_mqtt);
     }
 
     terminate(0);
diff --git a/src/models/relay.c b/src/models/relay.c
index 6667520..2ca7f34 100644
--- a/src/models/relay.c
+++ b/src/models/relay.c
@@ -15,6 +15,8 @@ relay_create(uint8_t number)
     new_relay->name[0] = '\0';
 
     new_relay->is_on = -1;
+    new_relay->is_on_schedule = -1;
+    new_relay->pulse_timer = 0;
     new_relay->sent_to_broker = 0;
 
     uuid_t off_id;
@@ -37,7 +39,7 @@ relay_set_name(relay_t *relay, const char *name)
 }
 
 int
-relay_is_active(relay_t *relay, struct tm *time_struct)
+relay_is_on_schedule(relay_t *relay, struct tm *time_struct)
 {
     schedule_t *schedule = relay->schedules[helper_get_weekday(time_struct)];
     if(schedule->length == 0)
diff --git a/src/models/relay_load.c b/src/models/relay_load.c
index b6a8471..2c6c214 100644
--- a/src/models/relay_load.c
+++ b/src/models/relay_load.c
@@ -65,7 +65,11 @@ relay_load(MDB_env *mdb_env, uint8_t num)
 
     new_relay = malloc(sizeof(relay_t));
     new_relay->number = num;
+
     new_relay->is_on = -1;
+    new_relay->is_on_schedule = -1;
+    new_relay->pulse_timer = 0;
+    new_relay->sent_to_broker = 0;
 
     MDB_val value;