// constructor - init all HAL pins, params, funct etc here static int instantiate(const char *name, const int argc, const char**argv) { struct inst_data *ip; // allocate a named instance, and some HAL memory for the instance data int inst_id = hal_inst_create(name, comp_id, sizeof(struct inst_data), (void **)&ip); if (inst_id < 0) return -1; // here ip is guaranteed to point to a blob of HAL memory of size sizeof(struct inst_data). HALERR("inst=%s argc=%d\n", name, argc); HALERR("instance parms: repeat=%d prefix='%s'", repeat, prefix); HALERR("module parms: answer=%d text='%s'", answer, text); // these pins/params/functs will be owned by the instance, and can be separately exited int retval = export_halobjs(ip, inst_id, name); // unittest: echo instance parameters into observer pins if (!retval) { *(ip->repeat_value) = repeat; *(ip->prefix_len) = strlen(prefix); } return retval; }
static int instantiate_lutn(const char *name, const int argc, const char**argv) { struct inst_data *ip; int i, inst_id; if ((inputs < 1) || (inputs > 5)) { hal_print_msg(RTAPI_MSG_ERR, "%s: invalid parameter inputs=%d, valid range=1..5", name, inputs); return -1; } if ((function == 0) || (function == -1)) { hal_print_msg(RTAPI_MSG_ERR, "%s: function=0x%x does not make sense", name, function); return -1; } if ((inst_id = hal_inst_create(name, comp_id, sizeof(struct inst_data) + inputs * sizeof(hal_bit_t *), (void **)&ip)) < 0) return -1; hal_print_msg(RTAPI_MSG_DBG, "%s: name='%s' inputs=%d function=0x%x ip=%p", __FUNCTION__, name, inputs, function, ip); // record instance params ip->inputs = inputs; ip->function = function; // export per-instance HAL objects for (i = 0; i < ip->inputs; i++) if (hal_pin_bit_newf(HAL_IN, &(ip->in[i]), inst_id, "%s.in%d", name, i)) return -1; if (hal_pin_bit_newf(HAL_OUT, &(ip->out), inst_id, "%s.out", name)) return -1; if (hal_export_functf(lutn, ip, 0, 0, inst_id, "%s.funct", name)) return -1; return 0; }
// init HAL objects static int export_halobjs(struct inst_data *ip, int owner_id, const char *name) { if (rring) { // if given, the ring MUST be a stream type plug_args_t rargs = { .type = PLUG_READER, .flags = RINGTYPE_STREAM, .ring_name = rring, .owner_name = name }; ip->rplug = halg_plug_new(1, &rargs); if (ip->rplug == NULL) return _halerrno; } if (wring) { // this plug accepts any ring type plug_args_t wargs = { .type = PLUG_WRITER, .flags = RINGTYPE_ANY, .ring_name = wring, .owner_name = name }; ip->wplug = halg_plug_new(1, &wargs); if (ip->wplug == NULL) return _halerrno; } // exporting '<instname>.funct' as an extended thread function // see lutn.c for a discussion of advantages hal_export_xfunct_args_t xfunct_args = { .type = FS_XTHREADFUNC, .funct.x = funct, .arg = ip, // the instance's HAL memory blob .uses_fp = 1, .reentrant = 0, .owner_id = owner_id }; return hal_export_xfunctf(&xfunct_args, "%s.funct", name); } // constructor - init all HAL pins, params, funct etc here static int instantiate(const int argc, const char**argv) { // argv[0]: component name const char *name = argv[1]; // instance name struct inst_data *ip; // allocate a named instance, and some HAL memory for the instance data int inst_id = hal_inst_create(name, comp_id, sizeof(struct inst_data), (void **)&ip); if (inst_id < 0) return -1; // here ip is guaranteed to point to a blob of HAL memory // of size sizeof(struct inst_data). HALDBG("inst=%s argc=%d\n", name, argc); HALDBG("instance parms: rring=%s wring=%s", rring, wring); // these pins/params/functs will be owned by the instance, // and can be separately exited 'halcmd delinst <instancename>' int retval = export_halobjs(ip, inst_id, name); return retval; } // custom destructor // pins, params, and functs are automatically deallocated by hal_exit(comp_id) // regardless if a destructor is used or not (see below), so usually it is not // needed // // however, some objects like vtables, rings, threads, signals are not owned by // a component, hence cannot be automatically exited by hal_exit() even if desired // // interaction with such objects may require a custom destructor like below for // cleanup actions // NB: if a customer destructor is used, it is called // - after the instance's functs have been removed from their respective threads // (so a thread funct call cannot interact with the destructor any more) // - any pins, params and plugs of this instance are still intact when the destructor is // called, and they are automatically destroyed by the HAL library once the // destructor returns static int delete(const char *name, void *inst, const int inst_size) { HALDBG("inst=%s size=%d %p\n", name, inst_size, inst); return 0; } int rtapi_app_main(void) { comp_id = hal_xinit(TYPE_RT, 0, 0, instantiate, delete, compname); if (comp_id < 0) return comp_id; hal_ready(comp_id); return 0; }
int rtapi_app_main(void) { int retval; dlist_init_entry(&head); if ((comp_id = hal_xinit(TYPE_RT, 0, 0, instantiate_encoder_pair, delete_encoder_pair, compname)) < 0) return comp_id; hal_export_xfunct_args_t u = { .type = FS_XTHREADFUNC, .funct.x = update, .arg = &head, .uses_fp = 1, .reentrant = 0, .owner_id = comp_id }; if ((retval = hal_export_xfunctf(&u, "%s.update", prefix)) < 0) return retval; hal_export_xfunct_args_t mp = { .type = FS_XTHREADFUNC, .funct.x = sample, .arg = &head, .uses_fp = 0, .reentrant = 0, .owner_id = comp_id }; if ((retval = hal_export_xfunctf(&mp, "%s.sample", prefix)) < 0) return retval; hal_ready(comp_id); return 0; } void rtapi_app_exit(void) { hal_exit(comp_id); } static int instantiate_encoder_pair(const int argc, const char**argv) { encoder_pair_t *p; int retval; int msg; const char* name; if(argc >= 2) name = argv[1]; else HALFAIL_RC(EINVAL, "ERROR: insufficient args in argv"); /* This function exports a lot of stuff, which results in a lot of logging if msg_level is at INFO or ALL. So we save the current value of msg_level and restore it later. */ msg = rtapi_get_msg_level(); #ifndef VERBOSE_SETUP rtapi_set_msg_level(RTAPI_MSG_WARN); #endif if ((retval = hal_inst_create(name, comp_id, sizeof(encoder_pair_t), (void **)&p)) < 0) return retval; p->inst_id = retval; if ((retval = export_encoder_pair(name, p->inst_id, p)) != 0) HALFAIL_RC(retval, "%s: ERROR: export(%s) failed", compname, name); // append to instance list dlist_init_entry(&p->list); dlist_add_after(&p->list, &head); /* restore saved message level */ rtapi_set_msg_level(msg); return 0; }
static int instantiate_interpolate(const int argc, const char **argv) { const char *name = argv[1]; struct inst_data *ip; int inst_id, i; if ((inst_id = hal_inst_create(name, comp_id, sizeof(struct inst_data) + count * sizeof(struct joint), (void **)&ip)) < 0) return -1; // instance-level values ip->count = count; // attach the command ringbuffer '<instancename>.traj' if it exists // must be record mode unsigned flags; if (!hal_ring_attachf(&(ip->traj), &flags, "%s.traj", name)) { if ((flags & RINGTYPE_MASK) != RINGTYPE_RECORD) { HALERR("ring %s.traj not a record mode ring: mode=%d",name, flags & RINGTYPE_MASK); return -EINVAL; } ip->traj.header->reader = inst_id; // we're the reader - advisory } else { HALERR("ring %s.traj does not exist", name); return -EINVAL; } // per-instance objects if (hal_pin_s32_newf(HAL_OUT, &(ip->serial), inst_id, "%s.serial", name) || hal_pin_u32_newf(HAL_IN, &(ip->degree), inst_id, "%s.degree", name) || hal_pin_bit_newf(HAL_IN, &(ip->jitter_correct), inst_id, "%s.jitter-correct", name) || hal_pin_float_newf(HAL_IN, &(ip->epsilon), inst_id, "%s.epsilon", name) || hal_pin_float_newf(HAL_OUT, &(ip->duration), inst_id, "%s.duration", name) || hal_pin_float_newf(HAL_OUT, &(ip->progress), inst_id, "%s.progress", name)) return -1; *(ip->serial) = 0; *(ip->degree) = 1; *(ip->jitter_correct) = 0; *(ip->epsilon) = 0; *(ip->duration) = 0; *(ip->progress) = 0; ip->time_from_start = 0; // per-joint objects for (i = 0; i < ip->count; i++) { struct joint *jp = &ip->joints[i]; if (hal_pin_float_newf(HAL_OUT, &(jp->end_pos), inst_id, "%s.%d.end-pos", name, i) || hal_pin_float_newf(HAL_OUT, &(jp->end_vel), inst_id, "%s.%d.end-vel", name, i) || hal_pin_float_newf(HAL_OUT, &(jp->end_acc), inst_id, "%s.%d.end-acc", name, i) || hal_pin_float_newf(HAL_OUT, &(jp->curr_pos), inst_id, "%s.%d.curr-pos", name, i) || hal_pin_float_newf(HAL_OUT, &(jp->curr_vel), inst_id, "%s.%d.curr-vel", name, i) || hal_pin_float_newf(HAL_OUT, &(jp->curr_acc), inst_id, "%s.%d.curr-acc", name, i) || hal_pin_bit_newf(HAL_OUT, &(jp->traj_busy), inst_id, "%s.%d.traj-busy", name, i)) return -1; // set all pin values to zero *(jp->end_pos) = 0; *(jp->end_vel) = 0; *(jp->end_acc) = 0; *(jp->curr_pos) = 0; *(jp->curr_vel) = 0; *(jp->curr_acc) = 0; *(jp->traj_busy) = false; } hal_export_xfunct_args_t xfunct_args = { .type = FS_XTHREADFUNC, .funct.x = update, .arg = ip, .uses_fp = 0, .reentrant = 0, .owner_id = inst_id }; return hal_export_xfunctf(&xfunct_args, "%s.update", name); } static int delete_interpolate(const char *name, void *inst, const int inst_size) { struct inst_data *ip = (struct inst_data *) inst; int retval; if (ringbuffer_attached(&ip->traj)) { if ((retval = hal_ring_detach(&ip->traj)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "%s: hal_ring_detach(%s.traj) failed: %d\n", compname, name, retval); return retval; } ip->traj.header->reader = 0; } return 0; } int rtapi_app_main(void) { comp_id = hal_xinit(TYPE_RT, 0, 0, (hal_constructor_t)instantiate_interpolate, delete_interpolate, compname); if (comp_id < 0) return comp_id; hal_ready(comp_id); return 0; }
// init HAL objects static int export_halobjs(struct inst_data *ip, int owner_id, const char *name) { if (hal_pin_float_newf(HAL_OUT, &ip->out, owner_id, "%s.out", name)) return -1; if (hal_pin_float_newf(HAL_IN, &ip->in, owner_id, "%s.in", name)) return -1; if (hal_param_s32_newf(HAL_RO, &ip->iter,owner_id, "%s.iter", name)) return -1; // unittest observer pins, per instance if (hal_pin_s32_newf(HAL_OUT, &ip->repeat_value, owner_id, "%s.repeat_value", name)) return -1; if (hal_pin_s32_newf(HAL_OUT, &ip->prefix_len, owner_id, "%s.prefix_len", name)) return -1; // exporting '<instname>.funct' as an extended thread function // see lutn.c for a discussion of advantages hal_export_xfunct_args_t xfunct_args = { .type = FS_XTHREADFUNC, .funct.x = funct, .arg = ip, // the instance's HAL memory blob .uses_fp = 1, .reentrant = 0, .owner_id = owner_id }; return hal_export_xfunctf(&xfunct_args, "%s.funct", name); } // constructor - init all HAL pins, params, funct etc here static int instantiate(const int argc, const char**argv) { // argv[0]: component name const char *name = argv[1]; // instance name struct inst_data *ip; // allocate a named instance, and some HAL memory for the instance data int inst_id = hal_inst_create(name, comp_id, sizeof(struct inst_data), (void **)&ip); if (inst_id < 0) return -1; // here ip is guaranteed to point to a blob of HAL memory // of size sizeof(struct inst_data). HALINFO("inst=%s argc=%d\n", name, argc); HALINFO("instance parms: repeat=%d prefix='%s'", repeat, prefix); HALINFO("module parms: answer=%d text='%s'", answer, text); // example - parse newinst arguments getopt-style: // straight from: http://www.informit.com/articles/article.aspx?p=175771&seqNum=3 int do_all, do_help, do_verbose; /* flag variables */ char *myfile; struct option longopts[] = { { "all", no_argument, & do_all, 1 }, { "file", required_argument, NULL, 'f' }, { "help", no_argument, & do_help, 1 }, { "verbose", no_argument, & do_verbose, 1 }, { 0, 0, 0, 0 } }; int c; while ((c = getopt_long(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'f': myfile = optarg; break; case 0: // getopt_long() set a variable, just keep going break; case ':': // missing option argument HALERR("%s: option `-%c' requires an argument\n", argv[1], optopt); break; case '?': default: // invalid option HALERR("%s: option `-%c' is invalid, ignored", argv[1], optopt); break; } } HALINFO("do_all=%d do_help=%d do_verbose=%d myfile=%s", do_all, do_help, do_verbose, myfile); // these pins/params/functs will be owned by the instance, // and can be separately exited via 'halcmd delinst <instancename>' int retval = export_halobjs(ip, inst_id, name); // unittest: echo instance parameters into observer pins if (!retval) { *(ip->repeat_value) = repeat; *(ip->prefix_len) = strlen(prefix); } return retval; } // custom destructor // pins, params, and functs are automatically deallocated by hal_exit(comp_id) // regardless if a destructor is used or not (see below), so usually it is not // needed // // however, some objects like vtables, rings, threads, signals are not owned by // a component, hence cannot be automatically exited by hal_exit() even if desired // // interaction with such objects may require a custom destructor like below for // cleanup actions // NB: if a customer destructor is used, it is called // - after the instance's functs have been removed from their respective threads // (so a thread funct call cannot interact with the destructor any more) // - any pins and params of this instance are still intact when the destructor is // called, and they are automatically destroyed by the HAL library once the // destructor returns static int delete(const char *name, void *inst, const int inst_size) { HALERR("inst=%s size=%d %p\n", name, inst_size, inst); HALERR("instance parms: repeat=%d prefix='%s'", repeat, prefix); HALERR("module parms: answer=%d text='%s'", answer, text); return 0; } int rtapi_app_main(void) { HALERR("instance parms: repeat=%d prefix='%s'", repeat, prefix); HALERR("module parms: answer=%d text='%s'", answer, text); // to use default destructor, use NULL instead of delete comp_id = hal_xinit(TYPE_RT, 0, 0, instantiate, delete, compname); if (comp_id < 0) return comp_id; #if 0 // this is how an 'instance' would have been done in the legacy way struct inst_data *ip = hal_malloc(sizeof(struct inst_data)); // these pins/params/functs will be owned by the component // NB: this 'instance' cannot be exited, and no new one created on the fly if (export_halobjs(ip, comp_id, "foo")) return -1; #endif // unittest only, see nosetests/unittest_instbindings.py and // nosetests/unittest_icomp.py // purpose: echo module params into observer pins // (cant set pins to strings, so just echo the string length) if ((cd = export_observer_pins(comp_id, compname)) == NULL) return -1; *(cd->answer_value) = answer; *(cd->text_len) = strlen(text); hal_ready(comp_id); return 0; }