From dd9e533f223aec5663435afa831b54a00e7bf7b1 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Mon, 24 Aug 2020 15:59:46 +0200
Subject: [PATCH] add: new commands to controller

---
 CMakeLists.txt                                |   3 +-
 include/command.h                             |  11 +-
 include/enums.h                               |  25 ----
 include/macros.h                              |   5 +
 src/command.c                                 | 125 +++++++++++++++---
 src/endpoints/api_v1_controllers_STR.c        |   2 +-
 .../api_v1_controllers_STR_relays_INT.c       |   2 +-
 .../api_v1_controllers_STR_relays_INT_pulse.c |   2 +-
 src/endpoints/api_v1_schedules_STR.c          |   7 +-
 src/models/controller.c                       |   3 +-
 src/models/schedule.c                         |   2 +-
 tests/controller.testing.ini                  |   2 +-
 12 files changed, 127 insertions(+), 62 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 617df21..9e6a2d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.7)
 project(core
-        VERSION 0.2.17
+        VERSION 0.3.0
         LANGUAGES C)
 
 add_executable(core src/main.c)
@@ -11,7 +11,6 @@ target_link_libraries(core -luuid)
 set(CMAKE_C_FLAGS "$ENV{CFLAGS}")
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=gnu99 -Wpedantic -Werror -Wall -Wextra -ffile-prefix-map=${CMAKE_SOURCE_DIR}/src/=")
 
-set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage")
 
 add_definitions("-DMG_ENABLE_EXTRA_ERRORS_DESC -DMG_ENABLE_MQTT_BROKER")
diff --git a/include/command.h b/include/command.h
index e69b7ff..55eed0e 100644
--- a/include/command.h
+++ b/include/command.h
@@ -5,15 +5,18 @@
 #include <models/relay.h>
 
 int
-command_set_relay_schedule(relay_t *relay);
+command_relay_schedules_set(relay_t *relay);
 
 int
-command_set_controller_name(controller_t *controller);
+command_controller_name_set(controller_t *controller);
 
 int
-command_send(controller_t *controller, int command_code, char *payload, uint32_t payload_size);
+command_send(controller_t *controller, char *payload, uint32_t payload_size);
 
 int
-command_pulse(relay_t *relay, uint8_t duration);
+command_relay_pulse(relay_t *relay, uint8_t duration);
+
+int
+command_schedule_update(schedule_t *schedule);
 
 #endif /* CORE_COMMAND_H */
diff --git a/include/enums.h b/include/enums.h
index a51ff31..1e740fc 100644
--- a/include/enums.h
+++ b/include/enums.h
@@ -7,31 +7,6 @@ typedef enum
     POLL_FDS_COMMAND
 } poll_fds_t;
 
