/** send data packet to arduino */ NftResult ad_txPacket(struct priv *p, unsigned char opcode, unsigned char *data, unsigned char size) { /* send opcode */ if(write(p->fd, &opcode, 1) == -1) { NFT_LOG_PERROR("write()"); return NFT_FAILURE; } /* send datasize */ if(write(p->fd, &size, 1) == -1) { NFT_LOG_PERROR("write()"); return NFT_FAILURE; } /* send data */ if(write(p->fd, data, (size_t) size) == -1) { NFT_LOG_PERROR("write()"); return NFT_FAILURE; } return NFT_SUCCESS; }
/** * show yes/no dialog and wat for answer */ gboolean ui_log_dialog_yesno( char *title, char *message, ...) { if(!message) NFT_LOG_NULL(false); /* allocate mem to build message */ char *tmp; if(!(tmp = alloca(MAX_MSG_SIZE))) { NFT_LOG_PERROR("alloca"); return false; } /* build message */ va_list ap; va_start(ap, message); /* print log-string */ if(vsnprintf((char *) tmp, MAX_MSG_SIZE, message, ap) < 0) { NFT_LOG_PERROR("vsnprintf"); return false; } va_end(ap); /* Create the widgets */ GtkWidget *dialog, *label, *content_area; dialog = gtk_dialog_new_with_buttons(title, NULL, 0, GTK_STOCK_NO, GTK_RESPONSE_REJECT, GTK_STOCK_YES, GTK_RESPONSE_ACCEPT, NULL); content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); label = gtk_label_new(tmp); /* Add the label, and show everything we've added to the dialog. */ gtk_container_add(GTK_CONTAINER(content_area), label); gtk_widget_show_all(dialog); /* wait for answer */ gboolean result = false; if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) result = true; gtk_widget_destroy(dialog); return result; }
/** * initialize this plugin */ static NftResult _init(void **privdata, LedHardware * hw) { /** create niftylino descriptor */ Niftylino *n; if(!(n = calloc(1, sizeof(Niftylino)))) { NFT_LOG_PERROR("calloc"); return NFT_FAILURE; } /* save Niftylino descriptor as private-data */ *privdata = n; /* initialize default usb timeout */ n->usb_timeout = 2500; /* save our hardware descriptor for later */ n->hw = hw; /* initialize usb subsystem */ usb_init(); /* enable debugging */ int level = 0; if(nft_log_level_is_noisier_than(nft_log_level_get(), L_VERBOSE)) level = 3; else if(nft_log_level_is_noisier_than(nft_log_level_get(), L_INFO)) level = 2; else if(nft_log_level_is_noisier_than(nft_log_level_get(), L_ERROR)) level = 1; usb_set_debug(level); return NFT_SUCCESS; }
/** * called upon plugin load */ static NftResult _init(void **privdata, LedHardware * h) { NFT_LOG(L_INFO, "Initializing plugin..."); /* allocate private structure */ struct priv *p; if(!(p = calloc(1, sizeof(struct priv)))) { NFT_LOG_PERROR("calloc"); return NFT_FAILURE; } /* register our config-structure */ *privdata = p; /* save our hardware descriptor */ p->hw = h; // ~ /* register dynamic property for artnet address */ // ~ if(!led_hardware_plugin_prop_register(h, "address", // LED_HW_CUSTOM_PROP_STRING)) // ~ return NFT_FAILURE; // ~ /* register dynamic property for artnet port / universe */ // ~ if(!led_hardware_plugin_prop_register(h, "port", // LED_HW_CUSTOM_PROP_INT)) // ~ return NFT_FAILURE; return NFT_SUCCESS; }
/** * sample current time */ NftResult led_fps_sample() { if(gettimeofday(&_last, NULL) != 0) { NFT_LOG_PERROR("gettimeofday"); return NFT_FAILURE; } return NFT_SUCCESS; }
/** * show alert/error message * * @param message printable text that will be presented to the user */ void ui_log_alert_show( char *message, ...) { /* just hide when message is NULL */ if(!message) { gtk_widget_set_visible(GTK_WIDGET(UI("alert_dialog")), FALSE); return; } /* allocate mem to build message */ char *tmp; if(!(tmp = alloca(MAX_MSG_SIZE))) { NFT_LOG_PERROR("alloca"); return; } /* build message */ va_list ap; va_start(ap, message); /* print log-string */ if(vsnprintf((char *) tmp, MAX_MSG_SIZE, message, ap) < 0) { NFT_LOG_PERROR("vsnprintf"); return; } va_end(ap); /* putout message through niftyled log mechanism also */ NFT_LOG(L_ERROR, "%s", tmp); /* set message */ gtk_label_set_text(GTK_LABEL(UI("alert_label")), tmp); /* show dialog */ gtk_widget_set_visible(GTK_WIDGET(UI("alert_dialog")), TRUE); }
/** * create preferences minimal buffer from NftPrefsNode - compared to * nft_prefs_node_to_buffer, this doesn't include any encapsulation or headers. * Just the bare information contained in the node. This should be used to * export single nodes, e.g. for copying them to a clipboard * * @param p NftPrefs context * @param n NftPrefsNode * @result string holding xml representation of object (use free() to deallocate) * @note s. @ref nft_prefs_node_to_file for description */ char *nft_prefs_node_to_buffer_minimal(NftPrefs *p, NftPrefsNode * n) { if(!n) NFT_LOG_NULL(NULL); /* result pointer (xml dump) */ char *dump = NULL; /* add prefs version to node */ if(!(_updater_node_add_version(p, n))) { NFT_LOG(L_ERROR, "failed to add version to node \"%s\"", nft_prefs_node_get_name(n)); return NULL; } /* create buffer */ xmlBufferPtr buf; if(!(buf = xmlBufferCreate())) { NFT_LOG(L_ERROR, "failed to xmlBufferCreate()"); return NULL; } /* dump node */ if(xmlNodeDump(buf, n->doc, n, 0, true) < 0) { NFT_LOG(L_ERROR, "xmlNodeDump() failed"); goto _pntb_exit; } /* allocate buffer */ size_t length = xmlBufferLength(buf); if(!(dump = malloc(length + 1))) { NFT_LOG_PERROR("malloc()"); goto _pntb_exit; } /* copy buffer */ strncpy(dump, (char *) xmlBufferContent(buf), length); dump[length] = '\0'; _pntb_exit: xmlBufferFree(buf); return dump; }
/** * initialize stream for ImageMagick */ NftResult im_open_stream(struct Ledcat *c) { #if HAVE_IMAGEMAGICK == 1 /* open a stream (for ImageMagick)? */ if(!c->raw) { /* open stream from file-descriptor */ if(!(c->file = fdopen(c->fd, "r"))) { NFT_LOG_PERROR("fdopen()"); return FALSE; } } #endif return TRUE; }
/** * read a complete raw pixel-frame */ int raw_read_frame(bool *running, char *buf, int fd, size_t size) { ssize_t bytes_to_read, bytes_read = 0; for(bytes_to_read = size; bytes_to_read > 0; bytes_to_read -= bytes_read) { /* read from stdin? */ //~ if(fd == STDIN_FILENO) //~ { //~ /* prepare stuff for select() */ //~ fd_set fds; //~ struct timeval tv; //~ FD_ZERO(&fds); //~ FD_SET(fd, &fds); //~ tv.tv_sec = 0; //~ tv.tv_usec = 500; //~ /* wait for incoming data */ //~ while(*running && (select(1, &fds, NULL, NULL, &tv) == 0)); //~ } /* break loop if we're not running anymore */ if(!*running) break; /* read data into buffer */ if((bytes_read = read(fd, buf, bytes_to_read)) < 0) { NFT_LOG_PERROR("read()"); return 0; } /* end of file? */ if(fd != STDIN_FILENO && bytes_read == 0) break; buf += bytes_read; } return bytes_read; }
/** * called upon plugin load * * You should: * - do any non-hardware initialization/checking here * - register plugin properties * - fill in "privdata" if you want to use a private pointer that's passed to * the plugin in subsequent calls. * * @param privdata space for a private pointer. * @param h LedHardware descriptor belonging to this plugin * @result NFT_SUCCESS or NFT_FAILURE upon error */ static NftResult _init(void **privdata, LedHardware * h) { NFT_LOG(L_DEBUG, "Initializing LDP8806 plugin..."); /* allocate private structure */ struct priv *p; if(!(p = calloc(1, sizeof(struct priv)))) { NFT_LOG_PERROR("calloc"); return NFT_FAILURE; } /* register our config-structure */ *privdata = p; /* save our hardware descriptor */ p->hw = h; /* defaults */ p->ledcount = 0; p->spiMode = SPI_MODE_0; p->spiBPW = 8; p->spiDelay = 0; p->spiSpeed = 500000; /* * register some dynamic properties for this plugin - those will be * set/read in the _get/set_handler() from this plugin */ if(!led_hardware_plugin_prop_register (h, "spi_speed", LED_HW_CUSTOM_PROP_INT)) return NFT_FAILURE; if(!led_hardware_plugin_prop_register (h, "spi_delay", LED_HW_CUSTOM_PROP_INT)) return NFT_FAILURE; return NFT_SUCCESS; }
/** send/receive SPI data */ NftResult spiTxData(int fd, uint8_t * tx, uint32_t len) { /* SPI transfer descriptor */ struct spi_ioc_transfer tr; /* zero initialize */ memset(&tr, 0, sizeof(struct spi_ioc_transfer)); tr.tx_buf = (unsigned long) tx; tr.len = len; tr.cs_change = false; if(ioctl(fd, SPI_IOC_MESSAGE(1), &tr) < 1) { NFT_LOG_PERROR("Failed to send SPI message:"); return NFT_FAILURE; } return NFT_SUCCESS; }
/** * delay until next frame is due */ NftResult led_fps_delay(int fps) { /* get current-time */ struct timeval current; if(gettimeofday(¤t, NULL) != 0) { NFT_LOG_PERROR("gettimeofday"); return NFT_FAILURE; } /* calc delay from fps */ long fps_sec = (1 / fps); long fps_usec = (1000000 / fps); /* delay if frame isn't due yet */ if(((_last.tv_sec + fps_sec) >= current.tv_sec) && ((_last.tv_usec + fps_usec) > current.tv_usec)) { /* calc time to delay */ unsigned long _usec = (_last.tv_usec + fps_usec) - current.tv_usec; unsigned long _sec = (_last.tv_sec + fps_sec) - current.tv_sec; usleep(_usec + (_sec * 1000000)); /* calculate current fps */ _current_fps = 1000000 / ((current.tv_usec - _last.tv_usec + (current.tv_sec - _last.tv_sec) * 1000000) + (_usec + (_sec * 1000000))); } else { /* calculate current fps */ _current_fps = 1000000 / (current.tv_usec - _last.tv_usec + (current.tv_sec - _last.tv_sec) * 1000000); } return NFT_SUCCESS; }
/** * initialize libniftyprefs - call this once before doing any other API call * * @result new NftPrefs descriptor or NULL upon failure */ NftPrefs *nft_prefs_init(unsigned int version) { /* * this initializes the library and check potential ABI mismatches * between the version it was compiled for and the actual shared * library used. */ if(!NFT_PREFS_CHECK_VERSION) return NULL; xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT); /* register error-logging function */ xmlSetGenericErrorFunc(NULL, _xml_error_handler); /* needed for indented output */ xmlKeepBlanksDefault(0); /* allocate new NftPrefs context */ NftPrefs *p; if(!(p = calloc(1, sizeof(NftPrefs)))) { NFT_LOG_PERROR("calloc"); return NULL; } /* save version */ p->version = version; /* allocate array to store classes that will be registered */ if(!_class_init_array(&p->classes)) { NFT_LOG(L_ERROR, "Failed to init class array"); free(p); return NULL; } return p; }
/** * called upon plugin load * * You should: * - do any non-hardware initialization/checking here * - register plugin properties * - fill in "privdata" if you want to use a private pointer that's passed to * the plugin in subsequent calls. * * @param privdata space for a private pointer. * @param h LedHardware descriptor belonging to this plugin * @result NFT_SUCCESS or NFT_FAILURE upon error */ static NftResult _init(void **privdata, LedHardware * h) { NFT_LOG(L_DEBUG, "Initializing arduino-max72xx plugin..."); /* allocate private structure */ struct priv *p; if(!(p = calloc(1, sizeof(struct priv)))) { NFT_LOG_PERROR("calloc"); return NFT_FAILURE; } /* register our config-structure */ *privdata = p; /* save our hardware descriptor */ p->hw = h; /* defaults */ p->ledcount = 0; p->threshold = 128; /* * register some dynamic properties for this plugin - those will be * set/read in the _get/set_handler() from this plugin */ if(!led_hardware_plugin_prop_register (h, "threshold", LED_HW_CUSTOM_PROP_INT)) return NFT_FAILURE; if(!led_hardware_plugin_prop_register (h, "scan_limit", LED_HW_CUSTOM_PROP_INT)) return NFT_FAILURE; return NFT_SUCCESS; }
/** * initialize hardware */ static NftResult _hw_init(void *privdata, const char *id) { NFT_LOG(L_DEBUG, "Initializing arduino-max72xx hardware"); struct priv *p = privdata; /* ... do checks ... */ /* pixelformat supported? */ LedPixelFormat *format = led_chain_get_format(led_hardware_get_chain(p->hw)); if(led_pixel_format_get_bytes_per_pixel(format) != 1) { NFT_LOG(L_ERROR, "This hardware only supports 1 bpp formats (e.g. \"Y u8\")"); return NFT_FAILURE; } if(led_pixel_format_get_n_components(format) != 1) { NFT_LOG(L_ERROR, "This hardware only supports 1 component per pixel (e.g. \"Y u8\")"); return NFT_FAILURE; } const char *fmtstring = led_pixel_format_to_string(led_chain_get_format (led_hardware_get_chain(p->hw))); NFT_LOG(L_DEBUG, "Using \"%s\" as pixel-format", fmtstring); /* * check if id = "*" in this case we should try to automagically find our device, * we'll just use a default in this case */ if(strcmp(id, "*") == 0) { strncpy(p->id, "/dev/ttyUSB0", sizeof(p->id)); } else { /* copy our id (and/or change it) */ strncpy(p->id, id, sizeof(p->id)); } /* open serial port */ if((p->fd = open(p->id, O_RDWR | O_NOCTTY)) == -1) { NFT_LOG(L_ERROR, "Failed to open port \"%s\"", p->id); NFT_LOG_PERROR("open()"); return NFT_FAILURE; } /* save current port settings */ tcgetattr(p->fd, &p->oldtio); /* space for new tio structure */ struct termios newtio; memset(&newtio, 0, sizeof(struct termios)); /* set new port settings */ newtio.c_cflag = B115200 | CS8 | CSTOPB | CLOCAL | CREAD; newtio.c_iflag = IGNPAR | IGNBRK; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VMIN] = 1; newtio.c_cc[VTIME] = 5; tcflush(p->fd, TCIFLUSH); tcsetattr(p->fd, TCSANOW, &newtio); return NFT_SUCCESS; }
/** * create preferences file from NftPrefsNode and child nodes * * This will create the same output as nft_prefs_node_to_file() would but * without all encapsulation/headers/footers/... of the underlying prefs mechanism. * e.g. for XML this omits the "<?xml version="1.0" encoding="UTF-8"?>" header. * This is used when one only needs an "incomplete" snippet of a configuration. * e.g. for copy/paste or to use the XInclude feature of XML * * @param p NftPrefs context * @param n NftPrefsNode * @param filename full path of file to be written * @param overwrite if a file called "filename" already exists, it * will be overwritten if this is "true", otherwise NFT_FAILURE will be returned * @result NFT_SUCCESS or NFT_FAILURE */ NftResult nft_prefs_node_to_file_minimal(NftPrefs *p, NftPrefsNode * n, const char *filename, bool overwrite) { if(!n || !filename) NFT_LOG_NULL(NFT_FAILURE); /* file already existing? */ struct stat sts; if(stat(filename, &sts) == -1) { /* continue if stat error was caused because file doesn't exist */ if(errno != ENOENT) { NFT_LOG(L_ERROR, "Failed to access \"%s\" - %s", filename, strerror(errno)); return NFT_FAILURE; } } /* stat succeeded, file exists */ else if(strcmp("-", filename) != 0) { /* remove old file? */ if(!overwrite) return NFT_FAILURE; /* delete existing file */ if(unlink(filename) == -1) { NFT_LOG(L_ERROR, "Failed to remove old version of \"%s\" - %s", filename, strerror(errno)); return NFT_FAILURE; } } /* overall result */ NftResult r = NFT_FAILURE; /* add prefs version to node */ if(!(_updater_node_add_version(p, n))) { NFT_LOG(L_ERROR, "failed to add version to node \"%s\"", nft_prefs_node_get_name(n)); return r; } /* create buffer */ xmlBufferPtr buf; if(!(buf = xmlBufferCreate())) { NFT_LOG(L_ERROR, "failed to xmlBufferCreate()"); return r; } /* dump node */ if(xmlNodeDump(buf, n->doc, n, 0, true) < 0) { NFT_LOG(L_ERROR, "xmlNodeDump() failed"); goto _pntf_exit; } /* stdout? */ int fd; if(strcmp("-", filename) == 0) { fd = STDOUT_FILENO; } /* open file */ else { #ifdef WIN32 if((fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) #else if((fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP)) == -1) #endif { NFT_LOG_PERROR("open"); goto _pntf_exit; } } /* write to file */ ssize_t length = xmlBufferLength(buf); if(write(fd, (char *) xmlBufferContent(buf), length) != length) { NFT_LOG_PERROR("write"); goto _pntf_exit; } if(fd != STDOUT_FILENO) close(fd); r = NFT_SUCCESS; _pntf_exit: xmlBufferFree(buf); return r; }
/** * create preferences buffer with all format specific encapsulation from a * NftPrefsNode. This is used when one needs a complete configuration. * * @param p NftPrefs context * @param n NftPrefsNode * @result string holding xml representation of object or NULL upon error * @note use free() to deallocate; s. @ref nft_prefs_node_to_file for description */ char *nft_prefs_node_to_buffer(NftPrefs *p, NftPrefsNode * n) { if(!n) NFT_LOG_NULL(NULL); /* add prefs version to node */ if(!(_updater_node_add_version(p, n))) { NFT_LOG(L_ERROR, "failed to add version to node \"%s\"", nft_prefs_node_get_name(n)); return NULL; } /* create copy of node */ NftPrefsNode *copy; if(!(copy = xmlCopyNode(n, 1))) return NULL; /* create temp xmlDoc */ xmlDoc *d = NULL; if(!(d = xmlNewDoc(BAD_CAST "1.0"))) { NFT_LOG(L_ERROR, "Failed to create new XML doc"); xmlFreeNode(copy); return NULL; } /* set node as root element of temporary doc */ xmlDocSetRootElement(d, copy); /* overall result */ char *r = NULL; xmlChar *dump = NULL; int length = 0; /* dump document to buffer */ xmlDocDumpFormatMemoryEnc(d, &dump, &length, "UTF-8", 1); if(!dump || length <= 0) { NFT_LOG(L_ERROR, "Failed to dump XML file"); goto _pntbwh_exit; } if(!(r = malloc(length + 1))) { NFT_LOG_PERROR("malloc"); goto _pntbwh_exit; } memcpy(r, dump, length); r[length] = '\0'; _pntbwh_exit: /* free node */ if(copy) { /* unlink node from document again */ xmlUnlinkNode(copy); xmlFreeNode(copy); } /* free xml buffer */ if(dump) xmlFree(dump); /* free temporary xmlDoc */ if(d) { xmlFreeDoc(d); } return r; }
int main(int argc, char *argv[]) { /** return value of main() */ int res = 1; /* current configuration */ LedPrefs *prefs = NULL; /* current setup */ LedSetup *setup = NULL; /** framebuffer for captured image */ LedFrame *frame = NULL; /* check binary version compatibility */ NFT_LED_CHECK_VERSION /* set default loglevel to INFO */ nft_log_level_set(L_INFO); /* initialize exit handlers */ int signals[] = { SIGHUP, SIGINT, SIGQUIT, SIGABRT }; unsigned int i; for(i=0; i<sizeof(signals)/sizeof(int); i++) { if(signal(signals[i], _exit_signal_handler) == SIG_ERR) { NFT_LOG_PERROR("signal()"); goto _m_exit; } } /* default fps */ _c.fps = 25; /* default mechanism */ _c.method = METHOD_MIN+1; /* default config-filename */ if(!led_prefs_default_filename(_c.prefsfile, sizeof(_c.prefsfile), ".ledcap.xml")) goto _m_exit; /* parse cmdline-arguments */ if(!_parse_args(argc, argv)) goto _m_exit; /* print welcome msg */ NFT_LOG(L_INFO, "%s %s (c) D.Hiepler 2006-2012", PACKAGE_NAME, ledcap_version_long()); NFT_LOG(L_VERBOSE, "Loglevel: %s", nft_log_level_to_string(nft_log_level_get())); /* initialize preferences context */ if(!(prefs = led_prefs_init())) return -1; /* parse prefs-file */ LedPrefsNode *pnode; if(!(pnode = led_prefs_node_from_file(_c.prefsfile))) { NFT_LOG(L_ERROR, "Failed to open configfile \"%s\"", _c.prefsfile); goto _m_exit; } /* create setup from prefs-node */ if(!(setup = led_prefs_setup_from_node(prefs, pnode))) { NFT_LOG(L_ERROR, "No valid setup found in preferences file."); led_prefs_node_free(pnode); goto _m_exit; } /* free preferences node */ led_prefs_node_free(pnode); /* determine width of input-frames */ LedFrameCord width, height; if((width = led_setup_get_width(setup)) > _c.width) { NFT_LOG(L_WARNING, "LED-Setup width (%d) > our width (%d). Using setup-value", width,_c.width); /* use dimensions of mapped chain */ _c.width = width; } /* determine height of input-frames */ if((height = led_setup_get_height(setup)) > _c.height) { NFT_LOG(L_WARNING, "LED-Setup height (%d) > our height (%d). Using setup-value.", height, _c.height); /* use dimensions of mapped chain */ _c.height = height; } if(_c.width < 0) { NFT_LOG(L_ERROR, "width (%d) < 0", _c.width); goto _m_exit; } if(_c.height < 0) { NFT_LOG(L_ERROR, "height (%d) < 0", _c.height); goto _m_exit; } /* sanitize x-offset @todo check for maximum */ if(_c.x < 0) { NFT_LOG(L_ERROR, "Invalid x coordinate: %d, using 0", _c.x); _c.x = 0; } /* sanitize y-offset @todo check for maximum */ if(_c.y < 0) { NFT_LOG(L_ERROR, "Invalid y coordinate: %d, using 0", _c.y); _c.y = 0; } /* initialize capture mechanism (only imlib for now) */ if(!capture_init(_c.method)) goto _m_exit; /* allocate framebuffer */ NFT_LOG(L_INFO, "Allocating frame: %dx%d (%s)", _c.width, _c.height, capture_format()); if(!(frame = led_frame_new(_c.width, _c.height, led_pixel_format_from_string(capture_format())))) goto _m_exit; /* respect endianess */ led_frame_set_big_endian(frame, capture_is_big_endian()); /* get first hardware */ LedHardware *hw; if(!(hw = led_setup_get_hardware(setup))) goto _m_exit; /* initialize pixel->led mapping */ if(!led_hardware_list_refresh_mapping(hw)) goto _m_exit; /* precalc memory offsets for actual mapping */ if(!led_chain_map_from_frame(led_hardware_get_chain(hw), frame)) goto _m_exit; /* set saved gain to all registered hardware instances */ if(!led_hardware_list_refresh_gain(hw)) goto _m_exit; /* print some debug-info */ led_frame_print(frame, L_VERBOSE); led_hardware_print(hw, L_VERBOSE); /* initially sample time for frametiming */ if(!led_fps_sample()) goto _m_exit; /* output some useful info */ NFT_LOG(L_INFO, "Capturing %dx%d pixels at position x/y: %d/%d", _c.width, _c.height, _c.x, _c.y); /* loop until _c.running is set to FALSE */ _c.running = TRUE; while(_c.running) { /* capture frame */ if(!(capture_frame(frame, _c.x, _c.y))) break; /* print frame for debugging */ //led_frame_buffer_print(frame); /* map from frame */ LedHardware *h; for(h = hw; h; h = led_hardware_list_get_next(h)) { if(!led_chain_fill_from_frame(led_hardware_get_chain(h), frame)) { NFT_LOG(L_ERROR, "Error while mapping frame"); break; } } /* send frame to hardware(s) */ led_hardware_list_send(hw); /* delay in respect to fps */ if(!led_fps_delay(_c.fps)) break; /* show frame */ led_hardware_list_show(hw); /* save time when frame is displayed */ if(!led_fps_sample()) break; } /* mark success */ res = 0; _m_exit: /* deinitialize capture mechanism */ capture_deinit(); /* free frame */ led_frame_destroy(frame); /* destroy config */ led_setup_destroy(setup); /* destroy config */ led_prefs_deinit(prefs); return res; }
/** * Object-to-Config function. * Creates a config-node (and subnodes) from a LedHardware model * @param c the current preferences context * @param n a freshly created prefs node that this function should fill with properties of obj * @param obj object of this class where preferences should be generated from * @result NFT_SUCCESS if everything went fine, NFT_FAILURE otherwise * @note you shouldn't call this function directly * It's used by nft_prefs_obj_to_node() etc. */ static NftResult _prefs_from_hardware(NftPrefs * p, NftPrefsNode * n, void *obj, void *userptr) { if(!p || !n || !obj) NFT_LOG_NULL(NFT_FAILURE); /* hardware "object" */ LedHardware *h = obj; /* name of hardware */ if(!nft_prefs_node_prop_string_set(n, LED_HARDWARE_PROP_NAME, (char *) led_hardware_get_name(h))) return NFT_FAILURE; /* plugin family of hardware */ if(!nft_prefs_node_prop_string_set(n, LED_HARDWARE_PROP_PLUGIN, (char *) led_hardware_plugin_get_family (h))) return NFT_FAILURE; /* id of hardware */ if(!nft_prefs_node_prop_string_set(n, LED_HARDWARE_PROP_ID, (char *) led_hardware_get_id(h))) return NFT_FAILURE; /* LED stride */ if(!nft_prefs_node_prop_int_set(n, LED_HARDWARE_PROP_STRIDE, led_hardware_get_stride(h))) return NFT_FAILURE; /* handle custom plugin properties */ int i, a = led_hardware_plugin_prop_get_count(h); for(i = 0; i < a; i++) { LedPluginCustomProp *prop; if(!(prop = led_hardware_plugin_prop_get_nth(h, i))) { NFT_LOG(L_ERROR, "Could not get property %d (but %d registered). This is a bug!", i, a); break; } /* create new node for property */ NftPrefsNode *pnode; if(! (pnode = nft_prefs_node_alloc(LED_HARDWARE_PROPERTY_NAME))) { NFT_LOG(L_ERROR, "Failed to create new node."); return NFT_FAILURE; } /* name of property */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_NAME, (char *) led_hardware_plugin_prop_get_name(prop))) return NFT_FAILURE; /* handle various types of properties */ switch (led_hardware_plugin_prop_get_type(prop)) { case LED_HW_CUSTOM_PROP_STRING: { /* save type */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_TYPE, "string")) return NFT_FAILURE; /* get string */ char *string; if(!led_hardware_plugin_prop_get_string(h, led_hardware_plugin_prop_get_name (prop), &string)) return NFT_FAILURE; /* save value */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_VALUE, string)) return NFT_FAILURE; break; } case LED_HW_CUSTOM_PROP_INT: { /* save type */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_TYPE, "int")) return NFT_FAILURE; /* get integer */ int integer; if(!led_hardware_plugin_prop_get_int(h, led_hardware_plugin_prop_get_name (prop), &integer)) return NFT_FAILURE; /* convert to string */ char *string; if(!(string = alloca(64))) { NFT_LOG_PERROR("alloca"); return NFT_FAILURE; } snprintf(string, 64, "%d", integer); /* save value */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_VALUE, string)) return NFT_FAILURE; break; } case LED_HW_CUSTOM_PROP_FLOAT: { /* save type */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_TYPE, "float")) return NFT_FAILURE; /* get float */ float fp; if(!led_hardware_plugin_prop_get_float(h, led_hardware_plugin_prop_get_name (prop), &fp)) return NFT_FAILURE; /* convert to string */ char *string; if(!(string = alloca(64))) { NFT_LOG_PERROR("alloca"); return NFT_FAILURE; } snprintf(string, 64, "%f", fp); /* save value */ if(!nft_prefs_node_prop_string_set (pnode, LED_HARDWARE_PROPERTY_PROP_VALUE, string)) return NFT_FAILURE; break; } /* unsupported type */ default: { NFT_LOG(L_WARNING, "Property \"%s\" is of unsupported type. Ignoring", led_hardware_plugin_prop_get_name (prop)); continue; } } /* add node as child of this node */ nft_prefs_node_add_child(n, pnode); } /* chain of this hardware */ LedChain *c; if((c = led_hardware_get_chain(h))) { /* generate prefs node from chain */ NftPrefsNode *node; if(!(node = led_prefs_chain_to_node(p, c))) return NFT_FAILURE; /* add node as child of this node */ nft_prefs_node_add_child(n, node); } /* tiles of this hardware */ LedTile *t; for(t = led_hardware_get_tile(h); t; t = led_tile_list_get_next(t)) { NftPrefsNode *node; if(!(node = led_prefs_tile_to_node(p, t))) return NFT_FAILURE; /* add node as child of this node */ nft_prefs_node_add_child(n, node); } /* all OK */ return NFT_SUCCESS; }
int main(int argc, char *argv[]) { /* current configuration */ LedPrefs *p = NULL; /** current setup */ LedSetup *s = NULL; /** list of LED hardware adapters */ LedHardware *hw = NULL; /* input pixel-frame buffer */ LedFrame *frame = NULL; /** width of map */ LedFrameCord width; /** height of map */ LedFrameCord height; /* check libniftyled binary version compatibility */ NFT_LED_CHECK_VERSION /* set default loglevel to INFO */ nft_log_level_set(L_INFO); /* initialize exit handlers */ #if WIN32 int signals[] = { SIGINT, SIGABRT }; #else int signals[] = { SIGHUP, SIGINT, SIGQUIT, SIGABRT }; #endif unsigned int i; for(i=0; i<sizeof(signals)/sizeof(int); i++) { if(signal(signals[i], _exit_signal_handler) == SIG_ERR) { NFT_LOG_PERROR("signal()"); return -1; } } /* default result of main() function */ int res = -1; /* default fps */ _c.fps = 25; /* default endianess */ _c.is_big_endian = FALSE; #if HAVE_IMAGEMAGICK == 1 /* default handle-input-as-raw */ _c.raw = FALSE; #endif /* default looping */ _c.do_loop = FALSE; /* set "running" flag */ _c.running = TRUE; /* default pixel-format */ strncpy(_c.pixelformat, "RGB u8", sizeof(_c.pixelformat)); /* default prefs-filename */ if(!led_prefs_default_filename(_c.prefsfile, sizeof(_c.prefsfile), ".ledcat.xml")) return -1; /* parse commandline arguments */ if(!_parse_args(argc, argv)) return -1; /* print welcome msg */ NFT_LOG(L_INFO, "%s %s (c) D.Hiepler 2006-2012", PACKAGE_NAME, ledcat_version_long()); NFT_LOG(L_VERBOSE, "Loglevel: %s", nft_log_level_to_string(nft_log_level_get())); #if HAVE_IMAGEMAGICK == 1 /* initialize imagemagick */ if(!_c.raw) { if(!im_init(&_c)) { NFT_LOG(L_ERROR, "Failed to initialize ImageMagick"); return -1; } } #endif /* initialize preferences context */ if(!(p = led_prefs_init())) return -1; /* parse prefs-file */ LedPrefsNode *pnode; if(!(pnode = led_prefs_node_from_file(_c.prefsfile))) { NFT_LOG(L_ERROR, "Failed to open configfile \"%s\"", _c.prefsfile); goto m_deinit; } /* create setup from prefs-node */ if(!(s = led_prefs_setup_from_node(p, pnode))) { NFT_LOG(L_ERROR, "No valid setup found in preferences file."); led_prefs_node_free(pnode); goto m_deinit; } /* free preferences node */ led_prefs_node_free(pnode); /* determine width of input-frames */ if(!_c.width) /* width of mapped chain */ width = led_setup_get_width(s); else /* use value from cmdline arguments */ width = _c.width; /* determine height of input-frames */ if(!_c.height) /* height of mapped chain */ height = led_setup_get_height(s); else height = _c.height; /* validate dimensions */ if(width <= 0 || height <= 0) { NFT_LOG(L_ERROR, "Dimensions %dx%d not possible in this universe. Exiting.", width, height); goto m_deinit; } /* allocate frame (where our pixelbuffer resides) */ NFT_LOG(L_INFO, "Allocating frame: %dx%d (%s)", width, height, _c.pixelformat); LedPixelFormat *format = led_pixel_format_from_string(_c.pixelformat); if(!(frame = led_frame_new(width, height, format))) goto m_deinit; /* get first toplevel hardware */ if(!(hw = led_setup_get_hardware(s))) goto m_deinit; /* initialize hardware */ /*if(!(led_hardware_init(hw, ledcount, (LedGreyscaleFormat) format))) { NFT_LOG(L_ERROR, "failed to initialize hardware."); goto m_deinit; }*/ /* initialize pixel->led mapping */ if(!led_hardware_list_refresh_mapping(hw)) goto m_deinit; /* precalc memory offsets for actual mapping */ LedHardware *ch; for(ch = hw; ch; ch = led_hardware_list_get_next(ch)) { if(!led_chain_map_from_frame(led_hardware_get_chain(ch), frame)) goto m_deinit; } /* set correct gain to hardware */ if(!led_hardware_list_refresh_gain(hw)) goto m_deinit; #if HAVE_IMAGEMAGICK == 1 /* determine format that ImageMagick should provide */ if(!_c.raw) { if(!(im_format(&_c, format))) { NFT_LOG(L_ERROR, "Failed to determine valid ImageMagick format"); goto m_deinit; } } #endif /* do we have at least one filename? */ if(!_c.files[0]) { NFT_LOG(L_ERROR, "No input file(s) given"); goto m_deinit; } /* initially sample time for frame-timing */ if(!led_fps_sample()) goto m_deinit; #if ! WIN32 /* initialize alarm-signal handler for periodical fps output */ { struct sigaction sa; struct itimerval timer; memset(&sa, 0, sizeof(sa)); sa.sa_handler = &_alarm_signal_handler; sigaction(SIGALRM, &sa, NULL); timer.it_value.tv_sec = 1; timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 1; timer.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); } #endif /* get data-buffer of frame to write our pixels to */ char *buf; if(!(buf = led_frame_get_buffer(frame))) { NFT_LOG(L_ERROR, "Frame has NULL buffer"); goto m_deinit; } /* walk all files (supplied as commandline arguments) and output them */ int filecount; for(filecount = 0; _c.files[filecount]; filecount++) { NFT_LOG(L_VERBOSE, "Getting pixels from \"%s\"", _c.files[filecount]); /* open file */ if(_c.files[filecount][0] == '-' && strlen(_c.files[filecount]) == 1) { _c.fd = STDIN_FILENO; } else { if((_c.fd = open(_c.files[filecount], O_RDONLY)) < 0) { NFT_LOG(L_ERROR, "Failed to open \"%s\": %s", _c.files[filecount], strerror(errno)); continue; } } #if HAVE_IMAGEMAGICK == 1 /** initialize stream for ImageMagick */ if(!_c.raw) { if(!(im_open_stream(&_c))) continue; } #endif /* output file frame-by-frame */ while(_c.running) { #if HAVE_IMAGEMAGICK == 1 /* use imagemagick to load file if we're not in "raw-mode" */ if(!_c.raw) { /* load frame to buffer using ImageMagick */ if(!im_read_frame(&_c, width, height, buf)) break; } else { #endif /* read raw frame */ if(raw_read_frame(&_c.running, buf, _c.fd, led_pixel_format_get_buffer_size( led_frame_get_format(frame), led_frame_get_width(frame)*led_frame_get_height(frame))) == 0) continue; #if HAVE_IMAGEMAGICK == 1 } #endif /* set endianess (flag will be changed when conversion occurs) */ led_frame_set_big_endian(frame, _c.is_big_endian); /* print frame for debugging */ //nft_frame_buffer_print(frame); /* fill chain of every hardware from frame */ LedHardware *h; for(h = hw; h; h = led_hardware_list_get_next(h)) { if(!led_chain_fill_from_frame(led_hardware_get_chain(h), frame)) { NFT_LOG(L_ERROR, "Error while mapping frame"); break; } } /* send frame to hardware(s) */ NFT_LOG(L_DEBUG, "Sending frame"); led_hardware_list_send(hw); /* delay in respect to fps */ if(!led_fps_delay(_c.fps)) break; /* latch hardware */ NFT_LOG(L_DEBUG, "Showing frame"); led_hardware_list_show(hw); /* save time when frame is displayed */ if(!led_fps_sample()) break; /* clear frame */ //nft_frame_clear_buffer(frame); } #if HAVE_IMAGEMAGICK == 1 if(!_c.raw) im_close_stream(&_c); #else close(_c.fd); #endif /* loop endlessly? */ if((_c.running) && (!_c.files[filecount+1]) && _c.do_loop) { /* start over by resetting the for-loop */ filecount = -1; } } /* all ok */ res = 0; m_deinit: /* free setup */ led_setup_destroy(s); /* free frame */ led_frame_destroy(frame); /* destroy config */ led_prefs_deinit(p); #if HAVE_IMAGEMAGICK == 1 /* deinitialize ImageMagick */ im_deinit(&_c); #endif return res; }
/** * initialize hardware */ static NftResult _spi_init(void *privdata, const char *id) { NFT_LOG(L_DEBUG, "Initializing LDP8806 hardware"); struct priv *p = privdata; /* pixelformat supported? */ LedPixelFormat *format = led_chain_get_format(led_hardware_get_chain(p->hw)); const char *fmtstring = led_pixel_format_to_string(format); int bytes_per_pixel = led_pixel_format_get_bytes_per_pixel(format); int components_per_pixel = led_pixel_format_get_n_components(format); int bytes_per_component = bytes_per_pixel / components_per_pixel; if(bytes_per_component != 1) { NFT_LOG(L_ERROR, "We need a format with 8 bits per pixel-component. Format %s has %d bytes-per-pixel and %d components-per-pixel.", fmtstring, bytes_per_pixel, components_per_pixel); return NFT_FAILURE; } NFT_LOG(L_DEBUG, "Using \"%s\" as pixel-format", fmtstring); /* * check if id = "*" in this case we should try to automagically find our device, * we'll just use a default in this case * @todo cycle through all devices */ if(strcmp(id, "*") == 0) { strncpy(p->id, "/dev/spidev0.0", sizeof(p->id)); } else { /* copy our id (and/or change it) */ strncpy(p->id, id, sizeof(p->id)); } /* open SPI port */ if((p->fd = open(p->id, O_RDWR)) == -1) { NFT_LOG(L_ERROR, "Failed to open port \"%s\"", p->id); NFT_LOG_PERROR("open()"); return NFT_FAILURE; } /* Set SPI parameters */ if(ioctl(p->fd, SPI_IOC_WR_MODE, &p->spiMode) < 0) return NFT_FAILURE; if(ioctl(p->fd, SPI_IOC_RD_MODE, &p->spiMode) < 0) return NFT_FAILURE; if(ioctl(p->fd, SPI_IOC_WR_BITS_PER_WORD, &p->spiBPW) < 0) return NFT_FAILURE; if(ioctl(p->fd, SPI_IOC_RD_BITS_PER_WORD, &p->spiBPW) < 0) return NFT_FAILURE; if(ioctl(p->fd, SPI_IOC_WR_MAX_SPEED_HZ, &p->spiSpeed) < 0) return NFT_FAILURE; if(ioctl(p->fd, SPI_IOC_RD_MAX_SPEED_HZ, &p->spiSpeed) < 0) return NFT_FAILURE; NFT_LOG(L_DEBUG, "SPI \"%d\" initialized (mode: %d, bits-per-word: %d, speed-hz: %d)", p->spiMode, p->spiBPW, p->spiSpeed); return NFT_SUCCESS; }
/** * allocate a fresh slot from array so the pointer to the slot element can be * received with nft_array_get_slot() * * @param a NftArray descriptor * @param s pointer where new free slot will be written to * @result NFT_SUCCESS or NFT_FAILURE * @note Use nft_array_free_slot() if you don't need the slot anymore */ NftResult nft_array_slot_alloc(NftArray * a, NftArraySlot * s) { if(!a) NFT_LOG_NULL(NFT_FAILURE); /* enough space left? */ if(a->arraysize <= a->elementcount) { /* increase element descriptor array by NFT_ARRAY_INC elements */ if(!(a->elements = realloc(a->elements, /* total elements new array can hold */ (a->arraysize + NFT_ARRAY_DEFAULT_INC) * /* size of one element descriptor */ (sizeof(NftElement))))) { NFT_LOG_PERROR("realloc()"); return NFT_FAILURE; } /* increase element buffer by NFT_ARRAY_INC elements */ if(!(a->buffer = realloc(a->buffer, (a->arraysize + NFT_ARRAY_DEFAULT_INC) * a->elementsize))) { NFT_LOG_PERROR("realloc()"); return NFT_FAILURE; } /* clear new memory */ memset(&a->elements[a->arraysize], 0, NFT_ARRAY_DEFAULT_INC * sizeof(NftElement)); memset(&a->buffer[a->elementsize * a->arraysize], 0, NFT_ARRAY_DEFAULT_INC * a->elementsize); /* remember new arraysize */ a->arraysize += NFT_ARRAY_DEFAULT_INC; } /* find free slot in list */ NftArraySlot i; for(i = 0; i < a->arraysize; i++) { if(!a->elements[i].occupied) { /* set element as occupied */ a->elements[i].occupied = TRUE; /* another element allocated... */ a->elementcount++; /* save slot */ *s = i; return NFT_SUCCESS; } } /* huh? */ NFT_LOG(L_ERROR, "No free slot found in array \"%s\" but buffer was not increased. Something went wrong! Expect fancy stuff.", nft_array_get_name(a)); return NFT_FAILURE; }