add: relay/piface support
This commit is contained in:
parent
fa6ceb2bf4
commit
db64e4f820
34 changed files with 1259 additions and 313 deletions
|
@ -5,7 +5,7 @@ add_executable(controller main.c)
|
||||||
|
|
||||||
option(WIRING_PI_DEBUG "Use WiringPi Debugging Tool" OFF)
|
option(WIRING_PI_DEBUG "Use WiringPi Debugging Tool" OFF)
|
||||||
|
|
||||||
SET(CMAKE_C_FLAGS "-Wall -Wextra -lwiringPi -luuid -llmdb -g")
|
SET(CMAKE_C_FLAGS "-Wall -Wextra -lwiringPi -lwiringPiDev -luuid -llmdb -g")
|
||||||
|
|
||||||
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
|
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
|
||||||
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
|
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
|
||||||
|
@ -16,14 +16,26 @@ if(WIRING_PI_DEBUG)
|
||||||
endif(WIRING_PI_DEBUG)
|
endif(WIRING_PI_DEBUG)
|
||||||
|
|
||||||
aux_source_directory(. SRC_DIR)
|
aux_source_directory(. SRC_DIR)
|
||||||
aux_source_directory(models MODEL_SRC)
|
aux_source_directory(models MODELS_SRC)
|
||||||
aux_source_directory(helpers HELPER_SRC)
|
aux_source_directory(helpers HELPERS_SRC)
|
||||||
|
aux_source_directory(handlers HANDLERS_SRC)
|
||||||
|
aux_source_directory(drivers DRIVERS_SRC)
|
||||||
|
|
||||||
target_sources(controller PRIVATE ${SRC_DIR} ${MODEL_SRC} ${HELPER_SRC})
|
target_sources(controller PRIVATE ${SRC_DIR} ${MODELS_SRC} ${HELPERS_SRC} ${HANDLERS_SRC} ${DRIVERS_SRC})
|
||||||
target_include_directories(controller PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
target_include_directories(controller PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
add_custom_target(run
|
add_custom_target(run
|
||||||
COMMAND controller
|
COMMAND ./controller
|
||||||
|
DEPENDS controller
|
||||||
|
WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
|
||||||
|
)
|
||||||
|
add_custom_target(debug
|
||||||
|
COMMAND valgrind ./controller
|
||||||
|
DEPENDS controller
|
||||||
|
WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
|
||||||
|
)
|
||||||
|
add_custom_target(debug-full
|
||||||
|
COMMAND valgrind --leak-check=full --show-leak-kinds=all ./controller
|
||||||
DEPENDS controller
|
DEPENDS controller
|
||||||
WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
|
WORKING_DIRECTORY ${CMAKE_PROJECT_DIR}
|
||||||
)
|
)
|
||||||
|
|
125
discovery.c
125
discovery.c
|
@ -1,125 +0,0 @@
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <uuid/uuid.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <logger.h>
|
|
||||||
#include <discovery.h>
|
|
||||||
#include <helper.h>
|
|
||||||
#include <binn.h>
|
|
||||||
|
|
||||||
enum DISCOVERY_MAPPING
|
|
||||||
{
|
|
||||||
DISCOVERY_MAPPING_ID = 0,
|
|
||||||
DISCOVERY_MAPPING_NAME = 1,
|
|
||||||
DISCOVERY_MAPPING_COMMAND_PORT = 2,
|
|
||||||
DISCOVERY_MAPPING_RELAY_COUNT = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
discovery_socket_open(uint16_t discovery_port)
|
|
||||||
{
|
|
||||||
struct addrinfo hints, *res;
|
|
||||||
int fd, status;
|
|
||||||
|
|
||||||
memset(&hints, 0, sizeof hints);
|
|
||||||
hints.ai_family = AF_INET; // use ipv4
|
|
||||||
hints.ai_socktype = SOCK_DGRAM; //set socket flag
|
|
||||||
hints.ai_flags = AI_PASSIVE; // get my IP
|
|
||||||
|
|
||||||
char* discovery_port_str = malloc(6 * sizeof(char));
|
|
||||||
sprintf(discovery_port_str, "%u", discovery_port);
|
|
||||||
|
|
||||||
//get connection info for our computer
|
|
||||||
if ((status = getaddrinfo(NULL, discovery_port_str, &hints, &res)) != 0)
|
|
||||||
{
|
|
||||||
LOG_FATAL("getaddrinfo: %s", gai_strerror(status));
|
|
||||||
freeaddrinfo(res);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//creating socket
|
|
||||||
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
||||||
int yes = 1;
|
|
||||||
|
|
||||||
// lose the pesky "Address already in use" error message
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
|
|
||||||
{
|
|
||||||
LOG_FATAL("setsockopt: %s", strerror(errno));
|
|
||||||
freeaddrinfo(res);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind(fd, res->ai_addr, res->ai_addrlen) == -1)
|
|
||||||
{
|
|
||||||
LOG_FATAL("bind: %s", strerror(errno));
|
|
||||||
freeaddrinfo(res);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(res);
|
|
||||||
|
|
||||||
LOG_DEBUG("opened discovery socket on port %u", discovery_port);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
discovery_handle_discover(int fd, controller *cntrlr)
|
|
||||||
{
|
|
||||||
ssize_t bytes_transferred;
|
|
||||||
uint16_t discovery_answer_port;
|
|
||||||
struct sockaddr_in si_other;
|
|
||||||
socklen_t slen = sizeof(si_other);
|
|
||||||
|
|
||||||
if((bytes_transferred = recvfrom(fd, &discovery_answer_port, sizeof(discovery_answer_port), 0, (struct sockaddr *) &si_other, &slen)) <= 0)
|
|
||||||
{
|
|
||||||
LOG_ERROR("received invalid discovery from %s", inet_ntoa(si_other.sin_addr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG_DEBUG("received discovery from %s for port %d", inet_ntoa(si_other.sin_addr), discovery_answer_port);
|
|
||||||
|
|
||||||
if(discovery_answer_port == 0)
|
|
||||||
{
|
|
||||||
LOG_ERROR("invalid port received");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
binn *map = binn_map();
|
|
||||||
|
|
||||||
binn_map_set_blob(map, DISCOVERY_MAPPING_ID, &cntrlr->id, sizeof(uuid_t));
|
|
||||||
binn_map_set_str(map, DISCOVERY_MAPPING_NAME, cntrlr->name);
|
|
||||||
binn_map_set_uint32(map, DISCOVERY_MAPPING_COMMAND_PORT, cntrlr->command_port);
|
|
||||||
binn_map_set_uint8(map, DISCOVERY_MAPPING_RELAY_COUNT, cntrlr->relay_count);
|
|
||||||
|
|
||||||
void *payload = binn_ptr(map);
|
|
||||||
size_t payload_size = binn_size(map);
|
|
||||||
|
|
||||||
char discover_answer_port_str[6];
|
|
||||||
sprintf(discover_answer_port_str, "%d", discovery_answer_port);
|
|
||||||
int fd_answer = helper_connect_server(inet_ntoa(si_other.sin_addr), discover_answer_port_str);
|
|
||||||
|
|
||||||
LOG_DEBUG("size: %ld (%ld)", payload_size, sizeof(payload_size));
|
|
||||||
|
|
||||||
if((bytes_transferred = send(fd_answer, &payload_size, sizeof(payload_size), 0)) <= 0)
|
|
||||||
{
|
|
||||||
LOG_ERROR("error during sending");
|
|
||||||
binn_free(map);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if((bytes_transferred = send(fd_answer, payload, payload_size, 0)) <= 0)
|
|
||||||
{
|
|
||||||
LOG_ERROR("error during sending");
|
|
||||||
binn_free(map);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd_answer);
|
|
||||||
}
|
|
11
drivers/gpio.c
Normal file
11
drivers/gpio.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#include <piFace.h>
|
||||||
|
#include <wiring_debug.h>
|
||||||
|
|
||||||
|
#include <drivers.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
driver_gpio_set(relay_t *relay, int value)
|
||||||
|
{
|
||||||
|
digitalWrite(relay->number, value);
|
||||||
|
}
|
11
drivers/piface.c
Normal file
11
drivers/piface.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#include <piFace.h>
|
||||||
|
#include <wiring_debug.h>
|
||||||
|
|
||||||
|
#include <drivers.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
driver_piface_set(relay_t *relay, int value)
|
||||||
|
{
|
||||||
|
digitalWrite(DRIVER_PIFACE_GPIO_BASE + relay->number, value);
|
||||||
|
}
|
113
handlers/command.c
Normal file
113
handlers/command.c
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
#include <handlers.h>
|
||||||
|
#include <helpers.h>
|
||||||
|
#include <enums.h>
|
||||||
|
#include <binn.h>
|
||||||
|
#include <models/schedule.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
handler_command_set_schedule(binn *map, controller_t *controller)
|
||||||
|
{
|
||||||
|
uint8_t relay_num = binn_map_uint8(map, COMMAND_MAPPING_RELAY_NUM);
|
||||||
|
int uuid_size = sizeof(uuid_t);
|
||||||
|
uuid_t schedule_id;
|
||||||
|
memmove(schedule_id, binn_map_blob(map, COMMAND_MAPPING_SCHEDULE_ID, &uuid_size), uuid_size);
|
||||||
|
uint16_t periods_count = binn_map_uint16(map, COMMAND_MAPPING_PERIODS_COUNT);
|
||||||
|
int periods_size = sizeof(uint16_t) * (periods_count * 2);
|
||||||
|
uint16_t *periods = binn_map_blob(map, COMMAND_MAPPING_PERIODS_BLOB, &periods_size);
|
||||||
|
|
||||||
|
relay_t *target_relay = controller->relays[relay_num];
|
||||||
|
|
||||||
|
if(target_relay->schedule)
|
||||||
|
{
|
||||||
|
schedule_free(target_relay->schedule);
|
||||||
|
}
|
||||||
|
target_relay->schedule = schedule_create(schedule_id, periods_count, periods);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handler_command_set_relay_name(binn *map, controller_t *controller)
|
||||||
|
{
|
||||||
|
uint8_t relay_num = binn_map_uint8(map, COMMAND_MAPPING_RELAY_NUM);
|
||||||
|
char *relay_name = binn_map_str(map, COMMAND_MAPPING_NAME);
|
||||||
|
|
||||||
|
if(relay_num < controller->relay_count)
|
||||||
|
{
|
||||||
|
relay_set_name(controller->relays[relay_num], relay_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handler_command(int fd, controller_t *controller)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage their_addr;
|
||||||
|
socklen_t addr_size;
|
||||||
|
int client_fd;
|
||||||
|
|
||||||
|
addr_size = sizeof(their_addr);
|
||||||
|
|
||||||
|
if((client_fd = accept(fd, (struct sockaddr *) &their_addr, &addr_size)) < 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("could not accept client: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t payload_length;
|
||||||
|
|
||||||
|
if(recv(client_fd, &payload_length, sizeof(payload_length), 0) <= 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("unable to receive header: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *payload = malloc((payload_length + 1));
|
||||||
|
ssize_t bytes_transferred;
|
||||||
|
|
||||||
|
if((bytes_transferred = recv(client_fd, payload, payload_length, 0)) <= 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("unable to receive payload: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t command_code = binn_map_uint8(payload, COMMAND_MAPPING_CODE);
|
||||||
|
|
||||||
|
LOG_INFO("received command %d", command_code);
|
||||||
|
|
||||||
|
switch(command_code)
|
||||||
|
{
|
||||||
|
case COMMAND_CODE_GET_TIME:
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_GET_ID:
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_SET_NAME:
|
||||||
|
controller_set_name(controller, binn_map_str(payload, COMMAND_MAPPING_NAME));
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_GET_NAME:
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_SET_SCHEDULE:
|
||||||
|
handler_command_set_schedule(payload, controller);
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_GET_SCHEDULE:
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_SET_RELAY_NAME:
|
||||||
|
handler_command_set_relay_name(payload, controller);
|
||||||
|
break;
|
||||||
|
case COMMAND_CODE_GET_RELAY_NAME:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(payload);
|
||||||
|
close(client_fd);
|
||||||
|
}
|
72
handlers/discovery.c
Normal file
72
handlers/discovery.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
#include <handlers.h>
|
||||||
|
#include <helpers.h>
|
||||||
|
#include <binn.h>
|
||||||
|
#include <enums.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
handler_discovery(int fd, controller_t *controller)
|
||||||
|
{
|
||||||
|
ssize_t bytes_transferred;
|
||||||
|
uint16_t discovery_answer_port;
|
||||||
|
struct sockaddr_in si_other;
|
||||||
|
socklen_t slen = sizeof(si_other);
|
||||||
|
|
||||||
|
if((bytes_transferred = recvfrom(fd, &discovery_answer_port, sizeof(discovery_answer_port), 0, (struct sockaddr *) &si_other, &slen)) <= 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("received invalid discovery from %s", inet_ntoa(si_other.sin_addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("received discovery from %s for port %d", inet_ntoa(si_other.sin_addr), discovery_answer_port);
|
||||||
|
|
||||||
|
if(discovery_answer_port == 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("invalid port received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
binn *map = binn_map();
|
||||||
|
|
||||||
|
binn_map_set_blob(map, DISCOVERY_MAPPING_ID, &controller->id, sizeof(uuid_t));
|
||||||
|
binn_map_set_str(map, DISCOVERY_MAPPING_NAME, controller->name);
|
||||||
|
binn_map_set_uint32(map, DISCOVERY_MAPPING_COMMAND_PORT, controller->command_port);
|
||||||
|
binn_map_set_uint8(map, DISCOVERY_MAPPING_RELAY_COUNT, controller->relay_count);
|
||||||
|
|
||||||
|
void *payload = binn_ptr(map);
|
||||||
|
size_t payload_size = binn_size(map);
|
||||||
|
|
||||||
|
int fd_answer = helper_connect_tcp_server(inet_ntoa(si_other.sin_addr), discovery_answer_port);
|
||||||
|
if(fd_answer == -1)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error during connecting");
|
||||||
|
binn_free(map);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((bytes_transferred = send(fd_answer, &payload_size, sizeof(payload_size), 0)) <= 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error during sending");
|
||||||
|
binn_free(map);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if((bytes_transferred = send(fd_answer, payload, payload_size, 0)) <= 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error during sending");
|
||||||
|
binn_free(map);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd_answer);
|
||||||
|
}
|
51
helpers/bind_server.c
Normal file
51
helpers/bind_server.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
#include <helpers.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
helper_bind_tcp_server(char* addr, uint16_t port, int max_client_backlog)
|
||||||
|
{
|
||||||
|
char port_str[6];
|
||||||
|
sprintf(port_str, "%d", port);
|
||||||
|
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int fd;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof hints);
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
|
if ((status = getaddrinfo(addr, port_str, &hints, &res)) != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("getaddrinfo: %s", gai_strerror(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||||
|
|
||||||
|
if ((status = bind(fd, res->ai_addr, res->ai_addrlen)) == -1)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error binding socket: %s", strerror(errno));
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status = listen(fd, max_client_backlog)) == -1)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error setting up listener: %s", strerror(errno));
|
||||||
|
freeaddrinfo(res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
|
@ -5,33 +5,35 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <logger.h>
|
#include <logger.h>
|
||||||
#include <helper.h>
|
#include <helpers.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
helper_connect_server(char* host, char* port)
|
helper_connect_tcp_server(char* host, uint16_t port)
|
||||||
{
|
{
|
||||||
|
char port_str[6];
|
||||||
|
sprintf(port_str, "%d", port);
|
||||||
|
|
||||||
int s, status;
|
int s, status;
|
||||||
struct addrinfo hints, *res;
|
struct addrinfo hints, *res;
|
||||||
memset(&hints, 0, sizeof hints);
|
memset(&hints, 0, sizeof hints);
|
||||||
hints.ai_family = AF_INET; //set IP Protocol flag (IPv4 or IPv6 - we don't care)
|
hints.ai_family = AF_INET; //set IP Protocol flag (IPv4 or IPv6 - we don't care)
|
||||||
hints.ai_socktype = SOCK_STREAM; //set socket flag
|
hints.ai_socktype = SOCK_STREAM; //set socket flag
|
||||||
|
|
||||||
if ((status = getaddrinfo(host, port, &hints, &res)) != 0) { //getaddrinfo() will evaluate the given address, using the hints-flags and port, and return an IP address and other server infos
|
if ((status = getaddrinfo(host, port_str, &hints, &res)) != 0) { //getaddrinfo() will evaluate the given address, using the hints-flags and port, and return an IP address and other server infos
|
||||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
|
LOG_ERROR("getaddrinfo: %s\n", gai_strerror(status));
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//res got filled out by getaddrinfo() for us
|
//res got filled out by getaddrinfo() for us
|
||||||
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //creating Socket
|
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //creating Socket
|
||||||
|
|
||||||
if ((status = connect(s, res->ai_addr, res->ai_addrlen)) != 0) {
|
if ((status = connect(s, res->ai_addr, res->ai_addrlen)) != 0) {
|
||||||
fprintf(stderr, "Keine Verbindung mit dem Netzwerk möglich.\n");
|
LOG_ERROR("connect() failed");
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
helpers/get_port.c
Normal file
24
helpers/get_port.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <helpers.h>
|
||||||
|
#include <logger.h>
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
helper_get_port(int sock)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
socklen_t len = sizeof(sin);
|
||||||
|
if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
|
||||||
|
{
|
||||||
|
LOG_ERROR("could not get socket name for port: %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ntohs(sin.sin_port);
|
||||||
|
}
|
||||||
|
}
|
57
helpers/open_discovery_socket.c
Normal file
57
helpers/open_discovery_socket.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
#include <helpers.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
helper_open_discovery_socket(uint16_t discovery_port)
|
||||||
|
{
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int fd, status;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof hints);
|
||||||
|
hints.ai_family = AF_INET; // use ipv4
|
||||||
|
hints.ai_socktype = SOCK_DGRAM; //set socket flag
|
||||||
|
hints.ai_flags = AI_PASSIVE; // get my IP
|
||||||
|
|
||||||
|
char discovery_port_str[6];
|
||||||
|
sprintf(discovery_port_str, "%u", discovery_port);
|
||||||
|
|
||||||
|
//get connection info for our computer
|
||||||
|
if ((status = getaddrinfo(NULL, discovery_port_str, &hints, &res)) != 0)
|
||||||
|
{
|
||||||
|
LOG_FATAL("getaddrinfo: %s", gai_strerror(status));
|
||||||
|
freeaddrinfo(res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//creating socket
|
||||||
|
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||||
|
int yes = 1;
|
||||||
|
|
||||||
|
// lose the pesky "Address already in use" error message
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
|
||||||
|
{
|
||||||
|
LOG_FATAL("setsockopt: %s", strerror(errno));
|
||||||
|
freeaddrinfo(res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(fd, res->ai_addr, res->ai_addrlen) == -1)
|
||||||
|
{
|
||||||
|
LOG_FATAL("bind: %s", strerror(errno));
|
||||||
|
freeaddrinfo(res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
LOG_INFO("opened discovery socket on port %u", discovery_port);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
|
@ -4,11 +4,11 @@
|
||||||
#include <log_levels.h>
|
#include <log_levels.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Limit the maximum length of a controller name
|
* @brief Limit the maximum length of a controller/relay/etc name
|
||||||
*
|
*
|
||||||
* The NULL terminator is not included. Arrays of length #CONTROLLER_NAME_LENGTH + 1 are required.
|
* The NULL terminator is not included. Arrays of length #MAX_NAME_LENGTH + 1 are required.
|
||||||
*/
|
*/
|
||||||
#define CONTROLLER_NAME_LENGTH 128
|
#define MAX_NAME_LENGTH 128
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Maximum number of dbs for the databases for the MDB_env
|
* @brief Maximum number of dbs for the databases for the MDB_env
|
||||||
|
|
3
include/constants.h
Normal file
3
include/constants.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#define SECONDS_PER_DAY 86400 // 60 * 60 * 24
|
||||||
|
|
||||||
|
#define SECONDS_PER_MINUTE 60
|
|
@ -1,27 +0,0 @@
|
||||||
#ifndef CONTROLLER_DISCOVERY_H
|
|
||||||
#define CONTROLLER_DISCOVERY_H
|
|
||||||
|
|
||||||
#include <models/controller.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Open socket for discovery
|
|
||||||
*
|
|
||||||
* Will exit program when unable to open socket.
|
|
||||||
*
|
|
||||||
* @param discovery_port Port number to listen on for discovery broadcasts
|
|
||||||
*
|
|
||||||
* @return Open socket to accept discovery broadcasts on
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
discovery_socket_open(uint16_t discovery_port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handle the discovery processing
|
|
||||||
*
|
|
||||||
* @param fd File descriptor to receive initial data from
|
|
||||||
* @param cntrlr Controller to use for answering discovery
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
discovery_handle_discover(int fd, controller *cntrlr);
|
|
||||||
|
|
||||||
#endif /* CONTROLLER_DISCOVERY_H */
|
|
14
include/drivers.h
Normal file
14
include/drivers.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef CONTROLLER_DRIVERS_H
|
||||||
|
#define CONTROLLER_DRIVERS_H
|
||||||
|
|
||||||
|
#include <models/relay.h>
|
||||||
|
|
||||||
|
#define DRIVER_PIFACE_GPIO_BASE 200
|
||||||
|
|
||||||
|
void
|
||||||
|
driver_piface_set(relay_t *relay, int value);
|
||||||
|
|
||||||
|
void
|
||||||
|
driver_gpio_set(relay_t *relay, int value);
|
||||||
|
|
||||||
|
#endif /* CONTROLLER_DRIVERS_H */
|
|
@ -1,8 +1,40 @@
|
||||||
#ifndef CONTROLLER_ENUMS_H
|
#ifndef CONTROLLER_ENUMS_H
|
||||||
#define CONTROLLER_ENUMS_H
|
#define CONTROLLER_ENUMS_H
|
||||||
|
|
||||||
enum poll_fgs {
|
enum poll_fgs
|
||||||
POLL_FGS_DISCOVERY
|
{
|
||||||
|
POLL_FGS_DISCOVERY,
|
||||||
|
POLL_FGS_COMMAND
|
||||||
|
};
|
||||||
|
|
||||||
|
enum discovery_mapping
|
||||||
|
{
|
||||||
|
DISCOVERY_MAPPING_ID = 0,
|
||||||
|
DISCOVERY_MAPPING_NAME = 1,
|
||||||
|
DISCOVERY_MAPPING_COMMAND_PORT = 2,
|
||||||
|
DISCOVERY_MAPPING_RELAY_COUNT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum control_mapping
|
||||||
|
{
|
||||||
|
COMMAND_MAPPING_CODE = 0,
|
||||||
|
COMMAND_MAPPING_NAME = 1,
|
||||||
|
COMMAND_MAPPING_RELAY_NUM = 2,
|
||||||
|
COMMAND_MAPPING_SCHEDULE_ID = 3,
|
||||||
|
COMMAND_MAPPING_PERIODS_COUNT = 4,
|
||||||
|
COMMAND_MAPPING_PERIODS_BLOB = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum command_code
|
||||||
|
{
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONTROLLER_ENUMS_H */
|
#endif /* CONTROLLER_ENUMS_H */
|
||||||
|
|
24
include/handlers.h
Normal file
24
include/handlers.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef CONTROLLER_HANDLERS_H
|
||||||
|
#define CONTROLLER_HANDLERS_H
|
||||||
|
|
||||||
|
#include <models/controller.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle the command processing
|
||||||
|
*
|
||||||
|
* @param fd File descriptor to receive initial data from
|
||||||
|
* @param controller Controller to use for answering command
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handler_command(int fd, controller_t *controller);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle the discovery processing
|
||||||
|
*
|
||||||
|
* @param fd File descriptor to receive initial data from
|
||||||
|
* @param controller Controller to use for answering discovery
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
handler_discovery(int fd, controller_t *controller);
|
||||||
|
|
||||||
|
#endif /* CONTROLLER_HANDLERS_H */
|
|
@ -1,7 +0,0 @@
|
||||||
#ifndef CONTROLLER_HELPER_H
|
|
||||||
#define CONTROLLER_HELPER_H
|
|
||||||
|
|
||||||
int
|
|
||||||
helper_connect_server(char* host, char* port);
|
|
||||||
|
|
||||||
#endif /* CONTROLLER_HELPER_H */
|
|
25
include/helpers.h
Normal file
25
include/helpers.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef CONTROLLER_HELPERS_H
|
||||||
|
#define CONTROLLER_HELPERS_H
|
||||||
|
|
||||||
|
int
|
||||||
|
helper_connect_tcp_server(char* host, uint16_t port);
|
||||||
|
|
||||||
|
int
|
||||||
|
helper_bind_tcp_server(char* addr, uint16_t port, int max_client_backlog);
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
helper_get_port(int sock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open socket for discovery
|
||||||
|
*
|
||||||
|
* Will exit program when unable to open socket.
|
||||||
|
*
|
||||||
|
* @param discovery_port Port number to listen on for discovery broadcasts
|
||||||
|
*
|
||||||
|
* @return Open socket to accept discovery broadcasts on
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
helper_open_discovery_socket(uint16_t discovery_port);
|
||||||
|
|
||||||
|
#endif /* CONTROLLER_HELPERS_H */
|
|
@ -2,45 +2,52 @@
|
||||||
#define CONTROLLER_LOGGER_H
|
#define CONTROLLER_LOGGER_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include <colors.h>
|
#include <colors.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
|
||||||
#define _LOGGER_MESSAGE(msg) COLOR_NONE " %s:%s:%d: " msg "\n", __FILENAME__, __func__, __LINE__
|
#define _LOGGER_TIMESTAMP_SIZE 32
|
||||||
|
char _LOGGER_TIMESTAMP[_LOGGER_TIMESTAMP_SIZE];
|
||||||
|
|
||||||
|
char*
|
||||||
|
logger_get_timestamp();
|
||||||
|
|
||||||
|
#define _LOGGER_MESSAGE(msg) COLOR_NONE " %s %s:%d:%s: " msg "\n", logger_get_timestamp(), __FILENAME__, __LINE__, __func__
|
||||||
|
|
||||||
#if LOG_LEVEL >= LOG_LEVEL_TRACE
|
#if LOG_LEVEL >= LOG_LEVEL_TRACE
|
||||||
#define LOG_TRACE(msg, ...) printf(COLOR_GREEN "[TRACE]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
#define LOG_TRACE(msg, ...) fprintf(stdout, COLOR_GREEN "[TRACE]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_TRACE(msg, ...)
|
#define LOG_TRACE(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
|
#if LOG_LEVEL >= LOG_LEVEL_DEBUG
|
||||||
#define LOG_DEBUG(msg, ...) printf(COLOR_BLUE "[DEBUG]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
#define LOG_DEBUG(msg, ...) fprintf(stdout, COLOR_BLUE "[DEBUG]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_DEBUG(msg, ...)
|
#define LOG_DEBUG(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOG_LEVEL >= LOG_LEVEL_INFO
|
#if LOG_LEVEL >= LOG_LEVEL_INFO
|
||||||
#define LOG_INFO(msg, ...) printf(COLOR_CYAN "[ INFO] " _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
#define LOG_INFO(msg, ...) fprintf(stdout, COLOR_CYAN "[ INFO]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_INFO(msg, ...)
|
#define LOG_INFO(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOG_LEVEL >= LOG_LEVEL_WARN
|
#if LOG_LEVEL >= LOG_LEVEL_WARN
|
||||||
#define LOG_WARN(msg, ...) printf(COLOR_YELLOW "[ WARN] " _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
#define LOG_WARN(msg, ...) fprintf(stdout, COLOR_YELLOW "[ WARN]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_WARN(msg, ...)
|
#define LOG_WARN(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOG_LEVEL >= LOG_LEVEL_ERROR
|
#if LOG_LEVEL >= LOG_LEVEL_ERROR
|
||||||
#define LOG_ERROR(msg, ...) printf(COLOR_RED "[ERROR]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
#define LOG_ERROR(msg, ...) fprintf(stderr, COLOR_RED "[ERROR]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_ERROR(msg, ...)
|
#define LOG_ERROR(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LOG_LEVEL >= LOG_LEVEL_FATAL
|
#if LOG_LEVEL >= LOG_LEVEL_FATAL
|
||||||
#define LOG_FATAL(msg, ...) printf(COLOR_MAGENTA "[FATAL]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
#define LOG_FATAL(msg, ...) fprintf(stderr, COLOR_MAGENTA "[FATAL]" _LOGGER_MESSAGE(msg), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define LOG_FATAL(msg, ...)
|
#define LOG_FATAL(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
/**
|
/**
|
||||||
* @brief Information about this controller
|
* @brief Information about this controller
|
||||||
*/
|
*/
|
||||||
typedef struct controller
|
typedef struct
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @brief A unique UUID for this controller
|
* @brief A unique UUID for this controller
|
||||||
|
@ -22,7 +22,7 @@ typedef struct controller
|
||||||
*
|
*
|
||||||
* Includes a \0 terminator.
|
* Includes a \0 terminator.
|
||||||
*/
|
*/
|
||||||
char name[CONTROLLER_NAME_LENGTH + 1];
|
char name[MAX_NAME_LENGTH + 1];
|
||||||
/**
|
/**
|
||||||
* @brief The command port the controller was bound to
|
* @brief The command port the controller was bound to
|
||||||
*/
|
*/
|
||||||
|
@ -35,22 +35,22 @@ typedef struct controller
|
||||||
* @brief Amount of relays available to this controller
|
* @brief Amount of relays available to this controller
|
||||||
*/
|
*/
|
||||||
uint8_t relay_count;
|
uint8_t relay_count;
|
||||||
relay **relays;
|
relay_t **relays;
|
||||||
|
|
||||||
} controller;
|
} controller_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Key to save controller information in database
|
* @brief Key to save controller information in database
|
||||||
*/
|
*/
|
||||||
typedef enum controller_db_key
|
typedef enum
|
||||||
{
|
{
|
||||||
KEY_META_ID = 0,
|
DB_KEY_CONTROLLER_ID = 0,
|
||||||
KEY_META_NAME = 1,
|
DB_KEY_CONTROLLER_NAME = 1,
|
||||||
KEY_META_COMMAND_PORT = 2,
|
DB_KEY_CONTROLLER_COMMAND_PORT = 2,
|
||||||
KEY_META_DISCOVERY_PORT = 3,
|
DB_KEY_CONTROLLER_DISCOVERY_PORT = 3,
|
||||||
KEY_META_RELAY_COUNT = 4,
|
DB_KEY_CONTROLLER_RELAY_COUNT = 4,
|
||||||
KEY_META_RELAYS = 5,
|
DB_KEY_CONTROLLER_RELAYS = 5,
|
||||||
} controller_db_key;
|
} db_key_controller_e;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new instance of controller
|
* @brief Create a new instance of controller
|
||||||
|
@ -59,7 +59,7 @@ typedef enum controller_db_key
|
||||||
*
|
*
|
||||||
* @return A new instance of #controller
|
* @return A new instance of #controller
|
||||||
*/
|
*/
|
||||||
controller*
|
controller_t*
|
||||||
controller_create(void);
|
controller_create(void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,20 +72,32 @@ controller_create(void);
|
||||||
*
|
*
|
||||||
* @return A loaded or new instance of controller or NULL on database error
|
* @return A loaded or new instance of controller or NULL on database error
|
||||||
*/
|
*/
|
||||||
controller*
|
controller_t*
|
||||||
controller_load(MDB_env *mdb_env);
|
controller_load(MDB_env *mdb_env);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Save a controller to the database
|
* @brief Save a controller to the database
|
||||||
*
|
*
|
||||||
* @param cntrlr Instance of a controller
|
* @param controller Instance of a controller
|
||||||
* @param mdb_env Already created MDB_env
|
* @param mdb_env Already created MDB_env
|
||||||
*
|
*
|
||||||
* @return Indicator to show success (0) or failure (!0)
|
* @return Indicator to show success (0) or failure (!0)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
controller_save(controller *cntrlr, MDB_env *mdb_env);
|
controller_save(controller_t *controller, MDB_env *mdb_env);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a name to a controller.
|
||||||
|
* This function won't perform any checks (e.g. no NULL checks)
|
||||||
|
*
|
||||||
|
* @param controller Set the name to this controller
|
||||||
|
* @param name Name to be set
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
controller_set_name(controller_t *controller, char *name);
|
||||||
|
|
||||||
|
void
|
||||||
|
controller_free(controller_t *controller);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Debug an instance of #controller
|
* @brief Debug an instance of #controller
|
||||||
|
@ -95,6 +107,6 @@ controller_save(controller *cntrlr, MDB_env *mdb_env);
|
||||||
* @param cntrlr #controller to debug
|
* @param cntrlr #controller to debug
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
controller_debug(controller *cntrlr);
|
controller_debug(controller_t *controller);
|
||||||
|
|
||||||
#endif //CONTROLLER_CONTROLLER_H
|
#endif //CONTROLLER_CONTROLLER_H
|
||||||
|
|
19
include/models/period.h
Normal file
19
include/models/period.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef CONTROLLER_PERIOD_H
|
||||||
|
#define CONTROLLER_PERIOD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t start;
|
||||||
|
uint16_t end;
|
||||||
|
} period_t;
|
||||||
|
|
||||||
|
period_t*
|
||||||
|
period_create(uint16_t start, uint16_t end);
|
||||||
|
|
||||||
|
int
|
||||||
|
period_includes_time(period_t *period, uint16_t timestamp);
|
||||||
|
|
||||||
|
#endif /* CONTROLLER_PERIOD_H */
|
|
@ -2,16 +2,63 @@
|
||||||
#define CONTROLLER_RELAY_H
|
#define CONTROLLER_RELAY_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <lmdb.h>
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <models/schedule.h>
|
||||||
|
|
||||||
typedef struct relay {
|
typedef struct
|
||||||
uint8_t index;
|
{
|
||||||
char name[128];
|
uint8_t number;
|
||||||
uint16_t *schedule;
|
char name[MAX_NAME_LENGTH + 1];
|
||||||
} relay;
|
schedule_t *schedule;
|
||||||
|
} relay_t;
|
||||||
|
|
||||||
relay*
|
/**
|
||||||
relay_init(uint8_t index);
|
* @brief Key to save relay information in database
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
DB_KEY_RELAY_NAME = 0,
|
||||||
|
DB_KEY_RELAY_SCHEDULE_ID = 1,
|
||||||
|
DB_KEY_RELAY_SCHEDULE_PERIODS = 2,
|
||||||
|
} db_key_relay_e;
|
||||||
|
|
||||||
|
relay_t*
|
||||||
|
relay_create(uint8_t number);
|
||||||
|
|
||||||
|
void
|
||||||
|
relay_set_name(relay_t *relay, char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a relay for database or create a new one
|
||||||
|
*
|
||||||
|
* @param mdb_env An opened MDB_env to load from
|
||||||
|
*
|
||||||
|
* @return A loaded or new instance of relay
|
||||||
|
*/
|
||||||
|
relay_t*
|
||||||
|
relay_load(MDB_env *mdb_env, uint8_t num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Save a relay to the database
|
||||||
|
*
|
||||||
|
* @param relay Instance of a relay
|
||||||
|
* @param mdb_env Already created MDB_env
|
||||||
|
*
|
||||||
|
* @return Indicator to show success (0) or failure (!0)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
relay_save(relay_t *relay, MDB_env *mdb_env);
|
||||||
|
|
||||||
|
int
|
||||||
|
relay_is_active(relay_t *relay, time_t timestamp_now);
|
||||||
|
|
||||||
|
void
|
||||||
|
relay_free(relay_t *relay);
|
||||||
|
|
||||||
|
void
|
||||||
|
relay_debug(relay_t *relay);
|
||||||
|
|
||||||
#endif //CONTROLLER_RELAY_H
|
#endif //CONTROLLER_RELAY_H
|
||||||
|
|
28
include/models/schedule.h
Normal file
28
include/models/schedule.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef CONTROLLER_SCHEDULE_H
|
||||||
|
#define CONTROLLER_SCHEDULE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
|
#include <models/period.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uuid_t id;
|
||||||
|
uint16_t length;
|
||||||
|
period_t **periods;
|
||||||
|
} schedule_t;
|
||||||
|
|
||||||
|
schedule_t*
|
||||||
|
schedule_create(uuid_t id, uint16_t length, uint16_t *periods_blob);
|
||||||
|
|
||||||
|
uint16_t*
|
||||||
|
schedule_periods_to_blob(schedule_t *schedule);
|
||||||
|
|
||||||
|
void
|
||||||
|
schedule_free(schedule_t *schedule);
|
||||||
|
|
||||||
|
void
|
||||||
|
schedule_debug(schedule_t *schedule);
|
||||||
|
|
||||||
|
#endif /* CONTROLLER_SCHEDULE_H */
|
|
@ -1,10 +1,15 @@
|
||||||
#ifndef CONTROLLER_WIRING_DEBUG_H
|
#ifndef CONTROLLER_WIRING_DEBUG_H
|
||||||
#define CONTROLLER_WIRING_DEBUG_H
|
#define CONTROLLER_WIRING_DEBUG_H
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
|
||||||
#ifdef WIRING_PI_DEBUG
|
#ifdef WIRING_PI_DEBUG
|
||||||
#define wiringPiSetup() LOG_INFO("wiringP wiringPiSetup()")
|
#define wiringPiSetup() LOG_INFO("wiringPi wiringPiSetup()")
|
||||||
|
#define wiringPiSetupSys() LOG_INFO("wiringPi wiringPiSetupSys()")
|
||||||
#define pinMode(x,y) LOG_INFO("wiringPi pinMode(%d, %d)", x, y)
|
#define pinMode(x,y) LOG_INFO("wiringPi pinMode(%d, %d)", x, y)
|
||||||
#define digitalWrite(x,y) LOG_INFO("wiringPi digitalWrite(%d, %d)", x, y)
|
#define digitalWrite(x,y) LOG_INFO("wiringPi digitalWrite(%d, %d)", x, y)
|
||||||
|
|
||||||
|
#define piFaceSetup(x) LOG_INFO("wiringPi piFaceSetup(%d)", x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* CONTROLLER_WIRING_DEBUG_H */
|
#endif /* CONTROLLER_WIRING_DEBUG_H */
|
||||||
|
|
10
logger.c
Normal file
10
logger.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include <logger.h>
|
||||||
|
|
||||||
|
char*
|
||||||
|
logger_get_timestamp()
|
||||||
|
{
|
||||||
|
time_t rawtime;
|
||||||
|
time(&rawtime);
|
||||||
|
strftime(_LOGGER_TIMESTAMP, _LOGGER_TIMESTAMP_SIZE, "%Y-%m-%d %H:%M:%S", localtime(&rawtime));
|
||||||
|
return _LOGGER_TIMESTAMP;
|
||||||
|
}
|
141
main.c
141
main.c
|
@ -1,17 +1,72 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
#include <lmdb.h>
|
#include <lmdb.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include <logger.h>
|
#include <logger.h>
|
||||||
#include <models/controller.h>
|
#include <models/controller.h>
|
||||||
#include <database.h>
|
#include <database.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <discovery.h>
|
#include <handlers.h>
|
||||||
|
#include <drivers.h>
|
||||||
#include <enums.h>
|
#include <enums.h>
|
||||||
|
#include <helpers.h>
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#include <piFace.h>
|
||||||
|
#include <wiring_debug.h>
|
||||||
|
|
||||||
|
static MDB_env *mdb_env;
|
||||||
|
static int fd_discovery;
|
||||||
|
static int fd_command;
|
||||||
|
static controller_t *this_controller;
|
||||||
|
|
||||||
|
static void
|
||||||
|
terminate(int signum)
|
||||||
|
{
|
||||||
|
LOG_INFO("terminating controller (%d)", signum);
|
||||||
|
|
||||||
|
close(fd_discovery);
|
||||||
|
close(fd_command);
|
||||||
|
|
||||||
|
mdb_env_close(mdb_env);
|
||||||
|
|
||||||
|
controller_free(this_controller);
|
||||||
|
|
||||||
|
exit(signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_poll(struct pollfd *fds, int fd_count)
|
||||||
|
{
|
||||||
|
/* An event on one of the fds has occurred. */
|
||||||
|
for(int i = 0; i < fd_count; i++) {
|
||||||
|
if(fds[i].revents & POLLIN)
|
||||||
|
{
|
||||||
|
/* data may be read on device number i. */
|
||||||
|
LOG_DEBUG("fd %i may read data", fds[i].fd);
|
||||||
|
switch(i)
|
||||||
|
{
|
||||||
|
case POLL_FGS_DISCOVERY:
|
||||||
|
handler_discovery(fd_discovery, this_controller);
|
||||||
|
break;
|
||||||
|
case POLL_FGS_COMMAND:
|
||||||
|
handler_command(fd_command, this_controller);
|
||||||
|
controller_save(this_controller, mdb_env);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fds[i].revents & POLLHUP)
|
||||||
|
{
|
||||||
|
/* A hangup has occurred on device number i. */
|
||||||
|
LOG_DEBUG("fd %i got closed", fds[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The main function
|
* @brief The main function
|
||||||
|
@ -27,18 +82,40 @@ main(int argc, char** argv)
|
||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
MDB_env *mdb_env;
|
signal(SIGINT, terminate);
|
||||||
|
signal(SIGABRT, terminate);
|
||||||
|
signal(SIGTERM, terminate);
|
||||||
|
|
||||||
|
if(sizeof(time_t) < 8)
|
||||||
|
{
|
||||||
|
LOG_WARN("this system is not using 8-bit time");
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************** SETUP DATABASE AND THIS CONTROLLER ********************/
|
||||||
|
|
||||||
database_setup(&mdb_env);
|
database_setup(&mdb_env);
|
||||||
|
|
||||||
controller *this_cntrlr = controller_load(mdb_env);
|
this_controller = controller_load(mdb_env);
|
||||||
controller_save(this_cntrlr, mdb_env);
|
|
||||||
|
|
||||||
int fd_discovery = discovery_socket_open(this_cntrlr->discovery_port);
|
fd_discovery = helper_open_discovery_socket(this_controller->discovery_port);
|
||||||
|
fd_command = helper_bind_tcp_server("0.0.0.0", this_controller->command_port, 128);
|
||||||
|
|
||||||
|
this_controller->command_port = helper_get_port(fd_command);
|
||||||
|
|
||||||
|
controller_save(this_controller, mdb_env);
|
||||||
|
|
||||||
|
|
||||||
|
/******************** SETUP WIRINGPI ********************/
|
||||||
|
|
||||||
|
wiringPiSetupSys();
|
||||||
|
piFaceSetup(200);
|
||||||
|
|
||||||
|
|
||||||
|
/******************** SETUP SOCKETS ********************/
|
||||||
|
|
||||||
struct pollfd fds[2];
|
struct pollfd fds[2];
|
||||||
int timeout_msecs = ACCEPT_TIMEOUT_MSECONDS;
|
int timeout_msecs = ACCEPT_TIMEOUT_MSECONDS;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
|
||||||
int fd_count = 0;
|
int fd_count = 0;
|
||||||
|
|
||||||
/* Open STREAMS device. */
|
/* Open STREAMS device. */
|
||||||
|
@ -46,6 +123,12 @@ main(int argc, char** argv)
|
||||||
fds[POLL_FGS_DISCOVERY].events = POLLIN;
|
fds[POLL_FGS_DISCOVERY].events = POLLIN;
|
||||||
LOG_DEBUG("setup fd_discovery as %i on index %i", fd_discovery, fd_count);
|
LOG_DEBUG("setup fd_discovery as %i on index %i", fd_discovery, fd_count);
|
||||||
fd_count++;
|
fd_count++;
|
||||||
|
fds[POLL_FGS_COMMAND].fd = fd_command;
|
||||||
|
fds[POLL_FGS_COMMAND].events = POLLIN;
|
||||||
|
LOG_DEBUG("setup fd_command as %i on index %i", fd_command, fd_count);
|
||||||
|
fd_count++;
|
||||||
|
|
||||||
|
/******************** START MAIN LOOP ********************/
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
@ -54,27 +137,37 @@ main(int argc, char** argv)
|
||||||
if(ret == 0)
|
if(ret == 0)
|
||||||
{
|
{
|
||||||
LOG_TRACE("idle loop");
|
LOG_TRACE("idle loop");
|
||||||
|
for(uint_fast8_t i = 0; i < this_controller->relay_count; ++i)
|
||||||
|
{
|
||||||
|
relay_t *relay = this_controller->relays[i];
|
||||||
|
if(relay_is_active(relay, time(NULL)))
|
||||||
|
{
|
||||||
|
LOG_DEBUG("relay %d is active", i);
|
||||||
|
if(relay->number >= 2)
|
||||||
|
{
|
||||||
|
driver_gpio_set(relay, HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
driver_piface_set(relay, HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(relay->number >= 2)
|
||||||
|
{
|
||||||
|
driver_gpio_set(relay, LOW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
driver_piface_set(relay, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(ret > 0)
|
if(ret > 0)
|
||||||
{
|
{
|
||||||
/* An event on one of the fds has occurred. */
|
handle_poll(fds, fd_count);
|
||||||
for(i = 0; i < fd_count; i++) {
|
|
||||||
if(fds[i].revents & POLLIN)
|
|
||||||
{
|
|
||||||
/* Priority data may be read on device number i. */
|
|
||||||
LOG_DEBUG("fd %i may read data", fds[i].fd);
|
|
||||||
switch(i)
|
|
||||||
{
|
|
||||||
case POLL_FGS_DISCOVERY:
|
|
||||||
discovery_handle_discover(fd_discovery, this_cntrlr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(fds[i].revents & POLLHUP)
|
|
||||||
{
|
|
||||||
/* A hangup has occurred on device number i. */
|
|
||||||
LOG_DEBUG("fd %i got closed", fds[i].fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,38 +7,62 @@
|
||||||
#include <models/controller.h>
|
#include <models/controller.h>
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
|
||||||
controller*
|
controller_t*
|
||||||
controller_create(void)
|
controller_create(void)
|
||||||
{
|
{
|
||||||
controller *result = malloc(sizeof(*result));
|
controller_t *new_controller = malloc(sizeof(*new_controller));
|
||||||
uuid_generate(result->id);
|
uuid_generate(new_controller->id);
|
||||||
|
|
||||||
strcpy(result->name, "new emgauwa device");
|
strcpy(new_controller->name, "new emgauwa device");
|
||||||
result->command_port = 0;
|
new_controller->command_port = 0;
|
||||||
result->discovery_port = 4421;
|
new_controller->discovery_port = 4421;
|
||||||
result->relay_count = 10;
|
new_controller->relay_count = 10;
|
||||||
|
|
||||||
result->relays = malloc(sizeof(*result->relays) * result->relay_count);
|
new_controller->relays = malloc(sizeof(relay_t) * new_controller->relay_count);
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for(i = 0; i < result->relay_count; i++)
|
for(i = 0; i < new_controller->relay_count; ++i)
|
||||||
{
|
{
|
||||||
result->relays[i] = relay_init(i);
|
new_controller->relays[i] = relay_create(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return new_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
controller_debug(controller *cntrlr)
|
controller_set_name(controller_t *controller, char *name)
|
||||||
{
|
{
|
||||||
if(cntrlr == NULL)
|
strncpy(controller->name, name, MAX_NAME_LENGTH);
|
||||||
|
controller->name[MAX_NAME_LENGTH] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
controller_free(controller_t *controller)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < controller->relay_count; ++i)
|
||||||
|
{
|
||||||
|
relay_free(controller->relays[i]);
|
||||||
|
}
|
||||||
|
free(controller->relays);
|
||||||
|
free(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
controller_debug(controller_t *controller)
|
||||||
|
{
|
||||||
|
if(controller == NULL)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("controller is NULL");
|
LOG_DEBUG("controller is NULL");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
char uuid_str[37];
|
char uuid_str[37];
|
||||||
uuid_unparse(cntrlr->id, uuid_str);
|
uuid_unparse(controller->id, uuid_str);
|
||||||
LOG_DEBUG("(1/4) %s @ %p", uuid_str, cntrlr);
|
LOG_DEBUG("(1/5) %s @ %p", uuid_str, controller);
|
||||||
LOG_DEBUG("(2/4) name: %s", cntrlr->name);
|
LOG_DEBUG("(2/5) name: %s", controller->name);
|
||||||
LOG_DEBUG("(3/4) relays: %3d", cntrlr->relay_count);
|
LOG_DEBUG("(3/5) command_port: %5d discovery_port: %5d", controller->command_port, controller->discovery_port);
|
||||||
LOG_DEBUG("(4/4) command_port: %5d discovery_port: %5d", cntrlr->command_port, cntrlr->discovery_port);
|
LOG_DEBUG("(4/5) relay count: %3d", controller->relay_count);
|
||||||
|
LOG_DEBUG("(5/5) relays @ %p:", controller->relays);
|
||||||
|
for(uint8_t i = 0; i < controller->relay_count; ++i)
|
||||||
|
{
|
||||||
|
relay_debug(controller->relays[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,73 +8,79 @@
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
controller_load_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, controller_db_key key_meta, MDB_val *value)
|
controller_load_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, db_key_controller_e key_controller, MDB_val *value)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
MDB_val key;
|
MDB_val key;
|
||||||
|
|
||||||
key.mv_size = sizeof(controller_db_key);
|
key.mv_size = sizeof(db_key_controller_e);
|
||||||
key.mv_data = &key_meta;
|
key.mv_data = &key_controller;
|
||||||
|
|
||||||
if((err = mdb_get(mdb_txn, mdb_dbi, &key, value)) != 0)
|
if((err = mdb_get(mdb_txn, mdb_dbi, &key, value)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "mdb_get error %s\n", mdb_strerror(err));
|
LOG_ERROR("mdb_get error %s", mdb_strerror(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
controller*
|
controller_t*
|
||||||
controller_load(MDB_env *mdb_env)
|
controller_load(MDB_env *mdb_env)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
MDB_txn *mdb_txn;
|
MDB_txn *mdb_txn;
|
||||||
MDB_dbi mdb_dbi;
|
MDB_dbi mdb_dbi;
|
||||||
|
|
||||||
controller *new_controller;
|
controller_t *new_controller;
|
||||||
|
|
||||||
if((err = mdb_txn_begin(mdb_env, NULL, MDB_RDONLY, &mdb_txn)) != 0)
|
if((err = mdb_txn_begin(mdb_env, NULL, MDB_RDONLY, &mdb_txn)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "mdb_txn_begin error %s\n", mdb_strerror(err));
|
LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if((err = mdb_dbi_open(mdb_txn, "meta", 0, &mdb_dbi)) != 0)
|
if((err = mdb_dbi_open(mdb_txn, "controller", 0, &mdb_dbi)) != 0)
|
||||||
{
|
{
|
||||||
switch(err)
|
switch(err)
|
||||||
{
|
{
|
||||||
case MDB_NOTFOUND:
|
case MDB_NOTFOUND:
|
||||||
|
LOG_INFO("no controller found in db. creating new one");
|
||||||
mdb_txn_abort(mdb_txn);
|
mdb_txn_abort(mdb_txn);
|
||||||
new_controller = controller_create();
|
new_controller = controller_create();
|
||||||
controller_save(new_controller, mdb_env);
|
controller_save(new_controller, mdb_env);
|
||||||
return new_controller;
|
return new_controller;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "mdb_txn_begin error %s\n", mdb_strerror(err));
|
LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new_controller = malloc(sizeof(*new_controller));
|
new_controller = malloc(sizeof(controller_t));
|
||||||
|
|
||||||
MDB_val value;
|
MDB_val value;
|
||||||
|
|
||||||
controller_load_single(mdb_txn, mdb_dbi, KEY_META_ID, &value);
|
controller_load_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_ID, &value);
|
||||||
memmove(new_controller->id, (uuid_t*)value.mv_data, sizeof(uuid_t));
|
memmove(new_controller->id, (uuid_t*)value.mv_data, sizeof(uuid_t));
|
||||||
|
|
||||||
controller_load_single(mdb_txn, mdb_dbi, KEY_META_NAME, &value);
|
controller_load_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_NAME, &value);
|
||||||
strncpy(new_controller->name, (char*)value.mv_data, CONTROLLER_NAME_LENGTH);
|
strncpy(new_controller->name, (char*)value.mv_data, MAX_NAME_LENGTH);
|
||||||
new_controller->name[CONTROLLER_NAME_LENGTH] = '\0';
|
new_controller->name[MAX_NAME_LENGTH] = '\0';
|
||||||
|
|
||||||
controller_load_single(mdb_txn, mdb_dbi, KEY_META_COMMAND_PORT, &value);
|
controller_load_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_COMMAND_PORT, &value);
|
||||||
new_controller->command_port = ((uint16_t*)value.mv_data)[0];
|
new_controller->command_port = ((uint16_t*)value.mv_data)[0];
|
||||||
|
|
||||||
controller_load_single(mdb_txn, mdb_dbi, KEY_META_DISCOVERY_PORT, &value);
|
controller_load_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_DISCOVERY_PORT, &value);
|
||||||
new_controller->discovery_port = ((uint16_t*)value.mv_data)[0];
|
new_controller->discovery_port = ((uint16_t*)value.mv_data)[0];
|
||||||
|
|
||||||
controller_load_single(mdb_txn, mdb_dbi, KEY_META_RELAY_COUNT, &value);
|
controller_load_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_RELAY_COUNT, &value);
|
||||||
new_controller->relay_count = ((uint8_t*)value.mv_data)[0];
|
new_controller->relay_count = ((uint8_t*)value.mv_data)[0];
|
||||||
|
|
||||||
controller_debug(new_controller);
|
|
||||||
|
|
||||||
mdb_txn_abort(mdb_txn); // transaction is read only
|
mdb_txn_abort(mdb_txn); // transaction is read only
|
||||||
|
|
||||||
|
new_controller->relays = malloc(sizeof(relay_t*) * new_controller->relay_count);
|
||||||
|
for(uint8_t i = 0; i < new_controller->relay_count; i++)
|
||||||
|
{
|
||||||
|
LOG_TRACE("loading relay %d", i);
|
||||||
|
new_controller->relays[i] = relay_load(mdb_env, i);
|
||||||
|
}
|
||||||
|
|
||||||
return new_controller;
|
return new_controller;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
#include <macros.h>
|
#include <macros.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
controller_save_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, controller_db_key key_meta, MDB_val value)
|
controller_save_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, db_key_controller_e key_controller, MDB_val value)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
MDB_val key;
|
MDB_val key;
|
||||||
key.mv_size = sizeof(controller_db_key);
|
key.mv_size = sizeof(db_key_controller_e);
|
||||||
key.mv_data = &key_meta;
|
key.mv_data = &key_controller;
|
||||||
|
|
||||||
if((err = mdb_put(mdb_txn, mdb_dbi, &key, &value, 0)) != 0)
|
if((err = mdb_put(mdb_txn, mdb_dbi, &key, &value, 0)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "mdb_put error %s\n", mdb_strerror(err));
|
LOG_ERROR("mdb_put error %s", mdb_strerror(err));
|
||||||
mdb_txn_abort(mdb_txn);
|
mdb_txn_abort(mdb_txn);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ controller_save_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, controller_db_key key_
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
controller_save(controller *cntrlr, MDB_env *mdb_env)
|
controller_save(controller_t *controller, MDB_env *mdb_env)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -34,56 +34,65 @@ controller_save(controller *cntrlr, MDB_env *mdb_env)
|
||||||
MDB_dbi mdb_dbi;
|
MDB_dbi mdb_dbi;
|
||||||
MDB_val value;
|
MDB_val value;
|
||||||
|
|
||||||
controller_debug(cntrlr);
|
|
||||||
|
|
||||||
if((err = mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn)) != 0)
|
if((err = mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "mdb_txn_begin error %s\n", mdb_strerror(err));
|
LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((err = mdb_dbi_open(mdb_txn, "meta", MDB_CREATE, &mdb_dbi)) != 0)
|
if((err = mdb_dbi_open(mdb_txn, "controller", MDB_CREATE, &mdb_dbi)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "mdb_dbi_open error %s\n", mdb_strerror(err));
|
LOG_ERROR("mdb_dbi_open error %s", mdb_strerror(err));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
value.mv_size = sizeof(cntrlr->id);
|
value.mv_size = sizeof(uuid_t);
|
||||||
value.mv_data = cntrlr->id;
|
value.mv_data = controller->id;
|
||||||
if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_ID, value))
|
if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_ID, value))
|
||||||
{
|
{
|
||||||
|
LOG_ERROR("failed to save ID");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
value.mv_size = sizeof(char) * (strlen(cntrlr->name) + 1);
|
value.mv_size = sizeof(char) * (strlen(controller->name) + 1);
|
||||||
value.mv_data = cntrlr->name;
|
value.mv_data = controller->name;
|
||||||
if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_NAME, value))
|
if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_NAME, value))
|
||||||
{
|
{
|
||||||
|
LOG_ERROR("failed to save name");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
value.mv_size = sizeof(cntrlr->command_port);
|
value.mv_size = sizeof(controller->command_port);
|
||||||
value.mv_data = &cntrlr->command_port;
|
value.mv_data = &controller->command_port;
|
||||||
if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_COMMAND_PORT, value))
|
if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_COMMAND_PORT, value))
|
||||||
{
|
{
|
||||||
|
LOG_ERROR("failed to save command port");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
value.mv_size = sizeof(cntrlr->discovery_port);
|
value.mv_size = sizeof(controller->discovery_port);
|
||||||
value.mv_data = &cntrlr->discovery_port;
|
value.mv_data = &controller->discovery_port;
|
||||||
if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_DISCOVERY_PORT, value))
|
if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_DISCOVERY_PORT, value))
|
||||||
{
|
{
|
||||||
|
LOG_ERROR("failed to save discovery port");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
value.mv_size = sizeof(cntrlr->relay_count);
|
value.mv_size = sizeof(controller->relay_count);
|
||||||
value.mv_data = &cntrlr->relay_count;
|
value.mv_data = &controller->relay_count;
|
||||||
if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_RELAY_COUNT, value))
|
if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_RELAY_COUNT, value))
|
||||||
{
|
{
|
||||||
|
LOG_ERROR("failed to save relay count");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mdb_txn_commit(mdb_txn);
|
mdb_txn_commit(mdb_txn);
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < controller->relay_count; ++i)
|
||||||
|
{
|
||||||
|
LOG_TRACE("saving relays[%d/%d]", i, controller->relay_count);
|
||||||
|
relay_save(controller->relays[i], mdb_env);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
44
models/period.c
Normal file
44
models/period.c
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
#include <constants.h>
|
||||||
|
#include <models/period.h>
|
||||||
|
|
||||||
|
period_t*
|
||||||
|
period_create(uint16_t start, uint16_t end)
|
||||||
|
{
|
||||||
|
period_t *new_period = malloc(sizeof(period_t));
|
||||||
|
new_period->start = start;
|
||||||
|
new_period->end = end;
|
||||||
|
|
||||||
|
return new_period;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
period_includes_time(period_t *period, uint16_t timestamp)
|
||||||
|
{
|
||||||
|
uint16_t start = period->start;
|
||||||
|
uint16_t end = period->end;
|
||||||
|
|
||||||
|
// "normal" timespan
|
||||||
|
if(start < end)
|
||||||
|
{
|
||||||
|
if(start <= timestamp && end > timestamp)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// timespan goes through 00:00
|
||||||
|
if(end < start)
|
||||||
|
{
|
||||||
|
if(start >= timestamp && end < timestamp)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,10 +1,83 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
|
#include <constants.h>
|
||||||
|
#include <logger.h>
|
||||||
#include <models/relay.h>
|
#include <models/relay.h>
|
||||||
|
|
||||||
relay*
|
relay_t*
|
||||||
relay_init(uint8_t index)
|
relay_create(uint8_t number)
|
||||||
{
|
{
|
||||||
(void)index;
|
relay_t *new_relay = malloc(sizeof(relay_t));
|
||||||
return NULL;
|
|
||||||
|
new_relay->number = number;
|
||||||
|
new_relay->name[0] = '\0';
|
||||||
|
|
||||||
|
uuid_t off_id;
|
||||||
|
memset(off_id, 0, sizeof(uuid_t));
|
||||||
|
memcpy(off_id, "off", 3);
|
||||||
|
|
||||||
|
new_relay->schedule = schedule_create(off_id, 0, NULL);
|
||||||
|
|
||||||
|
return new_relay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relay_set_name(relay_t *relay, char *name)
|
||||||
|
{
|
||||||
|
strncpy(relay->name, name, MAX_NAME_LENGTH);
|
||||||
|
relay->name[MAX_NAME_LENGTH] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
relay_is_active(relay_t *relay, time_t timestamp_now)
|
||||||
|
{
|
||||||
|
if(relay->schedule->length == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't need days. reduce to hours, minutes and seconds
|
||||||
|
timestamp_now %= SECONDS_PER_DAY;
|
||||||
|
// finally remove seconds
|
||||||
|
timestamp_now /= SECONDS_PER_MINUTE;
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < relay->schedule->length; ++i)
|
||||||
|
{
|
||||||
|
if(period_includes_time(relay->schedule->periods[i], timestamp_now))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//struct tm time_start, time_now, time_end;
|
||||||
|
//localtime_r(×tamp_start, &time_start);
|
||||||
|
//localtime_r(×tamp_now, &time_now);
|
||||||
|
//localtime_r(×tamp_end, &time_end);
|
||||||
|
//LOG_DEBUG("%02d:%02d - %02d:%02d - %02d:%02d", time_start.tm_hour, time_start.tm_min, time_now.tm_hour, time_now.tm_min, time_end.tm_hour, time_end.tm_min);
|
||||||
|
|
||||||
|
void
|
||||||
|
relay_debug(relay_t *relay)
|
||||||
|
{
|
||||||
|
if(relay == NULL)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("relay is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("(1/3) %d @ %p", relay->number, relay);
|
||||||
|
LOG_DEBUG("(2/3) name: %s", relay->name);
|
||||||
|
LOG_DEBUG("(3/3) schedule:");
|
||||||
|
schedule_debug(relay->schedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relay_free(relay_t *relay)
|
||||||
|
{
|
||||||
|
if(relay->schedule)
|
||||||
|
{
|
||||||
|
schedule_free(relay->schedule);
|
||||||
|
}
|
||||||
|
free(relay);
|
||||||
}
|
}
|
||||||
|
|
100
models/relay_load.c
Normal file
100
models/relay_load.c
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
|
#include <models/relay.h>
|
||||||
|
#include <macros.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
relay_load_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, db_key_relay_e key_relay, uint8_t num, MDB_val *value)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
size_t key_size = sizeof(db_key_relay_e) + sizeof(uint8_t);
|
||||||
|
void *key_data = malloc(key_size);
|
||||||
|
memmove(key_data, &key_relay, sizeof(db_key_relay_e));
|
||||||
|
memmove(key_data + sizeof(db_key_relay_e), &num, sizeof(uint8_t));
|
||||||
|
|
||||||
|
MDB_val key;
|
||||||
|
key.mv_size = key_size;
|
||||||
|
key.mv_data = key_data;
|
||||||
|
|
||||||
|
if((err = mdb_get(mdb_txn, mdb_dbi, &key, value)) != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("mdb_get error %s", mdb_strerror(err));
|
||||||
|
mdb_txn_abort(mdb_txn);
|
||||||
|
free(key_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
free(key_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
relay_t*
|
||||||
|
relay_load(MDB_env *mdb_env, uint8_t num)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
MDB_txn *mdb_txn;
|
||||||
|
MDB_dbi mdb_dbi;
|
||||||
|
|
||||||
|
relay_t *new_relay;
|
||||||
|
|
||||||
|
if((err = mdb_txn_begin(mdb_env, NULL, MDB_RDONLY, &mdb_txn)) != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
|
||||||
|
return relay_create(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((err = mdb_dbi_open(mdb_txn, "relays", 0, &mdb_dbi)) != 0)
|
||||||
|
{
|
||||||
|
switch(err)
|
||||||
|
{
|
||||||
|
case MDB_NOTFOUND:
|
||||||
|
LOG_INFO("no relay for num %d found in db. returning new one (no relays db)", num);
|
||||||
|
mdb_txn_abort(mdb_txn);
|
||||||
|
return relay_create(num);
|
||||||
|
default:
|
||||||
|
LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
|
||||||
|
return relay_create(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_relay = malloc(sizeof(relay_t));
|
||||||
|
new_relay->number = num;
|
||||||
|
|
||||||
|
MDB_val value;
|
||||||
|
|
||||||
|
if((err = relay_load_single(mdb_txn, mdb_dbi, DB_KEY_RELAY_NAME, num, &value)) != 0)
|
||||||
|
{
|
||||||
|
LOG_INFO("no relay for num %d found in db. returning new one", num);
|
||||||
|
mdb_txn_abort(mdb_txn); // transaction is read only
|
||||||
|
return relay_create(num);
|
||||||
|
}
|
||||||
|
strncpy(new_relay->name, (char*)value.mv_data, MAX_NAME_LENGTH);
|
||||||
|
new_relay->name[MAX_NAME_LENGTH] = '\0';
|
||||||
|
|
||||||
|
if((err = relay_load_single(mdb_txn, mdb_dbi, DB_KEY_RELAY_SCHEDULE_ID, num, &value)) != 0)
|
||||||
|
{
|
||||||
|
LOG_INFO("no relay for num %d found in db. returning new one", num);
|
||||||
|
mdb_txn_abort(mdb_txn); // transaction is read only
|
||||||
|
return relay_create(num);
|
||||||
|
}
|
||||||
|
uuid_t *schedule_id = (uuid_t*)value.mv_data;
|
||||||
|
|
||||||
|
if((err = relay_load_single(mdb_txn, mdb_dbi, DB_KEY_RELAY_SCHEDULE_PERIODS, num, &value)) != 0)
|
||||||
|
{
|
||||||
|
LOG_INFO("no relay for num %d found in db. returning new one", num);
|
||||||
|
mdb_txn_abort(mdb_txn); // transaction is read only
|
||||||
|
return relay_create(num);
|
||||||
|
}
|
||||||
|
uint16_t schedule_periods_length = ((uint16_t*)value.mv_data)[0];
|
||||||
|
uint16_t *schedule_periods = ((uint16_t*)value.mv_data) + 1;
|
||||||
|
|
||||||
|
new_relay->schedule = schedule_create(*schedule_id, schedule_periods_length, schedule_periods);
|
||||||
|
|
||||||
|
mdb_txn_abort(mdb_txn); // transaction is read only
|
||||||
|
|
||||||
|
return new_relay;
|
||||||
|
}
|
88
models/relay_save.c
Normal file
88
models/relay_save.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
|
#include <models/relay.h>
|
||||||
|
#include <macros.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
relay_save_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, db_key_relay_e key_relay, uint8_t num, MDB_val value)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
size_t key_size = sizeof(db_key_relay_e) + sizeof(uint8_t);
|
||||||
|
void *key_data = malloc(key_size);
|
||||||
|
memmove(key_data, &key_relay, sizeof(db_key_relay_e));
|
||||||
|
memmove(key_data + sizeof(db_key_relay_e), &num, sizeof(uint8_t));
|
||||||
|
|
||||||
|
MDB_val key;
|
||||||
|
key.mv_size = key_size;
|
||||||
|
key.mv_data = key_data;
|
||||||
|
|
||||||
|
if((err = mdb_put(mdb_txn, mdb_dbi, &key, &value, 0)) != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("mdb_put error %s", mdb_strerror(err));
|
||||||
|
mdb_txn_abort(mdb_txn);
|
||||||
|
free(key_data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
free(key_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
relay_save(relay_t *relay, MDB_env *mdb_env)
|
||||||
|
{
|
||||||
|
LOG_TRACE("saving relay %d @ %p", relay->number, relay);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
MDB_txn *mdb_txn;
|
||||||
|
MDB_dbi mdb_dbi;
|
||||||
|
MDB_val value;
|
||||||
|
|
||||||
|
if((err = mdb_txn_begin(mdb_env, NULL, 0, &mdb_txn)) != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((err = mdb_dbi_open(mdb_txn, "relays", MDB_CREATE, &mdb_dbi)) != 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("mdb_dbi_open error %s", mdb_strerror(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
value.mv_size = sizeof(char) * (strlen(relay->name) + 1);
|
||||||
|
value.mv_data = relay->name;
|
||||||
|
if(relay_save_single(mdb_txn, mdb_dbi, DB_KEY_RELAY_NAME, relay->number, value))
|
||||||
|
{
|
||||||
|
LOG_ERROR("failed to save name");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
value.mv_size = sizeof(uuid_t);
|
||||||
|
value.mv_data = relay->schedule->id;
|
||||||
|
if(relay_save_single(mdb_txn, mdb_dbi, DB_KEY_RELAY_SCHEDULE_ID, relay->number, value))
|
||||||
|
{
|
||||||
|
LOG_ERROR("failed to save ID");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save periods blob
|
||||||
|
uint16_t *periods_blob = schedule_periods_to_blob(relay->schedule);
|
||||||
|
value.mv_size = sizeof(uint16_t) * ((periods_blob[0] * 2) + 1);
|
||||||
|
value.mv_data = periods_blob;
|
||||||
|
if(relay_save_single(mdb_txn, mdb_dbi, DB_KEY_RELAY_SCHEDULE_PERIODS, relay->number, value))
|
||||||
|
{
|
||||||
|
free(periods_blob);
|
||||||
|
LOG_ERROR("failed to save periods");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
free(periods_blob);
|
||||||
|
|
||||||
|
mdb_txn_commit(mdb_txn);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
89
models/schedule.c
Normal file
89
models/schedule.c
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <logger.h>
|
||||||
|
#include <models/schedule.h>
|
||||||
|
|
||||||
|
schedule_t*
|
||||||
|
schedule_create(uuid_t id, uint16_t length, uint16_t *periods_blob)
|
||||||
|
{
|
||||||
|
schedule_t *new_schedule = malloc(sizeof(schedule_t));
|
||||||
|
|
||||||
|
memmove(new_schedule->id, id, sizeof(uuid_t));
|
||||||
|
|
||||||
|
new_schedule->length = length;
|
||||||
|
new_schedule->periods = NULL;
|
||||||
|
|
||||||
|
if(length)
|
||||||
|
{
|
||||||
|
new_schedule->periods = malloc(sizeof(period_t*) * length);
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
uint16_t start = periods_blob[0 + (i * 2)];
|
||||||
|
uint16_t end = periods_blob[1 + (i * 2)];
|
||||||
|
new_schedule->periods[i] = period_create(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t*
|
||||||
|
schedule_periods_to_blob(schedule_t *schedule)
|
||||||
|
{
|
||||||
|
uint16_t *periods_blob = malloc(sizeof(uint16_t) * ((2 * schedule->length) + 1));
|
||||||
|
periods_blob[0] = schedule->length;
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < schedule->length; ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
periods_blob[1 + (i * 2)] = schedule->periods[i]->start;
|
||||||
|
periods_blob[2 + (i * 2)] = schedule->periods[i]->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return periods_blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
schedule_free(schedule_t *schedule)
|
||||||
|
{
|
||||||
|
for(uint16_t i = 0; i < schedule->length; ++i)
|
||||||
|
{
|
||||||
|
free(schedule->periods[i]);
|
||||||
|
}
|
||||||
|
free(schedule->periods);
|
||||||
|
free(schedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
schedule_debug(schedule_t *schedule)
|
||||||
|
{
|
||||||
|
if(schedule == NULL)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("schedule is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char uuid_str[37];
|
||||||
|
uuid_unparse(schedule->id, uuid_str);
|
||||||
|
LOG_DEBUG("(1/3) %s @ %p", uuid_str, schedule);
|
||||||
|
LOG_DEBUG("(2/3) period count: %3d", schedule->length);
|
||||||
|
|
||||||
|
// one block: "HH:MM-HH:MM, " --> size: 13 (14 with '\0')
|
||||||
|
char *periods_debug_str = malloc(sizeof(char) * ((schedule->length * 13) + 1));
|
||||||
|
periods_debug_str[0] = '\0';
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < schedule->length; ++i)
|
||||||
|
{
|
||||||
|
sprintf(
|
||||||
|
periods_debug_str + (13 * i),
|
||||||
|
"%02d:%02d-%02d:%02d, ",
|
||||||
|
schedule->periods[i]->start / 60,
|
||||||
|
schedule->periods[i]->start % 60,
|
||||||
|
schedule->periods[i]->end / 60,
|
||||||
|
schedule->periods[i]->end % 60
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("(3/3) periods: %s", periods_debug_str);
|
||||||
|
}
|
Loading…
Reference in a new issue