-typedef enum
-{
-    COMMAND_MAPPING_CODE = 0,
-    COMMAND_MAPPING_NAME = 1,
-    COMMAND_MAPPING_RELAY_NUM = 2,
-    COMMAND_MAPPING_SCHEDULES_ARRAY = 3,
-    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
-{
-    COMMAND_CODE_GET_TIME = 1,
-    COMMAND_CODE_GET_ID = 2,
-    COMMAND_CODE_SET_NAME = 100,
-    COMMAND_CODE_GET_NAME = 101,
-    COMMAND_CODE_SET_SCHEDULE = 102,
-    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
 {
     RELAY_DRIVER_NONE,
diff --git a/include/macros.h b/include/macros.h
index 5aca3d6..4242abe 100644
--- a/include/macros.h
+++ b/include/macros.h
@@ -1 +1,6 @@
+#ifndef CORE_MACROS_H
+#define CORE_MACROS_H
+
 #define STRLEN(s) ((sizeof(s)/sizeof(s[0])) - sizeof(s[0]))
+
+#endif /* CORE_MACROS_H */
diff --git a/src/command.c b/src/command.c
index 141e5a6..098ca93 100644
--- a/src/command.c
+++ b/src/command.c
@@ -10,8 +10,96 @@
 #include <enums.h>
 #include <models/controller.h>
 
+typedef enum
+{
+    COMMAND_CODE_CONTROLLER_ID_GET = 0,
+    COMMAND_CODE_CONTROLLER_TIME_GET = 1,
+    COMMAND_CODE_CONTROLLER_NAME_SET = 2,
+    COMMAND_CODE_CONTROLLER_NAME_GET = 3,
+
+    COMMAND_CODE_RELAY_SCHEDULES_SET = 100,
+    COMMAND_CODE_RELAY_SCHEDULES_GET = 101,
+    COMMAND_CODE_RELAY_NAME_SET = 102,
+    COMMAND_CODE_RELAY_NAME_GET = 103,
+    COMMAND_CODE_RELAY_PULSE = 200,
+
+    COMMAND_CODE_SCHEDULE_UPDATE = 300
+} command_code_t;
+
+typedef enum
+{
+    COMMAND_MAPPING_CODE = 0,
+    COMMAND_MAPPING_NAME = 1,
+    COMMAND_MAPPING_RELAY_NUM = 2,
+    COMMAND_MAPPING_SCHEDULES_ARRAY = 3,
+    COMMAND_MAPPING_SCHEDULE_ID = 4,
+    COMMAND_MAPPING_PERIODS_COUNT = 5,
+    COMMAND_MAPPING_PERIODS_BLOB = 6,
+    COMMAND_MAPPING_PULSE_DURATION = 7,
+} control_mapping_t;
+
 int
-command_set_relay_schedule(relay_t *relay)
+command_schedule_update(schedule_t *schedule)
+{
+    char* payload;
+    size_t payload_size;
+    mpack_writer_t writer;
+    mpack_writer_init_growable(&writer, &payload, &payload_size);
+
+    // 4 = code, periods_count, schedule_id, periods_blob
+    mpack_start_map(&writer, 4);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
+    mpack_write_u16(&writer, COMMAND_CODE_SCHEDULE_UPDATE);
+
+    uint16_t *periods_blob = schedule_periods_to_blob(schedule);
+    uint16_t periods_count = periods_blob[0];
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_COUNT);
+    mpack_write_u16(&writer, periods_count);
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULE_ID);
+    mpack_write_bin(&writer, (char*)schedule->uid, sizeof(uuid_t));
+
+    mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_BLOB);
+    // periods + 1 to skip length in periods[0]
+    // periods_count * 2 because each uint16_t is a timestamp. 2 are start and end
+    mpack_write_bin(&writer, (char*)(periods_blob + 1), sizeof(uint16_t) * periods_count * 2);
+
+    free(periods_blob);
+
+    mpack_finish_array(&writer);
+
+    mpack_finish_map(&writer);
+
+    // finish writing
+    if (mpack_writer_destroy(&writer) != mpack_ok)
+    {
+        LOGGER_ERR("an error occurred encoding the data");
+        return 1;
+    }
+
+    int result = 0;
+
+    relay_t **relays = relay_get_with_schedule(schedule->id);
+    for(int i = 0; relays[i] != NULL; ++i)
+    {
+        controller_t *controller = controller_get_by_id(relays[i]->controller_id);
+        if(!controller)
+        {
+            LOGGER_ERR("couldn't find controller for relay %d\n", relays[i]->id);
+            continue;
+        }
+        controller_free(controller);
+        result |= command_send(controller, payload, payload_size);
+    }
+    relay_free_list(relays);
+
+    return result;
+}
+
+int
+command_relay_schedules_set(relay_t *relay)
 {
     controller_t *controller = controller_get_by_id(relay->controller_id);
     if(!controller)
@@ -29,7 +117,7 @@ command_set_relay_schedule(relay_t *relay)
     mpack_start_map(&writer, 3);
 
     mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
-    mpack_write_u8(&writer, COMMAND_CODE_SET_SCHEDULE);
+    mpack_write_u16(&writer, COMMAND_CODE_RELAY_SCHEDULES_GET);
 
     mpack_write_uint(&writer, COMMAND_MAPPING_RELAY_NUM);
     mpack_write_u8(&writer, relay->number);
@@ -39,27 +127,28 @@ command_set_relay_schedule(relay_t *relay)
     mpack_start_array(&writer, 7);
     for(int i = 0; i < 7; ++i)
     {
+        // 3 = uid, periods count, periods blob
+        mpack_start_map(&writer, 3);
+
         uint16_t *periods_blob = schedule_periods_to_blob(relay->schedules[i]);
         uint16_t periods_count = periods_blob[0];
 
-        // 3 = code, relaynum, schedules(array)
-        mpack_start_map(&writer, 3);
+        mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULE_ID);
+        mpack_write_bin(&writer, (char*)relay->schedules[i]->uid, sizeof(uuid_t));
 
         mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_COUNT);
         mpack_write_u16(&writer, periods_count);
 
