po_hi_driver_linux_serial.c 16 KB
Newer Older
1
2
3
4
5
/*
 * This is a part of PolyORB-HI-C distribution, a minimal
 * middleware written for generated code from AADL models.
 * You should use it with the Ocarina toolsuite.
 *
6
7
8
 * For more informations, please visit http://ocarina.enst.fr
 *
 * Copyright (C) 2010, European Space Agency (ESA).
9
10
 */

11
#include <drivers/po_hi_driver_linux_serial.h>
12
#include <drivers/configuration/serial.h>
13

14
15
16
#if defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX) || \
    defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX_SENDER) || \
    defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX_RECEIVER)
17

18
#include <po_hi_debug.h>
jdelange's avatar
jdelange committed
19
#include <po_hi_returns.h>
20
#include <po_hi_utils.h>
21
22
#include <po_hi_messages.h>
#include <po_hi_transport.h>
23
#include <po_hi_gqueue.h>
24
#include <drivers/po_hi_driver_serial_common.h>
25
26
/* po-hi-c related files */

27
28
29
30
31
#include <activity.h>
#include <marshallers.h>
#include <deployment.h>
/* generated files */

32
33
34
35
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
36
#include <unistd.h>
37
#include <string.h>
38
39
/* Linux-specific files */

40
41
int po_hi_c_driver_serial_fd_read;
int po_hi_c_driver_serial_fd_write;
42

43
44
#if defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX) || \
    defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX_RECEIVER)
45
46
47

void __po_hi_c_driver_serial_linux_poller (void)
{
48
49
50
   int n;
   int ts;

51
52
   unsigned long* swap_pointer;
   unsigned long swap_value;
53

54
55
   __po_hi_msg_t msg;
   __po_hi_request_t request;
56

57
   __PO_HI_DEBUG_DEBUG ("[LINUX SERIAL] Hello, i'm the serial poller , must read %d bytes!\n", __PO_HI_MESSAGES_MAX_SIZE);
58
59

   __po_hi_msg_reallocate (&msg);
60

61
   n = read (po_hi_c_driver_serial_fd_read, &(msg.content[0]), __PO_HI_MESSAGES_MAX_SIZE); 
62

63
#ifdef __PO_HI_DEBUG_INFO
64
   __PO_HI_DEBUG_INFO  ("[LINUX SERIAL] Message: 0x");
65
66
67

   for (ts = 0 ; ts < __PO_HI_MESSAGES_MAX_SIZE ; ts++)
   {
68
      __PO_HI_DEBUG_INFO ("%x", msg.content[ts]);
69
   }
70
   __PO_HI_DEBUG_INFO ("\n");
71
#endif
72
73
   
   if (n == -1)
74
   {
75
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Cannot read on socket !\n");
76
      return;
77
   }
78

79
80
81
82
83
   if (n == 0)
   {
      return;
   }

84
85
   if (n != __PO_HI_MESSAGES_MAX_SIZE)
   {
86
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Inconsistent received message size (received %d bytes)!\n", n);
87
88
      return;
   }
89

90
   __PO_HI_DEBUG_DEBUG ("[LINUX SERIAL] read() returns %d\n", n);
91

92
   msg.length = n;
93
94
95
   swap_pointer  = (unsigned long*) &msg.content[0];
   swap_value    = *swap_pointer;
   *swap_pointer = __po_hi_swap_byte (swap_value);
96

97
#ifdef __PO_HI_DEBUG_INFO
98
   __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Message after swapped port: 0x");
99
   for (ts = 0 ; ts < msg.length ; ts++)
100
   {
101
        __PO_HI_DEBUG_INFO ("%x", msg.content[ts]);
102
   }
103
   __PO_HI_DEBUG_INFO ("\n");
104

105
   __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Received: %s\n", msg.content);
106
#endif
107

108
109
   __po_hi_unmarshall_request (&request, &msg);

110
111
112
113
114
115
   if (request.port > __PO_HI_NB_PORTS)
   {
      __PO_HI_DEBUG_WARNING ("[LINUX SERIAL] Invalid port number !\n");
      return;
   }

116
   __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Destination port: %d\n", request.port);
117
   __po_hi_main_deliver (&request);
118
}
119
120
121
122
123
124
125
126
#endif


#if defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX) || \
    defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX_SENDER)

