BlinkenArea - GitList
Repositories
Blog
Wiki
libetherpix
Code
Commits
Branches
Tags
Search
Tree:
fb91a00
Branches
Tags
master
libetherpix
src
displayer.c
v1.0.5
Stefan Schuermans
commited
fb91a00
at 2011-09-11 17:17:19
displayer.c
Blame
History
Raw
/* * FlexiPix library * !version: 1.0.5! !date: 2010-12-22! * * Copyright 2010 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 <pthread.h> #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/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 (pthread_mutex_init(&p_displayer->mtx, NULL)) { 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 (pthread_cond_init(&p_displayer->cond, NULL)) { pthread_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 (pthread_create(&p_displayer->tid, NULL, flp_displayer_thread, (void *)p_displayer)) { pthread_cond_destroy(&p_displayer->cond); pthread_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; pthread_cond_signal(&p_displayer->cond); pthread_join(p_displayer->tid, NULL); pthread_cond_destroy(&p_displayer->cond); pthread_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) { pthread_mutex_lock(&p_displayer->mtx); flp_display_get_size(p_displayer->p_display, p_width, p_height); pthread_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; pthread_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) { pthread_mutex_lock(&p_displayer->mtx); flp_display_data_clear(p_displayer->p_display); pthread_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) { pthread_mutex_lock(&p_displayer->mtx); flp_display_data(p_displayer->p_display, p_data, stride_x, stride_y, x, y, width, height); pthread_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; pthread_cond_signal(&p_displayer->cond); } #define FLP_MMFI_MS_S (FLP_MCUF_MAX_FRAME_INTERVAL_MS / 1000) #define FLP_MMFI_MS_US ((FLP_MCUF_MAX_FRAME_INTERVAL_MS % 1000) * 1000) #define FLP_MMFI_MS_NS ((FLP_MCUF_MAX_FRAME_INTERVAL_MS % 1000) * 1000000) /** * \brief output thread of displayer object * * \param[in] vp_displayer pointer to displayer object * \return unused, always NULL */ void * flp_displayer_thread(void *vp_displayer) { flp_displayer_t *p_displayer = (flp_displayer_t *)vp_displayer; struct timeval last, now, delta; struct timespec until; int timed_send; pthread_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 > FLP_MMFI_MS_S || (delta.tv_sec == FLP_MMFI_MS_S && delta.tv_usec >= FLP_MMFI_MS_US); /* 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 */ until.tv_sec = last.tv_sec + FLP_MMFI_MS_S; until.tv_nsec = last.tv_usec * 1000 + FLP_MMFI_MS_NS; if (until.tv_nsec > 1000000000) { until.tv_nsec -= 1000000000; until.tv_sec++; } pthread_cond_timedwait(&p_displayer->cond, &p_displayer->mtx, &until); } /* if (p_displayer->active) */ /* inactive */ else { /* sleep */ pthread_cond_wait(&p_displayer->cond, &p_displayer->mtx); } /* if (p_displayer->active) ... else */ } /* while(!p_displayer->end) */ pthread_mutex_unlock(&p_displayer->mtx); return NULL; }