sk6812d/src/udpproto.c

122 lines
2.6 KiB
C

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include "logger.h"
#include "fader.h"
#include "udpproto.h"
#define SET_COLOUR 0
#define FADE_COLOUR 1
#define ADD_COLOUR 2
#define SET_FADESTEP 3
int sock;
int udpproto_init(uint16_t port)
{
struct sockaddr_in listen_addr;
// initialize UDP server socket
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sock == -1) {
LOG(LVL_ERR, "udpproto: Could not initialize UDP socket: %s.", strerror(errno));
return -1;
}
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons(port);
listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock, (struct sockaddr*)&listen_addr, sizeof(listen_addr)) == -1) {
LOG(LVL_ERR, "udpproto: Could not bind socket to port %i: %s.", port, strerror(errno));
return -1;
}
return 0;
}
int udpproto_process(void)
{
socklen_t remote_addr_len;
struct sockaddr remote_addr;
uint8_t pkgbuf[65536];
ssize_t rcvbytes, offset = 0;
uint8_t r, g, b, w, action, module;
int fds_ready;
// check if there is data to be read (to prevent blocking)
struct pollfd pfd = {
.fd = sock,
.events = POLLIN,
.revents = 0
};
fds_ready = poll(&pfd, 1, 0);
if(fds_ready == -1) {
LOG(LVL_ERR, "udpproto: poll() failed: %s.", strerror(errno));
return -1;
} else if(fds_ready == 0) {
// there's nothing to be read
return 0;
}
// receive the data
remote_addr_len = sizeof(remote_addr);
rcvbytes = recvfrom(sock, pkgbuf, 65536, 0, (struct sockaddr*)&remote_addr, &remote_addr_len);
if(rcvbytes == -1) {
LOG(LVL_ERR, "udpproto: recvfrom() failed: %s.", strerror(errno));
return -1;
}
pkgbuf[rcvbytes] = 0;
// parse commands from packet
offset = 0;
while(offset <= rcvbytes - 5) {
action = pkgbuf[offset + 0];
module = pkgbuf[offset + 1];
r = pkgbuf[offset + 2];
g = pkgbuf[offset + 3];
b = pkgbuf[offset + 4];
w = pkgbuf[offset + 5];
offset += 5;
switch(action) {
case SET_COLOUR:
fader_set_colour(module, r, g, b, w);
break;
case FADE_COLOUR:
fader_fade_colour(module, r, g, b, w);
break;
case ADD_COLOUR:
fader_add_colour(module, r, g, b, w);
break;
case SET_FADESTEP:
fader_set_fadestep(r); // red channel contains the fadestep in this case
break;
default:
LOG(LVL_DEBUG, "udpproto: Action %u not implemented yet.", action);
}
}
return rcvbytes / 6; // number of commands in packet
}
void udpproto_shutdown(void)
{
close(sock);
}