void __po_hi_c_driver_serial_linux_init_sender (__po_hi_device_id id)
{
127
128
   struct termios             oldtio,newtio;
   __po_hi_c_serial_conf_t*   serialconf;
129

130
   __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Init sender\n");
131

132
   serialconf = (__po_hi_c_serial_conf_t*)__po_hi_get_device_configuration (id);
133

134
   if (serialconf == NULL)
135
   {
136
      __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Cannot get the configuration of the device !\n");
137
138
139
      return;
   }

140
   po_hi_c_driver_serial_fd_write = open (serialconf->devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
141
142
143

   if (po_hi_c_driver_serial_fd_write < 0)
   {
144
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error while opening device %s\n", serialconf->devname);
145
146
147
   }
   else
   {
148
      __PO_HI_DEBUG_DEBUG ("[LINUX SERIAL] Device successfully opened, fd=%d\n", po_hi_c_driver_serial_fd_write);
149
150
151
   }

   tcgetattr (po_hi_c_driver_serial_fd_write, &oldtio);  /* save current serial port settings */
152
   memset (&newtio, '\0', sizeof(newtio));                /* clear struct for new port settings */
153
154
155
156
157
158
159
160
161
162
        
   /* 
    * BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
    * CRTSCTS : output hardware flow control (only used if the cable has
    *           all necessary lines. See sect. 7 of Serial-HOWTO)
    * CS8     : 8n1 (8bit,no parity,1 stopbit)
    * CLOCAL  : local connection, no modem contol
    * CREAD   : enable receiving characters
    */

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
   newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;

   switch (__po_hi_c_driver_serial_common_get_speed (id))
   {
      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_19200:
         newtio.c_cflag |= B19200;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_38400:
         newtio.c_cflag |= B38400;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_57600:
         newtio.c_cflag |= B57600;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_115200:
         newtio.c_cflag |= B115200;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_UNKNWON:
         __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Unknwon speed for the serial line\n");
         break;
   }

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
         
   /*
    *  IGNPAR  : ignore bytes with parity errors
    *  ICRNL   : map CR to NL (otherwise a CR input on the other computer
    *            will not terminate input) otherwise make device raw 
    *            (no other input processing)
    */
   newtio.c_iflag = IGNPAR | ICRNL;
         
   /*
    * Raw output.
    */
   newtio.c_oflag = 1;
         
   /*
    * ICANON  : enable canonical input
    * disable all echo functionality, and don't send signals to calling program
    */
   newtio.c_lflag = ICANON;
207

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
   /* 
    * Initialize all control characters 
    * default values can be found in /usr/include/termios.h, and are given
    * in the comments, but we don't need them here.
    */
   newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
   newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
   newtio.c_cc[VERASE]   = 0;     /* del */
   newtio.c_cc[VKILL]    = 0;     /* @ */
   newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
   newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
   newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
   newtio.c_cc[VSWTC]    = 0;     /* '\0' */
   newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
   newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
   newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
   newtio.c_cc[VEOL]     = 0;     /* '\0' */
   newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
   newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
   newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
   newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
   newtio.c_cc[VEOL2]    = 0;     /* '\0' */

   /* 
    * clean the serial line and activate the settings for the port
    */
   if (tcflush (po_hi_c_driver_serial_fd_write, TCIOFLUSH) == -1)
   {
236
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error in tcflush()\n");
237
238
239
240
   }

   if (tcsetattr (po_hi_c_driver_serial_fd_write, TCSANOW, &newtio) == -1)
   {
241
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error in tcsetattr()\n");
242
243
   }

244
    __PO_HI_DEBUG_INFO ("[LINUX SERIAL] End of init\n");
245
246
247
248
249
250
251
252
}
#endif


#if defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX) || \
    defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX_RECEIVER)
