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)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")
 | 
			
		||||
| 
						 | 
				
			
			@ -16,14 +16,26 @@ if(WIRING_PI_DEBUG)
 | 
			
		|||
endif(WIRING_PI_DEBUG)
 | 
			
		||||
 | 
			
		||||
aux_source_directory(. SRC_DIR)
 | 
			
		||||
aux_source_directory(models MODEL_SRC)
 | 
			
		||||
aux_source_directory(helpers HELPER_SRC)
 | 
			
		||||
aux_source_directory(models MODELS_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)
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
    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 <logger.h>
 | 
			
		||||
#include <helper.h>
 | 
			
		||||
#include <helpers.h>
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
helper_connect_server(char* host, char* port)
 | 
			
		||||
helper_connect_tcp_server(char* host, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
  int s, status;
 | 
			
		||||
  struct addrinfo hints, *res;
 | 
			
		||||
  memset(&hints, 0, sizeof hints);
 | 
			
		||||
  hints.ai_family = AF_INET; //set IP Protocol flag (IPv4 or IPv6 - we don't care)
 | 
			
		||||
  hints.ai_socktype = SOCK_STREAM; //set socket flag
 | 
			
		||||
    char port_str[6];
 | 
			
		||||
    sprintf(port_str, "%d", port);
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
 | 
			
		||||
      exit(EXIT_FAILURE);
 | 
			
		||||
  }
 | 
			
		||||
    int s, status;
 | 
			
		||||
    struct addrinfo hints, *res;
 | 
			
		||||
    memset(&hints, 0, sizeof hints);
 | 
			
		||||
    hints.ai_family = AF_INET; //set IP Protocol flag (IPv4 or IPv6 - we don't care)
 | 
			
		||||
    hints.ai_socktype = SOCK_STREAM; //set socket flag
 | 
			
		||||
 | 
			
		||||
  //res got filled out by getaddrinfo() for us
 | 
			
		||||
  s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //creating Socket
 | 
			
		||||
    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
 | 
			
		||||
        LOG_ERROR("getaddrinfo: %s\n", gai_strerror(status));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if ((status = connect(s, res->ai_addr, res->ai_addrlen)) != 0) {
 | 
			
		||||
      fprintf(stderr, "Keine Verbindung mit dem Netzwerk möglich.\n");
 | 
			
		||||
      freeaddrinfo(res);
 | 
			
		||||
      exit(EXIT_FAILURE);
 | 
			
		||||
  }
 | 
			
		||||
    //res got filled out by getaddrinfo() for us
 | 
			
		||||
    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); //creating Socket
 | 
			
		||||
 | 
			
		||||
  freeaddrinfo(res);
 | 
			
		||||
    if ((status = connect(s, res->ai_addr, res->ai_addrlen)) != 0) {
 | 
			
		||||
        LOG_ERROR("connect() failed");
 | 
			
		||||
        freeaddrinfo(res);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return s;
 | 
			
		||||
    freeaddrinfo(res);
 | 
			
		||||
 | 
			
		||||
    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>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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
 | 
			
		||||
#define CONTROLLER_ENUMS_H
 | 
			
		||||
 | 
			
		||||
enum poll_fgs {
 | 
			
		||||
    POLL_FGS_DISCOVERY
 | 
			
		||||
enum poll_fgs
 | 
			
		||||
{
 | 
			
		||||
    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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#include <colors.h>
 | 
			
		||||
#include <config.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
 | 
			
		||||
    #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
 | 
			
		||||
    #define LOG_TRACE(msg, ...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
    #define LOG_DEBUG(msg, ...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
    #define LOG_INFO(msg, ...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
    #define LOG_WARN(msg, ...) 
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
    #define LOG_ERROR(msg, ...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
    #define LOG_FATAL(msg, ...)
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @brief Information about this controller
 | 
			
		||||
 */
 | 
			
		||||
typedef struct controller
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief A unique UUID for this controller
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ typedef struct controller
 | 
			
		|||
     *
 | 
			
		||||
     * 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
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -35,22 +35,22 @@ typedef struct controller
 | 
			
		|||
     * @brief Amount of relays available to this controller
 | 
			
		||||
     */
 | 
			
		||||
    uint8_t relay_count;
 | 
			
		||||
    relay **relays;
 | 
			
		||||
    relay_t **relays;
 | 
			
		||||
 | 
			
		||||
} controller;
 | 
			
		||||
} controller_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Key to save controller information in database
 | 
			
		||||
 */
 | 
			
		||||
typedef enum controller_db_key
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
    KEY_META_ID = 0,
 | 
			
		||||
    KEY_META_NAME = 1,
 | 
			
		||||
    KEY_META_COMMAND_PORT = 2,
 | 
			
		||||
    KEY_META_DISCOVERY_PORT = 3,
 | 
			
		||||
    KEY_META_RELAY_COUNT = 4,
 | 
			
		||||
    KEY_META_RELAYS = 5,
 | 
			
		||||
} controller_db_key;
 | 
			
		||||
    DB_KEY_CONTROLLER_ID = 0,
 | 
			
		||||
    DB_KEY_CONTROLLER_NAME = 1,
 | 
			
		||||
    DB_KEY_CONTROLLER_COMMAND_PORT = 2,
 | 
			
		||||
    DB_KEY_CONTROLLER_DISCOVERY_PORT = 3,
 | 
			
		||||
    DB_KEY_CONTROLLER_RELAY_COUNT = 4,
 | 
			
		||||
    DB_KEY_CONTROLLER_RELAYS = 5,
 | 
			
		||||
} db_key_controller_e;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Create a new instance of controller
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ typedef enum controller_db_key
 | 
			
		|||
 *
 | 
			
		||||
 * @return A new instance of #controller
 | 
			
		||||
 */
 | 
			
		||||
