From bb31f0c0f0a040d4edb757b58dd9b4c43acfc90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Sat, 22 Oct 2022 14:34:10 +0200 Subject: ttyartnet --- fixtures/American-DJ-Encore-FR150Z.qxf | 59 ++ fixtures/FixturesMap.xml.encore | 1624 ++++++++++++++++++++++++++++++++ sw/ttyartnet.c | 235 +++++ 3 files changed, 1918 insertions(+) create mode 100644 fixtures/American-DJ-Encore-FR150Z.qxf create mode 100644 fixtures/FixturesMap.xml.encore create mode 100644 sw/ttyartnet.c diff --git a/fixtures/American-DJ-Encore-FR150Z.qxf b/fixtures/American-DJ-Encore-FR150Z.qxf new file mode 100644 index 0000000..f9695ab --- /dev/null +++ b/fixtures/American-DJ-Encore-FR150Z.qxf @@ -0,0 +1,59 @@ + + + + + Q Light Controller Plus + 4.12.6 + KUD Trzin + + American DJ + Encore FR150Z + Strobe + + + + Shutter + OFF + ON + Variable Strobe slow to fast + ON + Pulse Effect slow to fast + ON + Random Strobe slow to fast + ON + + + Maintenance + Standard + Stage + TV + Architectural + Theatre + Default to Unit Setting + + + Dimmer + + + Dimmer + Strobe + + + Dimmer + Strobe + Dimmer Mode + + + Dimmer + Dimmer Fine + Strobe + Dimmer Mode + + + + + + + + + diff --git a/fixtures/FixturesMap.xml.encore b/fixtures/FixturesMap.xml.encore new file mode 100644 index 0000000..7d84961 --- /dev/null +++ b/fixtures/FixturesMap.xml.encore @@ -0,0 +1,1624 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sw/ttyartnet.c b/sw/ttyartnet.c new file mode 100644 index 0000000..544f773 --- /dev/null +++ b/sw/ttyartnet.c @@ -0,0 +1,235 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define termios asmtermios +#define winsize asmwinsize +#define termio asmtermio +#include +#undef termios +#undef winsize +#undef termio +#define S0(x) (x ? x : "") +// start bit: low, 2 stop bits high +struct artnet { + char name[8]; // Art-Net\0 + char opcode[2]; // 0x5000 in LE: { 0x00, 0x50 } + uint8_t version_hi; // 0 + uint8_t version_li; // 14 + uint8_t sequence; // set to 0 to disable sequencing + uint8_t physical; // original universe + uint8_t sub_uni; + uint8_t net; + uint8_t length_hi; + uint8_t length_lo; + unsigned char data[512]; + +} __attribute__((packed)); +int samomor = 0; +void handle_me (int s __attribute__((unused))) { + samomor++; +} +int rate (int what_rate, int uart) { + int r = 0; + struct termios2 uartattr2; + if (ioctl(uart, TCGETS2, &uartattr2) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "ioctl TCGETS2, fd: %d", uart); + r = 1; + goto r; + } + uartattr2.c_cflag &= ~CBAUD; + uartattr2.c_cflag |= BOTHER; + uartattr2.c_ispeed = what_rate; + uartattr2.c_ospeed = what_rate; + if (ioctl(uart, TCSETS2, &uartattr2) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "ioctl TCSETS2"); + r = 2; + goto r; + } +r: + return r; +} +int main (int argc, char ** argv) { + int r = 0; + if (argc != 1+1) + error_at_line(1, 0, __FILE__, __LINE__, "usage: %s /dev/ttyUSB0", S0(argv[0])); + struct sigaction act = { + .sa_handler = handle_me, + .sa_flags = SA_RESTART + }; + if (sigaction(SIGINT, &act, NULL) == -1) + error_at_line(2, errno, __FILE__, __LINE__, "sigaction"); + int sock = -1; + int uart = open(argv[1], O_WRONLY | O_NOCTTY | O_NDELAY | O_CLOEXEC); + if (uart == -1) + error_at_line(3, errno, __FILE__, __LINE__, "open"); + struct termios uartattr; + if (tcgetattr(uart, &uartattr) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "tcgetattr"); + r = 4; + goto r; + } + uartattr.c_iflag = 0; + uartattr.c_oflag = 0; + uartattr.c_cflag = CS8 | CSTOPB; + uartattr.c_lflag = 0; + if (tcflush(uart, TCIOFLUSH) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "tcflush"); + r = 5; + goto r; + } + if (tcsetattr(uart, TCSANOW, &uartattr) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "tcsetattr"); + r = 6; + goto r; + } + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "socket"); + r = 7; + goto r; + } + int z = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &z, sizeof z) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "setsockopt"); + r = 8; + goto r; + } + struct sockaddr_in bind_address = { + .sin_family = AF_INET, + .sin_port = htons(6454), + .sin_addr = { + .s_addr = INADDR_ANY + } + }; + if (bind(sock, (struct sockaddr *) &bind_address, sizeof bind_address) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "bind"); + r = 9; + goto r; + } + long long last_dmx_burst = 0; + struct artnet udp; + while (!samomor) { + struct pollfd pollfds[2]; + pollfds[0].fd = sock; + pollfds[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; + // pollfds[1].fd = uart; + // pollfds[1].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL; + int poll_return; +fprintf(stderr, "before poll\n"); + if ((poll_return = poll(pollfds, 1 /* corr: I don't care about uart */, -1)) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "poll"); + r = 10; + goto r; + } +fprintf(stderr, "after poll\n"); + if (!poll_return) { // this can't happen, timeout is -1 + error_at_line(0, 0, __FILE__, __LINE__, "this can't happen, poll returned 0 and timeout was -1\n"); + r = 11; + goto r; + } + int both_events = pollfds[0].revents /* | pollfds[1].revents */; + if ((both_events & POLLERR) | (both_events & POLLHUP) | (both_events & POLLNVAL)) { + error_at_line(0, 0, __FILE__, __LINE__, "(both_events & POLLERR) | (both_events & POLLHUP) | (both_events & POLLNVAL)"); + r = 12; + goto r; + } + struct sockaddr_in sender; + socklen_t sender_len = sizeof sender; + ssize_t bytes = recvfrom(sock, &udp, sizeof udp, MSG_DONTWAIT, (struct sockaddr *) &sender, &sender_len); + if (bytes == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "recvfrom"); + r = 13; + goto r; + } else { + fprintf(stderr, "received %ld bytes from %s:%d\n", bytes, inet_ntoa(sender.sin_addr), ntohs(sender.sin_port)); + } + if (udp.opcode[0] != 0x00 || udp.opcode[1] != 0x50) + continue; + // if (bytes < 530) + // raise(SIGINT); + for (int i = 0; i < 512; i++) + if (udp.data[i] != 0) + fprintf(stderr, "\tDMX channel %d is %u\n", i+1, udp.data[i]); + struct timespec current_time; + if (clock_gettime(CLOCK_MONOTONIC, ¤t_time) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "clock_gettime"); + r = 14; + goto r; + } + long long current_time_ms = current_time.tv_sec*1000+current_time.tv_nsec/1000000; + if (current_time_ms >= last_dmx_burst+50) { + last_dmx_burst = current_time_ms; + } else + continue; + if (tcflush(uart, TCIOFLUSH) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "tcflush"); + r = 15; + goto r; + } + switch (rate(10000, uart)) { + case 1: + r = 16; + goto r; + break; + case 2: + r = 17; + goto r; + break; + default: + break; + } + if (tcflush(uart, TCIOFLUSH) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "tcflush"); + r = 18; + goto r; + } + usleep(10000); + if (write(uart, "\0", 1) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "write packet start sequence"); + r = 19; + goto r; + } + usleep(1000); + switch (rate(250000, uart)) { + case 1: + r = 20; + goto r; + break; + case 2: + r = 21; + goto r; + break; + default: + break; + } + udp.data[-1] = '\0'; +#pragma GCC diagnostic ignored "-Wstringop-overread" + if (write(uart, udp.data-1, 513) == -1) { + error_at_line(0, errno, __FILE__, __LINE__, "write packet data"); + r = 21; + goto r; + } +#pragma GCC diagnostic pop + } +r: + fprintf(stderr, "closing fds and returning\n"); + if (close(uart) == -1) + error_at_line(22, errno, __FILE__, __LINE__, "close(uart)"); + if (sock != -1) + if (close(sock) == -1) + error_at_line(23, errno, __FILE__, __LINE__, "close(sock)"); + return r; +} -- cgit v1.2.3