/** function to generate a People "object" from a preferences description */ static NftResult _people_from_prefs(NftPrefs *p, void **newObj, NftPrefsNode *node, void *userptr) { people.people_count = sizeof(persons)/sizeof(struct Person); /* call toObj() of child objects */ NftPrefsNode *child; size_t i = 0; for(child = nft_prefs_node_get_first_child(node); child; child = nft_prefs_node_get_next(child)) { if(i >= sizeof(persons)/sizeof(struct Person)) { NFT_LOG(L_ERROR, "more persons in prefs file than expected"); return NFT_FAILURE; } /* call toObj function of child node (should be a <person> node) */ if(!(people.people[i++] = nft_prefs_obj_from_node(p, child, userptr))) { NFT_LOG(L_ERROR, "Failed to create object from preference node"); return NFT_FAILURE; } } /* save pointer to new object */ *newObj = &people; return NFT_SUCCESS; }
/** * register object class * * @param p NftPrefs context where new class should be registered to * @param className unique name of new class * @param toObj pointer to NftPrefsToObjFunc used by the new class * @param fromObj pointer to NftPrefsFromObjFunc used by the new class * @result NFT_SUCCESS or NFT_FAILURE */ NftResult nft_prefs_class_register(NftPrefs * p, const char *className, NftPrefsToObjFunc * toObj, NftPrefsFromObjFunc * fromObj) { if(!p || !className) NFT_LOG_NULL(NFT_FAILURE); if(strlen(className) == 0) { NFT_LOG(L_ERROR, "class name may not be empty"); return NFT_FAILURE; } /** check if class is already registered */ NFT_LOG(L_DEBUG, "Checking if another class \"%s\" is already registered...", className); if(prefs_class_find_by_name(prefs_classes(p), className)) { NFT_LOG(L_ERROR, "class named \"%s\" already registered", className); return NFT_FAILURE; } /** allocate new slot in class array */ NftArraySlot s; if(!(nft_array_slot_alloc(prefs_classes(p), &s))) { NFT_LOG(L_ERROR, "Failed to allocate new slot"); return NFT_FAILURE; } /* get empty array element */ NftPrefsClass *n; if(!(n = nft_array_get_element(prefs_classes(p), s))) { NFT_LOG(L_ERROR, "Failed to get element from array"); goto _pcr_error; } /* register new class */ strncpy(n->name, className, NFT_PREFS_MAX_CLASSNAME); n->toObj = toObj; n->fromObj = fromObj; n->slot = s; return NFT_SUCCESS; _pcr_error: nft_array_slot_free(prefs_classes(p), s); return NFT_FAILURE; }
/** function to update a Person prefs-node from version 0 to version 1 */ NftResult _update_person(NftPrefsNode *node, unsigned int version, void *userptr) { /* get "email" property from node */ char *email; if(!(email = nft_prefs_node_prop_string_get(node, "email"))) { NFT_LOG(L_ERROR, "failed to get \"email\" property from node \"%s\"", nft_prefs_node_get_name(node)); return NFT_FAILURE; } /* function result */ NftResult result = NFT_FAILURE; /* split "email" property into "email_user" and "email_host" */ char *email_user = strtok(email, "@"); char *email_host = strtok(NULL, "@"); NFT_LOG(L_NOTICE, "Extracted email_host: \"%s\" and email_user: \"%s\"", email_user, email_host); /* add new "email_user" property to node */ if(!(nft_prefs_node_prop_string_set(node, "email_user", email_user))) { NFT_LOG(L_ERROR, "failed to set \"email_user\" property to \"%s\"", email_user); goto _up_exit; } /* add new "email_user" property to node */ if(!(nft_prefs_node_prop_string_set(node, "email_host", email_host))) { NFT_LOG(L_ERROR, "failed to set \"email_host\" property to \"%s\"", email_host); goto _up_exit; } /* remove old "email" property */ if(!(nft_prefs_node_prop_unset(node, "email"))) { NFT_LOG(L_ERROR, "failed to remove \"email\" property from node."); goto _up_exit; } result = NFT_SUCCESS; _up_exit: /* free string */ nft_prefs_free(email); return result; }
/** function to generate a Person "object" from a preferences description */ static NftResult _person_from_prefs(NftPrefs *p, void **newObj, NftPrefsNode *node, void *userptr) { static size_t i; /* only fill reserved space, not more */ if(i >= sizeof(persons)/sizeof(struct Person)) return NFT_FAILURE; char *name; if(!(name = nft_prefs_node_prop_string_get(node, "name"))) { NFT_LOG(L_ERROR, "failed to get property \"name\" from prefs-node"); return NFT_FAILURE; } char *email; if(!(email = nft_prefs_node_prop_string_get(node, "email"))) { NFT_LOG(L_ERROR, "failed to get property \"email\" from prefs-node"); return NFT_FAILURE; } int age; if(!nft_prefs_node_prop_int_get(node, "age", &age)) { NFT_LOG(L_ERROR, "failed to get property \"age\" from prefs-node"); return NFT_FAILURE; } bool alive; if(!nft_prefs_node_prop_boolean_get(node, "alive", &alive)) { NFT_LOG(L_ERROR, "failed to get property \"alive\" from prefs-node"); return NFT_FAILURE; } strncpy(persons[i].name, name, sizeof(persons[i].name)); strncpy(persons[i].email, email, sizeof(persons[i].email)); persons[i].age = age; persons[i].alive = alive; /* free strings */ nft_prefs_free(name); nft_prefs_free(email); /* save pointer to new object */ *newObj = &persons[i++]; return NFT_SUCCESS; }
/** * create new NftPrefsNode from preferences file * * @param p NftPrefs context * @param filename full path of file * @result newly created NftPrefsNode or NULL */ NftPrefsNode *nft_prefs_node_from_file(NftPrefs *p, const char *filename) { if(!filename) NFT_LOG_NULL(NULL); /* parse XML */ xmlDocPtr doc; if(!(doc = xmlReadFile(filename, NULL, 0))) { NFT_LOG(L_ERROR, "Failed to xmlReadFile(\"%s\")", filename); return NULL; } /* parse XInclude stuff */ int xinc_res; if((xinc_res = xmlXIncludeProcess(doc)) == -1) { NFT_LOG(L_ERROR, "XInclude parsing failed."); goto _npnff_error; } NFT_LOG(L_DEBUG, "%d XInclude substitutions done", xinc_res); /* get node */ xmlNode *node; if(!(node = xmlDocGetRootElement(doc))) { NFT_LOG(L_ERROR, "No root element found in XML"); goto _npnff_error; } /* update node */ if(!_updater_node_process(p, node)) { NFT_LOG(L_ERROR, "Preference update failed for node \"%s\". This is a fatal bug. Aborting.", nft_prefs_node_get_name(node)); goto _npnff_error; } /* return node */ return node; _npnff_error: xmlFreeDoc(doc); return NULL; }
/** * 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; }
/** * 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; }
/** * capture image */ static NftResult _capture(LedFrame *frame, LedFrameCord x, LedFrameCord y) { if(!frame) NFT_LOG_NULL(NFT_FAILURE); /* get screen-portion from X server */ XImage *image = NULL; if(!(image = XGetImage(_c.display, RootWindow(_c.display, _c.screen), x, y, led_frame_get_width(frame), led_frame_get_height(frame), AllPlanes, ZPixmap))) { NFT_LOG(L_ERROR, "XGetImage() failed"); return NFT_FAILURE; } /* copy framebuffer */ memcpy(led_frame_get_buffer(frame), image->data, led_frame_get_buffersize(frame)); /* destroy images */ XDestroyImage(image); return NFT_SUCCESS; }
/** * plugin getter - this will be called if core wants to get stuff */ NftResult _get_handler(void *privdata, LedPluginParam o, LedPluginParamData * data) { Niftylino *n = privdata; /** decide about object to give back to the core (s. hardware.h) */ switch (o) { case LED_HW_ID: { data->id = n->id; return NFT_SUCCESS; } case LED_HW_LEDCOUNT: { data->ledcount = n->ledcount; return NFT_SUCCESS; } default: { NFT_LOG(L_ERROR, "Request to get unhandled object from plugin"); return NFT_FAILURE; } } return NFT_FAILURE; }
/** * determine format that ImageMagick should provide */ NftResult im_format(struct Ledcat *c, LedPixelFormat *format) { #if HAVE_IMAGEMAGICK == 1 /* determine map format for MagickGetImagePixels */ strncpy(c->map, led_pixel_format_colorspace_to_string(format), sizeof(c->map)); /* determine storage format for MagickGetImagePixels */ char type[16]; strncpy(type, led_pixel_format_get_component_type(format, 0), sizeof(type)); if(strncmp(type, "u8", sizeof(type)) == 0) c->storage = CharPixel; else if(strncmp(type, "u16", sizeof(type)) == 0) c->storage = ShortPixel; else if(strncmp(type, "u32", sizeof(type)) == 0) c->storage = IntegerPixel; else if(strncmp(type, "u64", sizeof(type)) == 0) c->storage = LongPixel; else if(strncmp(type, "double", sizeof(type)) == 0) c->storage = DoublePixel; else if(strncmp(type, "float", sizeof(type)) == 0) c->storage = FloatPixel; else { NFT_LOG(L_ERROR, "Unhandled pixel-format: \"%s\"", type); return FALSE; } #endif return TRUE; }
/** menuitem "save" selected */ G_MODULE_EXPORT void on_action_setup_save_activate(GtkAction * a, gpointer u) { if(!ui_setup_save(NULL)) { NFT_LOG(L_ERROR, "Error while saving current setup."); return; } }
/** * trigger hardware to show data * * - if you previously uploaded your data to your hardware, output it now to LEDs * - if you can't do this, try to send all data except last bit/value/... in * _send() so that sent data is not immediately visible. Then send last portion here * - if you can't do this, send all data here as quick as possible :) */ NftResult _show(void *privdata) { NFT_LOG(L_DEBUG, "Showing arduino-max72xx data"); struct priv *p = privdata; ad_latch(p); return NFT_SUCCESS; }
/** * deinitialize hardware */ static void _spi_deinit(void *privdata) { NFT_LOG(L_DEBUG, "Deinitializing LDP8806 hardware"); struct priv *p = privdata; close(p->fd); /* free buffer */ // free(p->txBuffer); }
/** * ImageMagick error-handler */ void im_error(MagickWand *wand) { #if HAVE_IMAGEMAGICK == 1 char *description; ExceptionType severity; description = MagickGetException(wand, &severity); NFT_LOG(L_ERROR, "%s %s %lu %s\n", GetMagickModule(), description); description = (char *) MagickRelinquishMemory(description); #endif }
/** * trigger hardware to show data * * - if you previously uploaded your data to your hardware, output it now to LEDs * - if you can't do this, try to send all data except last bit/value/... in * _send() so that sent data is not immediately visible. Then send last portion here * - if you can't do this, send all data here as quick as possible :) */ NftResult _show(void *privdata) { NFT_LOG(L_DEBUG, "Showing LDP8806 data"); struct priv *p = privdata; /* send zero byte to latch */ uint8_t latch = 0; return spiTxData(p->fd, &latch, 1); }
/** * plugin setter - this will be called if core wants to set stuff */ NftResult _set_handler(void *privdata, LedPluginParam o, LedPluginParamData * data) { Niftylino *n = privdata; /** decide about type of data (s. hardware.h) */ switch (o) { case LED_HW_GAIN: { return _set_gain(n, data->gain.pos, data->gain.value); } case LED_HW_ID: { NFT_LOG(L_DEBUG, "Setting \"%s\" ID: %s", led_hardware_get_name(n->hw), data->id); strncpy(n->id, data->id, sizeof(n->id)); return NFT_SUCCESS; } case LED_HW_LEDCOUNT: { NFT_LOG(L_DEBUG, "Setting \"%s\" to ledcount: %d", led_hardware_get_name(n->hw), data->ledcount); if(!_set_ledcount(n, data->ledcount)) return NFT_FAILURE; n->ledcount = data->ledcount; return NFT_SUCCESS; } default: { return NFT_SUCCESS; } } return NFT_FAILURE; }
/** * called upon plugin unload. Hardware will be deinitialized before that. * * You should: * - unregister all properties you registered before * - finally free all resources you needed * */ static void _deinit(void *privdata) { NFT_LOG(L_DEBUG, "Deinitializing LDP8806 plugin..."); struct priv *p = privdata; /* unregister or settings-handlers */ led_hardware_plugin_prop_unregister(p->hw, "spi_speed"); led_hardware_plugin_prop_unregister(p->hw, "spi_delay"); /* free structure we allocated in _init() */ free(privdata); }
/** * called upon plugin unload. Hardware will be deinitialized before that. */ static void _deinit(void *privdata) { NFT_LOG(L_INFO, "Deinitializing plugin..."); // struct priv *p = privdata; /* unregister dynamic properties */ // ~ led_hardware_plugin_prop_unregister(p->hw, "address"); // ~ led_hardware_plugin_prop_unregister(p->hw, "port"); /** free structure we allocated in _init() */ free(privdata); }
/** * deinitialize hardware */ static void _hw_deinit(void *privdata) { NFT_LOG(L_DEBUG, "Deinitializing arduino-max72xx hardware"); struct priv *p = privdata; /* restore old serial port settings */ tcflush(p->fd, TCIFLUSH); tcsetattr(p->fd, TCSANOW, &p->oldtio); /* close serial port */ close(p->fd); }
/** find class by name */ NftPrefsClass *prefs_class_find_by_name(NftPrefsClasses * c, const char *name) { /* find class in array */ NftArraySlot slot; if(!nft_array_find_slot (c, &slot, _class_find_by_name, (void *) name, NULL)) { NFT_LOG(L_DEBUG, "Class \"%s\" not found", name); return NULL; } return nft_array_get_element(c, slot); }
/** "save" button in filechooser clicked */ G_MODULE_EXPORT void on_setup_save_save_clicked(GtkButton * b, gpointer u) { char *filename; if(!(filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (_ui ("filechooserdialog_save"))))) { NFT_LOG(L_ERROR, "No filename received from dialog."); return; } if(!ui_setup_save(filename)) { NFT_LOG(L_ERROR, "Error while saving file \"%s\"", filename); goto osssc_exit; } gtk_widget_hide(GTK_WIDGET(_ui("filechooserdialog_save"))); osssc_exit: g_free(filename); }
/** * get URI of document this node was parsed from (or NULL) * * @result URI of node origin or NULL if unset */ const char *nft_prefs_node_get_uri(NftPrefsNode * n) { if(!n) NFT_LOG_NULL(NULL); if(!n->doc) { NFT_LOG(L_DEBUG, "node \"%s\" has no uri set.", nft_prefs_node_get_name(n)); return NULL; } return (const char *) n->doc->URL; }
/** * send data in chain to hardware (only use this if hardware doesn't show data right after * data is received to avoid blanking. If the data is shown immediately, you have * to transmit it in _show() */ NftResult _send(void *privdata, LedChain * c, LedCount count, LedCount offset) { NFT_LOG(L_DEBUG, "Sending arduino-max72xx data"); struct priv *p = privdata; /* 8 bits-per-pixel buffer as given by niftyled */ unsigned char *buffer = led_chain_get_buffer(c); /* 1 bit-per-pixel buffer as needed by arduino */ unsigned char packed[64]; /* clear buffer */ memset(packed, 0, sizeof(packed)); /* convert to 8bpp to 1bpp */ LedCount i; for(i = 0; i < p->ledcount; i++) { packed[i / 8] = packed[i / 8] << 1; if(buffer[i] >= p->threshold) packed[i / 8] |= 1; } NFT_LOG(L_NOISY, "Packed buffer: %x %x %x %x %x %x %x %x", packed[0], packed[1], packed[2], packed[3], packed[4], packed[5], packed[6], packed[7]); /* send buffer */ ad_sendBuffer(p, packed, (p->ledcount % 8 == 0 ? p->ledcount / 8 : p->ledcount / 8 + 1)); return NFT_SUCCESS; }
/** * initialize hardware */ static NftResult _hw_init(void *privdata, const char *id) { NFT_LOG(L_DEBUG, "Initializing dummy hardware"); // ~ struct priv *p = privdata; // ~ /* ... do checks ... */ // ~ /* copy our id (and/or change it; check for "*" wildcard) */ // ~ strncpy(p->id, id, sizeof(p->id)); return NFT_SUCCESS; }
/** New setup */ G_MODULE_EXPORT void on_action_setup_new_activate(GtkAction * a, gpointer u) { LedSetup *s; if(!(s = led_setup_new())) { NFT_LOG(L_ERROR, "Failed to create new settings descriptor."); return; } /* save new settings */ setup_register_to_gui(s); setup_set_current_filename("Unnamed.xml"); ui_setup_tree_clear(); ui_renderer_all_queue_draw(); }
/** * check if NftArraySlot is plausible * * @param a NftArray descriptor * @param s NftArraySlot * @result TRUE if slot is plausible, FALSE otherwise */ static bool _slot_is_valid(NftArray * a, NftArraySlot s) { if(!a) NFT_LOG_NULL(FALSE); if(s >= a->arraysize) { NFT_LOG(L_ERROR, "requested slot %d from array \"%s\" that only has %d slots", s + 1, nft_array_get_name(a), a->arraysize); return FALSE; } return TRUE; }
/** * send data in chain to hardware (only use this if hardware doesn't show data right after * data is received to avoid blanking. If the data is shown immediately, you have * to transmit it in _show() */ NftResult _send(void *privdata, LedChain * c, LedCount count, LedCount offset) { NFT_LOG(L_DEBUG, "Sending LDP8806 data"); struct priv *p = privdata; uint8_t *buf = led_chain_get_buffer(c); /* seek to offset */ int bytes_per_component = led_chain_get_buffer_size(c) / led_chain_get_ledcount(c); buf += offset * bytes_per_component; /* send buffer */ return spiTxData(p->fd, buf, bytes_per_component * count); }
/** * called upon plugin unload. Hardware will be deinitialized before that. * * You should: * - unregister all properties you registered before * - finally free all resources you needed * */ static void _deinit(void *privdata) { NFT_LOG(L_DEBUG, "Deinitializing arduino-max72xx plugin..."); struct priv *p = privdata; /* unregister or settings-handlers */ led_hardware_plugin_prop_unregister(p->hw, "threshold"); led_hardware_plugin_prop_unregister(p->hw, "scan_limit"); /* free buffer */ free(p->buffer); /* free structure we allocated in _init() */ free(privdata); }
/** * generate LedChain from LedPrefsNode * * @param p LedPrefs context * @param n LedPrefsNode * @result newly created LedChain */ LedChain *led_prefs_chain_from_node(LedPrefs * p, LedPrefsNode * n) { if(!p || !n) NFT_LOG_NULL(NULL); /* check if node is of expected class */ if(!led_prefs_is_chain_node(n)) { NFT_LOG(L_ERROR, "got wrong LedPrefsNode class. Expected \"%s\" but got \"%s\"", LED_CHAIN_NAME, nft_prefs_node_get_name(n)); return NULL; } return nft_prefs_obj_from_node(p, n, NULL); }
/** * generate LedHardware from LedPrefsNode * * @param p LedPrefs context * @param n LedPrefsNode * @result newly created LedHardware */ LedHardware *led_prefs_hardware_from_node(LedPrefs * p, LedPrefsNode * n) { if(!p || !n) NFT_LOG_NULL(NULL); /* check if node is of expected class */ if(strcmp(nft_prefs_node_get_name(n), LED_HARDWARE_NAME) != 0) { NFT_LOG(L_ERROR, "got wrong LedPrefsNode class. Expected \"%s\" but got \"%s\"", LED_HARDWARE_NAME, nft_prefs_node_get_name(n)); return NULL; } return nft_prefs_obj_from_node(p, n, NULL); }