BlinkenArea - GitList
Repositories
Blog
Wiki
libetherpix
Code
Commits
Branches
Tags
Search
Tree:
9b23234
Branches
Tags
master
libetherpix
src
display.c
update Windows support
Stefan Schuermans
commited
9b23234
at 2017-09-24 08:46:27
display.c
Blame
History
Raw
/* * EtherPix library * * Copyright 2010-2017 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 <errno.h> #include <stdlib.h> #include <string.h> #include <etherpix/display.h> #include <etherpix/msg.h> #include <etherpix/types.h> #include <intern/config.h> #include <intern/constants.h> #include <intern/net.h> #include <intern/types.h> /** * \brief create a new EtherPix display * * \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 EtherPix display on success * or NULL on error */ etp_display_t *etp_display_create(const char *sz_config_file, etp_msg_func_p_t p_msg_func, void *p_msg_ctx) { etp_display_t *p_display; /* basic display setup */ /* create display structure */ p_display = (etp_display_t *)calloc(1, sizeof (etp_display_t)); if (!p_display) { if (p_msg_func) p_msg_func(p_msg_ctx, etp_msg_type_err, "out of memory\n"); return NULL; } /* set default bind address */ p_display->bind_addr.sin_family = AF_INET; p_display->bind_addr.sin_port = htons(ETP_BIND_PORT); p_display->bind_addr.sin_addr.s_addr = htonl(ETP_BIND_IP); /* no socket yet */ p_display->sock = -1; /* config file */ /* read config file */ if(etp_config_proc_file(p_display, sz_config_file, p_msg_func, p_msg_ctx)) { etp_display_free(p_display); /* cleanup everything that config file processing might heave created already */ if (p_msg_func) p_msg_func(p_msg_ctx, etp_msg_type_err, "reading config file failed\n"); return NULL; } /* set up UDP socket */ /* create socket */ #ifdef WINDOWS p_display->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (p_display->sock != INVALID_SOCKET) { u_long arg = 1; if (ioctlsocket(p_display->sock, FIONBIO, &arg) != 0) { closesocket(p_display->sock); p_display->sock = INVALID_SOCKET; } } #else p_display->sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); #endif if (!etp_sock_is_valid(p_display->sock)) { etp_display_free(p_display); if (p_msg_func) { char errmsg[256]; etp_sock_get_last_error(errmsg, sizeof(errmsg)); p_msg_func(p_msg_ctx, etp_msg_type_err, "could not create UDP socket: %s\n", errmsg); } return NULL; } /* bind socket */ if (bind(p_display->sock, (struct sockaddr *)&p_display->bind_addr, sizeof (p_display->bind_addr))) { etp_display_free(p_display); if (p_msg_func) { char errmsg[256]; etp_sock_get_last_error(errmsg, sizeof(errmsg)); p_msg_func(p_msg_ctx, etp_msg_type_err, "could not bind UDP socket to \"%s:%u\": %s\n", inet_ntoa(p_display->bind_addr.sin_addr), (unsigned int)ntohs(p_display->bind_addr.sin_port), errmsg); } return NULL; } /* clear display */ etp_display_data_clear(p_display); return p_display; } /** * \brief free a EtherPix display * * \param[in] p_display pointer to EtherPix display */ void etp_display_free(etp_display_t *p_display) { int i; if (p_display) { /* free distributors */ for (i = 0; i < ETP_DISTRI_MAX_CNT; i++) { if (p_display->distri_ptrs[i]) { etp_distri_t *p_distri = p_display->distri_ptrs[i]; free(p_distri->p_pixels); free(p_distri->p_msg_buf); free(p_distri); } } /* close network connection */ if (etp_sock_is_valid(p_display->sock)) closesocket(p_display->sock); /* free display structutre */ free(p_display); } /* if (p_display) */ } /** * \brief get size of display * * \param[in] p_display pointer to EtherPix display * \param[out] p_width width of display * \param[out] p_height height of display */ void etp_display_get_size(etp_display_t *p_display, unsigned int *p_width, unsigned int *p_height) { *p_width = (unsigned int)p_display->size.x; *p_height = (unsigned int)p_display->size.y; } /** * \brief clear image data to output on EtherPix display * * clears the stored image data, * stored image data can later be sent to the distributors using * etp_display_send() * * \param[in] p_display pointer to EtherPix display */ void etp_display_data_clear(etp_display_t *p_display) { etp_u8_t black[3] = { 0, 0, 0 }; etp_display_data_fmt(p_display, black, 0, 0, 0, 0, p_display->size.x, p_display->size.y, etp_pixfmt_rgb24); } /** * \brief set image data to output on EtherPix display * * updates (part of) the stored image data, * stored image data can later be sent to the distributors using * etp_display_send() * * \param[in] p_display pointer to EtherPix display * \param[in] p_data pointer to rectangular section of image data * \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 * \param[in] pixfmt format of pixel data */ void etp_display_data_fmt(etp_display_t *p_display, etp_u8_t *p_data, int stride_x, int stride_y, unsigned int x, unsigned int y, unsigned int width, unsigned int height, etp_pixfmt_t pixfmt) { unsigned int distri, out, pix, i; etp_distri_t *p_distri; etp_u8_t *dest, *src; etp_pixel_t *p_pixel; int rx, ry; /* set data for all distributors */ for (distri = 0; distri < ETP_DISTRI_MAX_CNT; distri++) { p_distri = p_display->distri_ptrs[distri]; if (p_distri) { /* set pointer to start of RGB data for pixels in message buffer (header is already set up and stays the same) */ dest = p_distri->p_msg_buf + ETP_MCUF_HDR_LEN; /* get RGB data of pixels for every output */ for (out = 0, i = 0; out < p_distri->output_cnt; out++) { for (pix = 0; pix < p_distri->pixel_cnt; pix++, i++) { p_pixel = &p_distri->p_pixels[i]; /* get pixel coordinates relative to rectangular area of image */ rx = p_pixel->x - (int)x; ry = p_pixel->y - (int)y; /* check if pixel is within rectangular area of image */ if (rx >= 0 && (unsigned int)rx < width && ry >= 0 && (unsigned int)ry < height) { /* get pixel data and map it */ src = (p_data + rx * stride_x + ry * stride_y); switch (pixfmt) { case etp_pixfmt_rgb24: dest[0] = p_distri->mapping[0].table[src[0]]; dest[1] = p_distri->mapping[1].table[src[1]]; dest[2] = p_distri->mapping[2].table[src[2]]; break; case etp_pixfmt_bgr24: dest[0] = p_distri->mapping[0].table[src[2]]; dest[1] = p_distri->mapping[1].table[src[1]]; dest[2] = p_distri->mapping[2].table[src[0]]; break; default: dest[0] = 0; dest[1] = 0; dest[2] = 0; } } dest += 3; } /* for (pix ...) */ } /* for (out ...) */ } /* if (p_distri) */ } /* for (distri ...) */ } /** * \brief set image data to output on EtherPix display * * see etp_display_data_fmt for documentation * pixfmt is fixed to etp_pixfmt_rgb24 */ void etp_display_data(etp_display_t *p_display, etp_u8_t *p_data, int stride_x, int stride_y, unsigned int x, unsigned int y, unsigned int width, unsigned int height) { etp_display_data_fmt(p_display, p_data, stride_x, stride_y, x, y, width, height, etp_pixfmt_rgb24); } /** * \brief send image data to distributors * * sends the currently stored image data to all configured distributors * * \param[in] p_display pointer to EtherPix display */ void etp_display_send(etp_display_t *p_display) { unsigned int distri, addr_i; etp_distri_t *p_distri; /* send data to all distributors */ for (distri = 0; distri < ETP_DISTRI_MAX_CNT; distri++) { p_distri = p_display->distri_ptrs[distri]; if (p_distri) { /* send message as UDP packet to each address */ for (addr_i = 0; addr_i < p_distri->addr_cnt; ++addr_i) { sendto(p_display->sock, (char *)p_distri->p_msg_buf, p_distri->msg_len, 0, (struct sockaddr *)&p_distri->addrs[addr_i], sizeof (p_distri->addrs[addr_i])); } /* for (addr_i ...) */ } /* if (p_distri) */ } /* for (distri ...) */ }