Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

node.cc

Go to the documentation of this file.
00001 /*********************************************************************
00002 * File: node.cc                                                      *
00003 * Description: C++  File for the RCS Systems Team's Library          *
00004 * Purpose:                                                           *
00005 *       RCS Systems are constructed using a heirarchy of nodes.      *
00006 * Each node recieves commands from its superior and returns a status *
00007 *  message to its superior. If it has subordinates the node will     *
00008 * be responsible for sending commands to that subordinate and        *
00009 * monitoring the subordinates status. Nodes may also read sensors,   *
00010 * process sensor data, update the world model, plan future moves,    *
00011 * execute commands and handle errors.  The NODE class is defined so  *
00012 * that application nodes can be constructed with a consistent        *
00013 * interface and to  provide application nodes with certain           *
00014 * utilities.                                                         *
00015 *********************************************************************/
00016 #include "rcs_defs.hh"          /* EXTERN_C_STD_HEADERS */
00017 
00018 /* Include Files */
00019 #ifdef EXTERN_C_STD_HEADERS
00020 extern "C"
00021 {
00022 #endif
00023 
00024 #include <stdlib.h>             /* malloc(), free() */
00025 #include <string.h>             /* strcpy() */
00026 #include <signal.h>             /* SIGINT */
00027 #include <sys/types.h>
00028 #ifdef VXWORKS
00029 #include <taskLib.h>
00030 #endif
00031 
00032 #ifdef EXTERN_C_STD_HEADERS
00033 }
00034 #endif
00035 
00036 #include "nml.hh"               /* class NML */
00037 #include "nmlmsg.hh"            /* class NMLmsg */
00038 #include "cmd_msg.hh"           /* class RCS_CMD_MSG, RCS_GENERIC_CMD, */
00039                                 /* class RCS_CMD_CHANNEL */
00040 #include "stat_msg.hh"          /* class RCS_STAT_MSG, RCS_GENERIC_STAT, */
00041                                 /* class RCS_STAT_CHANNEL */
00042 #include "wm_msg.hh"            /* class RCS_WM_MSG, RCS_GENERIC_WM, */
00043                                 /* class RCS_WM_CHANNEL */
00044 #include "node.hh"              /* class NODE */
00045 #include "nodelink.hh"          /* class NODE_LINK */
00046 #include "rcs_prnt.hh"          /* rcs_print_error, rcs_print_debug */
00047 
00048 /* Constructors and Destructors */
00049 
00050 
00051 long default_node_config_flags = NODE_USE_GENERIC_COMMANDS |
00052   NODE_USE_STAT_BUFFER | NODE_USE_WM_BUFFER |
00053   NODE_CHECK_TIMES | NODE_RESET_STATE_ON_NEW_COMMAND |
00054   NODE_SEND_EXECUTING_ON_NEW_COMMAND;
00055 
00056 /*******************************************************************
00057  Class: NODE
00058  Function: (Constructor)
00059  Parameters:
00060     NML_FORMAT_PTR _format_ptr; - pointer to a function which
00061          handles the neutral data format encoding and decoding
00062          for the buffers used by this node. (See NML Doc.)
00063     char _name; - string including the name of this node
00064           (The names of the buffers connecting to this name are
00065            computed from my_name by adding suffixes like "_cmd".)
00066     char _config_file; - name of NML configuration file.
00067     RCS_CMD_MSG _startup_cmd; - pointer to command message for
00068           this node to use until its superior sends it a command
00069  Purpose: To initialize a new NODE object.
00070  NOTES: valid will equal 1 if the NODE was properly initialized.
00071  Returns: NONE.
00072 *******************************************************************/
00073 NODE::NODE (NML_FORMAT_PTR _format_ptr, char *_name, char *_config_file,
00074             RCS_CMD_MSG * _startup_cmd)
00075 {
00076   /* Indicate to user when the NODE is constructed. */
00077   rcs_print_debug (PRINT_NODE_CONSTRUCTORS,
00078                    "%s NODE constructor called.\n", _name);
00079 
00080   /* Set all the dynamically allocated pointers to NULL so the */
00081   /* so the destructors won't destroy them if they were never malloced, */
00082   /* and initialize some other NODE variables. */
00083   initialize_node_variables ();
00084 
00085   /* Set valid to zero incase we need to return from constructor early. */
00086   valid = 0;
00087 
00088   /* Store constructor parameters. */
00089   format_ptr = _format_ptr;
00090   config_file = _config_file;
00091   startup_cmd = _startup_cmd;
00092 
00093   /* Store the _name parameter in a new place. */
00094   name_length = strlen (_name);
00095   name = (char *) malloc (name_length + 1);
00096   if (NULL == name)
00097     {
00098       rcs_print_error ("NODE constructor: Couldn`t malloc space for name.\n");
00099       return;
00100     }
00101   strcpy (name, _name);
00102 
00103   /* Create an empty subordinate list. */
00104   sub_list = new RCS_LINKED_LIST;
00105   if (NULL == sub_list)
00106     {
00107       rcs_print_error ("%s: Couldn`t malloc space for list.\n", name);
00108       return;
00109     }
00110 
00111   wm_in_list = new RCS_LINKED_LIST;
00112   if (NULL == wm_in_list)
00113     {
00114       rcs_print_error ("%s: Couldn`t malloc space for list.\n", name);
00115       return;
00116     }
00117 
00118 
00119   if (-1 == initialize_command_buffer ())
00120     {
00121       return;
00122     }
00123   if (config_flags & NODE_SAVE_LAST_COMMAND && NULL != cmd_in)
00124     {
00125       if (NULL != cmd_in->cms)
00126         {
00127           last_cmd_in_msg = (RCS_CMD_MSG *) malloc (cmd_in->cms->size);
00128         }
00129     }
00130 
00131   if (config_flags & NODE_USE_STAT_BUFFER)
00132     {
00133       if (-1 == initialize_status_buffer ())
00134         {
00135           return;
00136         }
00137     }
00138 
00139   if (config_flags & NODE_USE_WM_BUFFER)
00140     {
00141       if (-1 == initialize_world_model_buffer ())
00142         {
00143           return;
00144         }
00145     }
00146 
00147   /* Set the valid flag to 1 since we made it this far. */
00148   valid = 1;
00149 
00150   /* Spawn servers for the command, status, and/or wm buffers if config */
00151   /* file says to. */
00152   nml_start ();
00153 
00154   /* Check if valid will set valid to zero if running this node could crash */
00155   /* the system. NODE::run() will do nothing if valid == 0 to avoid this. */
00156   check_if_valid ();
00157 
00158   rcs_print_debug (PRINT_NODE_CONSTRUCTORS,
00159                    "%s NODE constructor finished. (valid = %d)\n", _name,
00160                    valid);
00161 }
00162 
00163 /* Functions called from constructor. */
00164 
00165 /********************************************************************
00166  Class: NODE
00167  Function: initialize_node_variables
00168  Parameters: NONE
00169  Purpose: To initialize the node variables.
00170  Returns: 0 for success or -1 for failure.
00171 *******************************************************************/
00172 int
00173 NODE::initialize_node_variables ()
00174 {
00175 
00176   /* Set all the dynamically allocated pointers to NULL so the */
00177   /* so the destructors won't destroy them if they were never malloced. */
00178   name = (char *) NULL;
00179   name_length = 0;
00180   cmd_in = (RCS_CMD_CHANNEL *) NULL;
00181   status_up = (RCS_STAT_CHANNEL *) NULL;
00182   wm_out = (RCS_WM_CHANNEL *) NULL;
00183 
00184   sub_list = (RCS_LINKED_LIST *) NULL;
00185   generic_status = (RCS_GENERIC_STATUS *) NULL;
00186   cycle_timer = (RCS_TIMER *) NULL;
00187   wm_in_list = (RCS_LINKED_LIST *) NULL;
00188 
00189   cmd_in_msg = (RCS_CMD_MSG *) NULL;
00190   last_cmd_in_msg = (RCS_CMD_MSG *) NULL;
00191 
00192   /* Initialize some other NODE variables. */
00193   node_status = NODE_INIT;
00194   status_up_new = 0;
00195   cmd_in_new = 1;
00196   cmd_in_type_new = 1;
00197   config_flags = default_node_config_flags;
00198   wm_out_new = 0;
00199   oper_in_new = 0;
00200   state = 0;
00201   error_code = 0;
00202   num_of_subord = 0;
00203   all_subordinates_done = 0;
00204   cycle_count = 0;
00205   abort_flag = 0;
00206   min_cycle_time = 360000;
00207   max_cycle_time = 0;
00208   min_process_time = 360000;
00209   max_process_time = 0;
00210   return (0);
00211 }
00212 
00213 /********************************************************************
00214  Class: NODE
00215  Function: initialize_command_buffer
00216  Parameters: NONE
00217  Purpose: To initialize the command buffer by creating it if neccessary,
00218   writing a generic command into it and verifying that that command is there.
00219  Returns: 0 for success or -1 for failure.
00220 *******************************************************************/
00221 int
00222 NODE::initialize_command_buffer ()
00223 {
00224 
00225   if (NULL == cmd_in)
00226     {
00227       /* Compute the name of the command buffer. */
00228       char *command_buffer_name;
00229       command_buffer_name =
00230         (char *) malloc (name_length + RCS_COMMAND_SUFFIX_LENGTH + 1);
00231       if (NULL == command_buffer_name)
00232         {
00233           rcs_print_error ("%s: malloc failed.\n", name);
00234           return (-1);
00235         }
00236       strcpy (command_buffer_name, name);
00237       strcat (command_buffer_name, RCS_COMMAND_SUFFIX);
00238 
00239       /* Create a channel to the command buffer. */
00240       cmd_in = new RCS_CMD_CHANNEL (format_ptr, command_buffer_name,
00241                                     name, config_file);
00242       free (command_buffer_name);
00243       command_buffer_name = (char *) NULL;
00244     }
00245 
00246   /* Make sure cmd in object created. */
00247   if (NULL == cmd_in)
00248     {
00249       rcs_print_error ("%s: Couldn`t create cmd_in channel.\n", name);
00250       return -1;
00251     }
00252 
00253   /* Check to see if cmd_in properly constructed. */
00254   if (!cmd_in->valid ())
00255     {
00256       rcs_print_error ("%s: Command buffer channel invalid. \n", name);
00257       return -1;
00258     }
00259 
00260   /* Create the startup command if none was passed to constructor. */
00261   int startup_cmd_created = 0;
00262   if (NULL == startup_cmd)
00263     {
00264       startup_cmd = new RCS_GENERIC_CMD;
00265       startup_cmd_created = 1;
00266     }
00267   if (NULL == startup_cmd)
00268     {
00269       rcs_print_error ("%s: Can't create startup command.\n", name);
00270       return -1;
00271     }
00272   ((RCS_GENERIC_CMD *) startup_cmd)->gen_id = GENERIC_INIT;
00273 
00274   /* Write the startup command into the command buffer. */
00275   if (-1 == cmd_in->write (startup_cmd))
00276     {
00277       rcs_print_error ("%s: Error on initial write to command buffer.\n",
00278                        name);
00279       return -1;
00280     }
00281 
00282   /* Read back the startup command. */
00283   if (-1 == cmd_in->read ())
00284     {
00285       rcs_print_error ("%s: Error on initial read of command buffer.\n",
00286                        name);
00287       return -1;
00288     }
00289   cmd_in_msg = (RCS_CMD_MSG *) cmd_in->get_address ();
00290   cmd_in_type = cmd_in_msg->type;
00291 
00292   /* Check to see if startup command matches command read back. */
00293   if (cmd_in_type != startup_cmd->type ||
00294       cmd_in_msg->serial_number != startup_cmd->serial_number)
00295     {
00296       rcs_print_error ("%s: Error initializing the command buffer. \n", name);
00297       return -1;
00298     }
00299 
00300   if (startup_cmd_created)
00301     {
00302       delete startup_cmd;
00303       startup_cmd = (RCS_CMD_MSG *) NULL;
00304     }
00305 
00306   /* Return "success". */
00307   return (0);
00308 }
00309 
00310 /********************************************************************
00311  Class: NODE
00312  Function: initialize_status_buffer
00313  Parameters: NONE
00314  Purpose: To initialize the status buffer by creating it if neccessary,
00315   writing a generic status message into it.
00316  Returns: 0 for success or -1 for failure.
00317 *******************************************************************/
00318 int
00319 NODE::initialize_status_buffer ()
00320 {
00321   if (status_up == NULL)
00322     {
00323       /* Compute the name of the status buffer. */
00324       char *status_buffer_name;
00325       status_buffer_name =
00326         (char *) malloc (name_length + RCS_STATUS_SUFFIX_LENGTH + 1);
00327       if (NULL == status_buffer_name)
00328         {
00329           rcs_print_error ("%s: malloc error.\n", name);
00330           return (-1);
00331         }
00332       strcpy (status_buffer_name, name);
00333       strcat (status_buffer_name, RCS_STATUS_SUFFIX);
00334 
00335       /* Create a new channel to the status buffer. */
00336       status_up = new RCS_STAT_CHANNEL (format_ptr, status_buffer_name,
00337                                         name, config_file);
00338 
00339       /* Free the space for the status_buffer_name */
00340       free (status_buffer_name);
00341       status_buffer_name = (char *) NULL;
00342     }
00343 
00344   /* Make sure status up object created. \n"); */
00345   if (NULL == status_up)
00346     {
00347       rcs_print_error ("%s: Couldn`t create status_up channel.\n", name);
00348       return (-1);
00349     }
00350 
00351   /* Check to see if status_up buffer properly constructed. */
00352   if (!status_up->valid ())
00353     {
00354       rcs_print_error ("%s: status_up object not properly constructed.\n",
00355                        name);
00356       return -1;
00357     }
00358 
00359   /* Create initial status object. */
00360   generic_status = new RCS_GENERIC_STATUS;
00361   if (NULL == generic_status)
00362     {
00363       rcs_print_error ("%s: Can't create initial status message.\n", name);
00364       return -1;
00365     }
00366   status_up_msg = generic_status;
00367   status_up_msg->node_status = NODE_INIT;
00368 
00369   /* Write initial status into status up buffer. */
00370   if (-1 == status_up->write (status_up_msg))
00371     {
00372       rcs_print_error ("%s: Error on initial write to status buffer.\n",
00373                        name);
00374       return -1;
00375     }
00376 
00377   /* Return "success". */
00378   return (0);
00379 }
00380 
00381 /********************************************************************
00382  Class: NODE
00383  Function: initialize_world_model_buffer
00384  Parameters: NONE
00385  Purpose: To initialize the status buffer by creating it if neccessary,
00386   writing a generic status message into it.
00387  Returns: 0 for success or -1 for failure.
00388 *******************************************************************/
00389 int
00390 NODE::initialize_world_model_buffer ()
00391 {
00392   if (NULL == wm_out)
00393     {
00394       /* Compute world model out buffer name. */
00395       char *wm_buffer_name;
00396       wm_buffer_name =
00397         (char *) malloc (name_length + RCS_WM_SUFFIX_LENGTH + 1);
00398       if (NULL == wm_buffer_name)
00399         {
00400           rcs_print_error ("%s: malloc error.\n", name);
00401         }
00402       strcpy (wm_buffer_name, name);
00403       strcat (wm_buffer_name, RCS_WM_SUFFIX);
00404 
00405       /* Create world model out channel. */
00406       wm_out =
00407         new RCS_WM_CHANNEL (format_ptr, wm_buffer_name, name, config_file);
00408 
00409       /* Release the memory for the buffer name. */
00410       free (wm_buffer_name);
00411       wm_buffer_name = NULL;
00412     }
00413 
00414   /* Check to see that wm_out created. */
00415   if (NULL == wm_out)
00416     {
00417       rcs_print_error ("%s: Can't create world model out channel. \n", name);
00418       return -1;
00419     }
00420 
00421   /* Check to see if wm_out properly constructed. */
00422   if (!wm_out->valid ())
00423     {
00424       rcs_print_error
00425         ("%s: World model out channel improperly constructed.\n", name);
00426       return -1;
00427     }
00428 
00429   /* Create initial world model message. */
00430   wm_out_msg = new RCS_GENERIC_WM;
00431   if (NULL == wm_out_msg)
00432     {
00433       rcs_print_error ("%s: Can't create initial world model message.\n",
00434                        name);
00435       return (-1);
00436     }
00437 
00438   if (-1 == wm_out->write (wm_out_msg))
00439     {
00440       rcs_print_error ("%s: Error on initial write to world model.\n", name);
00441       return -1;
00442     }
00443   delete wm_out_msg;
00444   wm_out_msg = NULL;
00445 
00446   /* Return "success". */
00447   return (0);
00448 }
00449 
00450 /*******************************************************************
00451 * Class: NODE                                                      *
00452 * Function: (Destructor)                                           *
00453 * Parameters: NONE.                                                *
00454 * Purpose: To deallocate and close a  NODE object.                 *
00455 * Returns: NONE.                                                   *
00456 *******************************************************************/
00457 NODE::~NODE ()
00458 {
00459   /* Indicate to user when the node is deleted. */
00460   rcs_print_debug (PRINT_NODE_DESTRUCTORS, "%s: Destructor called.\n", name);
00461 
00462   if (NULL != name)
00463     {
00464       free (name);
00465       name = NULL;
00466     }
00467   if (NULL != generic_status)
00468     {
00469       delete generic_status;
00470       generic_status = NULL;
00471     }
00472   if (NULL != sub_list)
00473     {
00474       delete sub_list;
00475       sub_list = NULL;
00476     }
00477   if (NULL != wm_in_list)
00478     {
00479       delete wm_in_list;
00480       wm_in_list = NULL;
00481     }
00482   if (NULL != last_cmd_in_msg)
00483     {
00484       free (last_cmd_in_msg);
00485       last_cmd_in_msg = NULL;
00486     }
00487   nml_cleanup ();
00488 
00489   rcs_print_debug (PRINT_NODE_DESTRUCTORS, "Destructor finished.\n");
00490 }
00491 
00492 /* Member Functions */
00493 
00494 /*******************************************************************
00495 * Class: NODE
00496 * Function: run
00497 * Parameters: NONE.
00498 * Purpose: To run a NODE  through one cycle.
00499 *         NODE::run calls each of the following functions which
00500 * applications nodes can override, it also checks the returns of
00501 * these functions and stops the rest of the cycle and calls the
00502 * error_handler.
00503 * FUNCTION                 WHEN SHOULD USER OVERRIDE
00504 * get_command_message              never.
00505 * get_subordinates_status          never.
00506 * read_world_model_in              never.
00507 * read_sensors                     to read some sensors.
00508 * get_oi_requests                  to get input from operator.
00509 * sensory_processor                to process sensor data.
00510 * world_modeler                    to compute world model information
00511 * process_oi_requests              to perform the operator interface request
00512 * command_independant_planner      to do processing regardless of current cmd
00513 * handle_generic_commands          never.
00514 * execute_commands                 to execute the current command
00515 * output_to_actuators              node is responsible for some actuators.
00516 * send_subordinates_commands       never.
00517 * send_status_message              never.
00518 * send_oi_reply                    to output to an operator interface
00519 * write_world_model_out            never.
00520 *
00521 * error_handler                    it's convienent to handle an error here.
00522 *
00523 * Returns: NONE.
00524 *******************************************************************/
00525 void
00526 NODE::run (RCS_TIMER * _timer)
00527 {
00528   if (!valid)
00529     {
00530       rcs_print_error ("%s: NODE not properly constructed. \n", name);
00531       abort_flag = 1;
00532       return;
00533     }
00534 
00535   check_timer (_timer);
00536 
00537   cycle_count++;
00538   last_state = state;
00539   rcs_print_debug (PRINT_NODE_CYCLES, "%s: Cycles = %d\n", name, cycle_count);
00540 
00541   if (-1 == cyclic_read ())
00542     {
00543       error_handler ();
00544       return;
00545     }
00546 
00547   if (-1 == cyclic_process ())
00548     {
00549       error_handler ();
00550       return;
00551     }
00552 
00553   if (-1 == cyclic_write ())
00554     {
00555       error_handler ();
00556       return;
00557     }
00558 
00559   wait_for_timer (_timer);
00560 
00561   if (abort_flag)
00562     {
00563       rcs_print_debug (PRINT_NODE_ABORT, "%s aborting!\n", name);
00564       return;
00565     }
00566   return;
00567 }
00568 
00569 /*******************************************************************
00570 * Class: NODE
00571 * Function: check_timer
00572 * Parameters:
00573 * RCS_TIMER *_timer;
00574 *
00575 * Purpose: Checks the cycle time, initializes the timer if neccessary,
00576 * and prints some debug information.
00577 * Outputs:  NONE.
00578 * Returns: NONE.
00579 *******************************************************************/
00580 void
00581 NODE::check_timer (RCS_TIMER * _timer)
00582 {
00583   double time_check;
00584   static old_cycle_count;
00585   if ((NULL != _timer) && (_timer != cycle_timer))
00586     {
00587       if (NULL != cycle_timer && cycle_timer_created)
00588         {
00589           delete cycle_timer;
00590         }
00591       cycle_timer = _timer;
00592       cycle_timer->sync ();
00593       cycle_timer_created = 0;
00594     }
00595 
00596   if (NULL != cycle_timer)
00597     {
00598       cycle_time = cycle_timer->timeout;
00599     }
00600 
00601   if (config_flags & NODE_CHECK_TIMES)
00602     {
00603       time_check = etime ();
00604       if (0 != cycle_count)
00605         {
00606           last_cycle_time = time_check - start_time;
00607           if (last_cycle_time < min_cycle_time)
00608             {
00609               min_cycle_time = last_cycle_time;
00610             }
00611           if (last_cycle_time > max_cycle_time)
00612             {
00613               max_cycle_time = last_cycle_time;
00614             }
00615           rcs_print_debug (PRINT_NODE_CYCLE_TIMES,
00616                            "%s: cycle times (last, min, max) = (%lf, %lf, %lf)\n",
00617                            name, last_cycle_time, min_cycle_time,
00618                            max_cycle_time); \}
00619       start_time = time_check;
00620     }
00621 }
00622 
00623 /*******************************************************************
00624 * Class: NODE                                                      *
00625 * Function: run                                                    *
00626 * Parameters:                                                      *
00627 * RCS_TIMER *_timer; - Timer used for syncronization.
00628 * Purpose: Waits until its time for the next cycle.
00629 * Outputs:  NONE.                                                  *
00630 * Returns: NONE.                                                   *
00631 *******************************************************************/
00632 void
00633 NODE::wait_for_timer (RCS_TIMER * _timer)
00634 {
00635   if (config_flags & NODE_CHECK_TIMES)
00636     {
00637       finish_time = etime ();
00638       last_process_time = finish_time - start_time;
00639       if (last_process_time < min_process_time)
00640         {
00641           min_process_time = last_process_time;
00642         }
00643       if (last_process_time > max_process_time)
00644         {
00645           max_process_time = last_process_time;
00646         }
00647       rcs_print_debug (PRINT_NODE_PROCESS_TIMES,
00648                        "%s: process times (last, min, max) = (%lf, %lf, %lf)\n",
00649                        name, last_process_time, min_process_time,
00650                        max_process_time);
00651     }
00652   if (NULL != cycle_timer)
00653     {
00654       int missed_cycles;
00655       missed_cycles = cycle_timer->wait ();
00656       if (missed_cycles > 0)
00657         {
00658           rcs_print_debug (PRINT_NODE_MISSED_CYCLES,
00659                            "%s: missed %d cycles.\n", name, missed_cycles);
00660         }
00661     }
00662   return;
00663 }
00664 
00665 /*******************************************************************
00666 * Class: NODE
00667 * Function: cyclic_read()
00668 * Purpose: Reads in data from various sources, for each cycle.
00669 * Returns: 0 for success or -1 for error.
00670 *******************************************************************/
00671 int
00672 NODE::cyclic_read ()
00673 {
00674   if (-1 == get_command_message ())     /* Read in cmd_in_message. */
00675     {
00676       current_section = NODE_GET_COMMAND_MESSAGE;
00677       return -1;
00678     }
00679 
00680   if (-1 == get_subordinates_status ()) /* Get status from subodinates. */
00681     {
00682       current_section = NODE_GET_SUBORDINATES_STATUS;
00683       return -1;;
00684     }
00685 
00686   if (-1 == read_world_model_in ())     /* Read wm_in_list */
00687     {
00688       current_section = NODE_READ_WORLD_MODEL_IN;
00689       return -1;
00690     }
00691 
00692   if (-1 == get_oi_requests ()) /* USER-DEFINED */
00693     {
00694       current_section = NODE_GET_OI_REQUESTS;
00695       return -1;
00696     }
00697 
00698   if (-1 == read_sensors ())    /* USER-DEFINED */
00699     {
00700       current_section = NODE_READ_SENSORS;
00701       return -1;
00702     }
00703   return 0;
00704 }
00705 
00706 /*******************************************************************
00707 * Class: NODE
00708 * Function: cyclic_process()
00709 * Purpose: Performs 1 cycles worth of processing.
00710 * Returns: 0 for success or -1 for error.
00711 *******************************************************************/
00712 int
00713 NODE::cyclic_process ()
00714 {
00715   if (-1 == process_oi_requests ())     /* USER-DEFINED */
00716     {
00717       current_section = NODE_PROCESS_OI_REQUESTS;
00718       return -1;
00719     }
00720 
00721   if (-1 == sensory_processor ())       /* USER-DEFINED */
00722     {
00723       current_section = NODE_SENSORY_PROCESSOR;
00724       return -1;
00725     }
00726 
00727   if (-1 == world_modeler ())   /* USER-DEFINED */
00728     {
00729       current_section = NODE_WORLD_MODELER;
00730       return -1;
00731     }
00732 
00733   if (-1 == command_independant_planner ())     /* USER-DEFINED */
00734     {
00735       current_section = NODE_COMMAND_INDEPENDANT_PLANNER;
00736       return -1;
00737     }
00738 
00739   if (cmd_in_new || !(config_flags & NODE_EXECUTE_NEW_COMMANDS_ONLY))
00740     {
00741       if (-1 == handle_generic_commands ())     /* Call init or halt if recieved. */
00742         {
00743           current_section = NODE_HANDLE_GENERIC_COMMANDS;
00744           return -1;
00745         }
00746 
00747       if (cmd_in_type == RCS_GENERIC_CMD_TYPE)
00748         {
00749           return 0;
00750         }
00751 
00752       if (-1 == execute_command ())     /* USER-DEFINED */
00753         {
00754           current_section = NODE_EXECUTE_COMMAND;
00755           return -1;
00756         }
00757     }
00758   return 0;
00759 }
00760 
00761 
00762 
00763 /*******************************************************************
00764 * Class: NODE
00765 * Function: cyclic_write()
00766 * Purpose: Writes data out to various sources for this cycle.
00767 * Returns: 0 for success or -1 for error.
00768 *******************************************************************/
00769 int
00770 NODE::cyclic_write ()
00771 {
00772   if (-1 == output_to_actuators ())     /* USER-DEFINED */
00773     {
00774       current_section = NODE_OUTPUT_TO_ACTUATORS;
00775       return -1;
00776     }
00777 
00778   if (-1 == send_oi_replies ()) /* USER-DEFINED */
00779     {
00780       current_section = NODE_SEND_OI_REPLIES;
00781       return -1;
00782     }
00783 
00784   if (-1 == write_world_model_out ())   /* USER-DEFINED */
00785     {
00786       current_section = NODE_WRITE_WORLD_MODEL_OUT;
00787       return -1;
00788     }
00789 
00790   if (-1 == send_subordinates_commands ())      /* Send Commands to Subs */
00791     {
00792       current_section = NODE_SEND_SUBORDINATES_COMMANDS;
00793       return -1;
00794     }
00795 
00796   if (-1 == send_status_message ())     /* Write status_up for my supervisor. */
00797     {
00798       current_section = NODE_SEND_STATUS_MESSAGE;
00799       return -1;
00800     }
00801   return (0);
00802 }
00803 
00804 /*******************************************************************
00805 * Class: NODE                                                      *
00806 * Function: run                                                    *
00807 * Parameters:                                                      *
00808 * double time; - time used for cycle_timer.                        *
00809 * Purpose: Runs the node at the specified cycle time.
00810 * Outputs:  NONE.                                                  *
00811 * Returns: NONE.                                                   *
00812 *******************************************************************/
00813 void
00814 NODE::run (double _time)
00815 {
00816   if (_time != cycle_time)
00817     {
00818       if (NULL != cycle_timer && cycle_timer_created)
00819         {
00820           delete cycle_timer;
00821           cycle_timer = NULL;
00822         }
00823     }
00824   if (NULL == cycle_timer)
00825     {
00826       cycle_timer = new RCS_TIMER (_time);
00827       cycle_time = _time;
00828       cycle_timer_created = 1;
00829     }
00830   run ();
00831 }
00832 
00833 
00834 /*******************************************************************
00835 * Class: NODE                                                      *
00836 * Function: task                                                   *
00837 * Parameters:                                                      *
00838 * double time; - time used for cycle_timer.                        *
00839 * Purpose: Reads in command messages and checks for old messages   *
00840 *   or errors on the communication channel.                        *
00841 * Outputs:  NONE.                                                  *
00842 * Returns: NONE.                                                   *
00843 *******************************************************************/
00844 void
00845 NODE::task (double time)
00846 {
00847   if (time != cycle_time)
00848     {
00849       if (NULL != cycle_timer)
00850         {
00851           delete cycle_timer;
00852           cycle_timer = NULL;
00853         }
00854     }
00855   if (NULL == cycle_timer)
00856     {
00857       cycle_timer = new RCS_TIMER (time);
00858       cycle_time = time;
00859       cycle_timer_created = 1;
00860     }
00861   while (!abort_flag)
00862     {
00863       run ();
00864     }
00865 }
00866 
00867 /*******************************************************************
00868 * Class: NODE                                                      *
00869 * Function: run                                                    *
00870 * Parameters:                                                      *
00871 * double time; - time used for cycle_timer.                        *
00872 * Purpose: Reads in command messages and checks for old messages   *
00873 *   or errors on the communication channel.                        *
00874 * Outputs:  NONE.                                                  *
00875 * Returns: NONE.                                                   *
00876 *******************************************************************/
00877 void
00878 NODE::task (RCS_TIMER * timer)
00879 {
00880   if ((NULL != cycle_timer) && cycle_timer_created)
00881     {
00882       delete cycle_timer;
00883       cycle_timer = NULL;
00884     }
00885 
00886   cycle_timer = timer;
00887   cycle_time = timer->timeout;
00888   cycle_timer_created = 0;
00889 
00890   while (!abort_flag)
00891     {
00892       run ();
00893     }
00894 }
00895 
00896 
00897 /*******************************************************************
00898 * Class: NODE                                                      *
00899 * Function: get_command_message                                    *
00900 * Parameters: NONE.                                                *
00901 * Purpose: Reads in command messages and checks for old messages   *
00902 *   or errors on the communication channel.                        *
00903 * Outputs:                                                         *
00904 *  RCS_CMD_MSG *cmd_in_msg; - pointer to message sent to       *
00905 *                               superior.                          *
00906 *  NMLTYPE cmd_in_type; - NML type id of last message recieved.    *
00907 *  int state; - set to zero when new cmd recieved.                 *
00908 *  int new_cmd_in; - set to one when new cmd recieved set to 0     *
00909 *                    otherwise.                                    *
00910 * Returns: 0 for success.                                          *
00911 *          -1 if an error occured.                                 *
00912 *******************************************************************/
00913 int
00914 NODE::get_command_message ()
00915 {
00916   NMLTYPE read_value;
00917   if (config_flags & NODE_SAVE_LAST_COMMAND && NULL != cmd_in_msg &&
00918       NULL != last_cmd_in_msg)
00919     {
00920       memcpy (last_cmd_in_msg, cmd_in_msg, cmd_in_msg->size);
00921     }
00922 
00923   switch (read_value = cmd_in->read ())
00924     {
00925     case -1:
00926       rcs_print_error ("%s::get_command_message: Can`t read command in.\n",
00927                        name);
00928       return (-1);
00929     case 0:
00930       cmd_in_new = 0;
00931       return (0);
00932     default:
00933       cmd_in_new = 1;
00934       cmd_in_msg = cmd_in->get_address ();
00935       last_state_of_last_command = state;
00936       if (config_flags & NODE_RESET_STATE_ON_NEW_COMMAND)
00937         {
00938           state = 0;
00939         }
00940       if (config_flags & NODE_SEND_EXECUTING_ON_NEW_COMMAND)
00941         {
00942           send_status (NODE_EXECUTING);
00943         }
00944       node_status = NODE_EXECUTING;
00945       cmd_in_type_new = (cmd_in_type != read_value);
00946       last_cmd_in_type = cmd_in_type;
00947       cmd_in_type = read_value;
00948       rcs_print_debug (PRINT_COMMANDS_RECIEVED,
00949                        "%s: New cmd recieved. (type = %ld (0x%lX))\n", name,
00950                        cmd_in_type, cmd_in_type);
00951     }
00952   return (0);
00953 }
00954 
00955 /*******************************************************************
00956 * Class: NODE                                                      *
00957 * Function: get_subordinates_status                                *
00958 * Parameters: NONE.                                                *
00959 * Outputs:    NONE.                                                *
00960 * Returns: 0 for success.                                          *
00961 *          -1 if an error occured.                                 *
00962 *******************************************************************/
00963 int
00964 NODE::get_subordinates_status ()
00965 {
00966   NODE_LINK *node_link;
00967 
00968   if (0 == num_of_subord)
00969     {
00970       all_subordinates_done = 1;
00971       return (0);
00972     }
00973 
00974   if (NULL == sub_list)
00975     {
00976       return (-1);
00977     }
00978   all_subordinates_done = 1;
00979 
00980   node_link = (NODE_LINK *) sub_list->get_head ();
00981   while (NULL != node_link)
00982     {
00983       if (-1 == node_link->get_status ())
00984         {
00985           rcs_print_error ("%s::get_subodinates_status:\n", name);
00986           rcs_print_error ("   Error getting  %s's status.\n",
00987                            node_link->name);
00988           all_subordinates_done = 0;
00989           return (-1);
00990         }
00991       if (NODE_DONE != node_link->node_status)
00992         {
00993           all_subordinates_done = 0;
00994         }
00995       node_link = (NODE_LINK *) sub_list->get_next ();
00996     }
00997 
00998   return (0);
00999 }
01000 
01001 /*******************************************************************
01002 * Class: NODE                                                      *
01003 * Function: get_oi_message                                         *
01004 * Parameters: NONE.                                                *
01005 * Outputs:    NONE.                                                *
01006 * Returns: 0 for success.                                          *
01007 *          -1 if an error occured.                                 *
01008 *******************************************************************/
01009 int
01010 NODE::get_oi_requests ()
01011 {
01012   return (0);
01013 }
01014 
01015 /*******************************************************************
01016 * Class: NODE                                                      *
01017 * Function: read_world_model_in                                    *
01018 * Parameters: NONE.                                                *
01019 * Outputs:    NONE.                                                *
01020 * Returns: 0 for success.                                          *
01021 *          -1 if an error occured.                                 *
01022 *******************************************************************/
01023 int
01024 NODE::read_world_model_in ()
01025 {
01026   NODE_LINK *node_link;
01027   if (NULL == wm_in_list)
01028     {
01029       return (-1);
01030     }
01031 
01032   node_link = (NODE_LINK *) wm_in_list->get_head ();
01033   while (NULL != node_link)
01034     {
01035       if (-1 == node_link->read_wm ())
01036         {
01037           rcs_print_error ("%s::read_world_model_in:\n", name);
01038           rcs_print_error ("   Error getting  %s's wm.\n", node_link->name);
01039           return (-1);
01040         }
01041       node_link = (NODE_LINK *) wm_in_list->get_next ();
01042     }
01043 
01044   return (0);
01045 }
01046 
01047 /*******************************************************************
01048 * Class: NODE                                                      *
01049 * Function: determine_command                                      *
01050 * Parameters: NONE.                                                *
01051 * Outputs:    NONE.                                                *
01052 * Returns: 0 for success.                                          *
01053 *          -1 if an error occured.                                 *
01054 *******************************************************************/
01055 int
01056 NODE::process_oi_requests ()
01057 {
01058   return (0);
01059 }
01060 
01061 /*******************************************************************
01062 * Class: NODE                                                      *
01063 * Function: read_sensors                                           *
01064 * Parameters: NONE.                                                *
01065 * Outputs:    NONE.                                                *
01066 * Returns: 0 for success.                                          *
01067 *          -1 if an error occured.                                 *
01068 *******************************************************************/
01069 int
01070 NODE::read_sensors ()
01071 {
01072   return (0);
01073 }
01074 
01075 /*******************************************************************
01076 * Class: NODE                                                      *
01077 * Function: sensory_processor                                      *
01078 * Parameters: NONE.                                                *
01079 * Outputs:    NONE.                                                *
01080 * Returns: 0 for success.                                          *
01081 *          -1 if an error occured.                                 *
01082 *******************************************************************/
01083 int
01084 NODE::sensory_processor ()
01085 {
01086   return (0);
01087 }
01088 
01089 /*******************************************************************
01090 * Class: NODE                                                      *
01091 * Function: world_modeler                                          *
01092 * Parameters: NONE.                                                *
01093 * Outputs:    NONE.                                                *
01094 * Returns: 0 for success.                                          *
01095 *          -1 if an error occured.                                 *
01096 *******************************************************************/
01097 int
01098 NODE::world_modeler ()
01099 {
01100   return (0);
01101 }
01102 
01103 /*******************************************************************
01104 * Class: NODE                                                      *
01105 * Function: command_independant_planner
01106 * Parameters: NONE.                                                *
01107 * Outputs:    NONE.                                                *
01108 * Returns: 0 for success.                                          *
01109 *          -1 if an error occured.                                 *
01110 *******************************************************************/
01111 int
01112 NODE::command_independant_planner ()
01113 {
01114   return (0);
01115 }
01116 
01117 /*******************************************************************
01118 * Class: NODE                                                      *
01119 * Function: handle_generic_commands                                *
01120 * Parameters: NONE.                                                *
01121 * Outputs:    NONE.                                                *
01122 * Returns: 0 for success.                                          *
01123 *          -1 if an error occured.                                 *
01124 *******************************************************************/
01125 int
01126 NODE::handle_generic_commands ()
01127 {
01128   RCS_GENERIC_CMD *gen_cmd;
01129 
01130 
01131   if (config_flags & NODE_USE_GENERIC_COMMANDS)
01132     {
01133       /* Check if the last command was a generic commands. */
01134       if ((RCS_GENERIC_CMD_TYPE == cmd_in_type) && (NULL != sub_list))
01135         {
01136           gen_cmd = ((RCS_GENERIC_CMD *) cmd_in_msg);
01137 
01138           /* Call the command function associated with this command. */
01139           switch (gen_cmd->gen_id)
01140             {
01141             case GENERIC_INIT:
01142               init ();
01143               break;
01144             case GENERIC_HALT:
01145               halt ();
01146               break;
01147             default:
01148               break;
01149             }
01150         }
01151     }
01152 
01153   return (0);
01154 }
01155 
01156 /*******************************************************************
01157 * Class: NODE                                                      *
01158 * Function: send_command_to_all                                    *
01159 * Parameters:                                                      *
01160 * RCS_CMD_MSG *cmd; - The command that will be sent to all         *
01161 * subordinates on the sub_list.                                    *
01162 * Outputs:    NONE.                                                *
01163 * Returns:   NONE.                                                 *
01164 *******************************************************************/
01165 void
01166 NODE::send_command_to_all (RCS_CMD_MSG * cmd)
01167 {
01168   NODE_LINK *node_link;
01169 
01170   if (NULL != sub_list)
01171     {
01172       /* Send the generic command to all the subnodes. */
01173       node_link = (NODE_LINK *) sub_list->get_head ();
01174       while (NULL != node_link)
01175         {
01176           node_link->new_command (cmd);
01177           node_link = (NODE_LINK *) sub_list->get_next ();
01178         }
01179     }
01180 }
01181 
01182 /*******************************************************************
01183 * Class: NODE                                                      *
01184 * Function: execute_commands
01185 * Parameters: NONE.                                                *
01186 * Outputs:    NONE.                                                *
01187 * Returns: 0 for success.                                          *
01188 *          -1 if an error occured.                                 *
01189 *******************************************************************/
01190 int
01191 NODE::execute_command ()
01192 {
01193   return (0);
01194 }
01195 
01196 /*******************************************************************
01197 * Class: NODE                                                      *
01198 * Function: initialize_state_variables                             *
01199 * Parameters: NONE.                                                *
01200 * Outputs:    NONE.                                                *
01201 * Returns: NONE.                                                   *
01202 *******************************************************************/
01203 void
01204 NODE::initialize_state_variables ()
01205 {
01206 }
01207 
01208 /*******************************************************************
01209 * Class: NODE                                                      *
01210 * Function: init                                                   *
01211 * Parameters: NONE.                                                *
01212 * Outputs:    NONE.                                                *
01213 * Returns: NONE.                                                   *
01214 *******************************************************************/
01215 void
01216 NODE::init ()
01217 {
01218   switch (state)
01219     {
01220     case 0:
01221       send_command_to_all (cmd_in_msg);
01222       initialize_state_variables ();
01223       state = 1;
01224       break;
01225     case 1:
01226       if (all_subordinates_done)
01227         {
01228           send_status (NODE_DONE);
01229           state = 2;
01230         }
01231       break;
01232     case 2:
01233       break;
01234     default:
01235       break;
01236     }
01237 }
01238 
01239 /*******************************************************************
01240 * Class: NODE                                                      *
01241 * Function: halt                                                   *
01242 * Parameters: NONE.                                                *
01243 * Outputs:    NONE.                                                *
01244 * Returns: NONE.                                                   *
01245 *******************************************************************/
01246 void
01247 NODE::halt ()
01248 {
01249   switch (state)
01250     {
01251     case 0:
01252       send_command_to_all (cmd_in_msg);
01253       abort_flag = 1;
01254       state = 1;
01255       break;
01256     case 1:
01257       break;
01258     default:
01259       break;
01260     }
01261 }
01262 
01263 /*******************************************************************
01264 * Class: NODE                                                      *
01265 * Function: output_to_actuators                                    *
01266 * Parameters: NONE.                                                *
01267 * Outputs:    NONE.                                                *
01268 * Returns: 0 for success.                                          *
01269 *          -1 if an error occured.                                 *
01270 *******************************************************************/
01271 int
01272 NODE::output_to_actuators ()
01273 {
01274   return (0);
01275 }
01276 
01277 
01278 /*******************************************************************
01279 * Class: NODE                                                      *
01280 * Function: send_oi_replies
01281 * Parameters: NONE.
01282 * Outputs:    NONE.
01283 * Returns: 0 for success.
01284 *          -1 if an error occured.
01285 *******************************************************************/
01286 int
01287 NODE::send_oi_replies ()
01288 {
01289   return (0);
01290 }
01291 
01292 /*******************************************************************
01293 * Class: NODE                                                      *
01294 * Function: write_world_model_out                                  *
01295 * Parameters: NONE.                                                *
01296 * Outputs:                                                         *
01297 * Returns: 0 for success.                                          *
01298 *          -1 if an error occured.                                 *
01299 *******************************************************************/
01300 int
01301 NODE::write_world_model_out ()
01302 {
01303   if (wm_out_new)
01304     {
01305       wm_out_new = 0;
01306       if (NULL != wm_out_msg)
01307         {
01308           if (-1 == wm_out->write (wm_out_msg))
01309             {
01310               rcs_print_error ("%s: Can`t write to wm.", name);
01311               return (-1);
01312             }
01313         }
01314       rcs_print_debug (PRINT_NEW_WM, "%s: New wm. \n", name);
01315     }
01316   return (0);
01317 }
01318 
01319 /*******************************************************************
01320 * Class: NODE                                                      *
01321 * Function: send_subordinates_commands                             *
01322 * Parameters: NONE.                                                *
01323 * Outputs:    NONE.                                                *
01324 * Returns: 0 for success.                                          *
01325 *          -1 if an error occured.                                 *
01326 *******************************************************************/
01327 int
01328 NODE::send_subordinates_commands ()
01329 {
01330   NODE_LINK *node_link;
01331   if (NULL == sub_list)
01332     {
01333       return (-1);
01334     }
01335 
01336   node_link = (NODE_LINK *) sub_list->get_head ();
01337   while (NULL != node_link)
01338     {
01339       if (-1 == node_link->send_command ())
01340         {
01341           rcs_print_error ("%s::send_subordinates_commands:\n", name);
01342           rcs_print_error ("   Error sending %s a command.\n",
01343                            node_link->name);
01344           return (-1);
01345         }
01346       node_link = (NODE_LINK *) sub_list->get_next ();
01347     }
01348   return (0);
01349 }
01350 
01351 /*******************************************************************
01352 * Class: NODE                                                      *
01353 * Function: send_status_up                                         *
01354 * Parameters: NONE.                                                *
01355 * Outputs:                                                         *
01356 * Returns: 0 for success.                                          *
01357 *          -1 if an error occured.                                 *
01358 *******************************************************************/
01359 int
01360 NODE::send_status_message ()
01361 {
01362   if (status_up_new)
01363     {
01364       status_up_new = 0;
01365       if (NULL != status_up_msg)
01366         {
01367           status_up_msg->serial_number = cmd_in_msg->serial_number;
01368           if (-1 == status_up->write (status_up_msg))
01369             {
01370               rcs_print_error
01371                 ("%s::send_status_up_message: Can`t send status.", name);
01372               return (-1);
01373             }
01374         }
01375       rcs_print_debug (PRINT_STATUS_SENT, "%s: New status sent. \n", name);
01376       rcs_print_debug (PRINT_STATUS_SENT,
01377                        " (type = %ld (0x%lX), status = %d)\n",
01378                        status_up_msg->type, status_up_msg->type,
01379                        status_up_msg->node_status);
01380     }
01381   return (0);
01382 }
01383 
01384 /*******************************************************************
01385 * Class: NODE                                                      *
01386 * Function: error_handler                                          *
01387 * Parameters: NONE.                                                *
01388 * Purpose: Prints an error message.                                *
01389 * Outputs: NONE.                                                   *
01390 * Returns: NONE.                                                   *
01391 *******************************************************************/
01392 void
01393 NODE::error_handler ()
01394 {
01395   rcs_print_error ("%s: error occured in section %d.\n", name,
01396                    current_section);
01397   rcs_print_error ("(error_code = %d)\n", error_code);
01398   switch (current_section)
01399     {
01400     case NODE_GET_COMMAND_MESSAGE:
01401     case NODE_GET_SUBORDINATES_STATUS:
01402     case NODE_GET_OI_REQUESTS:
01403     case NODE_READ_WORLD_MODEL_IN:
01404     case NODE_WRITE_WORLD_MODEL_OUT:
01405     case NODE_SEND_SUBORDINATES_COMMANDS:
01406     case NODE_SEND_STATUS_MESSAGE:
01407       valid = 0;
01408       break;
01409     default:
01410       break;
01411     }
01412 }
01413 
01414 
01415 /*******************************************************************
01416 * Class: NODE                                                      *
01417 * Function: check_if_valid                                         *
01418 * Parameters: NONE.                                                *
01419 * Outputs:                                                         *
01420 * int valid; - set to 0 if any required communication channel      *
01421 *     has an invalid configuration.                                *
01422 *   (valid must not be 0 for the node to run.)                     *
01423 * Returns: NONE.                                                   *
01424 *******************************************************************/
01425 void
01426 NODE::check_if_valid ()
01427 {
01428   if (NULL == cmd_in)
01429     {
01430       valid = 0;
01431       return;
01432     }
01433   if (!cmd_in->valid ())
01434     {
01435       valid = 0;
01436       return;
01437     }
01438   if (config_flags & NODE_USE_STAT_BUFFER)
01439     {
01440       if (NULL == status_up)
01441         {
01442           valid = 0;
01443           return;
01444         }
01445       if (!status_up->valid ())
01446         {
01447           valid = 0;
01448           return;
01449         }
01450     }
01451   if (config_flags & NODE_USE_WM_BUFFER)
01452     {
01453       if (NULL == wm_out)
01454         {
01455           valid = 0;
01456           return;
01457         }
01458       if (!wm_out->valid ())
01459         {
01460           valid = 0;
01461           return;
01462         }
01463     }
01464 }
01465 
01466 /* Handle Simple Status Messages. */
01467 void
01468 NODE::send_status (NODE_STATUS_TYPE new_status, RCS_STAT_MSG * new_msg)
01469 {
01470   node_status = new_status;
01471   if (NULL != new_msg)
01472     {
01473       new_msg->node_status = new_status;
01474       status_up_msg = new_msg;
01475     }
01476   else
01477     {
01478       generic_status->node_status = new_status;
01479       status_up_msg = generic_status;
01480     }
01481   status_up_new = 1;
01482 }

Generated on Sun Dec 2 15:56:51 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001