controller*
 | 
			
		||||
controller_t*
 | 
			
		||||
controller_create(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -72,20 +72,32 @@ controller_create(void);
 | 
			
		|||
 *
 | 
			
		||||
 * @return A loaded or new instance of controller or NULL on database error
 | 
			
		||||
 */
 | 
			
		||||
controller*
 | 
			
		||||
controller_t*
 | 
			
		||||
controller_load(MDB_env *mdb_env);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @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
 | 
			
		||||
 *
 | 
			
		||||
 * @return Indicator to show success (0) or failure (!0)
 | 
			
		||||
 */
 | 
			
		||||
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
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +107,6 @@ controller_save(controller *cntrlr, MDB_env *mdb_env);
 | 
			
		|||
 * @param cntrlr #controller to debug
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
controller_debug(controller *cntrlr);
 | 
			
		||||
controller_debug(controller_t *controller);
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <lmdb.h>
 | 
			
		||||
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#include <models/schedule.h>
 | 
			
		||||
 | 
			
		||||
typedef struct relay {
 | 
			
		||||
    uint8_t index;
 | 
			
		||||
    char name[128];
 | 
			
		||||
    uint16_t *schedule;
 | 
			
		||||
} relay;
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
    uint8_t number;
 | 
			
		||||
    char name[MAX_NAME_LENGTH + 1];
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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
 | 
			
		||||
#define CONTROLLER_WIRING_DEBUG_H
 | 
			
		||||
 | 
			
		||||
#include <logger.h>
 | 
			
		||||
 | 
			
		||||
#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 digitalWrite(x,y) LOG_INFO("wiringPi digitalWrite(%d, %d)", x, y)
 | 
			
		||||
 | 
			
		||||
    #define piFaceSetup(x) LOG_INFO("wiringPi piFaceSetup(%d)", x)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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 <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <lmdb.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
 | 
			
		||||
#include <logger.h>
 | 
			
		||||
#include <models/controller.h>
 | 
			
		||||
#include <database.h>
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#include <discovery.h>
 | 
			
		||||
#include <handlers.h>
 | 
			
		||||
#include <drivers.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
 | 
			
		||||
| 
						 | 
				
			
			@ -27,18 +82,40 @@ main(int argc, char** argv)
 | 
			
		|||
    (void)argc;
 | 
			
		||||
    (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);
 | 
			
		||||
 | 
			
		||||
    controller *this_cntrlr = controller_load(mdb_env);
 | 
			
		||||
    controller_save(this_cntrlr, mdb_env);
 | 
			
		||||
    this_controller = controller_load(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];
 | 
			
		||||
    int timeout_msecs = ACCEPT_TIMEOUT_MSECONDS;
 | 
			
		||||
    int ret;
 | 
			
		||||
    int i;
 | 
			
		||||
    int fd_count = 0;
 | 
			
		||||
 | 
			
		||||
    /* Open STREAMS device. */
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +123,12 @@ main(int argc, char** argv)
 | 
			
		|||
    fds[POLL_FGS_DISCOVERY].events = POLLIN;
 | 
			
		||||
    LOG_DEBUG("setup fd_discovery as %i on index %i", fd_discovery, 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)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -54,27 +137,37 @@ main(int argc, char** argv)
 | 
			
		|||
        if(ret == 0)
 | 
			
		||||
        {
 | 
			
		||||
            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)
 | 
			
		||||
        {
 | 
			
		||||
            /* An event on one of the fds has occurred. */
 | 
			
		||||
            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);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            handle_poll(fds, fd_count);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,38 +7,62 @@
 | 
			
		|||
#include <models/controller.h>
 | 
			
		||||
#include <macros.h>
 | 
			
		||||
 | 
			
		||||
controller*
 | 
			
		||||
controller_t*
 | 
			
		||||
controller_create(void)
 | 
			
		||||
{
 | 
			
		||||
    controller *result = malloc(sizeof(*result));
 | 
			
		||||
    uuid_generate(result->id);
 | 
			
		||||
    controller_t *new_controller = malloc(sizeof(*new_controller));
 | 
			
		||||
    uuid_generate(new_controller->id);
 | 
			
		||||
 | 
			
		||||
    strcpy(result->name, "new emgauwa device");
 | 
			
		||||
    result->command_port = 0;
 | 
			
		||||
    result->discovery_port = 4421;
 | 
			
		||||
    result->relay_count = 10;
 | 
			
		||||
    strcpy(new_controller->name, "new emgauwa device");
 | 
			
		||||
    new_controller->command_port = 0;
 | 
			
		||||
    new_controller->discovery_port = 4421;
 | 
			
		||||
    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;
 | 
			
		||||
    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
 | 
			
		||||
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");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    char uuid_str[37];
 | 
			
		||||
    uuid_unparse(cntrlr->id, uuid_str);
 | 
			
		||||
    LOG_DEBUG("(1/4) %s @ %p", uuid_str, cntrlr);
 | 
			
		||||
    LOG_DEBUG("(2/4) name: %s", cntrlr->name);
 | 
			
		||||
    LOG_DEBUG("(3/4) relays: %3d", cntrlr->relay_count);
 | 
			
		||||
    LOG_DEBUG("(4/4) command_port: %5d discovery_port: %5d", cntrlr->command_port, cntrlr->discovery_port);
 | 
			
		||||
    uuid_unparse(controller->id, uuid_str);
 | 
			
		||||
    LOG_DEBUG("(1/5) %s @ %p", uuid_str, controller);
 | 
			
		||||
    LOG_DEBUG("(2/5) name: %s", controller->name);
 | 
			
		||||
    LOG_DEBUG("(3/5) command_port: %5d discovery_port: %5d", controller->command_port, controller->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>
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    MDB_val key;
 | 
			
		||||
 | 
			
		||||
    key.mv_size = sizeof(controller_db_key);
 | 
			
		||||
    key.mv_data = &key_meta;
 | 
			
		||||
    key.mv_size = sizeof(db_key_controller_e);
 | 
			
		||||
    key.mv_data = &key_controller;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
controller*
 | 
			
		||||
controller_t*
 | 
			
		||||
controller_load(MDB_env *mdb_env)
 | 
			
		||||
{
 | 
			
		||||
    int err;
 | 
			
		||||
    MDB_txn *mdb_txn;
 | 
			
		||||
    MDB_dbi mdb_dbi;
 | 
			
		||||
    
 | 
			
		||||
    controller *new_controller;
 | 
			
		||||
    controller_t *new_controller;
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
    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)
 | 
			
		||||
        {
 | 
			
		||||
            case MDB_NOTFOUND:
 | 
			
		||||
                LOG_INFO("no controller found in db. creating new one");
 | 
			
		||||
                mdb_txn_abort(mdb_txn);
 | 
			
		||||
                new_controller =  controller_create();
 | 
			
		||||
                new_controller = controller_create();
 | 
			
		||||
                controller_save(new_controller, mdb_env);
 | 
			
		||||
                return new_controller;
 | 
			
		||||
            default:
 | 
			
		||||
                fprintf(stderr, "mdb_txn_begin error %s\n", mdb_strerror(err));
 | 
			
		||||
                LOG_ERROR("mdb_txn_begin error %s", mdb_strerror(err));
 | 
			
		||||
                return NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new_controller = malloc(sizeof(*new_controller));
 | 
			
		||||
    new_controller = malloc(sizeof(controller_t));
 | 
			
		||||
 | 
			
		||||
    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));
 | 
			
		||||
 | 
			
		||||
    controller_load_single(mdb_txn, mdb_dbi, KEY_META_NAME, &value);
 | 
			
		||||
    strncpy(new_controller->name, (char*)value.mv_data, CONTROLLER_NAME_LENGTH);
 | 
			
		||||
    new_controller->name[CONTROLLER_NAME_LENGTH] = '\0';
 | 
			
		||||
    controller_load_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_NAME, &value);
 | 
			
		||||
    strncpy(new_controller->name, (char*)value.mv_data, MAX_NAME_LENGTH);
 | 
			
		||||
    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];
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
 | 
			
		||||
    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];
 | 
			
		||||
 | 
			
		||||
    controller_debug(new_controller);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,17 +8,17 @@
 | 
			
		|||
