/ src / hal / utils / halcmd_commands.c
halcmd_commands.c
   1  /* Copyright (C) 2007 Jeff Epler <jepler@unpythonic.net>
   2   * Copyright (C) 2003 John Kasunich
   3   *                     <jmkasunich AT users DOT sourceforge DOT net>
   4   *
   5   *  Other contributers:
   6   *                     Martin Kuhnle
   7   *                     <mkuhnle AT users DOT sourceforge DOT net>
   8   *                     Alex Joni
   9   *                     <alex_joni AT users DOT sourceforge DOT net>
  10   *                     Benn Lipkowitz
  11   *                     <fenn AT users DOT sourceforge DOT net>
  12   *                     Stephen Wille Padnos
  13   *                     <swpadnos AT users DOT sourceforge DOT net>
  14   *
  15   *  This program is free software; you can redistribute it and/or
  16   *  modify it under the terms of version 2 of the GNU General
  17   *  Public License as published by the Free Software Foundation.
  18   *  This library is distributed in the hope that it will be useful,
  19   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  20   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21   *  GNU General Public License for more details.
  22   *
  23   *  You should have received a copy of the GNU General Public
  24   *  License along with this library; if not, write to the Free Software
  25   *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  26   *
  27   *  THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
  28   *  ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
  29   *  TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
  30   *  harming persons must have provisions for completely removing power
  31   *  from all motors, etc, before persons enter any danger area.  All
  32   *  machinery must be designed to comply with local and national safety
  33   *  codes, and the authors of this software can not, and do not, take
  34   *  any responsibility for such compliance.
  35   *
  36   *  This code was written as part of the EMC HAL project.  For more
  37   *  information, go to www.linuxcnc.org.
  38   */
  39  
  40  #include "config.h"
  41  #include "rtapi.h"		/* RTAPI realtime OS API */
  42  #include "hal.h"		/* HAL public API decls */
  43  #include "../hal_priv.h"	/* private HAL decls */
  44  #include "halcmd_commands.h"
  45  #include <rtapi_mutex.h>
  46  
  47  #include <stdio.h>
  48  #include <stdlib.h>
  49  #include <ctype.h>
  50  #include <string.h>
  51  #include <sys/stat.h>
  52  #include <sys/wait.h>
  53  #include <unistd.h>
  54  #include <fcntl.h>
  55  #include <errno.h>
  56  #include <time.h>
  57  #include <fnmatch.h>
  58  
  59  
  60  static int unloadrt_comp(char *mod_name);
  61  static void print_comp_info(char **patterns);
  62  static void print_pin_info(int type, char **patterns);
  63  static void print_pin_aliases(char **patterns);
  64  static void print_param_aliases(char **patterns);
  65  static void print_sig_info(int type, char **patterns);
  66  static void print_script_sig_info(int type, char **patterns);
  67  static void print_param_info(int type, char **patterns);
  68  static void print_funct_info(char **patterns);
  69  static void print_thread_info(char **patterns);
  70  static void print_comp_names(char **patterns);
  71  static void print_pin_names(char **patterns);
  72  static void print_sig_names(char **patterns);
  73  static void print_param_names(char **patterns);
  74  static void print_funct_names(char **patterns);
  75  static void print_thread_names(char **patterns);
  76  static void print_lock_status();
  77  static int count_list(int list_root);
  78  static void print_mem_status();
  79  static const char *data_type(int type);
  80  static const char *data_type2(int type);
  81  static const char *pin_data_dir(int dir);
  82  static const char *param_data_dir(int dir);
  83  static const char *data_arrow1(int dir);
  84  static const char *data_arrow2(int dir);
  85  static char *data_value(int type, void *valptr);
  86  static char *data_value2(int type, void *valptr);
  87  static void save_comps(FILE *dst);
  88  static void save_aliases(FILE *dst);
  89  static void save_signals(FILE *dst, int only_unlinked);
  90  static void save_links(FILE *dst, int arrows);
  91  static void save_nets(FILE *dst, int arrows);
  92  static void save_params(FILE *dst);
  93  static void save_unconnected_input_pin_values(FILE *dst);
  94  static void save_threads(FILE *dst);
  95  static void print_help_commands(void);
  96  
  97  static int tmatch(int req_type, int type) {
  98      return req_type == -1 || type == req_type;
  99  }
 100  
 101  static int match(char **patterns, char *value) {
 102      int i;
 103      if(!patterns || !patterns[0] || !patterns[0][0]) return 1;
 104      for(i=0; patterns[i] && *patterns[i]; i++) {
 105  	char *pattern = patterns[i];
 106  	if(strncmp(pattern, value, strlen(pattern)) == 0) return 1;
 107  	if (fnmatch(pattern, value, 0) == 0) return 1;
 108      }
 109      return 0;
 110  }
 111  
 112  int do_lock_cmd(char *command)
 113  {
 114      int retval=0;
 115  
 116      /* if command is blank or "all", want to lock everything */
 117      if ((command == NULL) || (strcmp(command, "all") == 0)) {
 118  	retval = hal_set_lock(HAL_LOCK_ALL);
 119      } else if (strcmp(command, "none") == 0) {
 120  	retval = hal_set_lock(HAL_LOCK_NONE);
 121      } else if (strcmp(command, "tune") == 0) {
 122  	retval = hal_set_lock(HAL_LOCK_LOAD & HAL_LOCK_CONFIG);
 123      } else if (strcmp(command, "all") == 0) {
 124  	retval = hal_set_lock(HAL_LOCK_ALL);
 125      }
 126  
 127      if (retval == 0) {
 128  	/* print success message */
 129  	halcmd_info("Locking completed");
 130      } else {
 131  	halcmd_error("Locking failed\n");
 132      }
 133      return retval;
 134  }
 135  
 136  int do_unlock_cmd(char *command)
 137  {
 138      int retval=0;
 139  
 140      /* if command is blank or "all", want to unlock everything */
 141      if ((command == NULL) || (strcmp(command, "all") == 0)) {
 142  	retval = hal_set_lock(HAL_LOCK_NONE);
 143      } else if (strcmp(command, "all") == 0) {
 144  	retval = hal_set_lock(HAL_LOCK_NONE);
 145      } else if (strcmp(command, "tune") == 0) {
 146  	retval = hal_set_lock(HAL_LOCK_LOAD & HAL_LOCK_CONFIG);
 147      }
 148  
 149      if (retval == 0) {
 150  	/* print success message */
 151  	halcmd_info("Unlocking completed");
 152      } else {
 153  	halcmd_error("Unlocking failed\n");
 154      }
 155      return retval;
 156  }
 157  
 158  int do_linkpp_cmd(char *first_pin_name, char *second_pin_name)
 159  {
 160      int retval;
 161      hal_pin_t *first_pin, *second_pin;
 162      static int dep_msg_printed = 0;
 163  
 164      if ( dep_msg_printed == 0 ) {
 165  	halcmd_warning("linkpp command is deprecated, use 'net'\n");
 166  	dep_msg_printed = 1;
 167      }
 168      rtapi_mutex_get(&(hal_data->mutex));
 169      /* check if the pins are there */
 170      first_pin = halpr_find_pin_by_name(first_pin_name);
 171      second_pin = halpr_find_pin_by_name(second_pin_name);
 172      if (first_pin == 0) {
 173  	/* first pin not found*/
 174  	rtapi_mutex_give(&(hal_data->mutex));
 175  	halcmd_error("pin '%s' not found\n", first_pin_name);
 176  	return -EINVAL; 
 177      } else if (second_pin == 0) {
 178  	rtapi_mutex_give(&(hal_data->mutex));
 179  	halcmd_error("pin '%s' not found\n", second_pin_name);
 180  	return -EINVAL; 
 181      }
 182      
 183      /* give the mutex, as the other functions use their own mutex */
 184      rtapi_mutex_give(&(hal_data->mutex));
 185      
 186      /* check that both pins have the same type, 
 187         don't want to create a sig, which after that won't be useful */
 188      if (first_pin->type != second_pin->type) {
 189  	halcmd_error("pins '%s' and '%s' not of the same type\n",
 190                  first_pin_name, second_pin_name);
 191  	return -EINVAL; 
 192      }
 193  	
 194      /* now create the signal */
 195      retval = hal_signal_new(first_pin_name, first_pin->type);
 196  
 197      if (retval == 0) {
 198  	/* if it worked, link the pins to it */
 199  	retval = hal_link(first_pin_name, first_pin_name);
 200  
 201  	if ( retval == 0 ) {
 202  	/* if that worked, link the second pin to the new signal */
 203  	    retval = hal_link(second_pin_name, first_pin_name);
 204  	}
 205      }
 206      if (retval < 0) {
 207  	halcmd_error("linkpp failed\n");
 208      }
 209      return retval;
 210  }
 211  
 212  int do_linkps_cmd(char *pin, char *sig)
 213  {
 214      int retval;
 215  
 216      retval = hal_link(pin, sig);
 217      if (retval == 0) {
 218  	/* print success message */
 219          halcmd_info("Pin '%s' linked to signal '%s'\n", pin, sig);
 220      } else {
 221          halcmd_error("link failed\n");
 222      }
 223      return retval;
 224  }
 225  
 226  int do_linksp_cmd(char *sig, char *pin) {
 227      return do_linkps_cmd(pin, sig);
 228  }
 229  
 230  
 231  int do_unlinkp_cmd(char *pin)
 232  {
 233      int retval;
 234  
 235      retval = hal_unlink(pin);
 236      if (retval == 0) {
 237  	/* print success message */
 238  	halcmd_info("Pin '%s' unlinked\n", pin);
 239      } else {
 240          halcmd_error("unlink failed\n");
 241      }
 242      return retval;
 243  }
 244  
 245  int do_source_cmd(char *hal_filename) {
 246      FILE *f = fopen(hal_filename, "r");
 247      char buf[MAX_CMD_LEN+1];
 248      int fd;
 249      int result = 0;
 250      int lineno_save = halcmd_get_linenumber();
 251      int linenumber = 1;
 252      char *filename_save = strdup(halcmd_get_filename());
 253  
 254      if(!f) {
 255          fprintf(stderr, "Could not open hal file '%s': %s\n",
 256                  hal_filename, strerror(errno));
 257  	free(filename_save);
 258          return -EINVAL;
 259      }
 260      fd = fileno(f);
 261      fcntl(fd, F_SETFD, FD_CLOEXEC);
 262  
 263      halcmd_set_filename(hal_filename);
 264  
 265      while(1) {
 266          char *readresult = fgets(buf, MAX_CMD_LEN, f);
 267          halcmd_set_linenumber(linenumber++);
 268          if(readresult == 0) {
 269              if(feof(f)) break;
 270              halcmd_error("Error reading file: %s\n", strerror(errno));
 271              result = -EINVAL;
 272              break;
 273          }
 274          result = halcmd_parse_line(buf);
 275          if(result != 0) break;
 276      }
 277  
 278      halcmd_set_linenumber(lineno_save);
 279      halcmd_set_filename(filename_save);
 280      free(filename_save);
 281      fclose(f);
 282      return result;
 283  }
 284  
 285  int do_start_cmd(void) {
 286      int retval = hal_start_threads();
 287      if (retval == 0) {
 288          /* print success message */
 289          halcmd_info("Realtime threads started\n");
 290      }
 291      return retval;
 292  }
 293  
 294  int do_stop_cmd(void) {
 295      int retval = hal_stop_threads();
 296      if (retval == 0) {
 297          /* print success message */
 298          halcmd_info("Realtime threads stopped\n");
 299      }
 300      return retval;
 301  }
 302  
 303  int do_echo_cmd(void) {
 304      printf("Echo on\n");
 305      return 0;
 306  }
 307  int do_unecho_cmd(void) {
 308      printf("Echo off\n");
 309      return 0;
 310  }
 311  int do_addf_cmd(char *func, char *thread, char **opt) {
 312      char *position_str = opt ? opt[0] : NULL;
 313      int position = -1;
 314      int retval;
 315  
 316      if(position_str && *position_str) position = atoi(position_str);
 317  
 318      retval = hal_add_funct_to_thread(func, thread, position);
 319      if(retval == 0) {
 320          halcmd_info("Function '%s' added to thread '%s'\n",
 321                      func, thread);
 322      } else {
 323          halcmd_error("addf failed\n");
 324      }
 325      return retval;
 326  }
 327  
 328  int do_alias_cmd(char *pinparam, char *name, char *alias) {
 329      int retval;
 330  
 331      if ( strcmp (pinparam, "pin" ) == 0 ) {
 332  	retval = hal_pin_alias(name, alias);
 333      } else if ( strcmp (pinparam, "param" ) == 0 ) {
 334  	retval = hal_param_alias(name, alias);
 335      } else {
 336  	retval = -EINVAL;
 337      }
 338      if(retval == 0) {
 339          halcmd_info("%s '%s' aliased to '%s'\n",
 340                      pinparam, name, alias);
 341      } else {
 342          halcmd_error("alias failed\n");
 343      }
 344      return retval;	
 345  }
 346  
 347  int do_unalias_cmd(char *pinparam, char *name) {
 348      int retval;
 349      if (strcmp(pinparam, "pin") == 0) {
 350          retval = hal_pin_alias(name, NULL);
 351      } else if ( strcmp (pinparam, "param" ) == 0 ) {
 352        retval = hal_param_alias(name, NULL);
 353      } else {
 354          return -EINVAL;
 355      };
 356      if(retval == 0) {
 357          halcmd_info("%s '%s' unaliased\n",
 358                      pinparam, name);
 359      } else {
 360          halcmd_error("unalias failed\n");
 361      }
 362      return retval;	
 363  }
 364  int do_delf_cmd(char *func, char *thread) {
 365      int retval;
 366  
 367      retval = hal_del_funct_from_thread(func, thread);
 368      if(retval == 0) {
 369          halcmd_info("Function '%s' removed from thread '%s'\n",
 370                      func, thread);
 371      } else {
 372          halcmd_error("delf failed\n");
 373      }
 374  
 375      return retval;
 376  }
 377  
 378  static int preflight_net_cmd(char *signal, hal_sig_t *sig, char *pins[]) {
 379      int i, type=-1, writers=0, bidirs=0, pincnt=0;
 380      char *writer_name=0, *bidir_name=0;
 381      /* if signal already exists, use its info */
 382      if (sig) {
 383  	type = sig->type;
 384  	writers = sig->writers;
 385  	bidirs = sig->bidirs;
 386      }
 387  
 388      if(writers || bidirs) 
 389      {
 390          hal_pin_t *pin;
 391          int next;
 392          for(next = hal_data->pin_list_ptr; next; next=pin->next_ptr) 
 393          {
 394              pin = SHMPTR(next);
 395              if(SHMPTR(pin->signal) == sig && pin->dir == HAL_OUT)
 396                  writer_name = pin->name;
 397              if(SHMPTR(pin->signal) == sig && pin->dir == HAL_IO)
 398                  bidir_name = writer_name = pin->name;
 399          }
 400      }
 401  
 402      for(i=0; pins[i] && *pins[i]; i++) {
 403          hal_pin_t *pin = 0;
 404          pin = halpr_find_pin_by_name(pins[i]);
 405          if(!pin) {
 406              halcmd_error("Pin '%s' does not exist\n",
 407                      pins[i]);
 408              return -ENOENT;
 409          }
 410          if(SHMPTR(pin->signal) == sig) {
 411  	     /* Already on this signal */
 412  	    pincnt++;
 413  	    continue;
 414  	} else if(pin->signal != 0) {
 415              hal_sig_t *osig = SHMPTR(pin->signal);
 416              halcmd_error("Pin '%s' was already linked to signal '%s'\n",
 417                      pin->name, osig->name);
 418              return -EINVAL;
 419  	}
 420  	if (type == -1) {
 421  	    /* no pre-existing type, use this pin's type */
 422  	    type = pin->type;
 423  	}
 424          if(type != pin->type) {
 425              halcmd_error(
 426                  "Signal '%s' of type '%s' cannot add pin '%s' of type '%s'\n",
 427                  signal, data_type2(type), pin->name, data_type2(pin->type));
 428              return -EINVAL;
 429          }
 430          if(pin->dir == HAL_OUT) {
 431              if(writers || bidirs) {
 432              dir_error:
 433                  halcmd_error(
 434                      "Signal '%s' can not add %s pin '%s', "
 435                      "it already has %s pin '%s'\n",
 436                          signal, pin_data_dir(pin->dir), pin->name,
 437                          bidir_name ? pin_data_dir(HAL_IO):pin_data_dir(HAL_OUT),
 438                          bidir_name ? bidir_name : writer_name);
 439                  return -EINVAL;
 440              }
 441              writer_name = pin->name;
 442              writers++;
 443          }
 444  	if(pin->dir == HAL_IO) {
 445              if(writers) {
 446                  goto dir_error;
 447              }
 448              bidir_name = pin->name;
 449              bidirs++;
 450          }
 451          pincnt++;
 452      }
 453      if(pincnt)
 454          return 0;
 455      halcmd_error("'net' requires at least one pin, none given\n");
 456      return -EINVAL;
 457  }
 458  
 459  int do_net_cmd(char *signal, char *pins[]) {
 460      hal_sig_t *sig;
 461      int i, retval;
 462  
 463      rtapi_mutex_get(&(hal_data->mutex));
 464      /* see if signal already exists */
 465      sig = halpr_find_sig_by_name(signal);
 466  
 467      /* verify that everything matches up (pin types, etc) */
 468      retval = preflight_net_cmd(signal, sig, pins);
 469      if(retval < 0) {
 470          rtapi_mutex_give(&(hal_data->mutex));
 471          return retval;
 472      }
 473  
 474      {
 475  	hal_pin_t *pin = halpr_find_pin_by_name(signal);
 476  	if(pin) {
 477  	    halcmd_error(
 478                      "Signal name '%s' must not be the same as a pin.  "
 479                      "Did you omit the signal name?\n",
 480  		signal);
 481  	    rtapi_mutex_give(&(hal_data->mutex));
 482  	    return -ENOENT;
 483  	}
 484      }
 485      if(!sig) {
 486          /* Create the signal with the type of the first pin */
 487          hal_pin_t *pin = halpr_find_pin_by_name(pins[0]);
 488          rtapi_mutex_give(&(hal_data->mutex));
 489          if(!pin) {
 490              return -ENOENT;
 491          }
 492          retval = hal_signal_new(signal, pin->type);
 493      } else {
 494  	/* signal already exists */
 495          rtapi_mutex_give(&(hal_data->mutex));
 496      }
 497      /* add pins to signal */
 498      for(i=0; retval == 0 && pins[i] && *pins[i]; i++) {
 499          retval = do_linkps_cmd(pins[i], signal);
 500      }
 501  
 502      return retval;
 503  }
 504  
 505  #if 0  /* newinst deferred to version 2.2 */
 506  int do_newinst_cmd(char *comp_name, char *inst_name) {
 507      hal_comp_t *comp = halpr_find_comp_by_name(comp_name);
 508  
 509      if(!comp) {
 510          halcmd_error( "No such component: %s\n", comp_name);
 511          return -ENOENT;
 512      }
 513      if(!comp->make) {
 514          halcmd_error( "%s does not support 'newinst'\n", comp_name);
 515          return -ENOSYS;
 516      }
 517      if ( *inst_name == '\0' ) {
 518          halcmd_error( "Must supply name for new instance\n");
 519          return -EINVAL;
 520      }	
 521  
 522  #if defined(RTAPI_USPACE)
 523      {
 524          char *argv[MAX_TOK];
 525          int m = 0, result;
 526          argv[m++] = EMC2_BIN_DIR "/rtapi_app";
 527          argv[m++] = "newinst";
 528          argv[m++] = comp_name;
 529          argv[m++] = inst_name;
 530          argv[m++] = 0;
 531          result = hal_systemv(argv);
 532          if(result != 0) {
 533              halcmd_error( "newinst failed: %d\n", result);
 534              return -EINVAL;
 535          }
 536      }
 537  #else
 538      {
 539      FILE *f;
 540      f = fopen("/proc/rtapi/hal/newinst", "w");
 541      if(!f) {
 542          halcmd_error( "cannot open proc entry: %s\n",
 543                  strerror(errno));
 544          return -EINVAL;
 545      }
 546  
 547      rtapi_mutex_get(&(hal_data->mutex));
 548  
 549      while(hal_data->pending_constructor) {
 550          struct timespec ts = {0, 100 * 1000 * 1000}; // 100ms
 551          rtapi_mutex_give(&(hal_data->mutex));
 552          nanosleep(&ts, NULL);
 553          rtapi_mutex_get(&(hal_data->mutex));
 554      }
 555      strncpy(hal_data->constructor_prefix, inst_name, HAL_NAME_LEN);
 556      hal_data->constructor_prefix[HAL_NAME_LEN]=0;
 557      hal_data->pending_constructor = comp->make;
 558      rtapi_mutex_give(&(hal_data->mutex));
 559  
 560      if(fputc(' ', f) == EOF) {
 561          halcmd_error( "cannot write to proc entry: %s\n",
 562                  strerror(errno));
 563          fclose(f);
 564          rtapi_mutex_get(&(hal_data->mutex));
 565          hal_data->pending_constructor = 0;
 566          rtapi_mutex_give(&(hal_data->mutex));
 567          return -EINVAL;
 568      }
 569      if(fclose(f) != 0) {
 570          halcmd_error(
 571                  "cannot close proc entry: %s\n",
 572                  strerror(errno));
 573          rtapi_mutex_get(&(hal_data->mutex));
 574          hal_data->pending_constructor = 0;
 575          rtapi_mutex_give(&(hal_data->mutex));
 576          return -EINVAL;
 577      }
 578  
 579      while(hal_data->pending_constructor) {
 580          struct timespec ts = {0, 100 * 1000 * 1000}; // 100ms
 581          nanosleep(&ts, NULL);
 582      }
 583      }
 584  #endif
 585      rtapi_mutex_get(&hal_data->mutex);
 586      {
 587      hal_comp_t *inst = halpr_alloc_comp_struct();
 588      if (inst == 0) {
 589          /* couldn't allocate structure */
 590          rtapi_mutex_give(&(hal_data->mutex));
 591          halcmd_error(
 592              "insufficient memory for instance '%s'\n", inst_name);
 593          return -ENOMEM;
 594      }
 595      inst->comp_id = comp->comp_id | 0x10000;
 596      inst->mem_id = -1;
 597      inst->type = 2;
 598      inst->pid = 0;
 599      inst->ready = 1;
 600      inst->shmem_base = 0;
 601      rtapi_snprintf(inst->name, sizeof(inst->name), "%s", inst_name);
 602      /* insert new structure at head of list */
 603      inst->next_ptr = hal_data->comp_list_ptr;
 604      hal_data->comp_list_ptr = SHMOFF(inst);
 605  
 606      rtapi_mutex_give(&(hal_data->mutex));
 607      }
 608      return 0;
 609  }
 610  #endif /* newinst deferred */
 611  
 612  int do_newsig_cmd(char *name, char *type)
 613  {
 614      int retval;
 615  
 616      if (strcasecmp(type, "bit") == 0) {
 617  	retval = hal_signal_new(name, HAL_BIT);
 618      } else if (strcasecmp(type, "float") == 0) {
 619  	retval = hal_signal_new(name, HAL_FLOAT);
 620      } else if (strcasecmp(type, "u32") == 0) {
 621  	retval = hal_signal_new(name, HAL_U32);
 622      } else if (strcasecmp(type, "s32") == 0) {
 623  	retval = hal_signal_new(name, HAL_S32);
 624      } else if (strcasecmp(type, "port") == 0) {
 625  	retval = hal_signal_new(name, HAL_PORT);
 626      } else {
 627  	halcmd_error("Unknown signal type '%s'\n", type);
 628  	retval = -EINVAL;
 629      }
 630      if (retval < 0) {
 631  	halcmd_error("newsig failed\n");
 632      }
 633      return retval;
 634  }
 635  
 636  static int set_common(hal_type_t type, void *d_ptr, char *value) {
 637      // This function assumes that the mutex is held
 638      int retval = 0;
 639      double fval;
 640      long lval;
 641      unsigned long ulval;
 642      unsigned uval;
 643      char *cp = value;
 644  
 645      switch (type) {
 646      case HAL_BIT:
 647  	if ((strcmp("1", value) == 0) || (strcasecmp("TRUE", value) == 0)) {
 648  	    *(hal_bit_t *) (d_ptr) = 1;
 649  	} else if ((strcmp("0", value) == 0)
 650  	    || (strcasecmp("FALSE", value)) == 0) {
 651  	    *(hal_bit_t *) (d_ptr) = 0;
 652  	} else {
 653  	    halcmd_error("value '%s' invalid for bit\n", value);
 654  	    retval = -EINVAL;
 655  	}
 656  	break;
 657      case HAL_FLOAT:
 658  	fval = strtod ( value, &cp );
 659  	if ((*cp != '\0') && (!isspace(*cp))) {
 660  	    /* invalid character(s) in string */
 661  	    halcmd_error("value '%s' invalid for float\n", value);
 662  	    retval = -EINVAL;
 663  	} else {
 664  	    *((hal_float_t *) (d_ptr)) = fval;
 665  	}
 666  	break;
 667      case HAL_S32:
 668  	lval = strtol(value, &cp, 0);
 669  	if ((*cp != '\0') && (!isspace(*cp))) {
 670  	    /* invalid chars in string */
 671  	    halcmd_error("value '%s' invalid for S32\n", value);
 672  	    retval = -EINVAL;
 673  	} else {
 674  	    *((hal_s32_t *) (d_ptr)) = lval;
 675  	}
 676  	break;
 677      case HAL_U32:
 678  	ulval = strtoul(value, &cp, 0);
 679  	if ((*cp != '\0') && (!isspace(*cp))) {
 680  	    /* invalid chars in string */
 681  	    halcmd_error("value '%s' invalid for U32\n", value);
 682  	    retval = -EINVAL;
 683  	} else {
 684  	    *((hal_u32_t *) (d_ptr)) = ulval;
 685  	}
 686  	break;
 687      case HAL_PORT:
 688          uval = strtoul(value, &cp, 0);
 689          if ((*cp != '\0') && (!isspace(*cp))) {
 690              halcmd_error("value '%s' invalid for PORT\n", value);
 691              retval = -EINVAL;
 692          } else {
 693              if((*((hal_port_t*)d_ptr) != 0) && (hal_port_buffer_size(*((hal_port_t*)d_ptr)) > 0)) {
 694                  halcmd_error("port is already allocated with %u bytes.\n", hal_port_buffer_size(*((hal_port_t*)d_ptr)));
 695                  retval = -EINVAL;
 696          } else {
 697              *((hal_port_t*) (d_ptr)) = hal_port_alloc(uval);
 698          }
 699      }
 700      break;
 701      default:
 702  	/* Shouldn't get here, but just in case... */
 703  	halcmd_error("bad type %d\n", type);
 704  	retval = -EINVAL;
 705      }
 706      return retval;
 707  }
 708  
 709  int do_setp_cmd(char *name, char *value)
 710  {
 711      int retval;
 712      hal_param_t *param;
 713      hal_pin_t *pin;
 714      hal_type_t type;
 715      void *d_ptr;
 716  
 717      halcmd_info("setting parameter '%s' to '%s'\n", name, value);
 718      /* get mutex before accessing shared data */
 719      rtapi_mutex_get(&(hal_data->mutex));
 720      /* search param list for name */
 721      param = halpr_find_param_by_name(name);
 722      if (param == 0) {
 723          pin = halpr_find_pin_by_name(name);
 724          if(pin == 0) {
 725              rtapi_mutex_give(&(hal_data->mutex));
 726              halcmd_error("parameter or pin '%s' not found\n", name);
 727              return -EINVAL;
 728          } else {
 729              /* found it */
 730              type = pin->type;
 731              if(pin->dir == HAL_OUT) {
 732                  rtapi_mutex_give(&(hal_data->mutex));
 733                  halcmd_error("pin '%s' is not writable\n", name);
 734                  return -EINVAL;
 735              }
 736              if(pin->signal != 0) {
 737                  rtapi_mutex_give(&(hal_data->mutex));
 738                  halcmd_error("pin '%s' is connected to a signal\n", name);
 739                  return -EINVAL;
 740              }
 741              // d_ptr = (void*)SHMPTR(pin->dummysig);
 742              d_ptr = (void*)&pin->dummysig;
 743          }
 744      } else {
 745          /* found it */
 746          type = param->type;
 747          /* is it read only? */
 748          if (param->dir == HAL_RO) {
 749              rtapi_mutex_give(&(hal_data->mutex));
 750              halcmd_error("param '%s' is not writable\n", name);
 751              return -EINVAL;
 752          }
 753          d_ptr = SHMPTR(param->data_ptr);
 754      }
 755  
 756      retval = set_common(type, d_ptr, value);
 757  
 758      rtapi_mutex_give(&(hal_data->mutex));
 759      if (retval == 0) {
 760  	/* print success message */
 761          if(param) {
 762              halcmd_info("Parameter '%s' set to %s\n", name, value);
 763          } else {
 764              halcmd_info("Pin '%s' set to %s\n", name, value);
 765  	}
 766      } else {
 767  	halcmd_error("setp failed\n");
 768      }
 769      return retval;
 770  
 771  }
 772  
 773  int do_ptype_cmd(char *name)
 774  {
 775      hal_param_t *param;
 776      hal_pin_t *pin;
 777      hal_type_t type;
 778      
 779      rtapi_print_msg(RTAPI_MSG_DBG, "getting parameter '%s'\n", name);
 780      /* get mutex before accessing shared data */
 781      rtapi_mutex_get(&(hal_data->mutex));
 782      /* search param list for name */
 783      param = halpr_find_param_by_name(name);
 784      if (param) {
 785          /* found it */
 786          type = param->type;
 787          halcmd_output("%s\n", data_type2(type));
 788          rtapi_mutex_give(&(hal_data->mutex));
 789          return 0;
 790      }
 791          
 792      /* not found, search pin list for name */
 793      pin = halpr_find_pin_by_name(name);
 794      if(pin) {
 795          /* found it */
 796          type = pin->type;
 797          halcmd_output("%s\n", data_type2(type));
 798          rtapi_mutex_give(&(hal_data->mutex));
 799          return 0;
 800      }   
 801      
 802      rtapi_mutex_give(&(hal_data->mutex));
 803      halcmd_error("pin or parameter '%s' not found\n", name);
 804      return -EINVAL;
 805  }
 806  
 807  
 808  int do_getp_cmd(char *name)
 809  {
 810      hal_param_t *param;
 811      hal_pin_t *pin;
 812      hal_sig_t *sig;
 813      hal_type_t type;
 814      void *d_ptr;
 815      
 816      rtapi_print_msg(RTAPI_MSG_DBG, "getting parameter '%s'\n", name);
 817      /* get mutex before accessing shared data */
 818      rtapi_mutex_get(&(hal_data->mutex));
 819      /* search param list for name */
 820      param = halpr_find_param_by_name(name);
 821      if (param) {
 822          /* found it */
 823          type = param->type;
 824          d_ptr = SHMPTR(param->data_ptr);
 825          halcmd_output("%s\n", data_value2((int) type, d_ptr));
 826          rtapi_mutex_give(&(hal_data->mutex));
 827          return 0;
 828      }
 829          
 830      /* not found, search pin list for name */
 831      pin = halpr_find_pin_by_name(name);
 832      if(pin) {
 833          /* found it */
 834          type = pin->type;
 835          if (pin->signal != 0) {
 836              sig = SHMPTR(pin->signal);
 837              d_ptr = SHMPTR(sig->data_ptr);
 838          } else {
 839              sig = 0;
 840              d_ptr = &(pin->dummysig);
 841          }
 842          halcmd_output("%s\n", data_value2((int) type, d_ptr));
 843          rtapi_mutex_give(&(hal_data->mutex));
 844          return 0;
 845      }   
 846      
 847      rtapi_mutex_give(&(hal_data->mutex));
 848      halcmd_error("pin or parameter '%s' not found\n", name);
 849      return -EINVAL;
 850  }
 851  
 852  int do_sets_cmd(char *name, char *value)
 853  {
 854      int retval;
 855      hal_sig_t *sig;
 856      hal_type_t type;
 857      void *d_ptr;
 858  
 859      rtapi_print_msg(RTAPI_MSG_DBG, "setting signal '%s'\n", name);
 860      /* get mutex before accessing shared data */
 861      rtapi_mutex_get(&(hal_data->mutex));
 862      /* search signal list for name */
 863      sig = halpr_find_sig_by_name(name);
 864      if (sig == 0) {
 865  	rtapi_mutex_give(&(hal_data->mutex));
 866  	halcmd_error("signal '%s' not found\n", name);
 867  	return -EINVAL;
 868      }
 869      /* found it - it have a writer? if it is a port we can set its buffer size */
 870      if ((sig->type != HAL_PORT) && (sig->writers > 0)) {
 871  	rtapi_mutex_give(&(hal_data->mutex));
 872  	halcmd_error("signal '%s' already has writer(s)\n", name);
 873  	return -EINVAL;
 874      }
 875      /* no writer, so we can safely set it */
 876      type = sig->type;
 877      d_ptr = SHMPTR(sig->data_ptr);
 878      retval = set_common(type, d_ptr, value);
 879      rtapi_mutex_give(&(hal_data->mutex));
 880      if (retval == 0) {
 881  	/* print success message */
 882  	halcmd_info("Signal '%s' set to %s\n", name, value);
 883      } else {
 884  	halcmd_error("sets failed\n");
 885      }
 886      return retval;
 887  
 888  }
 889  
 890  int do_stype_cmd(char *name)
 891  {
 892      hal_sig_t *sig;
 893      hal_type_t type;
 894  
 895      rtapi_print_msg(RTAPI_MSG_DBG, "getting signal '%s'\n", name);
 896      /* get mutex before accessing shared data */
 897      rtapi_mutex_get(&(hal_data->mutex));
 898      /* search signal list for name */
 899      sig = halpr_find_sig_by_name(name);
 900      if (sig == 0) {
 901  	rtapi_mutex_give(&(hal_data->mutex));
 902  	halcmd_error("signal '%s' not found\n", name);
 903  	return -EINVAL;
 904      }
 905      /* found it */
 906      type = sig->type;
 907      halcmd_output("%s\n", data_type2(type));
 908      rtapi_mutex_give(&(hal_data->mutex));
 909      return 0;
 910  }
 911  
 912  int do_gets_cmd(char *name)
 913  {
 914      hal_sig_t *sig;
 915      hal_type_t type;
 916      void *d_ptr;
 917  
 918      rtapi_print_msg(RTAPI_MSG_DBG, "getting signal '%s'\n", name);
 919      /* get mutex before accessing shared data */
 920      rtapi_mutex_get(&(hal_data->mutex));
 921      /* search signal list for name */
 922      sig = halpr_find_sig_by_name(name);
 923      if (sig == 0) {
 924  	rtapi_mutex_give(&(hal_data->mutex));
 925  	halcmd_error("signal '%s' not found\n", name);
 926  	return -EINVAL;
 927      }
 928      /* found it */
 929      type = sig->type;
 930      d_ptr = SHMPTR(sig->data_ptr);
 931      halcmd_output("%s\n", data_value2((int) type, d_ptr));
 932      rtapi_mutex_give(&(hal_data->mutex));
 933      return 0;
 934  }
 935  
 936  static int get_type(char ***patterns) {
 937      char *typestr = 0;
 938      if(!(*patterns)) return -1;
 939      if(!(*patterns)[0]) return -1;
 940      if((*patterns)[0][0] != '-' || (*patterns)[0][1] != 't') return -1;
 941      if((*patterns)[0][2]) {
 942  	typestr = &(*patterns)[0][2];
 943  	*patterns += 1;
 944      } else if((*patterns)[1][0]) {
 945  	typestr = (*patterns)[1];
 946  	*patterns += 2;
 947      }
 948      if(!typestr) return -1;
 949      if(strcmp(typestr, "float") == 0) return HAL_FLOAT;
 950      if(strcmp(typestr, "bit") == 0) return HAL_BIT;
 951      if(strcmp(typestr, "s32") == 0) return HAL_S32;
 952      if(strcmp(typestr, "u32") == 0) return HAL_U32;
 953      if(strcmp(typestr, "signed") == 0) return HAL_S32;
 954      if(strcmp(typestr, "unsigned") == 0) return HAL_U32;
 955      if(strcmp(typestr, "port") == 0) return HAL_PORT;
 956      return -1;
 957  }
 958  
 959  int do_show_cmd(char *type, char **patterns)
 960  {
 961  
 962      if (rtapi_get_msg_level() == RTAPI_MSG_NONE) {
 963  	/* must be -Q, don't print anything */
 964  	return 0;
 965      }
 966      if (!type || *type == '\0') {
 967  	/* print everything */
 968  	print_comp_info(NULL);
 969  	print_pin_info(-1, NULL);
 970  	print_pin_aliases(NULL);
 971  	print_sig_info(-1, NULL);
 972  	print_param_info(-1, NULL);
 973  	print_param_aliases(NULL);
 974  	print_funct_info(NULL);
 975  	print_thread_info(NULL);
 976      } else if (strcmp(type, "all") == 0) {
 977  	/* print everything, using the pattern */
 978  	print_comp_info(patterns);
 979  	print_pin_info(-1, patterns);
 980  	print_pin_aliases(patterns);
 981  	print_sig_info(-1, patterns);
 982  	print_param_info(-1, patterns);
 983  	print_param_aliases(patterns);
 984  	print_funct_info(patterns);
 985  	print_thread_info(patterns);
 986      } else if (strcmp(type, "comp") == 0) {
 987  	print_comp_info(patterns);
 988      } else if (strcmp(type, "pin") == 0) {
 989  	int type = get_type(&patterns);
 990  	print_pin_info(type, patterns);
 991      } else if (strcmp(type, "sig") == 0) {
 992  	int type = get_type(&patterns);
 993  	print_sig_info(type, patterns);
 994      } else if (strcmp(type, "signal") == 0) {
 995  	int type = get_type(&patterns);
 996  	print_sig_info(type, patterns);
 997      } else if (strcmp(type, "param") == 0) {
 998  	int type = get_type(&patterns);
 999  	print_param_info(type, patterns);
1000      } else if (strcmp(type, "parameter") == 0) {
1001  	int type = get_type(&patterns);
1002  	print_param_info(type, patterns);
1003      } else if (strcmp(type, "funct") == 0) {
1004  	print_funct_info(patterns);
1005      } else if (strcmp(type, "function") == 0) {
1006  	print_funct_info(patterns);
1007      } else if (strcmp(type, "thread") == 0) {
1008  	print_thread_info(patterns);
1009      } else if (strcmp(type, "alias") == 0) {
1010  	print_pin_aliases(patterns);
1011  	print_param_aliases(patterns);
1012      } else {
1013  	halcmd_error("Unknown 'show' type '%s'\n", type);
1014  	return -1;
1015      }
1016      return 0;
1017  }
1018  
1019  int do_list_cmd(char *type, char **patterns)
1020  {
1021      if ( !type) {
1022  	halcmd_error("'list' requires type'\n");
1023  	return -1;
1024      }
1025      if (rtapi_get_msg_level() == RTAPI_MSG_NONE) {
1026  	/* must be -Q, don't print anything */
1027  	return 0;
1028      }
1029      if (strcmp(type, "comp") == 0) {
1030  	print_comp_names(patterns);
1031      } else if (strcmp(type, "pin") == 0) {
1032  	print_pin_names(patterns);
1033      } else if (strcmp(type, "sig") == 0) {
1034  	print_sig_names(patterns);
1035      } else if (strcmp(type, "signal") == 0) {
1036  	print_sig_names(patterns);
1037      } else if (strcmp(type, "param") == 0) {
1038  	print_param_names(patterns);
1039      } else if (strcmp(type, "parameter") == 0) {
1040  	print_param_names(patterns);
1041      } else if (strcmp(type, "funct") == 0) {
1042  	print_funct_names(patterns);
1043      } else if (strcmp(type, "function") == 0) {
1044  	print_funct_names(patterns);
1045      } else if (strcmp(type, "thread") == 0) {
1046  	print_thread_names(patterns);
1047      } else {
1048  	halcmd_error("Unknown 'list' type '%s'\n", type);
1049  	return -1;
1050      }
1051      return 0;
1052  }
1053  
1054  int do_status_cmd(char *type)
1055  {
1056  
1057      if (rtapi_get_msg_level() == RTAPI_MSG_NONE) {
1058  	/* must be -Q, don't print anything */
1059  	return 0;
1060      }
1061      if ((type == NULL) || (strcmp(type, "all") == 0)) {
1062  	/* print everything */
1063  	/* add other status functions here if/when they are defined */
1064  	print_lock_status();
1065  	print_mem_status();
1066      } else if (strcmp(type, "lock") == 0) {
1067  	print_lock_status();
1068      } else if (strcmp(type, "mem") == 0) {
1069  	print_mem_status();
1070      } else {
1071  	halcmd_error("Unknown 'status' type '%s'\n", type);
1072  	return -1;
1073      }
1074      return 0;
1075  }
1076  
1077  int do_loadrt_cmd(char *mod_name, char *args[])
1078  {
1079      char arg_string[MAX_CMD_LEN+1];
1080      int m=0, n=0, retval;
1081      hal_comp_t *comp;
1082      char *argv[MAX_TOK+3];
1083      char *cp1;
1084  #if defined(RTAPI_USPACE)
1085      argv[m++] = "-Wn";
1086      argv[m++] = mod_name;
1087      argv[m++] = EMC2_BIN_DIR "/rtapi_app";
1088      argv[m++] = "load";
1089      argv[m++] = mod_name;
1090      /* loop thru remaining arguments */
1091      while ( args[n] && args[n][0] != '\0' ) {
1092          argv[m++] = args[n++];
1093      }
1094      argv[m++] = NULL;
1095      retval = do_loadusr_cmd(argv);
1096  #else
1097      static char *rtmod_dir = EMC2_RTLIB_DIR;
1098      struct stat stat_buf;
1099      char mod_path[MAX_CMD_LEN+1];
1100  
1101      if (hal_get_lock()&HAL_LOCK_LOAD) {
1102  	halcmd_error("HAL is locked, loading of modules is not permitted\n");
1103  	return -EPERM;
1104      }
1105      if ( (strlen(rtmod_dir)+strlen(mod_name)+5) > MAX_CMD_LEN ) {
1106  	halcmd_error("Module path too long\n");
1107  	return -1;
1108      }
1109  
1110      /* make full module name '<path>/<name>.o' */
1111      {
1112          int r;
1113          r = snprintf(mod_path, sizeof(mod_path), "%s/%s%s", rtmod_dir, mod_name, MODULE_EXT);
1114          if (r < 0) {
1115              halcmd_error("error making module path for %s/%s%s\n", rtmod_dir, mod_name, MODULE_EXT);
1116              return -1;
1117          } else if (r >= sizeof(mod_path)) {
1118              // truncation!
1119              halcmd_error("module path too long (max %lu) for %s/%s%s\n", (unsigned long)sizeof(mod_path)-1, rtmod_dir, mod_name, MODULE_EXT);
1120              return -1;
1121          }
1122      }
1123  
1124      /* is there a file with that name? */
1125      if ( stat(mod_path, &stat_buf) != 0 ) {
1126          /* can't find it */
1127          halcmd_error("Can't find module '%s' in %s\n", mod_name, rtmod_dir);
1128          return -1;
1129      }
1130      
1131      argv[0] = EMC2_BIN_DIR "/linuxcnc_module_helper";
1132      argv[1] = "insert";
1133      argv[2] = mod_path;
1134      /* loop thru remaining arguments */
1135      n = 0;
1136      m = 3;
1137      while ( args[n] && args[n][0] != '\0' ) {
1138          argv[m++] = args[n++];
1139      }
1140      /* add a NULL to terminate the argv array */
1141      argv[m] = NULL;
1142  
1143      retval = hal_systemv(argv);
1144  #endif
1145  
1146      if ( retval != 0 ) {
1147  	halcmd_error("insmod for %s failed, returned %d\n"
1148  #if !defined(RTAPI_USPACE)
1149              "See the output of 'dmesg' for more information.\n"
1150  #endif
1151          , mod_name, retval );
1152  	return -1;
1153      }
1154      /* make the args that were passed to the module into a single string */
1155      n = 0;
1156      arg_string[0] = '\0';
1157      while ( args[n] && args[n][0] != '\0' ) {
1158  	strncat(arg_string, args[n++], MAX_CMD_LEN);
1159  	strncat(arg_string, " ", MAX_CMD_LEN);
1160      }
1161      /* allocate HAL shmem for the string */
1162      cp1 = hal_malloc(strlen(arg_string)+1);
1163      if ( cp1 == NULL ) {
1164  	halcmd_error("failed to allocate memory for module args\n");
1165  	return -1;
1166      }
1167      /* copy string to shmem */
1168      strcpy (cp1, arg_string);
1169      /* get mutex before accessing shared data */
1170      rtapi_mutex_get(&(hal_data->mutex));
1171      /* search component list for the newly loaded component */
1172      comp = halpr_find_comp_by_name(mod_name);
1173      if (comp == 0) {
1174  	rtapi_mutex_give(&(hal_data->mutex));
1175  	halcmd_error("module '%s' not loaded\n", mod_name);
1176  	return -EINVAL;
1177      }
1178      /* link args to comp struct */
1179      comp->insmod_args = SHMOFF(cp1);
1180      rtapi_mutex_give(&(hal_data->mutex));
1181      /* print success message */
1182      halcmd_info("Realtime module '%s' loaded\n", mod_name);
1183      return 0;
1184  }
1185  
1186  int do_delsig_cmd(char *mod_name)
1187  {
1188      int next, retval, retval1, n;
1189      hal_sig_t *sig;
1190      char sigs[MAX_EXPECTED_SIGS][HAL_NAME_LEN+1];
1191  
1192      /* check for "all" */
1193      if ( strcmp(mod_name, "all" ) != 0 ) {
1194  	retval = hal_signal_delete(mod_name);
1195  	if (retval == 0) {
1196  	    /* print success message */
1197  	    halcmd_info("Signal '%s' deleted'\n", mod_name);
1198  	}
1199  	return retval;
1200      } else {
1201  	/* build a list of signal(s) to delete */
1202  	n = 0;
1203  	rtapi_mutex_get(&(hal_data->mutex));
1204  
1205  	next = hal_data->sig_list_ptr;
1206  	while (next != 0) {
1207  	    sig = SHMPTR(next);
1208  	    /* we want to unload this signal, remember its name */
1209  	    if ( n < ( MAX_EXPECTED_SIGS - 1 ) ) {
1210  	        strncpy(sigs[n], sig->name, HAL_NAME_LEN );
1211  		sigs[n][HAL_NAME_LEN] = '\0';
1212  		n++;
1213  	    }
1214  	    next = sig->next_ptr;
1215  	}
1216  	rtapi_mutex_give(&(hal_data->mutex));
1217  	sigs[n][0] = '\0';
1218  
1219  	if ( sigs[0][0] == '\0' ) {
1220  	    /* desired signals not found */
1221  	    halcmd_error("no signals found to be deleted\n");
1222  	    return -1;
1223  	}
1224  	/* we now have a list of components, unload them */
1225  	n = 0;
1226  	retval1 = 0;
1227  	while ( sigs[n][0] != '\0' ) {
1228  	    retval = hal_signal_delete(sigs[n]);
1229  	/* check for fatal error */
1230  	    if ( retval < -1 ) {
1231  		return retval;
1232  	    }
1233  	    /* check for other error */
1234  	    if ( retval != 0 ) {
1235  		retval1 = retval;
1236  	    }
1237  	    if (retval == 0) {
1238  		/* print success message */
1239  		halcmd_info("Signal '%s' deleted'\n",
1240  		sigs[n]);
1241  	    }
1242  	    n++;
1243  	}
1244      }
1245      return retval1;
1246  }
1247  
1248  int do_unloadusr_cmd(char *mod_name)
1249  {
1250      int next, all;
1251      hal_comp_t *comp;
1252      pid_t ourpid = getpid();
1253  
1254      /* check for "all" */
1255      if ( strcmp(mod_name, "all" ) == 0 ) {
1256  	all = 1;
1257      } else {
1258  	all = 0;
1259      }
1260      /* build a list of component(s) to unload */
1261      rtapi_mutex_get(&(hal_data->mutex));
1262      next = hal_data->comp_list_ptr;
1263      while (next != 0) {
1264  	comp = SHMPTR(next);
1265  	if ( comp->type == 0 && comp->pid != ourpid) {
1266  	    /* found a userspace component besides us */
1267  	    if ( all || ( strcmp(mod_name, comp->name) == 0 )) {
1268  		/* we want to unload this component, send it SIGTERM */
1269                  kill(abs(comp->pid), SIGTERM);
1270  	    }
1271  	}
1272  	next = comp->next_ptr;
1273      }
1274      rtapi_mutex_give(&(hal_data->mutex));
1275      return 0;
1276  }
1277  
1278  
1279  int do_unloadrt_cmd(char *mod_name)
1280  {
1281      int next, retval, retval1, n, all;
1282      hal_comp_t *comp;
1283      char comps[64][HAL_NAME_LEN+1];
1284  
1285      /* check for "all" */
1286      if ( strcmp(mod_name, "all" ) == 0 ) {
1287  	all = 1;
1288      } else {
1289  	all = 0;
1290      }
1291      /* build a list of component(s) to unload */
1292      n = 0;
1293      rtapi_mutex_get(&(hal_data->mutex));
1294      next = hal_data->comp_list_ptr;
1295      while (next != 0) {
1296  	comp = SHMPTR(next);
1297  	if ( comp->type == 1 ) {
1298  	    /* found a realtime component */
1299  	    if ( all || ( strcmp(mod_name, comp->name) == 0 )) {
1300  		/* we want to unload this component, remember its name */
1301  		if ( n < 63 ) {
1302  		    strncpy(comps[n], comp->name, HAL_NAME_LEN );
1303  		    comps[n][HAL_NAME_LEN] = '\0';
1304  		    n++;
1305  		}
1306  	    }
1307  	}
1308  	next = comp->next_ptr;
1309      }
1310      rtapi_mutex_give(&(hal_data->mutex));
1311      /* mark end of list */
1312      comps[n][0] = '\0';
1313      if ( !all && ( comps[0][0] == '\0' )) {
1314  	/* desired component not found */
1315  	halcmd_error("component '%s' is not loaded\n", mod_name);
1316  	return -1;
1317      }
1318      /* we now have a list of components, unload them */
1319      n = 0;
1320      retval1 = 0;
1321      while ( comps[n][0] != '\0' ) {
1322          // special case: initial prefix means it is not a real comp
1323          if (strstr(comps[n],HAL_PSEUDO_COMP_PREFIX) == comps[n] ) {
1324             n++;
1325             continue;
1326          }
1327  	retval = unloadrt_comp(comps[n++]);
1328  	/* check for fatal error */
1329  	if ( retval < -1 ) {
1330  	    return retval;
1331  	}
1332  	/* check for other error */
1333  	if ( retval != 0 ) {
1334  	    retval1 = retval;
1335  	}
1336      }
1337      if (retval1 < 0) {
1338  	halcmd_error("unloadrt failed\n");
1339      }
1340      return retval1;
1341  }
1342  
1343  static int unloadrt_comp(char *mod_name)
1344  {
1345      int retval;
1346      char *argv[4];
1347  
1348  #if defined(RTAPI_USPACE)
1349      argv[0] = EMC2_BIN_DIR "/rtapi_app";
1350      argv[1] = "unload";
1351  #else
1352      argv[0] = EMC2_BIN_DIR "/linuxcnc_module_helper";
1353      argv[1] = "remove";
1354  #endif
1355      argv[2] = mod_name;
1356      /* add a NULL to terminate the argv array */
1357      argv[3] = NULL;
1358  
1359      retval = hal_systemv(argv);
1360  
1361      if ( retval != 0 ) {
1362  	halcmd_error("rmmod failed, returned %d\n", retval);
1363  	return -1;
1364      }
1365      /* print success message */
1366      halcmd_info("Realtime module '%s' unloaded\n",
1367  	mod_name);
1368      return 0;
1369  }
1370  
1371  int do_unload_cmd(char *mod_name) {
1372      if(strcmp(mod_name, "all") == 0) {
1373          int res = do_unloadusr_cmd(mod_name);
1374          if(res) return res;
1375          return do_unloadrt_cmd(mod_name);
1376      } else {
1377          hal_comp_t *comp;
1378          int type = -1;
1379          rtapi_mutex_get(&(hal_data->mutex));
1380          comp = halpr_find_comp_by_name(mod_name);
1381          if(comp) type = comp->type;
1382          rtapi_mutex_give(&(hal_data->mutex));
1383          if(type == -1) {
1384              halcmd_error("component '%s' is not loaded\n",
1385                  mod_name);
1386              return -1;
1387          }
1388          if(type == 1) return do_unloadrt_cmd(mod_name);
1389          else return do_unloadusr_cmd(mod_name);
1390      }
1391  }
1392  
1393  static char *guess_comp_name(char *prog_name)
1394  {
1395      static char name[HAL_NAME_LEN+1];
1396      char *last_slash = strrchr(prog_name, '/');
1397      char *st = last_slash ? last_slash + 1 : prog_name;
1398      char *last_dot = strrchr(st, '.');
1399      char *en = last_dot ? last_dot : prog_name + strlen(prog_name);
1400      size_t len = en-st;
1401  
1402      snprintf(name, sizeof(name), "%.*s", (int)len, st);
1403      return name;
1404  }
1405  
1406  static void reset_getopt_state() {
1407  /*
1408  
1409  It turns out that it is not portable to reset the state of getopt, so that
1410  a different argv list can be parsed.
1411  
1412  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=192834
1413  
1414  (though that thread ends with the bug being closed as fixed in lenny, it
1415  is not fixed or has regressed by debian jessie)
1416  */
1417  
1418  #ifdef __GNU_LIBRARY__
1419      optind = 0;
1420  #else
1421      optind = 1;
1422  #endif
1423  
1424  #ifdef HAVE_OPTRESET
1425      optreset = 1;
1426  #endif
1427  }
1428  
1429  int do_loadusr_cmd(char *args[])
1430  {
1431      int wait_flag, wait_comp_flag, ignore_flag;
1432      char *prog_name, *new_comp_name=NULL;
1433      char *argv[MAX_TOK+1];
1434      int n, m, retval, status;
1435      pid_t pid;
1436  
1437      int argc = 0;
1438      while(args[argc] && *args[argc]) argc++;
1439      args--; argc++;
1440  
1441      if (hal_get_lock()&HAL_LOCK_LOAD) {
1442  	halcmd_error("HAL is locked, loading of programs is not permitted\n");
1443  	return -EPERM;
1444      }
1445      wait_flag = 0;
1446      wait_comp_flag = 0;
1447      ignore_flag = 0;
1448      prog_name = NULL;
1449  
1450      /* check for options (-w, -i, and/or -r) */
1451      reset_getopt_state();
1452      while (1) {
1453  	int c = getopt(argc, args, "+wWin:");
1454  	if(c == -1) break;
1455  
1456  	switch(c) {
1457  	    case 'w':
1458  		wait_flag = 1; break;
1459  	    case 'W':
1460  		wait_comp_flag = 1; break;
1461  	    case 'i':
1462  		ignore_flag = 1; break;
1463  	    case 'n':
1464  		new_comp_name = optarg; break;
1465  	    default:
1466  		return -EINVAL;
1467  		break;
1468  	}
1469      }
1470      /* get program and component name */
1471      args += optind;
1472      prog_name = *args++;
1473      if (prog_name == 0) { return -EINVAL; }
1474      if(!new_comp_name) {
1475  	new_comp_name = guess_comp_name(prog_name);
1476      }
1477      /* prepare to exec() the program */
1478      argv[0] = prog_name;
1479      /* loop thru remaining arguments */
1480      n = 0;
1481      m = 1;
1482      while ( args[n] && args[n][0] != '\0' ) {
1483          argv[m++] = args[n++];
1484      }
1485      /* add a NULL to terminate the argv array */
1486      argv[m] = NULL;
1487      /* start the child process */
1488      pid = hal_systemv_nowait(argv);
1489      /* make sure we reconnected to the HAL */
1490      if (comp_id < 0) {
1491  	fprintf(stderr, "halcmd: hal_init() failed after fork: %d\n",
1492  	    comp_id );
1493  	exit(-1);
1494      }
1495      hal_ready(comp_id);
1496      if ( wait_comp_flag ) {
1497          int ready = 0, count=0, exited=0;
1498          hal_comp_t *comp = NULL;
1499  	retval = 0;
1500          while(!ready && !exited) {
1501  	    /* sleep for 10mS */
1502              struct timespec ts = {0, 10 * 1000 * 1000};
1503              nanosleep(&ts, NULL);
1504  	    /* check for program ending */
1505  	    retval = waitpid( pid, &status, WNOHANG );
1506  	    if ( retval != 0 ) {
1507  		    exited = 1;
1508  	        if (WIFEXITED(status) && WEXITSTATUS(status)) {
1509  	            halcmd_error("waitpid failed %s %s\n",prog_name,new_comp_name);
1510  	            ready = 0;
1511  	            break;
1512  	        }
1513  	    }
1514  	    /* check for program becoming ready */
1515              rtapi_mutex_get(&(hal_data->mutex));
1516              comp = halpr_find_comp_by_name(new_comp_name);
1517              if(comp && comp->ready) {
1518                  ready = 1;
1519              }
1520              rtapi_mutex_give(&(hal_data->mutex));
1521  	    /* pacify the user */
1522              count++;
1523              if(count == 200) {
1524                  fprintf(stderr, "Waiting for component '%s' to become ready.",
1525                          new_comp_name);
1526                  fflush(stderr);
1527              } else if(count > 200 && count % 10 == 0) {
1528                  fprintf(stderr, ".");
1529                  fflush(stderr);
1530              }
1531          }
1532          if (count >= 100) {
1533  	    /* terminate pacifier */
1534  	    fprintf(stderr, "\n");
1535  	}
1536  	/* did it work? */
1537  	if (ready) {
1538  	    halcmd_info("Component '%s' ready\n", new_comp_name);
1539  	} else {
1540  	    if ( retval < 0 ) {
1541  		halcmd_error("\nwaitpid(%d) failed\n", pid);
1542  	    } else {
1543  		halcmd_error("%s exited without becoming ready\n", prog_name);
1544  	    }
1545  	    return -1;
1546  	}
1547      }
1548      if ( wait_flag ) {
1549  	/* wait for child process to complete */
1550  	retval = waitpid ( pid, &status, 0 );
1551  	/* check result of waitpid() */
1552  	if ( retval < 0 ) {
1553  	    halcmd_error("waitpid(%d) failed\n", pid);
1554  	    return -1;
1555  	}
1556  	if ( WIFEXITED(status) == 0 ) {
1557  	    halcmd_error("program '%s' did not exit normally\n", prog_name );
1558  	    return -1;
1559  	}
1560  	if ( ignore_flag == 0 ) {
1561  	    retval = WEXITSTATUS(status);
1562  	    if ( retval != 0 ) {
1563  		halcmd_error("program '%s' failed, returned %d\n", prog_name, retval );
1564  		return -1;
1565  	    }
1566  	}
1567  	/* print success message */
1568  	halcmd_info("Program '%s' finished\n", prog_name);
1569      } else {
1570  	/* print success message */
1571  	halcmd_info("Program '%s' started\n", prog_name);
1572      }
1573      return 0;
1574  }
1575  
1576  
1577  int do_waitusr_cmd(char *comp_name)
1578  {
1579      hal_comp_t *comp;
1580      int exited;
1581  
1582      if (*comp_name == '\0') {
1583  	halcmd_error("component name missing\n");
1584  	return -EINVAL;
1585      }
1586      rtapi_mutex_get(&(hal_data->mutex));
1587      comp = halpr_find_comp_by_name(comp_name);
1588      if (comp == NULL) {
1589  	rtapi_mutex_give(&(hal_data->mutex));
1590  	halcmd_info("component '%s' not found or already exited\n", comp_name);
1591  	return 0;
1592      }
1593      if (comp->type != 0) {
1594  	rtapi_mutex_give(&(hal_data->mutex));
1595  	halcmd_error("'%s' is not a userspace component\n", comp_name);
1596  	return -EINVAL;
1597      }
1598      rtapi_mutex_give(&(hal_data->mutex));
1599      /* let the user know what is going on */
1600      halcmd_info("Waiting for component '%s'\n", comp_name);
1601      exited = 0;
1602      while(!exited) {
1603  	/* sleep for 200mS */
1604  	struct timespec ts = {0, 200 * 1000 * 1000};
1605  	nanosleep(&ts, NULL);
1606  	/* check for component still around */
1607  	rtapi_mutex_get(&(hal_data->mutex));
1608  	comp = halpr_find_comp_by_name(comp_name);
1609  	if(comp == NULL) {
1610  		exited = 1;
1611  	}
1612  	rtapi_mutex_give(&(hal_data->mutex));
1613      }
1614      halcmd_info("Component '%s' finished\n", comp_name);
1615      return 0;
1616  }
1617  
1618  
1619  static void print_comp_info(char **patterns)
1620  {
1621      int next;
1622      hal_comp_t *comp;
1623  
1624      if (scriptmode == 0) {
1625  	halcmd_output("Loaded HAL Components:\n");
1626  	halcmd_output("ID      Type  %-*s PID   State\n", HAL_NAME_LEN, "Name");
1627      }
1628      rtapi_mutex_get(&(hal_data->mutex));
1629      next = hal_data->comp_list_ptr;
1630      while (next != 0) {
1631  	comp = SHMPTR(next);
1632  	if ( match(patterns, comp->name) ) {
1633              if(comp->type == 2) {
1634                  hal_comp_t *comp1 = halpr_find_comp_by_id(comp->comp_id & 0xffff);
1635                  halcmd_output("    INST %s %s",
1636                          comp1 ? comp1->name : "(unknown)", 
1637                          comp->name);
1638              } else {
1639                  halcmd_output(" %5d  %-4s  %-*s",
1640                      comp->comp_id, (comp->type ? "RT" : "User"),
1641                      HAL_NAME_LEN, comp->name);
1642                  if(comp->type == 0) {
1643                          halcmd_output(" %5d %s", comp->pid, comp->ready > 0 ?
1644                                  "ready" : "initializing");
1645                  } else {
1646                          halcmd_output(" %5s %s", "", comp->ready > 0 ?
1647                                  "ready" : "initializing");
1648                  }
1649              }
1650              halcmd_output("\n");
1651  	}
1652  	next = comp->next_ptr;
1653      }
1654      rtapi_mutex_give(&(hal_data->mutex));
1655      halcmd_output("\n");
1656  }
1657  
1658  static void print_pin_info(int type, char **patterns)
1659  {
1660      int next;
1661      hal_pin_t *pin;
1662      hal_comp_t *comp;
1663      hal_sig_t *sig;
1664      void *dptr;
1665  
1666      if (scriptmode == 0) {
1667  	halcmd_output("Component Pins:\n");
1668  	halcmd_output("Owner   Type  Dir         Value  Name\n");
1669      }
1670      rtapi_mutex_get(&(hal_data->mutex));
1671      next = hal_data->pin_list_ptr;
1672      while (next != 0) {
1673  	pin = SHMPTR(next);
1674  	if ( tmatch(type, pin->type) && match(patterns, pin->name) ) {
1675  	    comp = SHMPTR(pin->owner_ptr);
1676  	    if (pin->signal != 0) {
1677  		sig = SHMPTR(pin->signal);
1678  		dptr = SHMPTR(sig->data_ptr);
1679  	    } else {
1680  		sig = 0;
1681  		dptr = &(pin->dummysig);
1682  	    }
1683  	    if (scriptmode == 0) {
1684  		halcmd_output(" %5d  %5s %-3s  %9s  %s",
1685  		    comp->comp_id,
1686  		    data_type((int) pin->type),
1687  		    pin_data_dir((int) pin->dir),
1688  		    data_value((int) pin->type, dptr),
1689  		    pin->name);
1690  	    } else {
1691  		halcmd_output("%s %s %s %s %s",
1692  		    comp->name,
1693  		    data_type((int) pin->type),
1694  		    pin_data_dir((int) pin->dir),
1695  		    data_value2((int) pin->type, dptr),
1696  		    pin->name);
1697  	    } 
1698  	    if (sig == 0) {
1699  		halcmd_output("\n");
1700  	    } else {
1701  		halcmd_output(" %s %s\n", data_arrow1((int) pin->dir), sig->name);
1702  	    }
1703  	}
1704  	next = pin->next_ptr;
1705      }
1706      rtapi_mutex_give(&(hal_data->mutex));
1707      halcmd_output("\n");
1708  }
1709  
1710  static void print_pin_aliases(char **patterns)
1711  {
1712      int next;
1713      hal_oldname_t *oldname;
1714      hal_pin_t *pin;
1715  
1716      if (scriptmode == 0) {
1717  	halcmd_output("Pin Aliases:\n");
1718  	halcmd_output(" %-*s  %s\n", HAL_NAME_LEN, "Alias", "Original Name");
1719      }
1720      rtapi_mutex_get(&(hal_data->mutex));
1721      next = hal_data->pin_list_ptr;
1722      while (next != 0) {
1723  	pin = SHMPTR(next);
1724  	if ( pin->oldname != 0 ) {
1725  	    /* name is an alias */
1726  	    oldname = SHMPTR(pin->oldname);
1727  	    if ( match(patterns, pin->name) || match(patterns, oldname->name) ) {
1728  		if (scriptmode == 0) {
1729  		    halcmd_output(" %-*s  %s\n", HAL_NAME_LEN, pin->name, oldname->name);
1730  		} else {
1731  		    halcmd_output(" %s  %s\n", pin->name, oldname->name);
1732  		}
1733  	    }
1734  	}
1735  	next = pin->next_ptr;
1736      }
1737      rtapi_mutex_give(&(hal_data->mutex));
1738      halcmd_output("\n");
1739  }
1740  
1741  static void print_sig_info(int type, char **patterns)
1742  {
1743      int next;
1744      hal_sig_t *sig;
1745      void *dptr;
1746      hal_pin_t *pin;
1747  
1748      if (scriptmode != 0) {
1749      	print_script_sig_info(type, patterns);
1750  	return;
1751      }
1752      halcmd_output("Signals:\n");
1753      halcmd_output("Type          Value  Name     (linked to)\n");
1754      rtapi_mutex_get(&(hal_data->mutex));
1755      next = hal_data->sig_list_ptr;
1756      while (next != 0) {
1757  	sig = SHMPTR(next);
1758  	if ( tmatch(type, sig->type) && match(patterns, sig->name) ) {
1759  	    dptr = SHMPTR(sig->data_ptr);
1760  	    halcmd_output("%s  %s  %s\n", data_type((int) sig->type),
1761  		data_value((int) sig->type, dptr), sig->name);
1762  	    /* look for pin(s) linked to this signal */
1763  	    pin = halpr_find_pin_by_sig(sig, 0);
1764  	    while (pin != 0) {
1765  		halcmd_output("                         %s %s\n",
1766  		    data_arrow2((int) pin->dir), pin->name);
1767  		pin = halpr_find_pin_by_sig(sig, pin);
1768  	    }
1769  	}
1770  	next = sig->next_ptr;
1771      }
1772      rtapi_mutex_give(&(hal_data->mutex));
1773      halcmd_output("\n");
1774  }
1775  
1776  static void print_script_sig_info(int type, char **patterns)
1777  {
1778      int next;
1779      hal_sig_t *sig;
1780      void *dptr;
1781      hal_pin_t *pin;
1782  
1783      if (scriptmode == 0) {
1784      	return;
1785      }
1786      rtapi_mutex_get(&(hal_data->mutex));
1787      next = hal_data->sig_list_ptr;
1788      while (next != 0) {
1789  	sig = SHMPTR(next);
1790  	if ( tmatch(type, sig->type) && match(patterns, sig->name) ) {
1791  	    dptr = SHMPTR(sig->data_ptr);
1792  	    halcmd_output("%s  %s  %s", data_type((int) sig->type),
1793  		data_value2((int) sig->type, dptr), sig->name);
1794  	    /* look for pin(s) linked to this signal */
1795  	    pin = halpr_find_pin_by_sig(sig, 0);
1796  	    while (pin != 0) {
1797  		halcmd_output(" %s %s",
1798  		    data_arrow2((int) pin->dir), pin->name);
1799  		pin = halpr_find_pin_by_sig(sig, pin);
1800  	    }
1801  	    halcmd_output("\n");
1802  	}
1803  	next = sig->next_ptr;
1804      }
1805      rtapi_mutex_give(&(hal_data->mutex));
1806      halcmd_output("\n");
1807  }
1808  
1809  static void print_param_info(int type, char **patterns)
1810  {
1811      int next;
1812      hal_param_t *param;
1813      hal_comp_t *comp;
1814  
1815      if (scriptmode == 0) {
1816  	halcmd_output("Parameters:\n");
1817  	halcmd_output("Owner   Type  Dir         Value  Name\n");
1818      }
1819      rtapi_mutex_get(&(hal_data->mutex));
1820      next = hal_data->param_list_ptr;
1821      while (next != 0) {
1822  	param = SHMPTR(next);
1823  	if ( tmatch(type, param->type), match(patterns, param->name) ) {
1824  	    comp = SHMPTR(param->owner_ptr);
1825  	    if (scriptmode == 0) {
1826  		halcmd_output(" %5d  %5s %-3s  %9s  %s\n",
1827  		    comp->comp_id, data_type((int) param->type),
1828  		    param_data_dir((int) param->dir),
1829  		    data_value((int) param->type, SHMPTR(param->data_ptr)),
1830  		    param->name);
1831  	    } else {
1832  		halcmd_output("%s %s %s %s %s\n",
1833  		    comp->name, data_type((int) param->type),
1834  		    param_data_dir((int) param->dir),
1835  		    data_value2((int) param->type, SHMPTR(param->data_ptr)),
1836  		    param->name);
1837  	    } 
1838  	}
1839  	next = param->next_ptr;
1840      }
1841      rtapi_mutex_give(&(hal_data->mutex));
1842      halcmd_output("\n");
1843  }
1844  
1845  static void print_param_aliases(char **patterns)
1846  {
1847      int next;
1848      hal_oldname_t *oldname;
1849      hal_param_t *param;
1850  
1851      if (scriptmode == 0) {
1852  	halcmd_output("Parameter Aliases:\n");
1853  	halcmd_output(" %-*s  %s\n", HAL_NAME_LEN, "Alias", "Original Name");
1854      }
1855      rtapi_mutex_get(&(hal_data->mutex));
1856      next = hal_data->param_list_ptr;
1857      while (next != 0) {
1858  	param = SHMPTR(next);
1859  	if ( param->oldname != 0 ) {
1860  	    /* name is an alias */
1861  	    oldname = SHMPTR(param->oldname);
1862  	    if ( match(patterns, param->name) || match(patterns, oldname->name) ) {
1863  		if (scriptmode == 0) {
1864  		    halcmd_output(" %-*s  %s\n", HAL_NAME_LEN, param->name, oldname->name);
1865  		} else {
1866  		    halcmd_output(" %s  %s\n", param->name, oldname->name);
1867  		}
1868  	    }
1869  	}
1870  	next = param->next_ptr;
1871      }
1872      rtapi_mutex_give(&(hal_data->mutex));
1873      halcmd_output("\n");
1874  }
1875  
1876  static void print_funct_info(char **patterns)
1877  {
1878      int next;
1879      hal_funct_t *fptr;
1880      hal_comp_t *comp;
1881  
1882      if (scriptmode == 0) {
1883  	halcmd_output("Exported Functions:\n");
1884  	halcmd_output("Owner   CodeAddr  Arg       FP   Users  Name\n");
1885      }
1886      rtapi_mutex_get(&(hal_data->mutex));
1887      next = hal_data->funct_list_ptr;
1888      while (next != 0) {
1889  	fptr = SHMPTR(next);
1890  	if ( match(patterns, fptr->name) ) {
1891  	    comp = SHMPTR(fptr->owner_ptr);
1892  	    if (scriptmode == 0) {
1893  		halcmd_output(" %05d  %08lx  %08lx  %-3s  %5d   %s\n",
1894  		    comp->comp_id,
1895  		    (long)fptr->funct,
1896  		    (long)fptr->arg, (fptr->uses_fp ? "YES" : "NO"),
1897  		    fptr->users, fptr->name);
1898  	    } else {
1899  		halcmd_output("%s %08lx %08lx %s %3d %s\n",
1900  		    comp->name,
1901  		    (long)fptr->funct,
1902  		    (long)fptr->arg, (fptr->uses_fp ? "YES" : "NO"),
1903  		    fptr->users, fptr->name);
1904  	    } 
1905  	}
1906  	next = fptr->next_ptr;
1907      }
1908      rtapi_mutex_give(&(hal_data->mutex));
1909      halcmd_output("\n");
1910  }
1911  
1912  static void print_thread_info(char **patterns)
1913  {
1914      int next_thread, n;
1915      hal_thread_t *tptr;
1916      hal_list_t *list_root, *list_entry;
1917      hal_funct_entry_t *fentry;
1918      hal_funct_t *funct;
1919  
1920      if (scriptmode == 0) {
1921  	halcmd_output("Realtime Threads:\n");
1922  	halcmd_output("     Period  FP     Name               (     Time, Max-Time )\n");
1923      }
1924      rtapi_mutex_get(&(hal_data->mutex));
1925      next_thread = hal_data->thread_list_ptr;
1926      while (next_thread != 0) {
1927  	tptr = SHMPTR(next_thread);
1928  	if ( match(patterns, tptr->name) ) {
1929  		/* note that the scriptmode format string has no \n */
1930              char name[HAL_NAME_LEN+1];
1931              hal_pin_t* pin;
1932              hal_sig_t *sig;
1933              void *dptr;
1934    
1935              snprintf(name, sizeof(name), "%s.time",tptr->name);
1936              pin = halpr_find_pin_by_name(name);
1937              if (pin) {
1938                  if (pin->signal != 0) {
1939                      sig = SHMPTR(pin->signal);
1940                      dptr = SHMPTR(sig->data_ptr);
1941                  } else {
1942                      sig = 0;
1943                      dptr = &(pin->dummysig);
1944                  }
1945  
1946                  halcmd_output(((scriptmode == 0) ? "%11ld  %-3s  %20s ( %8ld, %8ld )\n"
1947                                                   : "%ld %s %s %8ld %ld"),
1948                                tptr->period,
1949                                (tptr->uses_fp ? "YES" : "NO"),
1950                                tptr->name,
1951                                (long)*(long*)dptr,
1952                                (long)tptr->maxtime);
1953              } else {
1954                  rtapi_print_msg(RTAPI_MSG_ERR,
1955                       "unexpected: cannot find time pin for %s thread",tptr->name);
1956              }
1957  
1958  
1959  	    list_root = &(tptr->funct_list);
1960  	    list_entry = list_next(list_root);
1961  	    n = 1;
1962  	    while (list_entry != list_root) {
1963  		/* print the function info */
1964  		fentry = (hal_funct_entry_t *) list_entry;
1965  		funct = SHMPTR(fentry->funct_ptr);
1966  		/* scriptmode only uses one line per thread, which contains: 
1967  		   thread period, FP flag, name, then all functs separated by spaces  */
1968  		if (scriptmode == 0) {
1969  		    halcmd_output("                 %2d %s\n", n, funct->name);
1970  		} else {
1971  		    halcmd_output(" %s", funct->name);
1972  		}
1973  		n++;
1974  		list_entry = list_next(list_entry);
1975  	    }
1976  	    if (scriptmode != 0) {
1977  		halcmd_output("\n");
1978  	    }
1979  	}
1980  	next_thread = tptr->next_ptr;
1981      }
1982      rtapi_mutex_give(&(hal_data->mutex));
1983      halcmd_output("\n");
1984  }
1985  
1986  static void print_comp_names(char **patterns)
1987  {
1988      int next;
1989      hal_comp_t *comp;
1990  
1991      rtapi_mutex_get(&(hal_data->mutex));
1992      next = hal_data->comp_list_ptr;
1993      while (next != 0) {
1994  	comp = SHMPTR(next);
1995  	if ( match(patterns, comp->name) ) {
1996  	    halcmd_output("%s ", comp->name);
1997  	}
1998  	next = comp->next_ptr;
1999      }
2000      rtapi_mutex_give(&(hal_data->mutex));
2001      halcmd_output("\n");
2002  }
2003  
2004  static void print_pin_names(char **patterns)
2005  {
2006      int next;
2007      hal_pin_t *pin;
2008  
2009      rtapi_mutex_get(&(hal_data->mutex));
2010      next = hal_data->pin_list_ptr;
2011      while (next != 0) {
2012  	pin = SHMPTR(next);
2013  	if ( match(patterns, pin->name) ) {
2014  	    halcmd_output("%s ", pin->name);
2015  	}
2016  	next = pin->next_ptr;
2017      }
2018      rtapi_mutex_give(&(hal_data->mutex));
2019      halcmd_output("\n");
2020  }
2021  
2022  static void print_sig_names(char **patterns)
2023  {
2024      int next;
2025      hal_sig_t *sig;
2026  
2027      rtapi_mutex_get(&(hal_data->mutex));
2028      next = hal_data->sig_list_ptr;
2029      while (next != 0) {
2030  	sig = SHMPTR(next);
2031  	if ( match(patterns, sig->name) ) {
2032  	    halcmd_output("%s ", sig->name);
2033  	}
2034  	next = sig->next_ptr;
2035      }
2036      rtapi_mutex_give(&(hal_data->mutex));
2037      halcmd_output("\n");
2038  }
2039  
2040  static void print_param_names(char **patterns)
2041  {
2042      int next;
2043      hal_param_t *param;
2044  
2045      rtapi_mutex_get(&(hal_data->mutex));
2046      next = hal_data->param_list_ptr;
2047      while (next != 0) {
2048  	param = SHMPTR(next);
2049  	if ( match(patterns, param->name) ) {
2050  	    halcmd_output("%s ", param->name);
2051  	}
2052  	next = param->next_ptr;
2053      }
2054      rtapi_mutex_give(&(hal_data->mutex));
2055      halcmd_output("\n");
2056  }
2057  
2058  static void print_funct_names(char **patterns)
2059  {
2060      int next;
2061      hal_funct_t *fptr;
2062  
2063      rtapi_mutex_get(&(hal_data->mutex));
2064      next = hal_data->funct_list_ptr;
2065      while (next != 0) {
2066  	fptr = SHMPTR(next);
2067  	if ( match(patterns, fptr->name) ) {
2068  	    halcmd_output("%s ", fptr->name);
2069  	}
2070  	next = fptr->next_ptr;
2071      }
2072      rtapi_mutex_give(&(hal_data->mutex));
2073      halcmd_output("\n");
2074  }
2075  
2076  static void print_thread_names(char **patterns)
2077  {
2078      int next_thread;
2079      hal_thread_t *tptr;
2080  
2081      rtapi_mutex_get(&(hal_data->mutex));
2082      next_thread = hal_data->thread_list_ptr;
2083      while (next_thread != 0) {
2084  	tptr = SHMPTR(next_thread);
2085  	if ( match(patterns, tptr->name) ) {
2086  	    halcmd_output("%s ", tptr->name);
2087  	}
2088  	next_thread = tptr->next_ptr;
2089      }
2090      rtapi_mutex_give(&(hal_data->mutex));
2091      halcmd_output("\n");
2092  }
2093  
2094  static void print_lock_status()
2095  {
2096      int lock;
2097  
2098      lock = hal_get_lock();
2099  
2100      halcmd_output("HAL locking status:\n");
2101      halcmd_output("  current lock value %d (%02x)\n", lock, lock);
2102      
2103      if (lock == HAL_LOCK_NONE) 
2104  	halcmd_output("  HAL_LOCK_NONE - nothing is locked\n");
2105      if (lock & HAL_LOCK_LOAD) 
2106  	halcmd_output("  HAL_LOCK_LOAD    - loading of new components is locked\n");
2107      if (lock & HAL_LOCK_CONFIG) 
2108  	halcmd_output("  HAL_LOCK_CONFIG  - link and addf is locked\n");
2109      if (lock & HAL_LOCK_PARAMS) 
2110  	halcmd_output("  HAL_LOCK_PARAMS  - setting params is locked\n");
2111      if (lock & HAL_LOCK_RUN) 
2112  	halcmd_output("  HAL_LOCK_RUN     - running/stopping HAL is locked\n");
2113  }
2114  
2115  static int count_list(int list_root)
2116  {
2117      int n, next;
2118  
2119      rtapi_mutex_get(&(hal_data->mutex));
2120      next = list_root;
2121      n = 0;
2122      while (next != 0) {
2123  	n++;
2124  	next = *((int *) SHMPTR(next));
2125      }
2126      rtapi_mutex_give(&(hal_data->mutex));
2127      return n;
2128  }
2129  
2130  static void print_mem_status()
2131  {
2132      int active, recycled, next;
2133      hal_pin_t *pin;
2134      hal_param_t *param;
2135  
2136      halcmd_output("HAL memory status\n");
2137      halcmd_output("  used/total shared memory:   %ld/%d\n", (long)(HAL_SIZE - hal_data->shmem_avail), HAL_SIZE);
2138      // count components
2139      active = count_list(hal_data->comp_list_ptr);
2140      recycled = count_list(hal_data->comp_free_ptr);
2141      halcmd_output("  active/recycled components: %d/%d\n", active, recycled);
2142      // count pins
2143      active = count_list(hal_data->pin_list_ptr);
2144      recycled = count_list(hal_data->pin_free_ptr);
2145      halcmd_output("  active/recycled pins:       %d/%d\n", active, recycled);
2146      // count parameters
2147      active = count_list(hal_data->param_list_ptr);
2148      recycled = count_list(hal_data->param_free_ptr);
2149      halcmd_output("  active/recycled parameters: %d/%d\n", active, recycled);
2150      // count aliases
2151      rtapi_mutex_get(&(hal_data->mutex));
2152      next = hal_data->pin_list_ptr;
2153      active = 0;
2154      while (next != 0) {
2155  	pin = SHMPTR(next);
2156  	if ( pin->oldname != 0 ) active++;
2157  	next = pin->next_ptr;
2158      }
2159      next = hal_data->param_list_ptr;
2160      while (next != 0) {
2161  	param = SHMPTR(next);
2162  	if ( param->oldname != 0 ) active++;
2163  	next = param->next_ptr;
2164      }
2165      rtapi_mutex_give(&(hal_data->mutex));
2166      recycled = count_list(hal_data->oldname_free_ptr);
2167      halcmd_output("  active/recycled aliases:    %d/%d\n", active, recycled);
2168      // count signals
2169      active = count_list(hal_data->sig_list_ptr);
2170      recycled = count_list(hal_data->sig_free_ptr);
2171      halcmd_output("  active/recycled signals:    %d/%d\n", active, recycled);
2172      // count functions
2173      active = count_list(hal_data->funct_list_ptr);
2174      recycled = count_list(hal_data->funct_free_ptr);
2175      halcmd_output("  active/recycled functions:  %d/%d\n", active, recycled);
2176      // count threads
2177      active = count_list(hal_data->thread_list_ptr);
2178      recycled = count_list(hal_data->thread_free_ptr);
2179      halcmd_output("  active/recycled threads:    %d/%d\n", active, recycled);
2180  }
2181  
2182  /* Switch function for pin/sig/param type for the print_*_list functions */
2183  static const char *data_type(int type)
2184  {
2185      const char *type_str;
2186  
2187      switch (type) {
2188      case HAL_BIT:
2189  	type_str = "bit  ";
2190  	break;
2191      case HAL_FLOAT:
2192  	type_str = "float";
2193  	break;
2194      case HAL_S32:
2195  	type_str = "s32  ";
2196  	break;
2197      case HAL_U32:
2198  	type_str = "u32  ";
2199  	break;
2200      case HAL_PORT:
2201  	type_str = "port ";
2202  	break;
2203      default:
2204  	/* Shouldn't get here, but just in case... */
2205  	type_str = "undef";
2206      }
2207      return type_str;
2208  }
2209  
2210  static const char *data_type2(int type)
2211  {
2212      const char *type_str;
2213  
2214      switch (type) {
2215      case HAL_BIT:
2216  	type_str = "bit";
2217  	break;
2218      case HAL_FLOAT:
2219  	type_str = "float";
2220  	break;
2221      case HAL_S32:
2222  	type_str = "s32";
2223  	break;
2224      case HAL_U32:
2225  	type_str = "u32";
2226  	break;
2227      case HAL_PORT:
2228  	type_str = "port";
2229  	break;
2230      default:
2231  	/* Shouldn't get here, but just in case... */
2232  	type_str = "undef";
2233      }
2234      return type_str;
2235  }
2236  
2237  /* Switch function for pin direction for the print_*_list functions  */
2238  static const char *pin_data_dir(int dir)
2239  {
2240      const char *pin_dir;
2241  
2242      switch (dir) {
2243      case HAL_IN:
2244  	pin_dir = "IN";
2245  	break;
2246      case HAL_OUT:
2247  	pin_dir = "OUT";
2248  	break;
2249      case HAL_IO:
2250  	pin_dir = "I/O";
2251  	break;
2252      default:
2253  	/* Shouldn't get here, but just in case... */
2254  	pin_dir = "???";
2255      }
2256      return pin_dir;
2257  }
2258  
2259  /* Switch function for param direction for the print_*_list functions  */
2260  static const char *param_data_dir(int dir)
2261  {
2262      const char *param_dir;
2263  
2264      switch (dir) {
2265      case HAL_RO:
2266  	param_dir = "RO";
2267  	break;
2268      case HAL_RW:
2269  	param_dir = "RW";
2270  	break;
2271      default:
2272  	/* Shouldn't get here, but just in case... */
2273  	param_dir = "??";
2274      }
2275      return param_dir;
2276  }
2277  
2278  /* Switch function for arrow direction for the print_*_list functions  */
2279  static const char *data_arrow1(int dir)
2280  {
2281      const char *arrow;
2282  
2283      switch (dir) {
2284      case HAL_IN:
2285  	arrow = "<==";
2286  	break;
2287      case HAL_OUT:
2288  	arrow = "==>";
2289  	break;
2290      case HAL_IO:
2291  	arrow = "<=>";
2292  	break;
2293      default:
2294  	/* Shouldn't get here, but just in case... */
2295  	arrow = "???";
2296      }
2297      return arrow;
2298  }
2299  
2300  /* Switch function for arrow direction for the print_*_list functions  */
2301  static const char *data_arrow2(int dir)
2302  {
2303      const char *arrow;
2304  
2305      switch (dir) {
2306      case HAL_IN:
2307  	arrow = "==>";
2308  	break;
2309      case HAL_OUT:
2310  	arrow = "<==";
2311  	break;
2312      case HAL_IO:
2313  	arrow = "<=>";
2314  	break;
2315      default:
2316  	/* Shouldn't get here, but just in case... */
2317  	arrow = "???";
2318      }
2319      return arrow;
2320  }
2321  
2322  /* Switch function to return var value for the print_*_list functions  */
2323  /* the value is printed in a 12 character wide field */
2324  static char *data_value(int type, void *valptr)
2325  {
2326      char *value_str;
2327      static char buf[15];
2328  
2329      switch (type) {
2330      case HAL_BIT:
2331  	if (*((char *) valptr) == 0)
2332  	    value_str = "       FALSE";
2333  	else
2334  	    value_str = "        TRUE";
2335  	break;
2336      case HAL_FLOAT:
2337  	snprintf(buf, 14, "%12.7g", (double)*((hal_float_t *) valptr));
2338  	value_str = buf;
2339  	break;
2340      case HAL_S32:
2341  	snprintf(buf, 14, "  %10ld", (long)*((hal_s32_t *) valptr));
2342  	value_str = buf;
2343  	break;
2344      case HAL_U32:
2345  	snprintf(buf, 14, "  0x%08lX", (unsigned long)*((hal_u32_t *) valptr));
2346  	value_str = buf;
2347  	break;
2348      case HAL_PORT:
2349  	snprintf(buf, 14, "  %10u", hal_port_buffer_size(*((hal_port_t*) valptr)));
2350  	value_str = buf;
2351  	break;
2352      default:
2353  	/* Shouldn't get here, but just in case... */
2354  	value_str = "   undef    ";
2355      }
2356      return value_str;
2357  }
2358  
2359  /* Switch function to return var value in string form  */
2360  /* the value is printed as a packed string (no whitespace */
2361  static char *data_value2(int type, void *valptr)
2362  {
2363      char *value_str;
2364      static char buf[15];
2365  
2366      switch (type) {
2367      case HAL_BIT:
2368  	if (*((char *) valptr) == 0)
2369  	    value_str = "FALSE";
2370  	else
2371  	    value_str = "TRUE";
2372  	break;
2373      case HAL_FLOAT:
2374  	snprintf(buf, 14, "%.7g", (double)*((hal_float_t *) valptr));
2375  	value_str = buf;
2376  	break;
2377      case HAL_S32:
2378  	snprintf(buf, 14, "%ld", (long)*((hal_s32_t *) valptr));
2379  	value_str = buf;
2380  	break;
2381      case HAL_U32:
2382  	snprintf(buf, 14, "%ld", (unsigned long)*((hal_u32_t *) valptr));
2383  	value_str = buf;
2384  	break;
2385      case HAL_PORT:
2386  	snprintf(buf, 14, "%u", hal_port_buffer_size(*((hal_port_t*) valptr)));
2387  	value_str = buf;
2388  	break;
2389  
2390      default:
2391  	/* Shouldn't get here, but just in case... */
2392  	value_str = "unknown_type";
2393      }
2394      return value_str;
2395  }
2396  
2397  int do_save_cmd(char *type, char *filename)
2398  {
2399      FILE *dst;
2400  
2401      if (rtapi_get_msg_level() == RTAPI_MSG_NONE) {
2402  	/* must be -Q, don't print anything */
2403  	return 0;
2404      }
2405      if (filename == NULL || *filename == '\0' ) {
2406  	dst = stdout;
2407      } else {
2408  	dst = fopen(filename, "w" );
2409  	if ( dst == NULL ) {
2410  	    halcmd_error("Can't open 'save' destination '%s'\n", filename);
2411  	return -1;
2412  	}
2413      }
2414      if (type == 0 || *type == '\0') {
2415  	type = "all";
2416      }
2417      if (   (strcmp(type, "all")  == 0)
2418  	|| (strcmp(type, "allu") == 0) ) {
2419  	/* save everything */
2420  	save_comps(dst);
2421  	save_aliases(dst);
2422  	save_signals(dst, 1);
2423  	save_nets(dst, 3);
2424  	save_params(dst);
2425  	if (strcmp(type,"allu") == 0) {
2426  	    save_unconnected_input_pin_values(dst);
2427  	}
2428  	save_threads(dst);
2429      } else if (strcmp(type, "comp") == 0) {
2430  	save_comps(dst);
2431      } else if (strcmp(type, "alias") == 0) {
2432  	save_aliases(dst);
2433      } else if (strcmp(type, "sig") == 0) {
2434  	save_signals(dst, 0);
2435      } else if (strcmp(type, "signal") == 0) {
2436  	save_signals(dst, 0);
2437      } else if (strcmp(type, "sigu") == 0) {
2438  	save_signals(dst, 1);
2439      } else if (strcmp(type, "link") == 0) {
2440  	save_links(dst, 0);
2441      } else if (strcmp(type, "linka") == 0) {
2442  	save_links(dst, 1);
2443      } else if (strcmp(type, "net") == 0) {
2444  	save_nets(dst, 0);
2445      } else if (strcmp(type, "neta") == 0) {
2446  	save_nets(dst, 1);
2447      } else if (strcmp(type, "netl") == 0) {
2448  	save_nets(dst, 2);
2449      } else if (strcmp(type, "netla") == 0 || strcmp(type, "netal") == 0) {
2450  	save_nets(dst, 3);
2451      } else if (strcmp(type, "param") == 0) {
2452  	save_params(dst);
2453      } else if (strcmp(type, "parameter") == 0) {
2454  	save_params(dst);
2455      } else if (strcmp(type, "thread") == 0) {
2456  	save_threads(dst);
2457      } else if (strcmp(type, "unconnectedinpins") == 0) {
2458  	save_unconnected_input_pin_values(dst);
2459      } else {
2460  	halcmd_error("Unknown 'save' type '%s'\n", type);
2461          if (dst != stdout) fclose(dst);
2462  	return -1;
2463      }
2464      if (dst != stdout) {
2465  	fclose(dst);
2466      }
2467      return 0;
2468  }
2469  
2470  static void save_comps(FILE *dst)
2471  {
2472      int next;
2473      hal_comp_t *comp;
2474  
2475      fprintf(dst, "# components\n");
2476      rtapi_mutex_get(&(hal_data->mutex));
2477  
2478      int ncomps = 0;
2479      next = hal_data->comp_list_ptr;
2480      while (next != 0) {
2481  	comp = SHMPTR(next);
2482  	if ( comp->type == 1 ) {
2483              ncomps ++;
2484          }
2485  	next = comp->next_ptr;
2486      }
2487  
2488      hal_comp_t *comps[ncomps], **compptr = comps;
2489      next = hal_data->comp_list_ptr;
2490      while(next != 0)  {
2491  	comp = SHMPTR(next);
2492  	if ( comp->type == 1 ) {
2493              *compptr++ = SHMPTR(next);
2494          }
2495  	next = comp->next_ptr;
2496      }
2497  
2498      int i;
2499      for(i=ncomps; i--;)
2500      {
2501          comp = comps[i];
2502          /* only print realtime components */
2503          if ( comp->insmod_args == 0 ) {
2504              fprintf(dst, "#loadrt %s  (not loaded by loadrt, no args saved)\n", comp->name);
2505          } else {
2506              fprintf(dst, "loadrt %s %s\n", comp->name,
2507                  (char *)SHMPTR(comp->insmod_args));
2508          }
2509      }
2510  #if 0  /* newinst deferred to version 2.2 */
2511      next = hal_data->comp_list_ptr;
2512      while (next != 0) {
2513  	comp = SHMPTR(next);
2514  	if ( comp->type == 2 ) {
2515              hal_comp_t *comp1 = halpr_find_comp_by_id(comp->comp_id & 0xffff);
2516              fprintf(dst, "newinst %s %s\n", comp1->name, comp->name);
2517          }
2518  	next = comp->next_ptr;
2519      }
2520  #endif
2521      rtapi_mutex_give(&(hal_data->mutex));
2522  }
2523  
2524  static void save_aliases(FILE *dst)
2525  {
2526      int next;
2527      hal_pin_t *pin;
2528      hal_param_t *param;
2529      hal_oldname_t *oldname;
2530  
2531      fprintf(dst, "# pin aliases\n");
2532      rtapi_mutex_get(&(hal_data->mutex));
2533      next = hal_data->pin_list_ptr;
2534      while (next != 0) {
2535  	pin = SHMPTR(next);
2536  	if ( pin->oldname != 0 ) {
2537  	    /* name is an alias */
2538  	    oldname = SHMPTR(pin->oldname);
2539  	    fprintf(dst, "alias pin %s %s\n", oldname->name, pin->name);
2540  	}
2541  	next = pin->next_ptr;
2542      }
2543      fprintf(dst, "# param aliases\n");
2544      next = hal_data->param_list_ptr;
2545      while (next != 0) {
2546  	param = SHMPTR(next);
2547  	if ( param->oldname != 0 ) {
2548  	    /* name is an alias */
2549  	    oldname = SHMPTR(param->oldname);
2550  	    fprintf(dst, "alias param %s %s\n", oldname->name, param->name);
2551  	}
2552  	next = param->next_ptr;
2553      }
2554      rtapi_mutex_give(&(hal_data->mutex));
2555  }
2556  
2557  static void save_signals(FILE *dst, int only_unlinked)
2558  {
2559      int next;
2560      hal_sig_t *sig;
2561  
2562      fprintf(dst, "# signals\n");
2563      rtapi_mutex_get(&(hal_data->mutex));
2564      
2565      for( next = hal_data->sig_list_ptr; next; next = sig->next_ptr) {
2566  	sig = SHMPTR(next);
2567          if(only_unlinked && (sig->readers || sig->writers)) continue;
2568  	fprintf(dst, "newsig %s %s\n", sig->name, data_type((int) sig->type));
2569      }
2570      rtapi_mutex_give(&(hal_data->mutex));
2571  }
2572  
2573  static void save_links(FILE *dst, int arrow)
2574  {
2575      int next;
2576      hal_pin_t *pin;
2577      hal_sig_t *sig;
2578      const char *arrow_str;
2579  
2580      fprintf(dst, "# links\n");
2581      rtapi_mutex_get(&(hal_data->mutex));
2582      next = hal_data->pin_list_ptr;
2583      while (next != 0) {
2584  	pin = SHMPTR(next);
2585  	if (pin->signal != 0) {
2586  	    sig = SHMPTR(pin->signal);
2587  	    if (arrow != 0) {
2588  		arrow_str = data_arrow1((int) pin->dir);
2589  	    } else {
2590  		arrow_str = "\0";
2591  	    }
2592  	    fprintf(dst, "linkps %s %s %s\n", pin->name, arrow_str, sig->name);
2593  	}
2594  	next = pin->next_ptr;
2595      }
2596      rtapi_mutex_give(&(hal_data->mutex));
2597  }
2598  
2599  static void save_nets(FILE *dst, int arrow)
2600  {
2601      int next;
2602      hal_pin_t *pin;
2603      hal_sig_t *sig;
2604      const char *arrow_str;
2605  
2606      fprintf(dst, "# nets\n");
2607      rtapi_mutex_get(&(hal_data->mutex));
2608      
2609      for (next = hal_data->sig_list_ptr; next != 0; next = sig->next_ptr) {
2610  	sig = SHMPTR(next);
2611          if(arrow == 3) {
2612              int state = 0, first = 1;
2613  
2614              /* If there are no pins connected to this signal, do nothing */
2615              pin = halpr_find_pin_by_sig(sig, 0);
2616              if(!pin) continue;
2617  
2618              fprintf(dst, "net %s", sig->name);
2619  
2620              /* Step 1: Output pin, if any */
2621              
2622              for(pin = halpr_find_pin_by_sig(sig, 0); pin;
2623                      pin = halpr_find_pin_by_sig(sig, pin)) {
2624                  if(pin->dir != HAL_OUT) continue;
2625                  fprintf(dst, " %s", pin->name);
2626                  state = 1;
2627              }
2628              
2629              /* Step 2: I/O pins, if any */
2630              for(pin = halpr_find_pin_by_sig(sig, 0); pin;
2631                      pin = halpr_find_pin_by_sig(sig, pin)) {
2632                  if(pin->dir != HAL_IO) continue;
2633                  fprintf(dst, " ");
2634                  if(state) { fprintf(dst, "=> "); state = 0; }
2635                  else if(!first) { fprintf(dst, "<=> "); }
2636                  fprintf(dst, "%s", pin->name);
2637                  first = 0;
2638              }
2639              if(!first) state = 1;
2640  
2641              /* Step 3: Input pins, if any */
2642              for(pin = halpr_find_pin_by_sig(sig, 0); pin;
2643                      pin = halpr_find_pin_by_sig(sig, pin)) {
2644                  if(pin->dir != HAL_IN) continue;
2645                  fprintf(dst, " ");
2646                  if(state) { fprintf(dst, "=> "); state = 0; }
2647                  fprintf(dst, "%s", pin->name);
2648              }
2649  
2650              fprintf(dst, "\n");
2651          } else if(arrow == 2) {
2652              /* If there are no pins connected to this signal, do nothing */
2653              pin = halpr_find_pin_by_sig(sig, 0);
2654              if(!pin) continue;
2655  
2656              fprintf(dst, "net %s", sig->name);
2657              pin = halpr_find_pin_by_sig(sig, 0);
2658              while (pin != 0) {
2659                  fprintf(dst, " %s", pin->name);
2660                  pin = halpr_find_pin_by_sig(sig, pin);
2661              }
2662              fprintf(dst, "\n");
2663          } else {
2664              fprintf(dst, "newsig %s %s\n",
2665                      sig->name, data_type((int) sig->type));
2666              pin = halpr_find_pin_by_sig(sig, 0);
2667              while (pin != 0) {
2668                  if (arrow != 0) {
2669                      arrow_str = data_arrow2((int) pin->dir);
2670                  } else {
2671                      arrow_str = "\0";
2672                  }
2673                  fprintf(dst, "linksp %s %s %s\n",
2674                          sig->name, arrow_str, pin->name);
2675                  pin = halpr_find_pin_by_sig(sig, pin);
2676              }
2677          }
2678      }
2679      rtapi_mutex_give(&(hal_data->mutex));
2680  }
2681  
2682  static void save_params(FILE *dst)
2683  {
2684      int next;
2685      hal_param_t *param;
2686  
2687      fprintf(dst, "# parameter values\n");
2688      rtapi_mutex_get(&(hal_data->mutex));
2689      next = hal_data->param_list_ptr;
2690      while (next != 0) {
2691  	param = SHMPTR(next);
2692  	if (param->dir != HAL_RO) {
2693  	    /* param is writable, save its value */
2694  	    fprintf(dst, "setp %s %s\n", param->name,
2695  		data_value((int) param->type, SHMPTR(param->data_ptr)));
2696  	}
2697  	next = param->next_ptr;
2698      }
2699      rtapi_mutex_give(&(hal_data->mutex));
2700  }
2701  
2702  static void save_threads(FILE *dst)
2703  {
2704      int next_thread;
2705      hal_thread_t *tptr;
2706      hal_list_t *list_root, *list_entry;
2707      hal_funct_entry_t *fentry;
2708      hal_funct_t *funct;
2709  
2710      fprintf(dst, "# realtime thread/function links\n");
2711      rtapi_mutex_get(&(hal_data->mutex));
2712      next_thread = hal_data->thread_list_ptr;
2713      while (next_thread != 0) {
2714  	tptr = SHMPTR(next_thread);
2715  	list_root = &(tptr->funct_list);
2716  	list_entry = list_next(list_root);
2717  	while (list_entry != list_root) {
2718  	    /* print the function info */
2719  	    fentry = (hal_funct_entry_t *) list_entry;
2720  	    funct = SHMPTR(fentry->funct_ptr);
2721  	    fprintf(dst, "addf %s %s\n", funct->name, tptr->name);
2722  	    list_entry = list_next(list_entry);
2723  	}
2724  	next_thread = tptr->next_ptr;
2725      }
2726      rtapi_mutex_give(&(hal_data->mutex));
2727  }
2728  
2729  static void save_unconnected_input_pin_values(FILE *dst)
2730  {
2731      hal_pin_t *pin;
2732      void *dptr;
2733      int next;
2734      fprintf(dst, "# unconnected pin values\n");
2735      for(next = hal_data->pin_list_ptr; next; next=pin->next_ptr)
2736      {
2737          pin = SHMPTR(next);
2738          if (   (pin->signal == 0)
2739              && ( (pin->dir == HAL_IN) || (pin->dir == HAL_IO) )
2740             ) {
2741              dptr = &(pin->dummysig);
2742              fprintf(dst, "setp %s %s\n",
2743                     pin->name, data_value((int) pin->type, dptr));
2744          }
2745      }
2746  }
2747  
2748  int do_setexact_cmd() {
2749      int retval = 0;
2750      rtapi_mutex_get(&(hal_data->mutex));
2751      if(hal_data->base_period) {
2752          halcmd_error(
2753              "HAL_LIB: Cannot run 'setexact'"
2754              " after a thread has been created\n");
2755          retval = -EINVAL;
2756      } else {
2757          halcmd_warning(
2758              "HAL_LIB: HAL will pretend that the exact"
2759              " base period requested is possible.\n"
2760              "This mode is not suitable for running real hardware.\n");
2761          hal_data->exact_base_period = 1;
2762      }
2763      rtapi_mutex_give(&(hal_data->mutex));
2764      return retval;
2765  }
2766  
2767  int do_help_cmd(char *command)
2768  {
2769      if (!command) {
2770          print_help_commands();
2771      } else if (strcmp(command, "help") == 0) {
2772  	printf("If you need help to use 'help', then I can't help you.\n");
2773      } else if (strcmp(command, "loadrt") == 0) {
2774  	printf("loadrt modname [modarg(s)]\n");
2775  	printf("  Loads realtime HAL module 'modname', passing 'modargs'\n");
2776  	printf("  to the module.\n");
2777  #if 0  /* newinst deferred to version 2.2 */
2778      } else if (strcmp(command, "newinst") == 0) {
2779  	printf("newinst modname instname\n");
2780  	printf("  Creates another instance of previously loaded module\n" );
2781  	printf("  'modname', nameing it 'instname'.\n");
2782  #endif
2783      } else if (strcmp(command, "unload") == 0) {
2784  	printf("unload compname\n");
2785  	printf("  Unloads HAL module 'compname', whether user space or realtime.\n");
2786          printf("  If 'compname' is 'all', unloads all components.\n");
2787      } else if (strcmp(command, "waitusr") == 0) {
2788  	printf("waitusr compname\n");
2789  	printf("  Waits for user space HAL module 'compname' to exit.\n");
2790      } else if (strcmp(command, "unloadusr") == 0) {
2791  	printf("unloadusr compname\n");
2792  	printf("  Unloads user space HAL module 'compname'.  If 'compname'\n");
2793  	printf("  is 'all', unloads all userspace components.\n");
2794      } else if (strcmp(command, "unloadrt") == 0) {
2795  	printf("unloadrt modname\n");
2796  	printf("  Unloads realtime HAL module 'modname'.  If 'modname'\n");
2797  	printf("  is 'all', unloads all realtime modules.\n");
2798      } else if (strcmp(command, "loadusr") == 0) {
2799  	printf("loadusr [options] progname [progarg(s)]\n");
2800  	printf("  Starts user space program 'progname', passing\n");
2801  	printf("  'progargs' to it.  Options are:\n");
2802  	printf("  -W  wait for HAL component to become ready\n");
2803  	printf("  -Wn NAME  wait for component named NAME to become ready\n");
2804  	printf("  -w  wait for program to finish\n");
2805  	printf("  -i  ignore program return value (use with -w)\n");
2806      } else if ((strcmp(command, "linksp") == 0) || (strcmp(command,"linkps") == 0)) {
2807  	printf("linkps pinname [arrow] signame\n");
2808  	printf("linksp signame [arrow] pinname\n");
2809  	printf("  Links pin 'pinname' to signal 'signame'.  Both forms do\n");
2810  	printf("  the same thing.  Use whichever makes sense.  The optional\n");
2811  	printf("  'arrow' can be '==>', '<==', or '<=>' and is ignored.  It\n");
2812  	printf("  can be used in files to show the direction of data flow,\n");
2813  	printf("  but don't use arrows on the command line.\n");
2814      } else if (strcmp(command, "linkpp") == 0) {
2815  	printf("linkpp firstpin secondpin\n");
2816  	printf("  Creates a signal with the name of the first pin,\n");	printf("  then links both pins to the signal. \n");
2817      } else if(strcmp(command, "net") == 0) {
2818          printf("net signame pinname ...\n");
2819          printf("Creates 'signame' with the type of 'pinname' if it does not yet exist\n");
2820          printf("And then links signame to each pinname specified.\n");
2821      }else if (strcmp(command, "unlinkp") == 0) {
2822  	printf("unlinkp pinname\n");
2823  	printf("  Unlinks pin 'pinname' if it is linked to any signal.\n");
2824      } else if (strcmp(command, "lock") == 0) {
2825  	printf("lock [all|tune|none]\n");
2826  	printf("  Locks HAL to some degree.\n");
2827  	printf("  none - no locking done.\n");
2828  	printf("  tune - some tuning is possible (setp & such).\n");
2829  	printf("  all  - HAL completely locked.\n");
2830      } else if (strcmp(command, "unlock") == 0) {
2831  	printf("unlock [all|tune]\n");
2832  	printf("  Unlocks HAL to some degree.\n");
2833  	printf("  tune - some tuning is possible (setp & such).\n");
2834  	printf("  all  - HAL completely unlocked.\n");
2835      } else if (strcmp(command, "newsig") == 0) {
2836  	printf("newsig signame type\n");
2837  	printf("  Creates a new signal called 'signame'.  Type\n");
2838  	printf("  is 'bit', 'float', 'port', 'u32', or 's32'.\n");
2839      } else if (strcmp(command, "delsig") == 0) {
2840  	printf("delsig signame\n");
2841  	printf("  Deletes signal 'signame'.  If 'signame is 'all',\n");
2842  	printf("  deletes all signals\n");
2843      } else if (strcmp(command, "setp") == 0) {
2844  	printf("setp paramname value\n");
2845  	printf("setp pinname value\n");
2846  	printf("paramname = value\n");
2847  	printf("  Sets parameter 'paramname' to 'value' (if writable).\n");
2848  	printf("  Sets pin 'pinname' to 'value' (if an unconnected input).\n");
2849  	printf("  'setp' and '=' work the same, don't use '=' on the\n");
2850  	printf("  command line.  'value' may be a constant such as 1.234\n");
2851  	printf("  or TRUE, or a reference to an environment variable,\n");
2852  #ifdef NO_INI
2853  	printf("  using the syntax '$name'./n");
2854  #else
2855  	printf("  using the syntax '$name'.  If option -i was given,\n");
2856  	printf("  'value' may also be a reference to an ini file entry\n");
2857  	printf("  using the syntax '[section]name'.\n");
2858  #endif
2859      } else if (strcmp(command, "sets") == 0) {
2860  	printf("sets signame value\n");
2861  	printf("  Sets a non-port signal 'signame' to 'value' (if signal has no writers).\n");
2862      printf("  If 'signame' is a port signal (that has not previously been allocated),\n");
2863      printf("  then 'value' is the new maximum size in bytes of that port.\n");
2864      } else if (strcmp(command, "getp") == 0) {
2865  	printf("getp paramname\n");
2866  	printf("getp pinname\n");
2867  	printf("  Gets the value of parameter 'paramname' or pin 'pinname'.\n");
2868      } else if (strcmp(command, "ptype") == 0) {
2869  	printf("ptype paramname\n");
2870  	printf("ptype pinname\n");
2871  	printf("  Gets the type of parameter 'paramname' or pin 'pinname'.\n");
2872      } else if (strcmp(command, "gets") == 0) {
2873  	printf("gets signame\n");
2874  	printf("  Gets the value of signal 'signame'.\n");
2875      printf("  If signal 'signame' is a port, returns the buffer size of that port.\n");
2876      } else if (strcmp(command, "stype") == 0) {
2877  	printf("stype signame\n");
2878  	printf("  Gets the type of signal 'signame'\n");
2879      } else if (strcmp(command, "addf") == 0) {
2880  	printf("addf functname threadname [position]\n");
2881  	printf("  Adds function 'functname' to thread 'threadname'.  If\n");
2882  	printf("  'position' is specified, adds the function to that spot\n");
2883  	printf("  in the thread, otherwise adds it to the end.  Negative\n");
2884  	printf("  'position' means position with respect to the end of the\n");
2885  	printf("  thread.  For example '1' is start of thread, '-1' is the\n");
2886  	printf("  end of the thread, '-3' is third from the end.\n");
2887      } else if (strcmp(command, "delf") == 0) {
2888  	printf("delf functname threadname\n");
2889  	printf("  Removes function 'functname' from thread 'threadname'.\n");
2890      } else if (strcmp(command, "show") == 0) {
2891  	printf("show [type] [pattern]\n");
2892  	printf("  Prints info about HAL items of the specified type.\n");
2893  	printf("  'type' is 'comp', 'pin', 'sig', 'param', 'funct',\n");
2894  	printf("  'thread', or 'all'.  If 'type' is omitted, it assumes\n");
2895  	printf("  'all' with no pattern.  If 'pattern' is specified\n");
2896  	printf("  it prints only those items whose names match the\n");
2897  	printf("  pattern, which may be a 'shell glob'.\n");
2898      } else if (strcmp(command, "list") == 0) {
2899  	printf("list type [pattern]\n");
2900  	printf("  Prints the names of HAL items of the specified type.\n");
2901  	printf("  'type' is 'comp', 'pin', 'sig', 'param', 'funct', or\n");
2902  	printf("  'thread'.  If 'pattern' is specified it prints only\n");
2903  	printf("  those names that match the pattern, which may be a\n");
2904  	printf("  'shell glob'.\n");
2905  	printf("  For 'sig', 'pin' and 'param', the first pattern may be\n");
2906  	printf("  -tdatatype where datatype is the data type (e.g., 'float')\n");
2907  	printf("  in this case, the listed pins, signals, or parameters\n");
2908  	printf("  are restricted to the given data type\n");
2909  	printf("  Names are printed on a single line, space separated.\n");
2910      } else if (strcmp(command, "status") == 0) {
2911  	printf("status [type]\n");
2912  	printf("  Prints status info about HAL.\n");
2913  	printf("  'type' is 'lock', 'mem', or 'all'. \n");
2914  	printf("  If 'type' is omitted, it assumes\n");
2915  	printf("  'all'.\n");
2916      } else if (strcmp(command, "save") == 0) {
2917  	printf("save [type] [filename]\n");
2918  	printf("  Prints HAL state to 'filename' (or stdout), as a series\n");
2919  	printf("  of HAL commands.  State can later be restored by using\n");
2920  	printf("  \"halcmd -f filename\".\n");
2921  	printf("  Type can be 'comp', 'alias', 'sig[u]', 'signal', 'link[a]'\n");
2922          printf("  'net[a]', 'netl', 'netla', netal', 'param', 'parameter,\n");
2923  	printf("  'unconnectedinpins', 'all, 'allu', or 'thread'.\n");
2924          printf("  (A final 'a' character (like 'neta' means show arrows for pin direction.)\n");
2925          printf("  If 'type' is 'allu'), does the equivalent of:\n");
2926  	printf("  'comp', 'alias', 'sigu', 'netla', 'param', 'unconnectedinpins' and 'thread'.\n\n");
2927          printf("  If 'type' is omitted (or type is 'all'), does the equivalent of:\n");
2928  	printf("  'comp', 'alias', 'sigu', 'netla', 'param', and 'thread'.\n\n");
2929          printf("  See the man page ($man halcmd) for save option details\n");
2930      } else if (strcmp(command, "start") == 0) {
2931  	printf("start\n");
2932  	printf("  Starts all realtime threads.\n");
2933      } else if (strcmp(command, "stop") == 0) {
2934  	printf("stop\n");
2935  	printf("  Stops all realtime threads.\n");
2936      } else if (strcmp(command, "quit") == 0) {
2937  	printf("quit\n");
2938  	printf("  Stop processing input and terminate halcmd (when\n");
2939  	printf("  reading from a file or stdin).\n");
2940      } else if (strcmp(command, "exit") == 0) {
2941  	printf("exit\n");
2942  	printf("  Stop processing input and terminate halcmd (when\n");
2943  	printf("  reading from a file or stdin).\n");
2944      } else if (strcmp(command, "alias") == 0) {
2945          printf("alias type name alias\n");
2946          printf("  Assigns \"alias\" as a second name for the pin or parameter\n");
2947          printf("  \"name\".  For most operations, an alias provides a second\n");
2948          printf("  name that can be used to refer to a pin or parameter, both the\n");
2949          printf("  original name and the alias will work.\n");
2950          printf("  \"type\" must be pin or param\n");
2951          printf("  \"name\" must be an existing name or alias of the specified type.\n");
2952      } else if (strcmp(command, "unalias") == 0) {
2953          printf("unalias type name\n");
2954          printf("  Removes any alias from the pin or parameter \"name\".\n");
2955          printf("  \"type\" must be pin or param\n");
2956          printf("  \"name\" must be an existing name or alias of the specified type.\n");
2957      } else if (strcmp(command, "echo") == 0) {
2958          printf("echo\n");
2959          printf("echo the commands from stdin to stderr\n");
2960          printf("Useful for debugging scripted commands from a running program\n");
2961      } else if (strcmp(command, "unecho") == 0) {
2962          printf("unecho\n");
2963          printf("Turn off echo of commands from stdin to stdout\n");
2964  
2965      } else {
2966  	printf("No help for unknown command '%s'\n", command);
2967      }
2968      return 0;
2969  }
2970  
2971  
2972  static void print_help_commands(void)
2973  {
2974      printf("Use 'help <command>' for more details about each command\n");
2975      printf("Available commands:\n");
2976      printf("  loadrt              Load realtime module(s)\n");
2977      printf("  loadusr             Start user space program\n");
2978      printf("  waitusr             Waits for userspace component to exit\n");
2979      printf("  unload              Unload realtime module or terminate userspace component\n");
2980      printf("  lock, unlock        Lock/unlock HAL behaviour\n");
2981      printf("  linkps              Link pin to signal\n");
2982      printf("  linksp              Link signal to pin\n");
2983      printf("  net                 Link a number of pins to a signal\n");
2984      printf("  unlinkp             Unlink pin\n");
2985      printf("  newsig, delsig      Create/delete a signal\n");
2986      printf("  getp, gets          Get the value of a pin, parameter or signal\n");
2987      printf("  ptype, stype        Get the type of a pin, parameter or signal\n");
2988      printf("  setp, sets          Set the value of a pin, parameter or signal\n");
2989      printf("  addf, delf          Add/remove function to/from a thread\n");
2990      printf("  show                Display info about HAL objects\n");
2991      printf("  list                Display names of HAL objects\n");
2992      printf("  source              Execute commands from another .hal file\n");
2993      printf("  status              Display status information\n");
2994      printf("  save                Print config as commands\n");
2995      printf("  start, stop         Start/stop realtime threads\n");
2996      printf("  alias, unalias      Add or remove pin or parameter name aliases\n");
2997      printf("  echo, unecho        Echo commands from stdin to stderr\n");
2998      printf("  quit, exit          Exit from halcmd\n");
2999  }