void __po_hi_c_driver_serial_linux_init_receiver (__po_hi_device_id id)
{
253
254
   struct termios             oldtio,newtio;
   __po_hi_c_serial_conf_t*   serialconf;
255

256
   __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Init receiver\n");
257

258
   serialconf = (__po_hi_c_serial_conf_t*)__po_hi_get_device_configuration (id);
259

260
   if (serialconf == NULL)
261
262
263
264
265
   {
      __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Cannot get the name of the device !\n");
      return;
   }

266
   po_hi_c_driver_serial_fd_read = open (serialconf->devname, O_RDONLY | O_NOCTTY);
267
268
269

   if (po_hi_c_driver_serial_fd_read < 0)
   {
270
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error while opening device %s\n", serialconf->devname);
271
272
273
   }
   else
   {
274
      __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Device successfully opened, fd=%d\n", po_hi_c_driver_serial_fd_read);
275
276
277
   }

   tcgetattr (po_hi_c_driver_serial_fd_read, &oldtio);  /* save current serial port settings */
278
   memset (&newtio, '\0', sizeof(newtio));                /* clear struct for new port settings */
279
280
281
282
283
284
285
286
287
288
        
   /* 
    * BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
    * CRTSCTS : output hardware flow control (only used if the cable has
    *           all necessary lines. See sect. 7 of Serial-HOWTO)
    * CS8     : 8n1 (8bit,no parity,1 stopbit)
    * CLOCAL  : local connection, no modem contol
    * CREAD   : enable receiving characters
    */

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
   newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;

   switch (__po_hi_c_driver_serial_common_get_speed (id))
   {
      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_19200:
         newtio.c_cflag |= B19200;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_38400:
         newtio.c_cflag |= B38400;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_57600:
         newtio.c_cflag |= B57600;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_115200:
         newtio.c_cflag |= B115200;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_UNKNWON:
         __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Unknwon speed for the serial line\n");
         break;
   }
 
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
         
   /*
    *  IGNPAR  : ignore bytes with parity errors
    *  ICRNL   : map CR to NL (otherwise a CR input on the other computer
    *            will not terminate input) otherwise make device raw 
    *            (no other input processing)
   newtio.c_iflag = IGNPAR | ICRNL;
    */
         
   /*
    * Raw output.
    */
   newtio.c_oflag = 1;
         
   /*
    * ICANON  : enable canonical input
    * disable all echo functionality, and don't send signals to calling program
   newtio.c_lflag = ICANON;
    */

   /* 
    * Initialize all control characters 
    * default values can be found in /usr/include/termios.h, and are given
    * in the comments, but we don't need them here.
    */

   /* 
    * clean the serial line and activate the settings for the port
    */
   if (tcflush (po_hi_c_driver_serial_fd_read, TCIOFLUSH) == -1)
   {
345
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error in tcflush()\n");
346
347
348
349
   }

   if (tcsetattr (po_hi_c_driver_serial_fd_read, TCSANOW, &newtio) == -1)
   {
350
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error in tcsetattr()\n");
351
352
   }

353
    __PO_HI_DEBUG_INFO ("[LINUX SERIAL] End of init\n");
354
355
356
357
358
}
#endif


#if defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX)
359