-        mpack_write_uint(&writer, COMMAND_MAPPING_SCHEDULE_ID);
-        mpack_write_bin(&writer, (char*)relay->schedules[0]->uid, sizeof(uuid_t));
-
         mpack_write_uint(&writer, COMMAND_MAPPING_PERIODS_BLOB);
         // periods + 1 to skip length in periods[0]
         // periods_count * 2 because each uint16_t is a timestamp. 2 are start and end
         mpack_write_bin(&writer, (char*)(periods_blob + 1), sizeof(uint16_t) * periods_count * 2);
 
-        mpack_finish_map(&writer);
-
         free(periods_blob);
+
+        mpack_finish_map(&writer);
     }
+
     mpack_finish_array(&writer);
 
     mpack_finish_map(&writer);
@@ -72,7 +161,7 @@ command_set_relay_schedule(relay_t *relay)
         return 1;
     }
 
-    int result = command_send(controller, COMMAND_CODE_SET_SCHEDULE, payload, payload_size);
+    int result = command_send(controller, payload, payload_size);
 
     controller_free(controller);
     free(payload);
@@ -80,7 +169,7 @@ command_set_relay_schedule(relay_t *relay)
 }
 
 int
-command_set_controller_name(controller_t *controller)
+command_controller_name_set(controller_t *controller)
 {
     char* payload;
     size_t payload_size;
@@ -91,7 +180,7 @@ command_set_controller_name(controller_t *controller)
     mpack_start_map(&writer, 2);
 
     mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
-    mpack_write_u8(&writer, COMMAND_CODE_SET_NAME);
+    mpack_write_u16(&writer, COMMAND_CODE_CONTROLLER_NAME_SET);
 
     mpack_write_uint(&writer, COMMAND_MAPPING_NAME);
     mpack_write_cstr(&writer, controller->name);
@@ -105,17 +194,15 @@ command_set_controller_name(controller_t *controller)
         return 1;
     }
 
-    int result = command_send(controller, COMMAND_CODE_SET_NAME, payload, payload_size);
+    int result = command_send(controller, payload, payload_size);
 
     free(payload);
     return result;
 }
     
 int
