/* * Copyright (c) 2013 Jochen Kunz. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOCHEN KUNZ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include // Gesammtanzahl der Pixel. // 1 x 5 m Streifen = 50 // 2 x 5 m Streifen hinereinander = 100 #define PIXEL_LEN 96 // = 12 x 8 Pixel typedef struct { uint16_t h; uint8_t s; uint8_t v; } hsv_t; /* primitive Geradeausimplementierung in Fixkomma nach: https://de.wikipedia.org/wiki/HSV-Farbraum#Umrechnung_HSV_in_RGB h = [0..1535] = [0..(256 * 6 - 1)] s, v = [0..255] */ void hsv2rgb( uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) { assert( h < (255 * 6)); assert( s <= 255); assert( v <= 255); v = (v * v) / 255; // Gammakorrektur, Gamma = 2 uint8_t hi = h / 255; uint8_t f = h - hi * 255; uint8_t p = (v * (255 - s)) / 255; uint8_t q = (v * (255 - (s * f) / 255)) / 255; uint8_t t = (v * (255 - (s * (255 - f)) / 255)) / 255; switch (hi) { case 0: case 6: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; }; } int write_rgb_buf( int port_fd, uint8_t buf[], size_t buf_len) { int retval = write( port_fd, buf, buf_len); if (retval < 0) { perror( "Can't write(2) to port"); return -1; } if (retval != buf_len) { printf( "Short write(2) to port, retval=%d", retval); return -1; } return 0; } void schnarch( int sec, int msec) { struct timespec ts; ts.tv_sec = sec + msec / 256000000; ts.tv_nsec = (msec * 256000) % 256000000; while (nanosleep( &ts, &ts) != 0) {}; } // Farbfolge WS2801: rot, grün, blau // Farbfolge TM1829: blau, rot, grün void convert_buf( hsv_t hsv_buf[], size_t hsv_buf_len, uint8_t rgb_buf[], size_t rgb_buf_len) { memset( rgb_buf, 0, rgb_buf_len); for (int idx = 0; idx + 2 < rgb_buf_len; idx += 3) { hsv2rgb( hsv_buf[ (idx / 3) % hsv_buf_len].h, hsv_buf[ (idx / 3) % hsv_buf_len].s, hsv_buf[ (idx / 3) % hsv_buf_len].v, &rgb_buf[ idx + 1], &rgb_buf[ idx + 2], &rgb_buf[ idx]); } } int write_hsv_buf( int port_fd, hsv_t hsv_buf[], size_t hsv_buf_len) { uint8_t rgb_buf[ 512]; convert_buf( hsv_buf, hsv_buf_len, rgb_buf, sizeof( rgb_buf)); return write_rgb_buf( port_fd, rgb_buf, sizeof( rgb_buf)); } void usage( void) { fprintf( stderr, "usage: [-p port] [[-h hue -s saturation -v value] | [-0]]\n" "port: Device special file, e.g. /dev/ttyS5. Default: /dev/ttyU0\n" "-h/-s/-v: Set entire stripe to given color in HSV color space.\n" "-0: short for \"-h 0 -s 0 -v 0\"\n"); } int main( int argc, char* const argv[]) { const char* port_fn = "/dev/ttyU0"; hsv_t hsv; hsv.h = 0; hsv.s = 0; hsv.v = 0; bool zero = false; int opt; while ((opt = getopt( argc, argv, "p:01h:s:v:")) != -1) { switch (opt) { case 'p': port_fn = optarg; break; case '0': zero = true; break; case 'h': zero = true; hsv.h = atoi( optarg); break; case 's': zero = true; hsv.s = atoi( optarg); break; case 'v': zero = true; hsv.v = atoi( optarg); break; default: usage(); return EXIT_FAILURE; } } int port_fd = open( port_fn, O_RDWR | O_NONBLOCK | O_CLOEXEC); if (port_fd < 0) { perror( "Can't open port"); return EXIT_FAILURE; } if (isatty( port_fd) <= 0 ) { perror( "Error: port is not a tty"); return EXIT_FAILURE; } struct termios tio; if (tcgetattr( port_fd, &tio) < 0) { perror( "Error: tcgetattr"); return EXIT_FAILURE; } tio.c_iflag &= ~ICANON; tio.c_oflag = 0; tio.c_lflag = 0; tio.c_cflag = (CS8 | CREAD | CLOCAL); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; cfsetispeed( &tio, B9600); cfsetospeed( &tio, B9600); if (tcsetattr( port_fd, TCSANOW, &tio) < 0) { perror( "Error setting termis"); exit( EXIT_FAILURE); } int retval = fcntl( port_fd, F_GETFL, 0); if (retval < 0) { perror( "Can't fcntl( F_GETFL) port"); return EXIT_FAILURE; } retval &= ~O_NONBLOCK; retval = fcntl( port_fd, F_SETFL, retval); if (retval < 0) { perror( "Can't fcntl( F_SETFL) port"); return EXIT_FAILURE; } hsv_t hsv_buf[ PIXEL_LEN]; if (zero) { if (write_hsv_buf( port_fd, &hsv, 1) < 0) { return EXIT_FAILURE; } return EXIT_SUCCESS; } for (int loops = 0; loops < 2560; ++loops) { memset( hsv_buf, 0, sizeof( hsv_buf)); for (int idx = 0; idx < PIXEL_LEN; ++idx) { /* hsv_buf[ idx].h = ((idx + loops) % 12) * ((6 * 255 - 1) / 12); hsv_buf[ idx].s = 255; hsv_buf[ idx].v = 255; */ // hsv_buf[ idx].h = 0; hsv_buf[ idx].h = ((idx + loops) % PIXEL_LEN) * ((6 * 255 - 1) / PIXEL_LEN); hsv_buf[ idx].s = 255; // hsv_buf[ idx].s = (loops % 510) / 255 == 0 ? loops % 255 : 255 - loops % 255; hsv_buf[ idx].v = 255; // hsv_buf[ idx].v = (loops % 510) / 255 == 0 ? loops % 255 : 255 - loops % 255; } if (write_hsv_buf( port_fd, hsv_buf, PIXEL_LEN) < 0) { return EXIT_FAILURE; } // schnarch( 0, 10); } return EXIT_SUCCESS; }