home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1988 / 06 / rtunix.lst < prev    next >
File List  |  1979-12-31  |  23KB  |  800 lines

  1.  
  2. /* Listing One -- Main routine for Solution A  */
  3.  
  4. #include <stdio.h>              /* standard Unix I/O header */
  5.  
  6. #include <termio.h>             /* file/port control headers */
  7. #include <fcntl.h>
  8.  
  9. #include <sys/types.h>          /* required headers for IPC */
  10. #include <sys/ipc.h>
  11. #include <sys/msg.h>
  12.  
  13. /* local constants */
  14.  
  15. #define TRUE (1==1)             /* boolean values */
  16. #define FALSE (1==0)
  17. #define SENSOR_1_DEV "/dev/tty45"/* tty port names for sensor ports */
  18. #define SENSOR_2_DEV "/dev/tty46"
  19. #define SENSOR_3_DEV "/dev/tty47"
  20. #define TIMEOUT (10L)           /* timeout if no input received */
  21. #define MAX_SENSOR_MSG (100)    /* maximum size of a sensor message */
  22. #define MAX_CMD_MSG (100)       /* maximum size of a command message */
  23.  
  24. /* local function declarations */
  25.  
  26. void 
  27.     process_timeout();          /* process sensor read timeout */
  28.    
  29. /* module-wide data */
  30.  
  31. int
  32.     timeout_id[3];              /* marktime timeout timer IDs */
  33.  
  34. /* Main routine for program */
  35.  
  36. main ()
  37. {
  38. int
  39.     cmd_size,                   /* number of bytes in command message */
  40.     msg_size,                   /* number of bytes in sensor message */
  41.     qid,                        /* message queue identifier */
  42.     sensor_1_fd,                /* file descriptors for the sensors */
  43.     sensor_2_fd, 
  44.     sensor_3_fd;
  45.  
  46. char
  47.     cmd_msg[MAX_CMD_MSG],       /* buffer for reading command queue */
  48.     sensor_msg[MAX_SENSOR_MSG]; /* buffer for reading sensor data */
  49.  
  50. /* open the sensor input files */
  51.  
  52. sensor_1_fd=open(SENSOR_1_DEV,O_RDWR|O_NDELAY);
  53. sensor_2_fd=open(SENSOR_2_DEV,O_RDWR|O_NDELAY);
  54. sensor_3_fd=open(SENSOR_3_DEV,O_RDWR|O_NDELAY);
  55. /* open the command queue */
  56.  
  57. qid=msgget(1,IPC_CREAT|0666);
  58.  
  59. /* establish initial timeouts for each sensor */
  60.  
  61. timeout_id[0]=marktime(TIMEOUT,(int*)NULL,process_timeout,(char*)1);
  62. timeout_id[1]=marktime(TIMEOUT,(int*)NULL,process_timeout,(char*)2);
  63. timeout_id[2]=marktime(TIMEOUT,(int*)NULL,process_timeout,(char*)3);
  64.  
  65. /* loop forever */
  66.  
  67. while (TRUE)
  68.     {
  69.     /* Read (or try) each sensor and process the input.  */
  70.  
  71.     if ( (msg_size=read(sensor_1_fd, sensor_msg, MAX_SENSOR_MSG)) > 0)
  72.         process_sensor (sensor_msg, msg_size, 1);
  73.     if ( (msg_size=read(sensor_2_fd, sensor_msg, MAX_SENSOR_MSG)) > 0)
  74.         process_sensor (sensor_msg, msg_size, 2);
  75.     if ( (msg_size=read(sensor_3_fd, sensor_msg, MAX_SENSOR_MSG)) > 0)
  76.         process_sensor (sensor_msg, msg_size, 3);
  77.  
  78.     /* check for input on the message queue */
  79.  
  80.     if ( (cmd_size=msgrcv(qid,cmd_msg,MAX_CMD_MSG,0,IPC_NOWAIT)) >= 0)
  81.         process_cmd_msg (cmd_msg, cmd_size);
  82.  
  83.     /* delay the program before continuing loop */
  84.  
  85.     nap (3);
  86.     }
  87. }
  88.  
  89. /* Function process_cmd_msg ()
  90. ** 
  91. ** This is a stub routine for handling command queue input.  It suspends
  92. ** timeouts while processing the input and then resumes them when it is
  93. ** done.
  94. */
  95.  
  96. static process_cmd_msg (msg, size)
  97.  
  98. char 
  99.     *msg;                       /* INPUT: pointer to command message */
  100.  
  101. int size;                       /* INPUT: size of *msg */
  102.  
  103. {
  104. timer_disable();
  105. /* (do some appropriate processing on the command) */
  106. timer_enable();
  107. return;
  108. }
  109. /* Function process_sensor()
  110. **
  111. ** This is a stub routine for handling sensor input.  It cancels the
  112. ** outstanding timeout timer and reschedule a new timeout.  It also 
  113. ** suspends timeout interrupts while it is processing the input.
  114. */
  115.  
  116. static process_sensor (msg, size, sensor_num)
  117.  
  118. char 
  119.     *msg;                       /* INPUT: pointer to sensor data */
  120.  
  121. int
  122.     size,                       /* INPUT: size of *msg */
  123.     sensor_num;                 /* INPUT: sensor number  */
  124.  
  125. {
  126. timer_disable();
  127. cancel_marktime (timeout_id[sensor_num-1]);
  128. /* (do some appropriate processing on the message) */
  129. timeout_id[sensor_num]=marktime(TIMEOUT,(int*)NULL,
  130.         process_timeout,(char*)sensor_num);
  131. timer_enable();
  132. return;
  133. }
  134.  
  135. /* Function process_timeout()
  136. **
  137. ** This is a stub for the sensor input timeout timer.  It is called as a
  138. ** completion routine from marktime(), which passes the sensor number 
  139. ** as an argument.  The function suspends timeouts while it processing
  140. ** the error and resumes processing when it is done.  It also resets the
  141. ** timeout before exiting, something that a real program may or may not
  142. ** want to do in real life, depending on the appication.
  143. */
  144.  
  145. static void process_timeout (sensor_num)
  146.  
  147. char
  148.     *sensor_num;                /* INPUT: sensor number which has */
  149.                                 /* timed out (declared char* because */
  150.                                 /*     that's what marktime() calls */
  151.                                 /*     it with.  Value is really int */
  152. {
  153. timer_disable();
  154. /* (do some appropriate processing on the error) */
  155. timeout_id[(int)sensor_num]=marktime(TIMEOUT,(int*)NULL,
  156.         process_timeout, sensor_num);
  157. timer_enable();
  158. return;
  159. }
  160.  
  161.  
  162. /* Listing Two -- nap() */
  163.  
  164. #include <stdio.h>              /* standard Unix I/O header */
  165.  
  166. #include <termio.h>             /* port file control headers */
  167. #include <fcntl.h>
  168.  
  169. #define TRUE (1==1)             /* boolean constants */
  170. #define FALSE (1==0)
  171.  
  172. /* Function nap()
  173. **
  174. ** This function provides a program delay function with resolution
  175. ** to a tenth of a second.  It works by opening a file to /dev/clk
  176. ** (which should be linked to some unused /dev/tty), setting the 
  177. ** input parameters to non-canonical, and setting the VTIME value
  178. ** to the passed argument.  It then does a read on the file which
  179. ** will time out after the indicated delay time.
  180. */
  181.  
  182. void nap (delay)
  183.  
  184. int
  185.     delay;                      /* INPUT: delay in tenths of a second */
  186. {
  187. static int
  188.     clock_opened=FALSE;         /* has the clock device been opened? */
  189.  
  190. static int
  191.     fd;                         /* clock file descriptor */
  192.  
  193. int
  194.     flags;                      /* file control flags */
  195.  
  196. char
  197.     buff[10];                   /* dummy read buffer */
  198.  
  199. struct termio
  200.     clock_termio;               /* terminal I/O parameters */
  201.  
  202. /*
  203. ** the first time through the routine, open the clock port
  204. ** and set the port parameters.
  205. */
  206.  
  207. if (!clock_opened)
  208.     {
  209.     fd=open("/dev/clk",O_RDONLY|O_NDELAY);
  210.     ioctl (fd, TCGETA, &clock_termio);
  211.     clock_termio.c_cflag |= CLOCAL;
  212.     clock_termio.c_lflag &= ~ICANON;
  213.     ioctl (fd, TCSETA, &clock_termio);
  214.     flags = fcntl (fd, F_GETFL, 0) & ~O_NDELAY;
  215.     fcntl (fd, F_SETFL, flags);    clock_opened = TRUE;
  216.     }
  217.  
  218. /* set the VTIME delay to the indicated value */
  219.  
  220. ioctl (fd, TCGETA, &clock_termio);
  221. clock_termio.c_cc[VMIN] = 0;
  222. clock_termio.c_cc[VTIME] = delay;
  223. ioctl (fd, TCSETAF, &clock_termio);
  224.  
  225. /* perform the dummy read */
  226.  
  227. read (fd, buff, 10);
  228.  
  229. return;
  230. }
  231.  
  232.  
  233. /* Listing Three -- marktime() and related functions */
  234.  
  235. #include <stdio.h>              /* standard input/output include */
  236. #include <sys/signal.h>         /* signal definitions  */
  237.  
  238. #define MAX_ELEMENT 10          /* maximum number of queued events */
  239. #define TRUE (1==1)
  240. #define FALSE (1==0)
  241.  
  242. struct tmq                      /* timer queue element structure */
  243.     {
  244.     unsigned long time;         /* expiration time (UNIX) of element */
  245.     void        (*ast)();       /* user ast to call at expiration */
  246.     char        *arg;           /* value passed to ast() (if called) */
  247.     struct tmq  *next;          /* pointer to next element */
  248.     int         *flag;          /* event count to bump at expiration */
  249.     };
  250.  
  251. static struct tmq
  252.     *queue_free,                /* first available element in queue */
  253.     *queue_head,                /* first element in clock queue */
  254.     *queue_tail,                /* last element in clock queue */
  255.     timer_queue[MAX_ELEMENT];   /* table of queue elements */
  256.  
  257. static int
  258.     q_busy = FALSE,             /* queue update in progress */
  259.     q_enabled = FALSE,          /* queue countdown operations enabled */
  260.     queue_init = FALSE;         /* queue initialized flag */
  261.  
  262. static unsigned long
  263.     next_event;                 /* last known value of expiration */
  264.                                 /*    time of head element (may */
  265.                                 /*    change during ast) */
  266.  
  267. extern unsigned long
  268.     time();                     /* get Unix time */
  269.  
  270. extern unsigned int
  271.     alarm();                    /* set system alarm clock */
  272.  
  273. void 
  274.     queue_ast();                /* internal asynchronous trap */
  275.  
  276. /* Function marktime()
  277. **
  278. ** This function inserts an element into the timer queue (performing
  279. ** queue initialization if necessary).  If the new element is at the
  280. ** top of the queue, it will reset the alarm clock.
  281. **
  282. **      Return values:
  283. **              -1      queue full
  284. **              >=0     element ID
  285. */
  286.  
  287. int marktime (time_of_event, flag, user_ast, user_arg)
  288. unsigned long
  289.     time_of_event;              /* INPUT: seconds until event */
  290.  
  291. char
  292.     *user_arg;                  /* INPUT: user-supplied argument (in */
  293.                                 /*    reality, this could be a */
  294.                                 /*    pointer to any data type, but */
  295.                                 /*    char* is a good enough */
  296.                                 /*    description */
  297.  
  298. void
  299.     (*user_ast)();              /* INPUT: user function to call at */
  300.                                 /*    expiration (may be NULL) */
  301. int
  302.     *flag;                      /* INPUT: pointer to flag to make */
  303.                                 /*    TRUE on expiration (may be NULL)*/
  304.  
  305. {
  306. int
  307.     element,                    /* offset into timer_queue */
  308.     found_slot,                 /* loop termination flag */
  309.     ret_val;                    /* >=0 element ID, -1 queue full */
  310.  
  311. register struct tmq
  312.     *new_element,               /* pointer to newly added element */
  313.     *last_ptr,                  /* previous pointer into timer_queue */
  314.     *q_ptr;                     /* pointer into timer_queue */
  315.  
  316.  
  317. /* if the queue is uninitialized, then initialize it */
  318.  
  319. if (!queue_init)
  320.     {
  321.     queue_free = &timer_queue[0];
  322.     for (element=0; element<MAX_ELEMENT; element++)
  323.         timer_queue[element].next = &timer_queue[element+1];
  324.     timer_queue[MAX_ELEMENT-1].next = NULL;
  325.     queue_head = NULL;
  326.     queue_tail = NULL;
  327.     q_busy = FALSE;
  328.     q_enabled = TRUE;
  329.     signal (SIGALRM, queue_ast);
  330.     queue_init = TRUE;
  331.     }
  332.  
  333. /* insert the new element into the linked list */
  334.  
  335. if ( (new_element=queue_free) != NULL)
  336.     {
  337.     q_busy = TRUE;
  338.     queue_free = queue_free->next;
  339.     new_element->time = time_of_event + time((long*)0);
  340.     if (flag != NULL)
  341.         {        new_element->flag = flag;
  342.         *flag = FALSE;
  343.         }
  344.     new_element->ast = user_ast;
  345.     new_element->arg = user_arg;
  346.     q_ptr = queue_head;
  347.     last_ptr = queue_head;
  348.     found_slot = FALSE;
  349.     while ( (q_ptr!=NULL) && !found_slot)
  350.         {
  351.         if (new_element->time < q_ptr->time)
  352.             found_slot = TRUE;
  353.         else
  354.             {
  355.             last_ptr = q_ptr;
  356.             q_ptr = q_ptr->next;
  357.             }
  358.         }
  359.     /* if the new element is first, then reset alarm for this element */
  360.     if (q_ptr == queue_head)
  361.         {
  362.         new_element->next = queue_head;
  363.         queue_head = new_element;
  364.         next_event = new_element->time;
  365.         if (q_enabled)
  366.             alarm ((unsigned int)(new_element->time - time((long*)0)));
  367.         }
  368.     else
  369.         {
  370.         new_element->next = q_ptr;
  371.         last_ptr->next = new_element;
  372.         }
  373.     ret_val = new_element - timer_queue;
  374.     q_busy = FALSE;
  375.     }
  376. else
  377.     ret_val = (-1);
  378.  
  379. return (ret_val);
  380.  
  381. }
  382.  
  383. /* Function queue_ast()
  384. **
  385. ** This function is called when the clock reaches the time
  386. ** at the head of the timer queue.  It sets the indicated
  387. ** flag (if non-NULL), and removes the head element
  388. ** from the queue.  It reschedules the internal timeout to the
  389. ** time of the new queue head element, if one exists. (If the
  390. ** time of the next element is less than the present time, the
  391. ** function schedule the event in one second.) Finally,
  392. ** if the user-supplied ast is non-NULL, it calls that routine,
  393. ** passing the user-supplied argument.
  394. **
  395. ** The function checks the q_busy flag (set by marktime() and** cancel_marktime()) to verify that the program isn't in the
  396. ** middle of a queue update.  If the flag is TRUE, queued_ast()
  397. ** reschedules itself 1 second from now, rather than attempting
  398. ** to hack at the queue blindly.
  399. **
  400. */
  401. static void queue_ast ()
  402.  
  403. {
  404. register struct tmq
  405.     *q_ptr;                     /* temporary queue pointer */
  406.  
  407. unsigned int
  408.     nexttime;                   /* seconds until next timeout */
  409.  
  410. /* 
  411. ** If it is safe to fiddle with the queue, pull out the next
  412. ** element and schedule the next timeout, if any. 
  413. */
  414.  
  415. if (!q_busy)
  416.     {
  417.     q_ptr = queue_head;
  418.     queue_head = q_ptr->next;
  419.     q_ptr->next = queue_free;
  420.     queue_free = q_ptr;
  421.     if (queue_head != NULL)
  422.         {
  423.         if (q_enabled)
  424.             {
  425.             if ( (nexttime=(unsigned int)queue_head->time -
  426.                     time((long*)0)) > 0)
  427.                 alarm (nexttime);
  428.             else
  429.                 alarm (1);
  430.             }
  431.         }
  432.     /* set the user's flag, if any is specified */
  433.  
  434.     if (q_ptr->flag != NULL)
  435.         *q_ptr->flag = TRUE;
  436.  
  437.     /* call the user's completion routine, if any specified */
  438.  
  439.     if (q_ptr->ast != NULL)
  440.         (*q_ptr->ast)(q_ptr->arg);
  441.     }
  442.  
  443. /* if the queue is busy, reschedule the timeout for later */
  444.  
  445. else
  446.     {
  447.     if (q_enabled)
  448.         alarm (1);
  449.     }
  450. /* reset signal catcher */
  451.  
  452. signal (SIGALRM, queue_ast);
  453.  
  454. return;
  455.  
  456. }
  457. /* Function cancel_marktime()
  458. **
  459. ** This function removes the specified timer request from the
  460. ** timer queue.
  461. **
  462. ** Return values:
  463. **      >=0             time remaining till expiration
  464. **      <0xFFFFFFFF     no such element
  465. **
  466. ** If the queue hasn't been initialized, the function returns
  467. ** 'no such element'.  It does NOT initialize the queue.
  468. **
  469. ** The element ID, used for identifying the event to be canceled
  470. ** is returned by marktime.
  471. */
  472.  
  473. unsigned long cancel_marktime (id)
  474.  
  475. int
  476.     id;                         /* INPUT: element id (returned from */
  477.                                 /*    marktime) */
  478.  
  479. {
  480. register struct tmq
  481.     *last_ptr,                  /* previous pointer into timer_queue */
  482.     *q_ptr;                     /* pointer into timer_queue */
  483.  
  484. int
  485.     found;                      /* loop termination flag */
  486.  
  487. unsigned long
  488.     ret_val;                    /* >=0 for success, <0 for failure */
  489.  
  490. unsigned int
  491.     neyvtime;                   /* time until next event expiration */
  492.  
  493. /* make sure that the queue is initialized */
  494. if (queue_init)
  495.     {
  496.     q_busy = TRUE;
  497.     /* make sure that the ID is legitimate */
  498.     if ( (id >= 0) && (id < MAX_ELEMENT) )
  499.         {
  500.         /*
  501.         ** Traverse the event queue until we find the requested element.
  502.         ** This ensures that the element has really been used and also
  503.         ** gives us the pointers for relinking the list.        */
  504.         for (q_ptr=queue_head, last_ptr=q_ptr, found=FALSE;
  505.                 q_ptr!=NULL && !found;
  506.                 last_ptr=q_ptr, q_ptr=q_ptr->next)
  507.             /* do we have a match? */
  508.             if (q_ptr == &timer_queue[id])
  509.                 {
  510.                 ret_val = q_ptr->time - time((long*)0);
  511.                 /*
  512.                 ** if the cancelled element was at the head, then
  513.                 ** reschedule the next timeout, if any exist.
  514.                 */
  515.                 if (q_ptr==queue_head)
  516.                     {
  517.                     queue_head = q_ptr->next;
  518.                     if (queue_head != NULL)
  519.                         {
  520.                         if (q_enabled)
  521.                             {
  522.                             if ((nexttime=(unsigned int)queue_head->time
  523.                                     - time((long*)0)) > 0)
  524.                                 alarm (nexttime);
  525.                             else
  526.                                 alarm (1);
  527.                             }
  528.                         }
  529.                     else
  530.                         alarm (0);
  531.                     }
  532.                 else
  533.                     last_ptr->next = q_ptr->next;
  534.                 q_ptr->next = queue_free;
  535.                 queue_free = q_ptr;
  536.                 found = TRUE;
  537.                 }
  538.         /* did we ever find a match? */
  539.         if (!found)
  540.             ret_val = (-1);
  541.         }
  542.     else
  543.         ret_val = (-1);
  544.     q_busy = FALSE;
  545.     }%]se
  546.     ret_val = (-1);
  547.  
  548. return (ret_val);
  549.  
  550. }
  551. /* Function timer_enable()
  552. **
  553. ** This function enables normal timer queue operations.  If
  554. ** there is an element on the top of the timer queue, it sets
  555. ** up the appropriate alarm; otherwise, just marks the queue
  556. ** as enabled.  If the time of the next event has already passed,
  557. ** it will schedule it to happen in one second (prevents unexpected** interrupt).
  558. */
  559.  
  560. void timer_enable()
  561. {
  562.  
  563. unsigned int
  564.     nexttime;                   /* seconds till next timeout */
  565.  
  566. q_enabled = TRUE;
  567. if (queue_head != NULL)
  568.     {
  569.     if ( (nexttime=(unsigned int)queue_head->time - time((long*)0)) > 0)
  570.         alarm (nexttime);
  571.     else
  572.         alarm (1);
  573.     }
  574. else 
  575.     alarm (0);
  576.  
  577. return;
  578.  
  579. }
  580. /* Function timer_disable()
  581. **
  582. ** This function disables normal timer queue operations.  If
  583. ** there is an element on the top of the timer queue, it cancels
  584. ** the alarm() timer; otherwise, just marks the queue as disabled.
  585. */
  586. void timer_disable()
  587. {
  588. q_enabled = FALSE;
  589. if (queue_head != NULL)
  590.     ai19m (0);
  591. return;
  592. }
  593.  
  594.  
  595. /*Listing Four -- Sensor message definition */
  596.  
  597. /* sensor message command queue message structure */
  598.  
  599. struct message_rec
  600.     {
  601.     long        mtype;          /* message type */
  602.     int         func;           /* message function code */
  603.     int         sensor_num;     /* sensor number */
  604.     char        data[100];      /* message data */
  605.     };
  606.  
  607.  
  608. /* sensor command queue function codes */
  609.  
  610. #define SENSOR_INPUT (1)
  611. #define SENSOR_TIMEOUT (2)
  612. #define SENSOR_COMMAND (3)
  613.  
  614.  
  615. /* Listing Five -- Main routine for Solution B  */
  616.  
  617. #include <stdio.h>              /* standard Unix I/O header */
  618.  
  619. #include <termio.h>             /* file/port control headers */
  620. #include <fcntl.h>
  621.  
  622. #include <sys/types.h>          /* required headers for IPC */
  623. #include <sys/ipc.h>
  624. #include <sys/msg.h>
  625.  
  626. #include "sensor.h"             /* defines sensor messages */
  627.  
  628. /* local constants */
  629.  
  630. #define TRUE (1==1)             /* boolean values */
  631. #define FALSE (1==0)
  632.  
  633. /* Main routine for program */
  634.  
  635. main ()
  636. {
  637. int
  638.     cmd_size,                   /* number of bytes in command message */
  639.     qid;                        /* message queue identifier */
  640.  
  641. struct message_rec
  642.     cmd_msg;                    /* buffer for reading queue message */
  643.  
  644. /* open the command queue */
  645.  
  646. qid=msgget(1,IPC_CREAT|0666);
  647.  
  648. /* loop forever */
  649.  
  650. while (TRUE)
  651.     {
  652.     /* wait for a new message on the command queue */
  653.  
  654.     /* check for input on the message queue */
  655.  
  656.     cmd_size = msgrcv (qid, &cmd_msg, sizeof(cmd_msg), 0, 0);
  657.     switch (cmd_msg.func)
  658.         {
  659.         case SENSOR_INPUT :
  660.             process_sensor (cmd_msg.data, cmd_size, cmd_msg.sensor_num);
  661.             break;
  662.         case SENSOR_TIMEOUT :
  663.             process_timeout (cmd_msg.sensor_num);
  664.             break;
  665.         case SENSOR_COMMAND :
  666.             process_cmd_msg (&cmd_msg, cmd_size);
  667.             break;
  668.             break;        }
  669.     }
  670. }
  671.  
  672.  
  673. /* Function process_cmd_msg ()
  674. ** 
  675. ** This is a stub routine for handling command queue input.
  676. */
  677.  
  678. static process_cmd_msg (msg, size)
  679.  
  680. char 
  681.     *msg;                       /* INPUT: pointer to command message */
  682.  
  683. int
  684.     size;                       /* INPUT: size of *msg */
  685.  
  686. {
  687. /* (do some appropriate processing on the command) */
  688. }
  689.  
  690.  
  691. /* Function process_sensor
  692. **
  693. ** This is a stub routine for handling sensor input.
  694. */
  695.  
  696. static process_sensor (msg, size, sensor_num)
  697.  
  698. char
  699.     *msg;                       /* INPUT: pointer to sensor data */
  700.  
  701. int
  702.     size,                       /* INPUT: size of *msg */
  703.     sensor_num;                 /* INPUT: sensor number  */
  704.  
  705. {
  706. /* (do some appropriate processing on the message) */
  707. }
  708.  
  709.  
  710. /* Function process_timeout()
  711. **
  712. ** This is a stub for the sensor input timeout timer.
  713. */
  714.  
  715. static process_timeout (sensor_num)
  716.  
  717. int
  718.     sensor_num;                 /* INPUT: sensor which has timed out */
  719. {
  720. /* (do some appropriate processing on the error) */
  721. }
  722.  
  723.  
  724. /* Listing Six -- Sensor input process (one per sensor) */
  725.  
  726. #include <stdio.h>              /* standard Unix I/O header */
  727. #include <termio.h>             /* file/port control headers */
  728. #include <fcntl.h>
  729. #include <sys/types.h>          /* required headers for IPC */
  730. #include <sys/ipc.h>
  731. #include <sys/msg.h>
  732. #include "sensor.h"             /* sensor command message structure */
  733.  
  734. #define TRUE (1==1)             /* boolean true and false */
  735. #define FALSE (1==0)
  736.  
  737. #define TIMEOUT (10L)           /* sensor timeout delay */
  738.  
  739. main(argc,argv)
  740. int
  741.     argc;                       /* INPUT: number of command line arguments */
  742.  
  743. char 
  744.     *argv[];                    /* INPUT: pointers to command line arguments */
  745. {
  746.  
  747. int
  748.     flags,                      /* file control flags */
  749.     marktime_id,                /* timeout timer ID */
  750.     qid,                        /* IPC message queue ID */
  751.     sensor_fd,                  /* file descriptor for sensor port */
  752.     timeout;                    /* marktime timeout flag */
  753.  
  754. char
  755.     filename[20];               /* name of port file */
  756.  
  757. struct message_rec
  758.     sensor_msg;                 /* buffer for sensor message */
  759.  
  760. struct termio
  761.     clock_termio;               /* terminal I/O parameters */
  762.  
  763. /* open the sensor port */
  764.  
  765. sprintf (filename, "/dev/tty%d", atoi(argv[1]));
  766. sensor_fd=open(filename,O_RDWR);
  767.  
  768. /* open IPC queue */
  769.  
  770. qid=msgget(1,IPC_CREAT|0666);
  771. sensor_msg.mtype = 1;
  772. sensor_msg.sensor_num = atoi(argv[1]);
  773.  
  774. /* main loop */
  775.  
  776. while (TRUE)
  777.     {
  778.     /* set up timeout */
  779.     marktime_id=marktime(TIMEOUT,&timeout,(void*)NULL,(char*)NULL);
  780.  
  781.     /* read until data received or timeout timer expires */
  782.  
  783.     read (sensor_fd, sensor_msg.data, sizeof(sensor_msg.data));
  784.     if (!timeout)
  785.         {
  786.         /* got data -- cancel timeout and pass to main program */
  787.         cancel_marktime (marktime_id);
  788.         sensor_msg.func = SENSOR_INPUT;
  789.         msgsnd (qid, &sensor_msg, sizeof(sensor_msg), 0);
  790.         }
  791.     else
  792.         {
  793.         /* timeout -- inform main program */
  794.         sensor_msg.func = SENSOR_TIMEOUT;
  795.         msgsnd (qid, &sensor_msg, sizeof(sensor_msg), 0);
  796.         marktime_id=marktime(TIMEOUT,&timeout,(void*)NULL,(char*)NULL);
  797.         }
  798.     }
  799. }
  800.