Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
project:alma [07.07.2014 20:52] – jkunz | project:alma [28.12.2015 23:42] (aktuell) – aktualisiert schmofu | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
====== ALMA – Aldi Led MAtrix | ====== ALMA – Aldi Led MAtrix | ||
+ | |||
+ | Die LED-Matrix steht derzeit im Erdgeschoss des Raums. Sie ist an die MediaBox angeschlossen. | ||
+ | |||
+ | Man kann sie mit Animationen bespielen. Hierzu wird der [[https:// | ||
+ | |||
+ | Zum Testen könnte man beispielsweise folgendes asuführen: | ||
+ | while true ; do python animations/ | ||
+ | |||
+ | :!: Die RGB-Werte Blau-Rot-Grün (also anders als bei mit der Lightwall). | ||
+ | |||
+ | |||
+ | ===== Details ===== | ||
Die 8 x 12 RGB-Pixel LED Matrix basiert auf den digital LED Streifen, die es dereinzt bei Feinkost-Albrecht, | Die 8 x 12 RGB-Pixel LED Matrix basiert auf den digital LED Streifen, die es dereinzt bei Feinkost-Albrecht, | ||
Zeile 6: | Zeile 18: | ||
An ALMA hängt ein kleiner USB Controller. (MicroUSB Kabel mitbringen.) Dieser erscheint als serielle Schnittstelle am Rechner. (USB CDC gebaut mit LUFA.) Er übernimt es die per USB empfangenen Bytes in das timingkritische Signal für die TM1829 zu übersetzen. Der USB Controller möchte die Daten immer in 512 Byte Blöcken. Also serielle Schnitte einmal öffnen, danach beliebig oft 512 Byte en Block senden und nach Empfang des 512ten Bytes schiebt der USB Controller die Bytes einfach 1:1 raus. | An ALMA hängt ein kleiner USB Controller. (MicroUSB Kabel mitbringen.) Dieser erscheint als serielle Schnittstelle am Rechner. (USB CDC gebaut mit LUFA.) Er übernimt es die per USB empfangenen Bytes in das timingkritische Signal für die TM1829 zu übersetzen. Der USB Controller möchte die Daten immer in 512 Byte Blöcken. Also serielle Schnitte einmal öffnen, danach beliebig oft 512 Byte en Block senden und nach Empfang des 512ten Bytes schiebt der USB Controller die Bytes einfach 1:1 raus. | ||
- | |||
- | Gerne würde ich hier jetzt ein Programm einfügen, das die Benutzung der Matrix mit einem MacOS X bzw. Linux Rechner demonstriert. Leider weigert sich dieses idiotische Wiki *.c Dateien als Medien hochzuladen. (" | ||
Zeile 18: | Zeile 28: | ||
{{: | {{: | ||
{{: | {{: | ||
+ | |||
+ | |||
+ | ===== Beispielcode ===== | ||
+ | |||
+ | Das folgende Programm demonstriert die Benutzung der Matrix mit einem MacOS X bzw. Linux Rechner. Wer weitere Fragen dazu hat kann einfach Jochen/ | ||
+ | |||
+ | <file c host_ctrl.c> | ||
+ | /* | ||
+ | * Copyright (c) 2013 Jochen Kunz. | ||
+ | * All rights reserved. | ||
+ | * | ||
+ | * Redistribution and use in source and binary forms, with or without | ||
+ | * modification, | ||
+ | * are met: | ||
+ | * 1. Redistributions of source code must retain the above copyright | ||
+ | | ||
+ | * 2. Redistributions in binary form must reproduce the above copyright | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ | ||
+ | * ``AS IS'' | ||
+ | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
+ | * PURPOSE ARE DISCLAIMED. | ||
+ | * 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 | ||
+ | # | ||
+ | |||
+ | typedef struct { | ||
+ | uint16_t h; | ||
+ | uint8_t s; | ||
+ | uint8_t v; | ||
+ | } hsv_t; | ||
+ | |||
+ | |||
+ | /* | ||
+ | primitive Geradeausimplementierung in Fixkomma nach: | ||
+ | https:// | ||
+ | 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, | ||
+ | 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( " | ||
+ | return -1; | ||
+ | } | ||
+ | if (retval != buf_len) { | ||
+ | printf( "Short write(2) to port, retval=%d", | ||
+ | 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, | ||
+ | memset( rgb_buf, 0, rgb_buf_len); | ||
+ | for (int idx = 0; idx + 2 < rgb_buf_len; | ||
+ | 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, | ||
+ | & | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | 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, | ||
+ | return write_rgb_buf( port_fd, rgb_buf, sizeof( rgb_buf)); | ||
+ | } | ||
+ | |||
+ | |||
+ | void | ||
+ | usage( void) { | ||
+ | fprintf( stderr, " | ||
+ | " | ||
+ | " | ||
+ | "-0: short for \"-h 0 -s 0 -v 0\" | ||
+ | } | ||
+ | |||
+ | |||
+ | int | ||
+ | main( int argc, char* const argv[]) { | ||
+ | const char* port_fn = "/ | ||
+ | hsv_t hsv; | ||
+ | hsv.h = 0; | ||
+ | hsv.s = 0; | ||
+ | hsv.v = 0; | ||
+ | bool zero = false; | ||
+ | int opt; | ||
+ | while ((opt = getopt( argc, argv, " | ||
+ | switch (opt) { | ||
+ | case ' | ||
+ | port_fn = optarg; | ||
+ | break; | ||
+ | case ' | ||
+ | zero = true; | ||
+ | break; | ||
+ | case ' | ||
+ | zero = true; | ||
+ | hsv.h = atoi( optarg); | ||
+ | break; | ||
+ | case ' | ||
+ | zero = true; | ||
+ | hsv.s = atoi( optarg); | ||
+ | break; | ||
+ | case ' | ||
+ | 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( " | ||
+ | return EXIT_FAILURE; | ||
+ | } | ||
+ | if (isatty( port_fd) <= 0 ) { | ||
+ | perror( " | ||
+ | return EXIT_FAILURE; | ||
+ | } | ||
+ | struct termios tio; | ||
+ | if (tcgetattr( port_fd, &tio) < 0) { | ||
+ | perror( " | ||
+ | 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( " | ||
+ | return EXIT_FAILURE; | ||
+ | } | ||
+ | |||
+ | retval &= ~O_NONBLOCK; | ||
+ | retval = fcntl( port_fd, F_SETFL, retval); | ||
+ | if (retval < 0) { | ||
+ | perror( " | ||
+ | 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 = ((idx + loops) % PIXEL_LEN) * ((6 * 255 - 1) / PIXEL_LEN); | ||
+ | hsv_buf[ idx].s = 255; | ||
+ | // | ||
+ | hsv_buf[ idx].v = 255; | ||
+ | // | ||
+ | } | ||
+ | if (write_hsv_buf( port_fd, hsv_buf, PIXEL_LEN) < 0) { | ||
+ | return EXIT_FAILURE; | ||
+ | } | ||
+ | // | ||
+ | } | ||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Metadaten ==== | ||
+ | ---- dataentry projekt ---- | ||
+ | name : ALMA | ||
+ | contact | ||
+ | tags_tags | ||
+ | type : projekt | ||
+ | subtype | ||
+ | sticky_hidden : no | ||
+ | ---- | ||