BlinkenArea - GitList
Repositories
Blog
Wiki
BlinkenLib
Code
Commits
Branches
Tags
Search
Tree:
860e91b
Branches
Tags
master
v0.1
v0.2
v0.3
v0.3.1
v0.4
v0.4.1
v0.5
v0.5.1
v0.5.2
v0.5.3
v0.5.4
v0.5.5
v0.6.0
v0.6.1
v0.6.2
v0.6.3
v0.6.4
v0.6.5
v0.6.6
v0.6.7
v0.6.8
v0.6.9
v0.7.0
v0.7.1
v0.7.10
v0.7.2
v0.7.3
v0.7.4
v0.7.5
v0.7.6
v0.7.7
v0.7.8
v0.7.9
v0.8.0
v0.8.1
BlinkenLib
tools
BlinkenDeviceOutput.c
format
Stefan Schuermans
commited
860e91b
at 2023-08-18 09:55:23
BlinkenDeviceOutput.c
Blame
History
Raw
/* BlinkenLib Copyright 2004-2014 Stefan Schuermans <stefan@schuermans.info> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ /* OS X support by Manfred Wuits <manfred@werkzeugH.at> */ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <sys/types.h> #include <termios.h> #include <time.h> #include <unistd.h> #include <BlinkenLib/BlinkenLib.h> // get serial settings from text static int serial_settings_parse(char *str, int *settings, int *speed) { int baud, data, stop; char parity; int set = 0, sp = 0; // split and parse settings string if (sscanf(str, "%i,%c,%i,%i", &baud, &parity, &data, &stop) != 4) return 0; // baud rate #define BAUD(rate) else if (baud == rate) sp = B##rate; if (0) { } BAUD(300) BAUD(600) BAUD(1200) BAUD(2400) BAUD(4800) BAUD(9600) BAUD(19200) BAUD(38400) BAUD(57600) BAUD(115200) #ifdef B230400 BAUD(230400) #endif #ifdef B460800 BAUD(460800) #endif #ifdef B576000 BAUD(576000) #endif #ifdef B921600 BAUD(921600) #endif #ifdef B1000000 BAUD(1000000) #endif #ifdef B1152000 BAUD(1152000) #endif #ifdef B1500000 BAUD(1500000) #endif #ifdef B2000000 BAUD(2000000) #endif #ifdef B2500000 BAUD(2500000) #endif #ifdef B3000000 BAUD(3000000) #endif #ifdef B3500000 BAUD(3500000) #endif #ifdef B4000000 BAUD(4000000) #endif else { printf("illegal baudrate: %d\n", baud); return 0; } // parity if (parity == 'n' || parity == 'N') set |= 0; else if (parity == 'e' || parity == 'E') set |= PARENB; else if (parity == 'o' || parity == 'O') set |= PARENB | PARODD; else { printf("invalid parity: %c\n", parity); return 0; } // data bits if (data == 5) set |= CS5; else if (data == 6) set |= CS6; else if (data == 7) set |= CS7; else if (data == 8) set |= CS8; else { printf("illegal number of data bits: %d\n", data); return 0; } // stop bits if (stop == 1) set |= 0; else if (stop == 2) set |= CSTOPB; else { printf("illegal number of stop bits: %d\n", stop); return 0; } // success *settings = set; *speed = sp; return 1; } // convert serial settings to text static void serial_settings_to_str(int settings, char *buf, unsigned int maxlen) { int baud, data, stop; char parity; // baud rate if (settings & B300) baud = 300; else if (settings & B600) baud = 600; else if (settings & B1200) baud = 1200; else if (settings & B2400) baud = 2400; else if (settings & B4800) baud = 4800; else if (settings & B9600) baud = 9600; else if (settings & B19200) baud = 19200; else if (settings & B38400) baud = 38400; else if (settings & B57600) baud = 57600; else if (settings & B115200) baud = 115200; else baud = 0; // parity if (settings & PARENB) if (settings & PARODD) parity = 'O'; else parity = 'E'; else parity = 'N'; // data bits if (settings & CS5) data = 5; else if (settings & CS6) data = 6; else if (settings & CS7) data = 7; else if (settings & CS8) data = 8; else data = 0; // stop bits if (settings & CSTOPB) stop = 2; else stop = 1; snprintf(buf, maxlen, "%d,%c,%d,%d", baud, parity, data, stop); } // set serial settings for fd static int serial_settings_set(int fd, int settings, int speed) { struct termios tio; // set port settings bzero(&tio, sizeof(tio)); tio.c_cflag = CLOCAL | HUPCL | CREAD | settings; tio.c_iflag = IGNBRK | IGNPAR; tio.c_oflag = 0; tio.c_lflag = 0; tio.c_cc[VTIME] = 10; // 1 sec timeout tio.c_cc[VMIN] = 0; // return on single char read #ifdef BLINKENLIB_CFG_OSX if (cfsetspeed(&tio, speed) == -1) { printf("cfsetspeed: error: %s\n", strerror(errno)); return 0; } #else // #ifdef BLINKENLIB_CFG_OSX tio.c_cflag |= speed; #endif // #ifdef BLINKENLIB_CFG_OSX if (tcsetattr(fd, TCSANOW, &tio) == -1) { printf("tcsetattr: error: %s\n", strerror(errno)); return 0; } // success return 1; } // output movie // dev_fd may be -1 for not doing anything with device // returns error code (not for device-errors, 0 for success) static int out_movie(stBlinkenMovie *pMovie, int dev_fd, unsigned int format_change, unsigned int format_height, unsigned int format_width, unsigned int format_channels, unsigned int format_colors, etBlinkenProto proto) { int frame_cnt, frame; stBlinkenFrame *pFrame; fd_set readFds, errFds; char buffer[65536]; // 64kB is more than maximum UDP size int maxFd, len, dev_eof, duration, borrow, ret; struct timeval next, cur, timeout; dev_eof = 0; gettimeofday(&next, NULL); frame_cnt = BlinkenMovieGetFrameCnt(pMovie); for (frame = 0; frame < frame_cnt; ++frame) { pFrame = BlinkenMovieGetFrame(pMovie, frame); if (pFrame == NULL) continue; pFrame = BlinkenFrameClone(pFrame); // clone frame, will be changed if (pFrame == NULL) continue; duration = BlinkenFrameGetDuration(pFrame); next.tv_usec += (duration % 1000) * 1000; next.tv_sec += duration / 1000; if (next.tv_usec >= 1000000) { next.tv_usec -= 1000000; next.tv_sec += 1; } // change format if (format_change) BlinkenFrameResize(pFrame, format_height, format_width, format_channels, format_colors - 1); // create output data from frame len = BlinkenFrameToNetwork(pFrame, proto, buffer, sizeof(buffer)); // free frame BlinkenFrameFree(pFrame); // output data to device if (dev_fd != -1 && len > 0) { if (write(dev_fd, buffer, len) != len) { printf("error writing to device\n"); break; } } // check for data from device or error on device do { FD_ZERO(&readFds); if (dev_fd != -1 && !dev_eof) FD_SET(dev_fd, &readFds); FD_ZERO(&errFds); if (dev_fd != -1) FD_SET(dev_fd, &errFds); maxFd = 0; if (dev_fd != -1 && dev_fd > maxFd) maxFd = dev_fd; gettimeofday(&cur, NULL); if (next.tv_usec >= cur.tv_usec) { timeout.tv_usec = next.tv_usec - cur.tv_usec; borrow = 0; } else { borrow = 1; timeout.tv_usec = 1000000 + next.tv_usec - cur.tv_usec; } if (next.tv_sec >= cur.tv_sec + borrow) { timeout.tv_sec = next.tv_sec - (cur.tv_sec + borrow); } else { timeout.tv_usec = 0; timeout.tv_sec = 0; } ret = select(maxFd + 1, &readFds, NULL, &errFds, &timeout); if (ret < 0) { // error printf("error during select: %s\n", strerror(errno)); BlinkenFrameFree(pFrame); break; } // error on device if (dev_fd != -1 && FD_ISSET(dev_fd, &errFds)) { printf("error on device\n"); BlinkenFrameFree(pFrame); break; } // received data from device if (dev_fd != -1 && FD_ISSET(dev_fd, &readFds)) { // read data len = read(dev_fd, buffer, sizeof(buffer)); if (len < 0) { printf("error reading from device\n"); break; } if (len == 0) dev_eof = 1; } } while (ret != 0); } // for frame return 0; } // open device and output movie // returns error code (not for device-errors, 0 for success) static int open_and_output(stBlinkenMovie *pMovie, char *device, int serial_settings_change, int serial_settings, int serial_speed, unsigned int format_change, unsigned int format_height, unsigned int format_width, unsigned int format_channels, unsigned int format_colors, etBlinkenProto proto) { int dev_fd, err; char txt[64]; printf("outputting movie to \"%s\"...\n", device); // open device dev_fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); if (dev_fd == -1) { printf("could not open \"%s\": error: %s\n", device, strerror(errno)); return 1; } // setup serial port if (serial_settings_change) { if (!serial_settings_set(dev_fd, serial_settings, serial_speed)) { serial_settings_to_str(serial_settings, txt, sizeof(txt)); printf("could not set serial port to \"%s\"\n", txt); close(dev_fd); return 1; } } // output movie to device err = out_movie(pMovie, dev_fd, format_change, format_height, format_width, format_channels, format_colors, proto); // close device close(dev_fd); printf("output to device finished...\n"); return err; } int main(int argCnt, char **args) { int i, serial_settings, serial_speed; char *device; etBlinkenProto proto; unsigned int format_change, format_height, format_width, format_channels, format_colors; unsigned int height, width, channels, colors; unsigned int send_cnt, loop_cnt, loop, ui; int serial_settings_change; stBlinkenMovie *pMovie; // print info printf("BlinkenLib - BlinkenDeviceOutput\n" "version %d.%d.%d\n" "config " BLINKENLIB_CONFIG "\n" "Copyright 2004-2014 Stefan Schuermans <stefan@schuermans.info>\n" "Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html\n" "a blinkenarea.org project\n\n", BLINKENLIB_VERSION_MAJOR, BLINKENLIB_VERSION_MINOR, BLINKENLIB_VERSION_REVISION); // print syntax if (argCnt <= 1) { #ifdef BLINKENLIB_CFG_MNG #define MNGEXT ", *.mng" #else #define MNGEXT #endif #ifdef BLINKENLIB_CFG_GIF #define GIFEXT ", *.gif" #else #define GIFEXT #endif printf("syntax: %s <parameter> [...]\n\n" "parameters:\n" " -p [BLP|EBLP|MCUF]\n" " protocol to output frames in (defaults to MCUF)\n" " -f <width>x<height>-<channels>/<colors>\n" " format to output frames in (defaults to no change)\n" " -d <device>\n" " device to output frames to (defaults to \"/dev/null\")\n" " -s <baud-rate>,<parity>,<data-bits>,<stop-bits>\n" " settings to use for serial devices (defaults to no change)\n" " -n <number>\n" " set number of times to send movies (defaults to 1)\n" " -i <file>\n" " read movie from file (*.blm, *.bmm, *.bml, *.bbm" MNGEXT GIFEXT ") and send it\n" " -l <number>\n" " loop number of times (defaults to 1, use 0 for forever)\n\n", args[0]); return 0; } // loop loop_cnt = 1; for (loop = 0; loop < loop_cnt || loop_cnt == 0; loop++) { // print loop message if (loop_cnt > 1) printf("--- loop %u/%u ---\n", loop + 1, loop_cnt); if (loop_cnt == 0) printf("--- loop %u ---\n", loop + 1); // process parameters proto = BlinkenProtoMcuf; format_change = 0; format_height = 0; format_width = 0; format_channels = 0; format_colors = 0; device = "/dev/null"; serial_settings = 0; serial_speed = 0; serial_settings_change = 0; send_cnt = 1; for (i = 1; i < argCnt; i++) { // protocol to output frames in if (strcmp(args[i], "-p") == 0) { if (i + 1 < argCnt) { i++; if (strcasecmp(args[i], "BLP") == 0) proto = BlinkenProtoBlp; else if (strcasecmp(args[i], "EBLP") == 0) proto = BlinkenProtoEblp; else if (strcasecmp(args[i], "MCUF") == 0) proto = BlinkenProtoMcuf; else printf("unknown protocol \"%s\"\n", args[i]); } else printf("missing protocol for \"-p\"\n"); } // format to output frames in else if (strcmp(args[i], "-f") == 0) { if (i + 1 < argCnt) { i++; if (sscanf(args[i], "%ux%u-%u/%u", &width, &height, &channels, &colors) == 4 && width > 0 && width < 1000 && height > 0 && height < 1000 && channels > 0 && channels < 20 && colors > 1 && colors <= 256) { format_change = 1; format_height = height; format_width = width; format_channels = channels; format_colors = colors; } else printf("invalid frame format \"%s\"\n", args[i]); } else printf("missing frame format for \"-r\"\n"); } // device to output frames to else if (strcmp(args[i], "-d") == 0) { if (i + 1 < argCnt) { i++; device = args[i]; } else printf("missing device name for \"-d\"\n"); } // settings for serial output devices else if (strcmp(args[i], "-s") == 0) { if (i + 1 < argCnt) { i++; if (serial_settings_parse(args[i], &serial_settings, &serial_speed)) { serial_settings_change = 1; } else printf("invalid serial settings \"%s\"\n", args[i]); } else printf("missing serial settings for \"-s\"\n"); } // number of times to send movies else if (strcmp(args[i], "-n") == 0) { if (i + 1 < argCnt) { i++; if (sscanf(args[i], "%u", &ui) == 1 && ui > 0) send_cnt = ui; else printf("invalid number \"%s\"\n", args[i]); } else printf("missing number for \"-n\"\n"); } // read movie and send it else if (strcmp(args[i], "-i") == 0) { if (i + 1 < argCnt) { i++; pMovie = BlinkenMovieLoad(args[i]); if (pMovie == NULL) printf("could not read movie \"%s\"\n", args[i]); else { printf("movie \"%s\" read\n", args[i]); for (ui = 0; ui < send_cnt; ui++) { printf("outputting movie \"%s\" (%u/%u)...\n", args[i], ui + 1, send_cnt); if (open_and_output(pMovie, device, serial_settings_change, serial_settings, serial_speed, format_change, format_height, format_width, format_channels, format_colors, proto) == 0) { printf("movie \"%s\" output successful\n", args[i]); } else { printf("movie \"%s\" output failed\n", args[i]); break; } } BlinkenMovieFree(pMovie); } } else printf("missing input filename for \"-i\"\n"); } // number of times to loop else if (strcmp(args[i], "-l") == 0) { if (i + 1 < argCnt) { i++; if (sscanf(args[i], "%u", &ui) == 1) loop_cnt = ui; else printf("invalid number \"%s\"\n", args[i]); } else printf("missing number for \"-l\"\n"); } // unknown parameter else printf( "unknown parameter \"%s\", call without parameters to get help\n", args[i]); } // for( i ... } // for( loop ... return 0; }