#include <macros.h>
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    MDB_val key;
 | 
			
		||||
    key.mv_size = sizeof(controller_db_key);
 | 
			
		||||
    key.mv_data = &key_meta;
 | 
			
		||||
    key.mv_size = sizeof(db_key_controller_e);
 | 
			
		||||
    key.mv_data = &key_controller;
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ controller_save_single(MDB_txn *mdb_txn, MDB_dbi mdb_dbi, controller_db_key key_
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
controller_save(controller *cntrlr, MDB_env *mdb_env)
 | 
			
		||||
controller_save(controller_t *controller, MDB_env *mdb_env)
 | 
			
		||||
{
 | 
			
		||||
    int err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,56 +34,65 @@ controller_save(controller *cntrlr, MDB_env *mdb_env)
 | 
			
		|||
    MDB_dbi mdb_dbi;
 | 
			
		||||
    MDB_val value;
 | 
			
		||||
 | 
			
		||||
    controller_debug(cntrlr);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value.mv_size = sizeof(cntrlr->id);
 | 
			
		||||
    value.mv_data = cntrlr->id;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_ID, value))
 | 
			
		||||
    value.mv_size = sizeof(uuid_t);
 | 
			
		||||
    value.mv_data = controller->id;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_ID, value))
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR("failed to save ID");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value.mv_size = sizeof(char) * (strlen(cntrlr->name) + 1);
 | 
			
		||||
    value.mv_data = cntrlr->name;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_NAME, value))
 | 
			
		||||
    value.mv_size = sizeof(char) * (strlen(controller->name) + 1);
 | 
			
		||||
    value.mv_data = controller->name;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_NAME, value))
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR("failed to save name");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value.mv_size = sizeof(cntrlr->command_port);
 | 
			
		||||
    value.mv_data = &cntrlr->command_port;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_COMMAND_PORT, value))
 | 
			
		||||
    value.mv_size = sizeof(controller->command_port);
 | 
			
		||||
    value.mv_data = &controller->command_port;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_COMMAND_PORT, value))
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR("failed to save command port");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value.mv_size = sizeof(cntrlr->discovery_port);
 | 
			
		||||
    value.mv_data = &cntrlr->discovery_port;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_DISCOVERY_PORT, value))
 | 
			
		||||
    value.mv_size = sizeof(controller->discovery_port);
 | 
			
		||||
    value.mv_data = &controller->discovery_port;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_DISCOVERY_PORT, value))
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR("failed to save discovery port");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value.mv_size = sizeof(cntrlr->relay_count);
 | 
			
		||||
    value.mv_data = &cntrlr->relay_count;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, KEY_META_RELAY_COUNT, value))
 | 
			
		||||
    value.mv_size = sizeof(controller->relay_count);
 | 
			
		||||
    value.mv_data = &controller->relay_count;
 | 
			
		||||
    if(controller_save_single(mdb_txn, mdb_dbi, DB_KEY_CONTROLLER_RELAY_COUNT, value))
 | 
			
		||||
    {
 | 
			
		||||
        LOG_ERROR("failed to save relay count");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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 <string.h>
 | 
			
		||||
#include <uuid/uuid.h>
 | 
			
		||||
 | 
			
		||||
#include <constants.h>
 | 
			
		||||
#include <logger.h>
 | 
			
		||||
#include <models/relay.h>
 | 
			
		||||
 | 
			
		||||
relay*
 | 
			
		||||
relay_init(uint8_t index)
 | 
			
		||||
relay_t*
 | 
			
		||||
relay_create(uint8_t number)
 | 
			
		||||
{
 | 
			
		||||
    (void)index;
 | 
			
		||||
    return NULL;
 | 
			
		||||
    relay_t *new_relay = malloc(sizeof(relay_t));
 | 
			
		||||
 | 
			
		||||
    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…
	
	Add table
		Add a link
		
	
		Reference in a new issue