vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Atmel.C
Go to the documentation of this file.
1 /***************************************************************************************************/
2 /* */
3 /* Copyright (C) 2003 Bauhaus University Weimar */
4 /* Released into the public domain on 6/23/2007 as part of the VRPN project */
5 /* by Jan P. Springer. */
6 /* */
7 /***************************************************************************************************/
8 /* */
9 /* module : vrpn_Atmel */
10 /* project : vrpn_Avango */
11 /* description: server for microcontroller based on Atmel chip */
12 /* hardware developed by Albotronic: www.albotronic.de */
13 /* */
14 /***************************************************************************************************/
15 
16 #ifndef _WIN32
17 
18 #include <errno.h> // for errno
19 #include <stdio.h> // for fprintf, stderr, printf, etc
20 #include <stdlib.h> // for exit
21 #include <sys/select.h> // for select, FD_SET, FD_ZERO, etc
22 #include <vrpn_Shared.h> // for vrpn_gettimeofday
23 
24 #include "vrpn_Atmel.h"
25 #include "vrpn_Connection.h" // for vrpn_Connection
26 #include "vrpn_Types.h" // for vrpn_float64
27 #include "vrpn_atmellib.h" // for getRegister, closePort, etc
28 #include "vrpn_atmellib_errno.h" // for ATMELLIB_NOERROR
29 
30 #include <termios.h> // for tcflush, TCIOFLUSH, termios
31 
32 #include <string.h> // for strerror
33 
34 /***************************************************************************************************/
35 /***************************************************************************************************/
36 namespace {
37 
38 struct termios init_params;
39 struct timeval wait;
40 
41 /***************************************************************************************************/
42 // check if there if the Atmel is connected to the serial
43 /***************************************************************************************************/
44 bool
45 check_serial(int fd)
46 {
47  int ret=0;
48 
49  // make a new fd set to watch
50  fd_set rfds;
51 
52  // clear the set
53  FD_ZERO( &rfds );
54  // ad the current fd to the set
55  FD_SET( fd, &rfds );
56 
57  wait.tv_sec = 5;
58  wait.tv_usec = 0;
59 
60  ret = select( fd+1 , &rfds , 0 , 0 , &wait);
61 
62  if (ret == 0) {
63 
64  printf("Atmel not connected to the specified port.\n");
65  printf("Connect and try again.\n");
66 
67  return false;
68  }
69  else if (ret<0) {
70 
71  printf("Error while checking if Atmel is connected.\n");
72  printf("Error: %s (%i)\n", strerror(errno), errno );
73 
74  return false;
75  }
76 
77  printf("Atmel started.\n\n");
78 
79  return true;
80 }
81 
82 } // end of namespace
83 
84 /***************************************************************************************************/
85 /* factory */
86 /***************************************************************************************************/
87 /* static */ vrpn_Atmel *
89  const char *port, long baud,
90  int channel_count ,
91  int * channel_mode)
92 {
93  int fd;
94 
95 #ifdef VRPN_ATMEL_SERIAL_VRPN
96 
97  if ( (fd=vrpn_open_commport(port, baud)) == -1) {
98 
99  fprintf(stderr,"vrpn_Atmel: can't Open serial port\n");
100 
101  return NULL;
102  }
103 #else
104  // Open the serial port
105  if ( (fd=openPort(port, baud, &init_params)) == -1) {
106 
107  fprintf(stderr,"vrpn_Atmel: can't Open serial port\n");
108 
109  return NULL;
110  }
111 
112  // look if the atmel is connected
113  if (! check_serial(fd) ) {
114 
115  return NULL;
116  }
117 #endif
118 
119  vrpn_Atmel * self = new vrpn_Atmel(name, c, fd);
120 
121  if ( (self->vrpn_Analog_Server::setNumChannels(channel_count) != channel_count)
122  || (self->vrpn_Analog_Output_Server::setNumChannels(channel_count) != channel_count) ) {
123 
124  fprintf(stderr,"vrpn_Atmel: the requested number of channels is not available\n");
125  delete self;
126 
127  return NULL;
128  }
129 
130 
131  // init the channels based on the infos given from the config file
132  self->init_channel_mode(channel_mode);
133 
135 
136  return self;
137 }
138 
139 
140 
141 /***************************************************************************************************/
142 /* constructor */
143 /***************************************************************************************************/
144 vrpn_Atmel::vrpn_Atmel(char* name, vrpn_Connection *c, int fd)
145  : vrpn_Analog_Server(name, c), vrpn_Analog_Output_Server(name, c),
146  _status(VRPN_ATMEL_STATUS_ERROR),
147  serial_fd(fd)
148 {
149  // find out what time it is - needed?
150  vrpn_gettimeofday(&timestamp, 0);
151  vrpn_gettimeofday(&_time_alive, 0);
152  vrpn_Analog::timestamp = timestamp;
153 }
154 
155 
156 /***************************************************************************************************/
157 /* destructor */
158 /***************************************************************************************************/
160 {
161 #ifdef VRPN_ATMEL_SERIAL_VRPN
162  vrpn_close_commport(serial_fd);
163 #else
164  closePort(serial_fd , &init_params);
165 #endif
166 
167 
168 }
169 
170 /***************************************************************************************************/
171 /* mainloop */
172 /***************************************************************************************************/
173 void
175 {
176  if (_status == VRPN_ATMEL_STATUS_ERROR) {
177 
178  return;
179  }
180 
181  // o_num_channel is used as reference against num_channel
182  if (o_num_channel != num_channel) {
183 
185  }
186 
187  server_mainloop();
188 
189  // get the pending messages so that the buffer to write down is updated
191 
192  if ( ! d_connection->connected()) {
193 
194  return;
195  }
196 
197  // it's the first time we are in mainloop after
199 
200  if (handle_new_connection()) {
201 
202  _status = VRPN_ATMEL_STATUS_RUNNING;
203 
204  fprintf(stderr,"vrpn_Atmel: mainloop()\n");
205  fprintf(stderr," new connection. status set to RUNNING\n");
206  }
207  else {
208 
209  _status = VRPN_ATMEL_STATUS_ERROR;
210 
211  fprintf(stderr,"vrpn_Atmel: mainloop()\n");
212  fprintf(stderr," error handling new connection. status set to ERROR\n");
213 
214  return;
215  }
216 
217  }
218 
219  // do the read/write operations on the serial port
220  if ( ! mainloop_serial_io() ) {
221 
222  fprintf(stderr,"vrpn_Atmel: mainloop()\n");
223  fprintf(stderr," error while io operations ERROR\n");
224 
225  }
226 
228  //vrpn_Analog::report_changes();
229 
231 }
232 
233 /***************************************************************************************************/
234 /* check if the connection to the Atmel is still reliable */
235 /***************************************************************************************************/
236 bool
237 vrpn_Atmel::Check_Serial_Alive()
238 {
239  struct timeval look_time;
240 
241  // check serial status every second
242  if ((timestamp.tv_sec - _time_alive.tv_sec) > VRPN_ATMEL_ALIVE_INTERVAL_SEC) {
243 
244  // reset time alive
245  vrpn_gettimeofday(&_time_alive,0);
246 
247  tcflush(serial_fd, TCIOFLUSH);
248 
249  // make a new fd set to watch
250  fd_set rfds;
251 
252  // clear the set
253  FD_ZERO( &rfds );
254  // ad the current fd to the set
255  FD_SET( serial_fd, &rfds );
256 
257  look_time.tv_sec = VRPN_ATMEL_ALIVE_TIME_LOOK_SEC;
258  look_time.tv_usec = VRPN_ATMEL_ALIVE_TIME_LOOK_USEC;
259 
260  if ((select( (serial_fd+1) , &rfds , 0 , 0 , &look_time)) <= 0) {
261 
262  fprintf(stderr, "\nExiting...\n");
263 
264  fprintf(stderr, "vrpn_Atmel::Check_Serial_Alive: connection timed out after (sec,msec):");
266  fprintf(stderr, "Killing Program!!!\n");
267 
268  return false;
269  }
270 
271 #ifdef VRPN_ATMEL_VERBOSE
272  fprintf(stderr, "Connection still available...\n");
273 #endif
274  }
275 
276  return true;
277 }
278 
279 /***************************************************************************************************/
280 /* io operations on the serial port in mainloop */
281 /***************************************************************************************************/
282 bool
283 vrpn_Atmel::mainloop_serial_io()
284 {
285  vrpn_gettimeofday(&timestamp, 0);
286  vrpn_Analog::timestamp = timestamp;
287 
288  // check if there is still a valid connection to the Chip
289  if (!Check_Serial_Alive()) {
290 
291  // kill the program
292  // use e.g. a cron job to init the whole connection mechanism again
293  exit(0);
294  }
295 
296  // do for all channels
297  for(int i=0; i<o_num_channel; ++i) {
298 
300 
301  // unused channel
302  continue;
303  }
304 
305  // find out which channels have to been written down to the device
306  if (o_channel[i] != channel[i]) {
307 
308  // test if channel is writable
309  if ( (_channel_mode[i] != VRPN_ATMEL_MODE_RW)
310  && (_channel_mode[i] != VRPN_ATMEL_MODE_WO) ) {
311 
312  fprintf(stderr,"vrpn_Atmel: mainloop_serial_io()\n");
313  fprintf(stderr," channel not writable\n");
314 
316 
317  continue;
318  }
319 
320  // test if it is a valid value: atmel uses 8 bit
321  if ((o_channel[i]<0) || (o_channel[i]>255)) {
322 
323  fprintf(stderr,"vrpn_Atmel: mainloop_serial_io()\n");
324  fprintf(stderr," value out of range\n");
325 
327 
328  continue;
329  }
330 
331  // try to write down
332  if (setRegister(serial_fd, i, (unsigned char) o_channel[i])
333  != ATMELLIB_NOERROR) {
334 
335  fprintf(stderr,"vrpn_Atmel: mainloop_serial_io()\n");
336  fprintf(stderr," error writing down value, channel: %d\n",i);
337 
339 
340  continue;
341  }
342  else {
343 
344  fprintf(stderr,"vrpn_Atmel: mainloop_serial_io()\n");
345  fprintf(stderr," written down value, channel: %d\n",i);
346  }
347 
348  // no error
349  channel[i] = o_channel[i];
350 
351  continue;
352  }
353 
354  // this values are not requested for change -> read them
355 
356  if ( (_channel_mode[i] == VRPN_ATMEL_MODE_RO)
357  || (_channel_mode[i] == VRPN_ATMEL_MODE_RW) ) {
358 
359  if ( (channel[i] = getRegister(serial_fd, i)) < 0) {
360 
361 #ifdef VRPN_ATMEL_VERBOSE
362  fprintf(stderr, "Channel read: i=%i val=%f\n",i,channel[i]);
363 
364  fprintf(stderr,"vrpn_Atmel: mainloop_serial_io()\n");
365  fprintf(stderr," error reading out value. channel=%d\n",i);
366 #endif
367  // reset to the old value - don't send the error
368  // in some cases it's propably useful to know the error
370  //channel[i] = last[i];
371  }
372  }
373 
374  } // end of for-loop
375 
376  for(int i=0; i<o_num_channel ;++i) {
377 
378  o_channel[i] = channel[i];
379  }
380 
381  return true;
382 }
383 
384 
385 /***************************************************************************************************/
386 /* init the io mode of the channels: */
387 /***************************************************************************************************/
388 void
389 vrpn_Atmel::init_channel_mode(int * channel_mode)
390 {
391  int val=0;
392 
393  for(int i=0; i<o_num_channel; ++i) {
394 
395  _channel_mode.push_back(channel_mode[i]);
396 
397  if ( (channel_mode[i] == VRPN_ATMEL_MODE_RO)
398  || (_channel_mode[i] == VRPN_ATMEL_MODE_RW) ) {
399 
400  // read the current value of the register
401  val=getRegister(serial_fd , i);
402  if (val < 0) {
403 
404  // error while reading register value
405  fprintf(stderr,"vrpn_Atmel: init_channel_mode()\n");
406  fprintf(stderr," error reading out value: %i\n", val);
407 
410  }
411  else {
412 
413  channel[i] = (float) val;
414  o_channel[i] = (float) val;
415 
416 #ifdef VRPN_ATMEL_VERBOSE
417  fprintf(stderr, "vrpn_Atmel: i=%d val=%d\n",i ,val);
418 #endif
419 
420  }
421  }
422  else {
423 
424  // channel is not for reading
427  }
428 
429  } // end of for loop
430 }
431 
432 
433 /***************************************************************************************************/
434 /* init the io mode of the channels: */
435 /***************************************************************************************************/
436 bool
437 vrpn_Atmel::handle_new_connection()
438 {
439  // request to send the current status of all registers
441 
442  printf("\nconnection received.\n\n");
443 
444  // really send the current status
446 
447  return true;
448 }
449 
450 #endif
451 
virtual int mainloop(const struct timeval *timeout=NULL)=0
Call each time through program main loop to handle receiving any incoming messages and sending any pa...
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
#define VRPN_ATMEL_MODE_WO
Definition: vrpn_Atmel.h:45
int vrpn_close_commport(int comm)
Definition: vrpn_Serial.C:345
#define VRPN_ATMEL_STATUS_ERROR
Definition: vrpn_Atmel.h:50
int vrpn_open_commport(const char *portname, long baud, int charsize, vrpn_SER_PARITY parity, bool rts_flow)
Open a serial port, given its name and baud rate.
Definition: vrpn_Serial.C:54
#define VRPN_ATMEL_MODE_RW
Definition: vrpn_Atmel.h:44
#define VRPN_ATMEL_STATUS_WAITING_FOR_CONNECTION
Definition: vrpn_Atmel.h:48
#define VRPN_ATMEL_ERROR_NOT_WRITABLE
Definition: vrpn_Atmel.h:41
vrpn_float64 o_channel[vrpn_CHANNEL_MAX]
vrpn_float64 channel[vrpn_CHANNEL_MAX]
Definition: vrpn_Analog.h:38
Generic connection class not specific to the transport mechanism.
#define VRPN_ATMEL_CHANNEL_NOT_VALID
Definition: vrpn_Atmel.h:52
virtual void report(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report whether something has changed or not (for servers) Optionally, tell what time to stamp ...
Definition: vrpn_Analog.C:94
static vrpn_Atmel * Create(char *name, vrpn_Connection *c, const char *port="/dev/ttyS0/", long baud=9600, int channel_count=0, int *channel_mode=NULL)
Definition: vrpn_Atmel.C:88
#define VRPN_ATMEL_STATUS_RUNNING
Definition: vrpn_Atmel.h:49
vrpn_int32 num_channel
Definition: vrpn_Analog.h:40
#define VRPN_ATMEL_MODE_RO
Definition: vrpn_Atmel.h:43
vrpn_Connection * d_connection
Connection that this object talks to.
virtual vrpn_bool connected(void) const
Returns vrpn_true if the connection has been established, vrpn_false if not (For a networkless connec...
#define VRPN_ATMEL_ALIVE_INTERVAL_SEC
Definition: vrpn_Atmel.h:56
#define VRPN_ATMEL_ALIVE_TIME_LOOK_USEC
Definition: vrpn_Atmel.h:55
#define VRPN_ATMEL_ERROR_OUT_OF_RANGE
Definition: vrpn_Atmel.h:40
#define VRPN_ATMEL_ERROR_WRITING_DOWN
Definition: vrpn_Atmel.h:39
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
void mainloop()
For this server, the user must normally call report() or report_changes() directly. This mainloop() only takes care of the things any server object should do.
Definition: vrpn_Atmel.C:174
#define VRPN_ATMEL_ALIVE_TIME_LOOK_SEC
Definition: vrpn_Atmel.h:54
#define VRPN_ATMEL_ERROR_READING_IN
Definition: vrpn_Atmel.h:38
struct timeval timestamp
Definition: vrpn_Analog.h:41