nuttx-apps/examples/pwfb/pwfb_main.c
Xiang Xiao 857158451b Unify the void cast usage
1.Remove void cast for function because many place ignore the returned value witout cast
2.Replace void cast for variable with UNUSED macro

Change-Id: Ie644129a563244a6397036789c4c3ea83c4e9b09
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2020-01-02 23:21:01 +08:00

828 lines
23 KiB
C

/****************************************************************************
* examples/pwfb/pwfb_main.c
*
* Copyright (C) 2019 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/boardctl.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sched.h>
#include <pthread.h>
#include <fixedmath.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <nuttx/nx/nx.h>
#include <nuttx/nx/nxtk.h>
#include <nuttx/nx/nxbe.h>
#include <nuttx/nx/nxfonts.h>
#ifdef CONFIG_NX_SWCURSOR
# undef CONFIG_NXWIDGETS_BPP
# define CONFIG_NXWIDGETS_BPP CONFIG_EXAMPLES_PWFB_BPP
# include "cursor-arrow1-30x30.h"
#endif
#include "pwfb_internal.h"
/****************************************************************************
* Private Data
****************************************************************************/
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 0
static const char g_wndomsg1[] = "NuttX is cool!";
#endif
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 1
static const char g_wndomsg2[] = "NuttX is fun!";
#endif
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 2
static const char g_wndomsg3[] = "NuttX is groovy!";
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pwfb_server_initialize
****************************************************************************/
static bool pwfb_server_initialize(FAR struct pwfb_state_s *st)
{
struct sched_param param;
int ret;
/* Set the client task priority */
param.sched_priority = CONFIG_EXAMPLES_PWFB_CLIENT_PRIO;
ret = sched_setparam(0, &param);
if (ret < 0)
{
printf("pwfb_server_initialize: ERROR: "
"sched_setparam failed: %d\n" ,
ret);
return false;
}
/* Start the NX server kernel thread */
ret = boardctl(BOARDIOC_NX_START, 0);
if (ret < 0)
{
printf("pwfb_server_initialize: ERROR: "
"Failed to start the NX server: %d\n",
errno);
return false;
}
/* Connect to the server */
st->hnx = nx_connect();
if (st->hnx)
{
#ifdef CONFIG_VNCSERVER
/* Setup the VNC server to support keyboard/mouse inputs */
struct boardioc_vncstart_s vnc =
{
0, st->hnx
};
ret = boardctl(BOARDIOC_VNC_START, (uintptr_t)&vnc);
if (ret < 0)
{
printf("pwfb_server_initialize: ERROR: "
"boardctl(BOARDIOC_VNC_START) failed: %d\n",
ret);
nx_disconnect(st->hnx);
g_exitcode = NXEXIT_FBINITIALIZE;
return ERROR;
}
#endif
}
else
{
printf("pwfb_server_initialize: ERROR: "
"nx_connect failed: %d\n",
errno);
return false;
}
return true;
}
/****************************************************************************
* Name: pwfb_listener_initialize
****************************************************************************/
static bool pwfb_listener_initialize(FAR struct pwfb_state_s *st)
{
struct sched_param param;
pthread_attr_t attr;
pthread_t thread;
int ret;
/* Start a separate thread to listen for server events. This is probably
* the least efficient way to do this, but it makes this example flow more
* smoothly.
*/
pthread_attr_init(&attr);
param.sched_priority = CONFIG_EXAMPLES_PWFB_LISTENER_PRIO;
pthread_attr_setschedparam(&attr, &param);
pthread_attr_setstacksize(&attr, CONFIG_EXAMPLES_PWFB_LISTENER_STACKSIZE);
ret = pthread_create(&thread, &attr, pwfb_listener, st);
if (ret != 0)
{
printf("pwfb_listener_initialize: ERROR: "
"pthread_create failed: %d\n",
ret);
return false;
}
/* Don't return until we are connected to the server */
while (!st->connected)
{
/* Wait for the listener thread to wake us up when we really
* are connected.
*/
sem_wait(&st->semevent);
}
return true;
}
/****************************************************************************
* Name: pwfb_state_initialize
****************************************************************************/
static bool pwfb_state_initialize(FAR struct pwfb_state_s *st)
{
FAR const struct nx_font_s *fontset;
/* Initialize semaphores */
sem_init(&st->semevent, 0, 0);
/* Initialize color information */
st->wndo[0].color[0] = CONFIG_EXAMPLES_PWFB_COLOR1;
st->wndo[1].color[0] = CONFIG_EXAMPLES_PWFB_COLOR2;
st->wndo[2].color[0] = CONFIG_EXAMPLES_PWFB_COLOR3;
st->color[0] = CONFIG_EXAMPLES_PWFB_TBCOLOR;
/* Connect each window to the font cache. They cannot share the
* font cache becuse of the differing background colors.
*/
st->wndo[0].fcache = nxf_cache_connect(CONFIG_EXAMPLES_PWFB_FONTID,
CONFIG_EXAMPLES_PWFB_FONTCOLOR,
CONFIG_EXAMPLES_PWFB_COLOR1,
CONFIG_EXAMPLES_PWFB_BPP, 8);
if (st->wndo[0].fcache == NULL)
{
printf("pwfb_state_initialize: ERROR: "
"Failed to connect to font cache for window 1,"
"font ID %d: %d\n",
CONFIG_EXAMPLES_PWFB_FONTID, errno);
return false;
}
st->wndo[1].fcache = nxf_cache_connect(CONFIG_EXAMPLES_PWFB_FONTID,
CONFIG_EXAMPLES_PWFB_FONTCOLOR,
CONFIG_EXAMPLES_PWFB_COLOR2,
CONFIG_EXAMPLES_PWFB_BPP, 8);
if (st->wndo[1].fcache == NULL)
{
printf("pwfb_state_initialize: ERROR: "
"Failed to connect to font cache for window 2,"
"font ID %d: %d\n",
CONFIG_EXAMPLES_PWFB_FONTID, errno);
goto errout_with_fcache1;
}
st->wndo[2].fcache = nxf_cache_connect(CONFIG_EXAMPLES_PWFB_FONTID,
CONFIG_EXAMPLES_PWFB_FONTCOLOR,
CONFIG_EXAMPLES_PWFB_COLOR3,
CONFIG_EXAMPLES_PWFB_BPP, 8);
if (st->wndo[2].fcache == NULL)
{
printf("pwfb_state_initialize: ERROR: "
"Failed to connect to font cache for window 3,"
"font ID %d: %d\n",
CONFIG_EXAMPLES_PWFB_FONTID, errno);
goto errout_with_fcache2;
}
/* Get the handle of the font managed by the font caches. Since the
* font is used, the same font handle can be shared.
*/
st->hfont = nxf_cache_getfonthandle(st->wndo[0].fcache);
if (st->hfont == NULL)
{
printf("pwfb_state_initialize: ERROR: "
"Failed to get handle for font ID %d: %d\n",
CONFIG_EXAMPLES_PWFB_FONTID, errno);
goto errout_with_fcache3;
}
/* Get information about the font set being used and save this in the
* state structure
*/
fontset = nxf_getfontset(st->hfont);
st->fheight = fontset->mxheight;
st->fwidth = fontset->mxwidth;
st->spwidth = fontset->spwidth;
return true;
errout_with_fcache3:
nxf_cache_disconnect(st->wndo[2].fcache);
errout_with_fcache2:
nxf_cache_disconnect(st->wndo[1].fcache);
errout_with_fcache1:
nxf_cache_disconnect(st->wndo[0].fcache);
return false;
}
/****************************************************************************
* Name: pwfb_putc
****************************************************************************/
static bool pwfb_putc(FAR struct pwfb_state_s *st,
FAR struct pwfb_window_s *wndo,
FAR struct nxgl_point_s *fpos,
uint8_t ch)
{
FAR const struct nxfonts_glyph_s *glyph;
FAR const struct nx_fontbitmap_s *fbm;
struct nxgl_rect_s bounds;
struct nxgl_size_s fsize;
FAR const void *src;
int ret;
/* Find (or create) the matching glyph */
glyph = nxf_cache_getglyph(wndo->fcache, ch);
if (glyph == NULL)
{
/* No, there is no font for this code. Treat it like a space. */
fpos->x += st->spwidth;
return true;
}
/* Get information about the glyph? */
fbm = nxf_getbitmap(st->hfont, ch);
if (fbm == NULL)
{
/* Should not happen ceause we already know that the character has a
* glyph.
*/
fpos->x += st->spwidth;
return true;
}
/* Get the font size */
fsize.w = fbm->metric.width + fbm->metric.xoffset;
fsize.h = fbm->metric.height + fbm->metric.yoffset;
/* Construct a bounding box for the glyph */
bounds.pt1.x = fpos->x;
bounds.pt1.y = fpos->y;
bounds.pt2.x = fpos->x + fsize.w - 1;
bounds.pt2.y = fpos->y + fsize.h - 1;
/* Render the glyph into the window */
src = (FAR const void *)glyph->bitmap;
ret = nxtk_bitmapwindow(wndo->hwnd, &bounds, &src,
fpos, (unsigned int)glyph->stride);
if (ret < 0)
{
printf("pwfb_putc: ERROR: "
"nxtk_bitmapwindow failed: %d\n",
errno);
return false;
}
/* Set up the next character position */
fpos->x += glyph->width;
return true;
}
/****************************************************************************
* Name: pwfb_configure_window
****************************************************************************/
static bool pwfb_configure_window(FAR struct pwfb_state_s *st, int wndx,
FAR struct nxgl_size_s *size,
FAR struct nxgl_point_s *pos,
FAR const char *text,
double deltax, double deltay)
{
FAR struct pwfb_window_s *wndo = &st->wndo[wndx];
FAR const char *ptr;
struct nxgl_rect_s rect;
struct nxgl_point_s textpos;
nxgl_coord_t tbheight;
int ret;
/* Set the size of the window */
printf("pwfb_configure_window: Set window %d size to (%d,%d)\n",
wndx + 1, size->w, size->h);
ret = nxtk_setsize(wndo->hwnd, size);
if (ret < 0)
{
printf("pwfb_configure_window: ERROR: "
"nxtk_setsize failed: %d\n", errno);
goto errout_with_hwnd;
}
/* Set the position of window */
printf("pwfb_configure_window: Set window %d position to (%d,%d)\n",
wndx + 1, pos->x, pos->y);
ret = nxtk_setposition(wndo->hwnd, pos);
if (ret < 0)
{
printf("pwfb_configure_window: ERROR: "
"nxtk_setposition failed: %d\n",
errno);
goto errout_with_hwnd;
}
/* Create a toolbar */
tbheight = size->h >> 3;
ret = nxtk_opentoolbar(wndo->hwnd, tbheight, &g_pwfb_tbcb, st);
if (ret < 0)
{
printf("nxeq_opentoolbar: nxtk_opentoolbar failed: %d\n", errno);
}
/* There is a race condition here we resolve by making the main thread
* lowest in priority. In order for the size and position to take effect,
* a command is sent to server which responds with an event. So we need
* to be synchronized at this point or the following fill will fail because
* it depends on current knowlede of the size and position.
* REVISIT: Use nx_synch()!
*/
/* Create a bounding box. This is actually too large because it does not
* account for the border widths. However, NX should clip the fill to
* stay within the frame.
*/
rect.pt1.x = 0;
rect.pt1.y = 0;
rect.pt2.x = size->w - 1;
rect.pt2.y = size->h - tbheight - 1;
/* Fill the window with the selected color */
ret = nxtk_fillwindow(wndo->hwnd, &rect, wndo->color);
if (ret < 0)
{
printf("pwfb_configure_window: ERROR: "
"nxtk_fillwindow failed: %d\n",
errno);
goto errout_with_hwnd;
}
/* Fill the toolbar with the selected color */
rect.pt2.y = tbheight - 1;
ret = nxtk_filltoolbar(wndo->hwnd, &rect, st->color);
if (ret < 0)
{
printf("pwfb_configure_window: ERROR: "
"nxtk_filltoobar failed: %d\n",
errno);
goto errout_with_hwnd;
}
/* Add the text to the display, character at a time */
textpos.x = st->spwidth;
textpos.y = st->fheight;
for (ptr = text; *ptr != '\0'; ptr++)
{
if (!pwfb_putc(st, wndo, &textpos, (uint8_t)*ptr))
{
printf("pwfb_configure_window: ERROR: "
"pwfb_putc failed\n");
goto errout_with_hwnd;
}
}
/* Set up for motion.
* REVISIT: The vertical limits, xmax andymax, seems to be off
* by about the height of the toolbar.
*/
wndo->xmax = itob16(st->xres - size->w - 1);
wndo->ymax = itob16(st->yres - size->h - 1);
wndo->ypos = itob16(pos->y);
wndo->xpos = itob16(pos->x);
wndo->deltax = dtob16(deltax);
wndo->deltay = dtob16(deltay);
return true;
errout_with_hwnd:
printf("pwfb_configure_window: Close window %d\n", wndx + 1);
ret = nxtk_closewindow(wndo->hwnd);
if (ret < 0)
{
printf("pwfb_configure_window: ERROR: "
"nxtk_closewindow failed: %d\n",
errno);
}
return false;
}
/****************************************************************************
* Name: pwfb_configure_cursor
****************************************************************************/
#ifdef CONFIG_NX_SWCURSOR
static bool pwfb_configure_cursor(FAR struct pwfb_state_s *st,
FAR struct nxgl_point_s *pos,
double deltax, double deltay)
{
int ret;
/* Initialize the data structure */
st->cursor.state = PFWB_CURSOR_MOVING;
st->cursor.countdown = CURSOR_MOVING_DELAY;
st->cursor.blinktime = 0;
st->cursor.xmax = itob16(st->xres - g_arrow1Cursor.size.w - 1);
st->cursor.ymax = itob16(st->yres - g_arrow1Cursor.size.h - 1);
st->cursor.xpos = itob16(pos->x);
st->cursor.ypos = itob16(pos->y);
st->cursor.deltax = dtob16(deltax);
st->cursor.deltay = dtob16(deltay);
/* Set the cursor image */
ret = nxcursor_setimage(st->hnx, &g_arrow1Cursor);
if (ret < 0)
{
printf("pwfb_configure_cursor: ERROR: "
"nxcursor_setimage failed: %d\n",
errno);
return false;
}
/* Set the cursor position */
ret = nxcursor_setposition(st->hnx, pos);
if (ret < 0)
{
printf("pwfb_configure_cursor: ERROR: "
"nxcursor_setposition failed: %d\n",
errno);
return false;
}
/* Enable the cursor */
ret = nxcursor_enable(st->hnx, true);
if (ret < 0)
{
printf("pwfb_configure_cursor: ERROR: "
"nxcursor_enable failed: %d\n",
errno);
return false;
}
return true;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: pwfb_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
struct pwfb_state_s wstate;
struct nxgl_size_s size;
struct nxgl_point_s pos;
nxgl_mxpixel_t color;
int errcode = EXIT_SUCCESS;
int ret;
/* Connect to the NX server */
memset(&wstate, 0, sizeof(struct pwfb_state_s));
if (!pwfb_server_initialize(&wstate) || wstate.hnx == NULL)
{
printf("pwfb_main: ERROR: "
"Failed to get NX handle\n");
goto errout;
}
printf("pwfb_main: NX handle=%p\n", wstate.hnx);
/* Start the listener thread */
if (!pwfb_listener_initialize(&wstate))
{
printf("pwfb_main: ERROR: "
"pwfb_listener_initialize failed\n");
goto errout_with_nx;
}
/* Initialize the window state, colors, font cache, etc. */
if (!pwfb_state_initialize(&wstate))
{
printf("pwfb_main: ERROR: "
"pwfb_state_initialize failed\n");
goto errout_with_nx;
}
/* Set the background to the configured background color */
printf("pwfb_main: Set background color=%d\n",
CONFIG_EXAMPLES_PWFB_BGCOLOR);
color = CONFIG_EXAMPLES_PWFB_BGCOLOR;
ret = nx_setbgcolor(wstate.hnx, &color);
if (ret < 0)
{
printf("pwfb_main: nx_setbgcolor failed: %d\n", errno);
goto errout_with_fontcache;
}
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 0
/* Open window 1 */
printf("pwfb_main: Open window 1\n");
wstate.wndo[0].hwnd = nxtk_openwindow(wstate.hnx, NXBE_WINDOW_RAMBACKED,
&g_pwfb_wncb, (FAR void *)&wstate);
if (wstate.wndo[0].hwnd == NULL)
{
printf("pwfb_main: ERROR: "
"nxtk_openwindow failed: %d\n",
errno);
goto errout_with_fontcache;
}
printf("pwfb_main: hwnd1=%p\n", wstate.wndo[0].hwnd);
/* Wait until we receive the screen resolution from the server. We only
* need to do this once after opening the first window.
*/
while (!wstate.haveres)
{
sem_wait(&wstate.semevent);
}
printf("pwfb_main: Screen resolution (%d,%d)\n",
wstate.xres, wstate.yres);
/* Configure window 1 */
size.w = wstate.xres / 2;
size.h = wstate.yres / 2;
pos.x = wstate.xres / 8;
pos.y = wstate.yres / 8;
if (!pwfb_configure_window(&wstate, 0, &size, &pos, g_wndomsg1, 4.200, 4.285))
{
printf("pwfb_main: ERROR: "
"pwfb_configure_window failed for window 1\n");
goto errout_with_hwnd1;
}
#endif
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 1
/* Open window 2 */
printf("pwfb_main: Open window 2\n");
wstate.wndo[1].hwnd = nxtk_openwindow(wstate.hnx, NXBE_WINDOW_RAMBACKED,
&g_pwfb_wncb, (FAR void *)&wstate);
if (wstate.wndo[1].hwnd == NULL)
{
printf("pwfb_main: ERROR: "
"nxtk_openwindow failed: %d\n",
errno);
goto errout_with_hwnd1;
}
printf("pwfb_main: hwnd1=%p\n", wstate.wndo[1].hwnd);
/* Configure window 2 (same size) */
pos.x = wstate.xres / 4;
pos.y = wstate.yres / 4;
if (!pwfb_configure_window(&wstate, 1, &size, &pos, g_wndomsg2, -3.317, 5.0))
{
printf("pwfb_main: ERROR: "
"pwfb_configure_window failed for window 2\n");
goto errout_with_hwnd2;
}
#endif
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 2
/* Open window 3 */
printf("pwfb_main: Open window 3\n");
wstate.wndo[2].hwnd = nxtk_openwindow(wstate.hnx, NXBE_WINDOW_RAMBACKED,
&g_pwfb_wncb, (FAR void *)&wstate);
if (wstate.wndo[2].hwnd == NULL)
{
printf("pwfb_main: ERROR: "
"nxtk_openwindow failed: %d\n",
errno);
goto errout_with_hwnd2;
}
printf("pwfb_main: hwnd2=%p\n", wstate.wndo[2].hwnd);
/* Configure window 3 (same size) */
pos.x = (3 * wstate.xres) / 8;
pos.y = (3 * wstate.yres) / 8;
if (!pwfb_configure_window(&wstate, 2, &size, &pos, g_wndomsg3, 4.600, -3.852))
{
printf("pwfb_main: ERROR: "
"pwfb_configure_window failed for window 2\n");
goto errout_with_hwnd3;
}
#endif
#ifdef CONFIG_NX_SWCURSOR
/* Configure the software cursor */
pos.x = wstate.xres / 2;
pos.y = wstate.yres / 2;
if (!pwfb_configure_cursor(&wstate, &pos, 2.900, -5.253))
{
printf("pwfb_main: ERROR: "
"pwfb_configure_cursor failed for window 2\n");
goto errout_with_hwnds;
}
#endif
/* Now loop animating the windows */
for (; ; )
{
usleep(CONFIG_EXAMPLES_PWFB_RATECONTROL * 1000);
if (!pwfb_motion(&wstate))
{
printf("pwfb_main: ERROR:"
"pwfb_motion failed\n");
goto errout_with_cursor;
}
}
errcode = EXIT_SUCCESS;
errout_with_cursor:
#ifdef CONFIG_NX_SWCURSOR
/* Disable the cursor */
nxcursor_enable(wstate.hnx, false);
errout_with_hwnds:
#endif
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 2
/* Close window 3 */
errout_with_hwnd3:
printf("pwfb_main: Close window #2\n");
ret = nxtk_closewindow(wstate.wndo[2].hwnd);
if (ret < 0)
{
printf("pwfb_main: ERROR: nxtk_closewindow failed: %d\n", errno);
}
#endif
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 1
/* Close window 2 */
errout_with_hwnd2:
printf("pwfb_main: Close window #2\n");
ret = nxtk_closewindow(wstate.wndo[1].hwnd);
if (ret < 0)
{
printf("pwfb_main: ERROR: nxtk_closewindow failed: %d\n", errno);
}
#endif
/* Close window1 */
#if CONFIG_EXAMPLES_PWFB_NWINDOWS > 0
errout_with_hwnd1:
printf("pwfb_main: Close window #1\n");
ret = nxtk_closewindow(wstate.wndo[0].hwnd);
if (ret < 0)
{
printf("pwfb_main: ERROR: nxtk_closewindow failed: %d\n", errno);
}
#endif
errout_with_fontcache:
/* Release the font cache */
nxf_cache_disconnect(wstate.wndo[0].fcache);
nxf_cache_disconnect(wstate.wndo[1].fcache);
nxf_cache_disconnect(wstate.wndo[2].fcache);
errout_with_nx:
/* Disconnect from the server */
printf("pwfb_main: Disconnect from the server\n");
nx_disconnect(wstate.hnx);
errout:
return errcode;
}