360
void __po_hi_c_driver_serial_linux_init (__po_hi_device_id id)
361
{
362
363
   struct                     termios oldtio,newtio;
   __po_hi_c_serial_conf_t*   serialconf;
364

365
   __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Init both sender and receiver\n");
366

367
368
369
   serialconf = (__po_hi_c_serial_conf_t*)__po_hi_get_device_configuration (id);

   if (serialconf == NULL)
370
371
372
373
374
   {
      __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Cannot get the name of the device !\n");
      return;
   }

375
   po_hi_c_driver_serial_fd_read = po_hi_c_driver_serial_fd_write = open(serialconf->devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
376

377
   if (po_hi_c_driver_serial_fd_read < 0)
378
   {
379
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error while opening device %s\n", serialconf->devname);
380
   }
381
382
   else
   {
383
      __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Device successfully opened, fd=%d\n", po_hi_c_driver_serial_fd_read);
384
   }
385

386
   tcgetattr (po_hi_c_driver_serial_fd_read, &oldtio);  /* save current serial port settings */
387
   memset (&newtio, '\0', sizeof(newtio));                /* clear struct for new port settings */
388
389
390
391
392
393
394
395
396
397
        
   /* 
    * BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
    * CRTSCTS : output hardware flow control (only used if the cable has
    *           all necessary lines. See sect. 7 of Serial-HOWTO)
    * CS8     : 8n1 (8bit,no parity,1 stopbit)
    * CLOCAL  : local connection, no modem contol
    * CREAD   : enable receiving characters
    */

398
   newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421

   switch (__po_hi_c_driver_serial_common_get_speed (id))
   {
      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_19200:
         newtio.c_cflag |= B19200;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_38400:
         newtio.c_cflag |= B38400;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_57600:
         newtio.c_cflag |= B57600;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_115200:
         newtio.c_cflag |= B115200;
         break;

      case __PO_HI_DRIVER_SERIAL_COMMON_SPEED_UNKNWON:
         __PO_HI_DEBUG_INFO ("[LINUX SERIAL] Unknwon speed for the serial line\n");
         break;
   }
422
423
424
425
426
427
428
429
430
431
432
433
         
   /*
    *  IGNPAR  : ignore bytes with parity errors
    *  ICRNL   : map CR to NL (otherwise a CR input on the other computer
    *            will not terminate input) otherwise make device raw 
    *            (no other input processing)
    */
   newtio.c_iflag = IGNPAR | ICRNL;
         
   /*
    * Raw output.
    */
434
   newtio.c_oflag = 1;
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
         
   /*
    * ICANON  : enable canonical input
    * disable all echo functionality, and don't send signals to calling program
    */
   newtio.c_lflag = ICANON;

   /* 
    * Initialize all control characters 
    * default values can be found in /usr/include/termios.h, and are given
    * in the comments, but we don't need them here.
    */
   newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
   newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
   newtio.c_cc[VERASE]   = 0;     /* del */
   newtio.c_cc[VKILL]    = 0;     /* @ */
   newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
   newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
   newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
   newtio.c_cc[VSWTC]    = 0;     /* '\0' */
   newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
   newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
   newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
   newtio.c_cc[VEOL]     = 0;     /* '\0' */
   newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
   newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
   newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
   newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
   newtio.c_cc[VEOL2]    = 0;     /* '\0' */

   /* 
    * clean the serial line and activate the settings for the port
    */
468
   if (tcflush (po_hi_c_driver_serial_fd_read, TCIOFLUSH) == -1)
469
   {
470
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error in tcflush()\n");
471
472
   }

473
   if (tcsetattr (po_hi_c_driver_serial_fd_read, TCSANOW, &newtio) == -1)
474
   {
475
      __PO_HI_DEBUG_CRITICAL ("[LINUX SERIAL] Error in tcsetattr()\n");
476
   }
477

478
    __PO_HI_DEBUG_INFO ("[LINUX SERIAL] End of init\n");
479
}
480
481
482
483
484
#endif


#if defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX) || \
    defined (__PO_HI_NEED_DRIVER_SERIAL_LINUX_SENDER)
485

486
int  __po_hi_c_driver_serial_linux_sender (__po_hi_task_id task_id, __po_hi_port_t port)
487
{
488
489
490
491
492
493
494
495
496
497
498
499
500
   int n;
   int ts;
   unsigned long* swap_pointer;
   unsigned long swap_value;
   __po_hi_local_port_t local_port;
   __po_hi_request_t* request;
   __po_hi_msg_t msg;
   __po_hi_port_t destination_port;

   local_port = __po_hi_get_local_port_from_global_port (port);

   request = __po_hi_gqueue_get_most_recent_value (task_id, local_port);

jdelange's avatar
jdelange committed
501
502
   if (request->port == -1)
   {
503
      __PO_HI_DEBUG_DEBUG ("[LINUX SERIAL] Send output task %d, port %d (local_port=%d): no value to send\n", task_id, port, local_port);
jdelange's avatar
jdelange committed
504
505
506
      return __PO_HI_SUCCESS;
   }

507
508
509
510
511
512
   destination_port     = __po_hi_gqueue_get_destination (task_id, local_port, 0);

   __po_hi_msg_reallocate (&msg);

   request->port = destination_port;

513
   __po_hi_marshall_request (request, &msg);
514

515
516
517
518
   /* Swap only the port (first 32 bytes) */
   swap_pointer  = (unsigned long*) &msg.content[0];
   swap_value    = *swap_pointer;
   *swap_pointer = __po_hi_swap_byte (swap_value);
519

520
   n = write (po_hi_c_driver_serial_fd_write, &msg, __PO_HI_MESSAGES_MAX_SIZE);
521

522
   __PO_HI_DEBUG_INFO  ("[LINUX SERIAL] Message sent: 0x");
523

524
525
   for (ts = 0 ; ts < __PO_HI_MESSAGES_MAX_SIZE ; ts++)
   {
526
      __PO_HI_DEBUG_INFO ("%x", msg.content[ts]);
527
   }
528
   __PO_HI_DEBUG_INFO ("\n");
529

jdelange's avatar
jdelange committed
530
531
   request->port = __PO_HI_GQUEUE_INVALID_PORT;

532
   return 1;
533
}
534
#endif
535

536
#endif