-command_send(controller_t *controller, int command_code, char *payload, uint32_t payload_size)
+command_send(controller_t *controller, char *payload, uint32_t payload_size)
 {
-    LOGGER_DEBUG("commanding %d\n", command_code);
-
     int bytes_transferred;
 
     int fd_controller = helper_connect_tcp_server(controller->ip, controller->port);
@@ -142,7 +229,7 @@ command_send(controller_t *controller, int command_code, char *payload, uint32_t
 }
 
 int
-command_pulse(relay_t *relay, uint8_t duration)
+command_relay_pulse(relay_t *relay, uint8_t duration)
 {
     controller_t *controller = controller_get_by_id(relay->controller_id);
     if(!controller)
@@ -160,7 +247,7 @@ command_pulse(relay_t *relay, uint8_t duration)
     mpack_start_map(&writer, 3);
 
     mpack_write_uint(&writer, COMMAND_MAPPING_CODE);
-    mpack_write_u8(&writer, COMMAND_CODE_PULSE);
+    mpack_write_u16(&writer, COMMAND_CODE_RELAY_PULSE);
 
     mpack_write_uint(&writer, COMMAND_MAPPING_RELAY_NUM);
     mpack_write_u8(&writer, relay->number);
@@ -178,7 +265,7 @@ command_pulse(relay_t *relay, uint8_t duration)
         return 1;
     }
 
-    int result = command_send(controller, COMMAND_CODE_PULSE, payload, payload_size);
+    int result = command_send(controller, payload, payload_size);
 
     controller_free(controller);
     free(payload);
diff --git a/src/endpoints/api_v1_controllers_STR.c b/src/endpoints/api_v1_controllers_STR.c
index 8056358..eb4c24d 100644
--- a/src/endpoints/api_v1_controllers_STR.c
+++ b/src/endpoints/api_v1_controllers_STR.c
@@ -147,7 +147,7 @@ api_v1_controllers_STR_PUT(struct mg_connection *nc, struct http_message *hm, en
     cJSON_Delete(json);
     json = controller_to_json(controller);
 
-    command_set_controller_name(controller);
+    command_controller_name_set(controller);
 
     endpoint_response_json(response, 200, json);
     cJSON_Delete(json);
diff --git a/src/endpoints/api_v1_controllers_STR_relays_INT.c b/src/endpoints/api_v1_controllers_STR_relays_INT.c
index ed2eea4..7705d3a 100644
--- a/src/endpoints/api_v1_controllers_STR_relays_INT.c
+++ b/src/endpoints/api_v1_controllers_STR_relays_INT.c
@@ -271,7 +271,7 @@ api_v1_controllers_STR_relays_INT_PUT(struct mg_connection *nc, struct http_mess
     json = relay_to_json(relay);
 
     LOGGER_DEBUG("commanding schedules");
-    command_set_relay_schedule(relay);
+    command_relay_schedules_set(relay);
 
     endpoint_response_json(response, 200, json);
     cJSON_Delete(json);
diff --git a/src/endpoints/api_v1_controllers_STR_relays_INT_pulse.c b/src/endpoints/api_v1_controllers_STR_relays_INT_pulse.c
index 9f5e0b2..22b158a 100644
--- a/src/endpoints/api_v1_controllers_STR_relays_INT_pulse.c
+++ b/src/endpoints/api_v1_controllers_STR_relays_INT_pulse.c
@@ -62,7 +62,7 @@ api_v1_controllers_STR_relays_INT_pulse_POST(struct mg_connection *nc, struct ht
     }
 
     LOGGER_DEBUG("commanding pulse to relay %d for controller %s\n", args[1].value.v_int, args[0].value.v_str);
-    command_pulse(relay, duration);
+    command_relay_pulse(relay, duration);
 
     endpoint_response_text(response, 200, "", 0);
     relay_free(relay);
diff --git a/src/endpoints/api_v1_schedules_STR.c b/src/endpoints/api_v1_schedules_STR.c
index ca315b4..03613d1 100644
--- a/src/endpoints/api_v1_schedules_STR.c
+++ b/src/endpoints/api_v1_schedules_STR.c
@@ -146,11 +146,7 @@ api_v1_schedules_STR_PUT(struct mg_connection *nc, struct http_message *hm, endp
         return;
     }
 
-    relay_t **relays = relay_get_with_schedule(schedule->id);
-    for(int i = 0; relays[i] != NULL; ++i)
-    {
-        command_set_relay_schedule(relays[i]);
-    }
+    command_schedule_update(schedule);
 
     cJSON *json_tag;
     cJSON *json_tags = cJSON_GetObjectItemCaseSensitive(json, "tags");
@@ -180,7 +176,6 @@ api_v1_schedules_STR_PUT(struct mg_connection *nc, struct http_message *hm, endp
 
     endpoint_response_json(response, 200, json);
     cJSON_Delete(json);
-    relay_free_list(relays);
     schedule_free(schedule);
 }
 
diff --git a/src/models/controller.c b/src/models/controller.c
index b70184a..c237ad9 100644
--- a/src/models/controller.c
+++ b/src/models/controller.c
@@ -30,6 +30,7 @@ db_update_insert(controller_t *controller, sqlite3_stmt *stmt)
 
     return rc != SQLITE_DONE;
 }
+
 static controller_t*
 controller_db_select_mapper(sqlite3_stmt *stmt)
 {
@@ -82,7 +83,7 @@ controller_db_select(sqlite3_stmt *stmt)
 
     int row = 0;
 
-    while(true)
+    for(;;)
     {
         int s;
 
diff --git a/src/models/schedule.c b/src/models/schedule.c
index cd1d783..abb6850 100644
--- a/src/models/schedule.c
+++ b/src/models/schedule.c
@@ -78,7 +78,7 @@ schedule_db_select(sqlite3_stmt *stmt)
 
     int row = 0;
 
-    while(true)
+    for(;;)
     {
         int s;
 
diff --git a/tests/controller.testing.ini b/tests/controller.testing.ini
index b21277d..d3577f6 100644
--- a/tests/controller.testing.ini
+++ b/tests/controller.testing.ini
@@ -8,7 +8,7 @@ mqtt-port = 1886
 mqtt-host = localhost
 
 relay-count = 10
-database = controller_db.lmdb
+database = controller.sqlite
 log-level = debug
 log-file = stdout