BlinkenArea - GitList
Repositories
Blog
Wiki
libflexipix
Code
Commits
Branches
Tags
Search
Tree:
aa3270a
Branches
Tags
master
v1.0.0
v1.0.1
v1.0.2
v1.0.3
v1.0.4
v1.0.5
v1.0.6
v1.0.7
v1.0.8
libflexipix
src
displayer.c
removed version information from file headers (manged via git now)
Stefan Schuermans
commited
aa3270a
at 2011-09-11 17:30:15
displayer.c
Blame
History
Raw
/* * FlexiPix library * * Copyright 2010-2011 Stefan Schuermans <stefan schuermans info> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <sys/time.h> #include <stdlib.h> #include <flexipix/display.h> #include <flexipix/displayer.h> #include <flexipix/msg.h> #include <flexipix/types.h> #include <intern/displayer.h> #include <intern/thread.h> #include <intern/types.h> /** * \brief create a new FlexiPix displayer * * A displayer manages a display and ensures that a the current * image data is sent often enough to the distributors so * that the pixels do detect a timeout and turn off automatically. * The displayer uses a thread to do this. * Initially, the new displayer is inactive and has to be activated * using flp_displayer_activate(). * * \param[in] sz_config_file name of config file to read * \param[in] p_msg_func message callback function or NULL * \param[in] p_msg_ctx user context for message callback * \return pointer to new FlexiPix displayer on success * or NULL on error */ flp_displayer_t *flp_displayer_create(const char *sz_config_file, flp_msg_func_p_t p_msg_func, void *p_msg_ctx) { flp_displayer_t *p_displayer; /* set up basic structure and display */ /* create displayer structure */ p_displayer = (flp_displayer_t *)calloc(1, sizeof (flp_displayer_t)); if (!p_displayer) { if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_err, "out of memory\n"); return NULL; } /* set up flags */ p_displayer->active = 0; /* not sending data to distributors */ p_displayer->send = 1; /* send first data as soon as active */ p_displayer->end = 0; /* do not end yet */ /* set up managed display */ p_displayer->p_display = flp_display_create(sz_config_file, p_msg_func, p_msg_ctx); if (!p_displayer->p_display) { free(p_displayer); if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_err, "could not create display\n"); return NULL; } /* set up output thread */ /* initialize mutex */ if (!flp_thread_mutex_init(&p_displayer->mtx)) { flp_display_free(p_displayer->p_display); free(p_displayer); if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_err, "could not initialize mutex\n"); return NULL; } /* initialize condition */ if (!flp_thread_cond_init(&p_displayer->cond)) { flp_thread_mutex_destroy(&p_displayer->mtx); flp_display_free(p_displayer->p_display); free(p_displayer); if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_err, "could not initialize condition\n"); return NULL; } /* create thread */ if (!flp_thread_create(&p_displayer->tid, flp_displayer_thread, (void *)p_displayer)) { flp_thread_cond_destroy(&p_displayer->cond); flp_thread_mutex_destroy(&p_displayer->mtx); flp_display_free(p_displayer->p_display); free(p_displayer); if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_err, "could not create thread\n"); return NULL; } return p_displayer; } /** * \brief free a FlexiPix displayer * * \param[in] p_displayer pointer to FlexiPix displayer */ void flp_displayer_free(flp_displayer_t *p_displayer) { /* tear down thread */ p_displayer->end = 1; flp_thread_cond_signal(&p_displayer->cond); flp_thread_join(p_displayer->tid); flp_thread_cond_destroy(&p_displayer->cond); flp_thread_mutex_destroy(&p_displayer->mtx); /* free managed display */ flp_display_free(p_displayer->p_display); /* free basic structure */ free(p_displayer); } /** * \brief get size of display managed by displayer * * \param[in] p_displayer pointer to FlexiPix displayer * \param[out] p_width width of display * \param[out] p_height height of display */ void flp_displayer_get_size(flp_displayer_t *p_displayer, unsigned int *p_width, unsigned int *p_height) { flp_thread_mutex_lock(&p_displayer->mtx); flp_display_get_size(p_displayer->p_display, p_width, p_height); flp_thread_mutex_unlock(&p_displayer->mtx); } /** * \brief activate the displayer * * set the displayer to active, i.e. make it send image data * to the distributors automatically, * this function might trigger sending of data if the last * sending time was too long ago * * \param[in] p_displayer pointer to FlexiPix displayer */ void flp_displayer_activate(flp_displayer_t *p_displayer) { p_displayer->active = 1; flp_thread_cond_signal(&p_displayer->cond); } /** * \brief deactivate the displayer * * set the displayer to deactive, i.e. prevent it from sening image * data to the distributors automatically, * * \param[in] p_displayer pointer to FlexiPix displayer */ void flp_displayer_deactivate(flp_displayer_t *p_displayer) { p_displayer->active = 0; /* no need to signal condition: thread does not need to do something yet */ } /** * \brief clear image data to output on FlexiPix displayer * * clears the stored image data * * \param[in] p_displayer pointer to FlexiPix displayer */ void flp_displayer_data_clear(flp_displayer_t *p_displayer) { flp_thread_mutex_lock(&p_displayer->mtx); flp_display_data_clear(p_displayer->p_display); flp_thread_mutex_unlock(&p_displayer->mtx); } /** * \brief set image data to output on FlexiPix display * * updates (part of) the stored image data * * \param[in] p_displayer pointer to FlexiPix displayer * \param[in] p_data pointer to rectangular section of image data, * pixels need to be in R8G8B8 format * \param[in] stride_x stride between two pixels in X direction * \param[in] stride_y stride between two pixels in Y direction * \param[in] x X coordinate of left side of rectangular area * \param[in] y Y coordinate of top side of rectangular area * \param[in] width with of rectangular area * \param[in] height height of rectangular area */ void flp_displayer_data(flp_displayer_t *p_displayer, flp_u8_t *p_data, int stride_x, int stride_y, unsigned int x, unsigned int y, unsigned int width, unsigned int height) { flp_thread_mutex_lock(&p_displayer->mtx); flp_display_data(p_displayer->p_display, p_data, stride_x, stride_y, x, y, width, height); flp_thread_mutex_unlock(&p_displayer->mtx); } /** * \brief trigger immediate sending of new image data to distributors * * this only works if the displayer is active * * \param[in] p_displayer pointer to FlexiPix displayer */ void flp_displayer_send(flp_displayer_t *p_displayer) { p_displayer->send = 1; flp_thread_cond_signal(&p_displayer->cond); } /** * \brief output thread of displayer object * * \param[in] vp_displayer pointer to displayer object * \return unused, always NULL */ FLP_THREAD_FUNC(flp_displayer_thread) { flp_displayer_t *p_displayer = (flp_displayer_t *)vp_displayer; struct timeval last, now, delta; int timed_send; int interval_ms = FLP_MCUF_MAX_FRAME_INTERVAL_MS; flp_thread_mutex_lock(&p_displayer->mtx); gettimeofday(&last, NULL); /* initialize last to some valid time */ /* while thread shall not end */ while (!p_displayer->end) { /* active */ if (p_displayer->active) { /* get current time */ gettimeofday(&now, NULL); /* get time since sending last frame */ delta.tv_sec = now.tv_sec - last.tv_sec; delta.tv_usec = now.tv_usec - last.tv_usec; if (delta.tv_usec < 0) { delta.tv_usec += 1000000; ++delta.tv_sec; } /* check if late enough for timed send */ timed_send = delta.tv_sec > interval_ms / 1000 || (delta.tv_sec == interval_ms / 1000 && delta.tv_usec >= (interval_ms % 1000) * 1000); /* send if send requested or late enough */ if (p_displayer->send || timed_send) { flp_display_send(p_displayer->p_display); /* send */ last = now; /* remember last send time */ p_displayer->send = 0; /* clear send request */ } /* sleep until next frame has to be sent */ flp_thread_cond_timedwait(&p_displayer->cond, &p_displayer->mtx, &last, interval_ms); } /* if (p_displayer->active) */ /* inactive */ else { /* sleep */ flp_thread_cond_wait(&p_displayer->cond, &p_displayer->mtx); } /* if (p_displayer->active) ... else */ } /* while(!p_displayer->end) */ flp_thread_mutex_unlock(&p_displayer->mtx); FLP_THREAD_RETURN(NULL); }