NXWidgets  1.19
cnxserver.cxx
Go to the documentation of this file.
1 /****************************************************************************
2  * NxWidgets/libnxwidgets/src/cnxserver.cxx
3  *
4  * Copyright (C) 2012, 2013, 2015-2016 Gregory Nutt. All rights reserved.
5  * Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  * 3. Neither the name NuttX, NxWidgets, nor the names of its contributors
18  * me be used to endorse or promote products derived from this software
19  * without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************/
35 
36 /****************************************************************************
37  * Included Files
38  ****************************************************************************/
39 
40 #include <nuttx/config.h>
41 
42 #include <sys/types.h>
43 #include <sys/boardctl.h>
44 #include <sys/prctl.h>
45 
46 #include <stdint.h>
47 #include <stdbool.h>
48 #include <unistd.h>
49 #include <cstdlib>
50 #include <cerrno>
51 #include <sched.h>
52 #include <pthread.h>
53 #include <debug.h>
54 
55 #include <nuttx/board.h>
56 
57 #ifdef CONFIG_VNCSERVER
58 # include <nuttx/video/vnc.h>
59 #endif
60 
61 #include "nxconfig.hxx"
62 #include "singletons.hxx"
63 #include "cnxserver.hxx"
64 
65 /****************************************************************************
66  * Static Data Members
67  ****************************************************************************/
68 
69 using namespace NXWidgets;
70 
71 uint8_t CNxServer::m_nServers; /**< The number of NX server instances */
72 
73 /****************************************************************************
74  * Method Implementations
75  ****************************************************************************/
76 
77 /**
78  * CNXServer constructor
79  */
80 
82 {
83  // Initialize server instance state data
84 
85  m_hDevice = (FAR NX_DRIVERTYPE *)NULL; // LCD/Framebuffer device handle
86  m_hNxServer = (NXHANDLE)NULL; // NX server handle
87  m_connected = false; // True: Connected to the server
88  sem_init(&m_connsem, 0, 0); // Wait for server connection
89 
90  // Increment the global count of NX servers. Normally there is only one
91  // but we don't want to preclude the case where there might be multiple
92  // displays, each with its own NX server instance
93 
94  m_nServers++;
95 
96  // Create miscellaneous singleton instances. Why is this done here?
97  // Because this needs to be done once before any widgets are created and we
98  // don't want to rely on static constructors.
99 
101 }
102 
103 /**
104  * CNXServer destructor
105  */
106 
108 {
109  // Disconnect from the server
110 
111  disconnect();
112 
113  // Decrement the count of NX servers. When that count goes to zero,
114  // delete all of the fake static instances
115 
116  if (--m_nServers == 0)
117  {
118  freeSingletons();
119  }
120 }
121 
122 /**
123  * Connect to the NX Server
124  */
125 
127 {
128  struct sched_param param;
129  pthread_t thread;
130  int ret;
131 
132  // Set the client task priority
133 
134  param.sched_priority = CONFIG_NXWIDGETS_CLIENTPRIO;
135  ret = sched_setparam(0, &param);
136  if (ret < 0)
137  {
138  gerr("ERROR: CNxServer::connect: sched_setparam failed: %d\n" , ret);
139  return false;
140  }
141 
142 #ifdef CONFIG_NXWIDGET_SERVERINIT
143  // Start the NX server kernel thread
144 
145  ginfo("CNxServer::connect: Starting NX server\n");
146  ret = boardctl(BOARDIOC_NX_START, 0);
147  if (ret < 0)
148  {
149  gerr("ERROR: CNxServer::connect: Failed to start the NX server: %d\n", errno);
150  return false;
151  }
152 #endif // CONFIG_NXWIDGET_SERVERINIT
153 
154  // Connect to the server
155 
156  m_hNxServer = nx_connect();
157  if (m_hNxServer)
158  {
159  pthread_attr_t attr;
160 
161 #ifdef CONFIG_VNCSERVER
162  // Setup the VNC server to support keyboard/mouse inputs
163 
164  ret = vnc_default_fbinitialize(0, m_hNxServer);
165  if (ret < 0)
166  {
167  gerr("ERROR: CNxServer::connect: vnc_default_fbinitialize failed: %d\n", ret);
168  m_running = false;
169  disconnect();
170  return false;
171  }
172 #endif
173 
174  // Start a separate thread to listen for server events. This is probably
175  // the least efficient way to do this, but it makes this logic flow more
176  // smoothly.
177 
178  (void)pthread_attr_init(&attr);
179  param.sched_priority = CONFIG_NXWIDGETS_LISTENERPRIO;
180  (void)pthread_attr_setschedparam(&attr, &param);
181  (void)pthread_attr_setstacksize(&attr, CONFIG_NXWIDGETS_LISTENERSTACK);
182 
183  m_stop = false;
184  m_running = true;
185 
186  ret = pthread_create(&thread, &attr, listener, (FAR void *)this);
187  if (ret != 0)
188  {
189  gerr("ERROR: NxServer::connect: pthread_create failed: %d\n", ret);
190  m_running = false;
191  disconnect();
192  return false;
193  }
194 
195  // Detach from the thread
196 
197  (void)pthread_detach(thread);
198 
199  // Don't return until we are connected to the server
200 
201  while (!m_connected && m_running)
202  {
203  // Wait for the listener thread to wake us up when we really
204  // are connected.
205 
206  (void)sem_wait(&m_connsem);
207  }
208 
209  // In the successful case, the listener is still running (m_running)
210  // and the server is connected (m_connected). Anything else is a failure.
211 
212  if (!m_connected || !m_running)
213  {
214  disconnect();
215  return false;
216  }
217  }
218  else
219  {
220  gerr("ERROR: NxServer::connect: nx_connect failed: %d\n", errno);
221  return false;
222  }
223 
224  return true;
225 }
226 
227 /**
228  * Disconnect from the NX Server
229  */
230 
232 {
233  // Is the listener running?
234  // Hmm.. won't this hang is the listener is in a blocking call?
235 
236  while (m_running)
237  {
238  // Yes.. stop the listener thread
239 
240  m_stop = true;
241  while (m_running)
242  {
243  // Wait for the listener thread to stop
244 
245  (void)sem_wait(&m_connsem);
246  }
247  }
248 
249  // Disconnect from the server
250 
251  if (m_hNxServer)
252  {
253  nx_disconnect(m_hNxServer);
254  m_hNxServer = NULL;
255  }
256 }
257 
258 /**
259  * This is the entry point of a thread that listeners for and dispatches
260  * events from the NX server.
261  */
262 
263 FAR void *CNxServer::listener(FAR void *arg)
264 {
265  // The argument must be the CNxServer instance
266 
267  CNxServer *This = (CNxServer*)arg;
268 
269 #if CONFIG_TASK_NAME_SIZE > 0
270  prctl(PR_SET_NAME, "CNxServer::listener", 0);
271 #endif
272 
273  // Process events forever
274 
275  while (!This->m_stop)
276  {
277  // Handle the next event. If we were configured blocking, then
278  // we will stay right here until the next event is received. Since
279  // we have dedicated a while thread to servicing events, it would
280  // be most natural to also select CONFIG_NX_BLOCKING -- if not, the
281  // following would be a tight infinite loop (unless we added addition
282  // logic with nx_eventnotify and sigwait to pace it).
283 
284  int ret = nx_eventhandler(This->m_hNxServer);
285  if (ret < 0)
286  {
287  // An error occurred... assume that we have lost connection with
288  // the server.
289 
290  gwarn("WARNING: Lost server connection: %d\n", errno);
291  break;
292  }
293 
294  // If we received a message, we must be connected
295 
296  if (!This->m_connected)
297  {
298  This->m_connected = true;
299  sem_post(&This->m_connsem);
300  ginfo("Connected\n");
301  }
302  }
303 
304  // We fall out of the loop when either (1) the server has died or
305  // we have been requested to stop
306 
307  This->m_running = false;
308  This->m_connected = false;
309  sem_post(&This->m_connsem);
310  return NULL;
311 }
312 
volatile bool m_stop
Definition: cnxserver.hxx:87
void instantiateSingletons(void)
Definition: singletons.cxx:114
virtual void disconnect(void)
Definition: cnxserver.cxx:231
virtual bool connect(void)
Definition: cnxserver.cxx:126
static FAR void * listener(FAR void *arg)
Definition: cnxserver.cxx:263
static uint8_t m_nServers
Definition: cnxserver.hxx:89
volatile bool m_running
Definition: cnxserver.hxx:85
volatile bool m_connected
Definition: cnxserver.hxx:86
void freeSingletons(void)
Definition: singletons.cxx:170
FAR NX_DRIVERTYPE * m_hDevice
Definition: cnxserver.hxx:83