loadusr command with multiple instance
We have checked all the manual pages and the forum pages as much as we can do and could not find any answer to our following problem. Apologies for any possible repetitive question.
The problem is:
Is there any method to create multiple instances of a userspace component just like the way we do for a realtime component using count keyword.
Explicitly defining the situation: the command "loadusr HALusrcomp count=3" does not yield three HAL components namely HALusrcomp.0, HALusrcomp.1, HALusrcomp.2 which we can do it for real time components using loadrt HALrtcomp count=3 for example.
We would be very glad if someone could give a link for the detailed usage for loadusr.
Best regards,
Mehmet DURNA
Please Log in or Create an account to join the conversation.
inifile addition:
[HAL]
...
HALFILE = nloadusr.tcl progname count
newfile named nloadusr.tcl (place in the ini directory)
# ini file usage: [HAL] nloadusr.tcl progname ct
# note: loadusr_options hardcoded herin
# note: progargs not supported
set loadusr_options "-w"
set this nloadusr.tcl
if {[llength $::argv] != 2} {
puts "\n$this Failed for args=$::argv"
puts "$this Usage:"
puts " \[HAL\]"
puts " HALFILE = $this progname count"
exit 1
} else {
set prog [lindex $::argv 0]
set ct [lindex $::argv 1]
}
for {set i 0} {$i < $ct} {incr i} {
set cmd "loadusr $loadusr_options $prog"
puts "$this i=$i cmd=$cmd"
eval $cmd
}
# ref for loadusr_options:
# $ halrun
# halcmd; help loadusr
# loadusr [options] progname [progarg(s)]
# Starts user space program 'progname', passing
# 'progargs' to it. Options are:
# -W wait for HAL component to become ready
# -Wn name to wait for the component, which will have the given name.
# -w wait for program to finish
# -i ignore program return value (use with -w)
#
modify to suit forloadusr_options
Please Log in or Create an account to join the conversation.
The real problem is with comp / halcompile
This is a simple test component taken from the docs
component test;
option userspace;
pin out float out;
license "GPL"; // indicates GPL v2 or later
;;
#include <unistd.h>
void user_mainloop(void) {
while(1) {
usleep(1000);
FOR_ALL_INSTS() out = drand48();
}
}
The .c code it produces is
/* Autogenerated by /usr/src/linuxcnc-dev-2.7/bin/halcompile on Mon Feb 23 16:25:09 2015 -- do not edit */
#include "rtapi.h"
#ifdef RTAPI
#include "rtapi_app.h"
#endif
#include "rtapi_string.h"
#include "rtapi_errno.h"
#include "hal.h"
static int comp_id;
#ifdef MODULE_INFO
MODULE_INFO(linuxcnc, "component:test:");
MODULE_INFO(linuxcnc, "pin:out:float:0:out::None:None");
MODULE_INFO(linuxcnc, "license:GPL");
MODULE_LICENSE("GPL");
#endif // MODULE_INFO
struct __comp_state {
struct __comp_state *_next;
hal_float_t *out;
};
#include <stdlib.h>
struct __comp_state *__comp_first_inst=0, *__comp_last_inst=0;
static int __comp_get_data_size(void);
#undef TRUE
#define TRUE (1)
#undef FALSE
#define FALSE (0)
#undef true
#define true (1)
#undef false
#define false (0)
static int export(char *prefix, long extra_arg) {
int r = 0;
int sz = sizeof(struct __comp_state) + __comp_get_data_size();
struct __comp_state *inst = hal_malloc(sz);
memset(inst, 0, sz);
r = hal_pin_float_newf(HAL_OUT, &(inst->out), comp_id,
"%s.out", prefix);
if(r != 0) return r;
if(__comp_last_inst) __comp_last_inst->_next = inst;
__comp_last_inst = inst;
if(!__comp_first_inst) __comp_first_inst = inst;
return 0;
}
static int default_count=1, count=0;
char *names[16] = {0,};
int rtapi_app_main(void) {
int r = 0;
int i;
comp_id = hal_init("test");
if(comp_id < 0) return comp_id;
if(count && names[0]) {
rtapi_print_msg(RTAPI_MSG_ERR,"count= and names= are mutually exclusive\n");
return -EINVAL;
}
if(!count && !names[0]) count = default_count;
if(count) {
for(i=0; i<count; i++) {
char buf[HAL_NAME_LEN + 1];
rtapi_snprintf(buf, sizeof(buf), "test.%d", i);
r = export(buf, i);
if(r != 0) break;
}
} else {
for(i=0; names[i]; i++) {
r = export(names[i], i);
if(r != 0) break;
}
}
if(r) {
hal_exit(comp_id);
} else {
hal_ready(comp_id);
}
return r;
}
void rtapi_app_exit(void) {
hal_exit(comp_id);
}
static void user_mainloop(void);
int argc=0; char **argv=0;
int main(int argc_, char **argv_) {
argc = argc_; argv = argv_;
if(rtapi_app_main() < 0) return 1;
user_mainloop();
rtapi_app_exit();
return 0;
}
#undef FUNCTION
#define FUNCTION(name) static void name(struct __comp_state *__comp_inst, long period)
#undef EXTRA_SETUP
#define EXTRA_SETUP() static int extra_setup(struct __comp_state *__comp_inst, char *prefix, long extra_arg)
#undef EXTRA_CLEANUP
#define EXTRA_CLEANUP() static void extra_cleanup(void)
#undef fperiod
#define fperiod (period * 1e-9)
#undef out
#define out (*__comp_inst->out)
#undef FOR_ALL_INSTS
#define FOR_ALL_INSTS() struct __comp_state *__comp_inst; for(__comp_inst = __comp_first_inst; __comp_inst; __comp_inst = __comp_inst->_next)
#line 7 "test.comp"
#include <unistd.h>
void user_mainloop(void) {
while(1) {
usleep(1000);
FOR_ALL_INSTS() out = drand48();
}
}
static int __comp_get_data_size(void) { return 0; }
Now look at rtapi_app_main(void)
This checks the values in count and names, and contains code to create numerous instances, but since these are not set anywhere from the commandline args, they will always default to a count of 1.
In a rt component, halcompile would insert the rt macros to get the args
if not options.get("userspace"):
print >>f, "RTAPI_MP_INT(count, \"number of %s\");" % comp_name
print >>f, "RTAPI_MP_ARRAY_STRING(names, 16, \"names of %s\");" % comp_name
A way to get these values is to define void userinit(int argc, char **argv) in your comp file
You can then get the args and change the values of count and names accordingly.
userinit is mentioned here, albeit briefly
www.linuxcnc.org/docs/devel/html/hal/comp.html#_options
I get the feeling that not many people write userspace components using comp / halcompile ( I certainly don't now)
There was another howler a while back, where the values of argv and argc were not being copied over properly, but no-one had ever noticed
regards
PS
Another way around is use a little known option
option default_count number - (default: 1) Normally, the module parameter count defaults to 1. If specified, the count will default to this value instead.
This will give a default number of instances.
There is another option
and I don't even know what this will do! Some experimenting coming up.option count_function yes - (default: no) Normally, the number of instances to create is specified in the module parameter count; if count_function is specified, the value returned by the function int get_count(void) is used instead, and the count module parameter is not defined.
Please Log in or Create an account to join the conversation.
Another way around is use a little known option
option default_count number - (default: 1) Normally, the module parameter count defaults to 1. If specified, the count will default to this value instead.
This will give a default number of instances.
And indeed it does, this modified test.comp
component test;
option userspace;
option default_count 3;
pin out float out;
license "GPL"; // indicates GPL v2 or later
;;
#include <unistd.h>
void user_mainloop(void) {
while(1) {
usleep(1000);
FOR_ALL_INSTS() out = drand48();
}
}
Gives this result
@INTEL-i7:/prog/EMC/Userspace_modules# halrun
halcmd: loadusr test
halcmd: show all
Loaded HAL Components:
ID Type Name PID State
6 User test 14662 ready
4 User halcmd14661 14661 ready
Component Pins:
Owner Type Dir Value Name
6 float OUT 0.8880438 test.0.out
6 float OUT 0.9029078 test.1.out
6 float OUT 0.6864016 test.2.out
Pin Aliases:
Alias Original Name
Signals:
Type Value Name (linked to)
Parameters:
Owner Type Dir Value Name
Parameter Aliases:
Alias Original Name
Exported Functions:
Owner CodeAddr Arg FP Users Name
Realtime Threads:
Period FP Name ( Time, Max-Time )
halcmd:
Please Log in or Create an account to join the conversation.
There is another option
option count_function yes - (default: no) Normally, the number of instances to create is specified in the module parameter count; if count_function is specified, the value returned by the function int get_count(void) is used instead, and the count module parameter is not defined.
and I don't even know what this will do! Some experimenting coming up.
Using the
option count_function yes;
line in a userspace component just gets an error at compilation,
so no use there, may be a rt only option or may just be that you have to provide the function yourself.undefined reference to 'get_count'
If you want proper control via commandline opts, you are going to have to implement as outlined yourself.
If you just want to be able to have a fixed number of instances, the option default_count N; works perfectly well.
regards+
Please Log in or Create an account to join the conversation.
- Fuzzy_Mind
- Offline
- New Member
- Posts: 6
- Thank you received: 0
Thanks for your replies but I'm new on linuxcnc and I couldn't figure out.
Here is my code:
component leuze;
option userspace;
option extra_link_args "-L. -lftd2xx";
param rw float portid = 0;
pin out float out;
license "GPL"; // indicates GPL v2 or later
;;
#include <ftd2xx.h>
#include <stdio.h>
FT_STATUS ftStatus;
FT_HANDLE ftHandle;
DWORD EventDWord;
DWORD RxBytes=10;
DWORD TxBytes;
DWORD BytesReceived;
char RxBuffer[256];
int int_data;
int gelen_data[5];
int counter=0;
int buffer_size;
float result;
void user_mainloop(void) {
ftStatus = FT_Open(0, &ftHandle);
if (ftStatus == FT_OK)
{
printf("Port Open Successful \n");
FT_SetBaudRate(ftHandle, 9600);
while(1)
{
FT_GetStatus(ftHandle, &RxBytes, &TxBytes, &EventDWord);
if(RxBytes>0)
{
FT_Read(ftHandle, RxBuffer, RxBytes, &BytesReceived);
int_data=RxBuffer[0]-48;
if (int_data<0)
{
counter=0;
}
else
{
gelen_data[counter]=RxBuffer[0]-48;
counter+=1;
if(counter==5)
{
result = gelen_data[0]*100+
gelen_data[1]*10+
gelen_data[2]*1+
gelen_data[3]*0.1+
gelen_data[4]*0.01;
FOR_ALL_INSTS() out=result;
counter=0;
}
}
}
}
}
else
{
FOR_ALL_INSTS() out = 0;
printf("Port Open Failed \n");
}
}
How can i use userinit ? hal component generator documentation not so clear for me.
Note: I don't have an ini file. I have only three files ( .hal file , glade file and .py file )
Please Log in or Create an account to join the conversation.
How can i use userinit ? hal component generator documentation not so clear for me.
www.linuxcnc.org/docs/devel/html/hal/comp.html#_options
[b]option userinit yes[/b] - (default: no) This option is ignored if the option userspace (see above) is set to no. If userinit is specified, the function userinit(argc,argv) is called before rtapi_app_main() (and thus before the call to hal_init() ). This function may process the commandline arguments or take other actions. Its return type is void; it may call exit() if it wishes to terminate rather than create a HAL component (for instance, because the commandline arguments were invalid).
It means you create a function called userinit.
It will be called first.
void userinit(int argc, char **argv)
{
// do stuff you need to initialise, eg get commandline args
}
Here is my code:
......
FOR_ALL_INSTS() out=result;
The rand example of a userspace component which you have copied, is a very bad one because it is so simplistic that all is does is assign a value to out.
All your code to be run in a loop which is run on each instance of a component, should be inside it.
A completely unrelated example from one of my components
void user_mainloop(void)
{
char line[32 * PARAM_LEN];
char filepath[80];
float val1;
int read, write;
int x = 0;
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
sprintf(filepath, "%s/linuxcnc/param.sav", homedir);
read = write = 0;
signal(SIGINT, adios);
signal(SIGTERM, adios);
while(!done)
{
usleep(250000);
FOR_ALL_INSTS()
{
if(!readtrigger && read) read = 0;
if(!writetrigger && write) write = 0;
if(readtrigger && !read)
// reads the file and sets the out pins to the values read
// connect to the spinbox param-pin which will update the widget display
{
FILE *fp1;
fp1 = fopen(filepath, "r");
x = 0;
while(!feof(fp1) && x < ARRAY_LEN)
{
fgets(line, sizeof(line), fp1);
if(sscanf(line, "%f", &val1) == 1)
*(inst->outvalue[x]) = val1;
x++;
}
fclose(fp1);
read = 1;
}
else if(writetrigger && ! write)
// reads the values from the in pins and write to file
// connect to the spinbox out pin
{
FILE *fp2;
fp2 = fopen(filepath, "w");
for(x = 0; x < ARRAY_LEN; x++)
fprintf(fp2, "%f\n", *(inst->invalue[x]));
fflush(fp2);
fclose(fp2);
write = 1;
}
}
}
exit(0);
}
Hope it becomes clearer
regards
Please Log in or Create an account to join the conversation.
- Fuzzy_Mind
- Offline
- New Member
- Posts: 6
- Thank you received: 0
Here is my solution:
component leuzex;
option userspace;
option userinit yes;
option count_function yes;
option extra_link_args "-L. -lftd2xx";
param rw float portid = 0;
pin out float out;
license "GPL"; // indicates GPL v2 or later
;;
#include <ftd2xx.h>
#include <stdio.h>
FT_STATUS ftStatus;
FT_HANDLE ftHandle;
DWORD EventDWord;
DWORD RxBytes=10;
DWORD TxBytes;
DWORD BytesReceived;
char RxBuffer[256];
int int_data;
int gelen_data[5];
int counter=0;
int buffer_size;
int count;
float result;
void userinit(int argc, char* argv[])
{
if (argc<2)
{
count=1;
printf("\nno argument \n");
}
else
{
count=*argv[1]-48;
printf("\nargument: %d \n", count);
}
}
int get_count(void)
{
return count;
}
void user_mainloop(void) {
ftStatus = FT_Open(0, &ftHandle);
if (ftStatus == FT_OK)
{
printf("Port Open Successful \n");
FT_SetBaudRate(ftHandle, 9600);
while(1)
{
FT_GetStatus(ftHandle, &RxBytes, &TxBytes, &EventDWord);
if(RxBytes>0)
{
FT_Read(ftHandle, RxBuffer, RxBytes, &BytesReceived);
int_data=RxBuffer[0]-48;
if (int_data<0)
{
counter=0;
}
else
{
gelen_data[counter]=RxBuffer[0]-48;
counter+=1;
if(counter==5)
{
result = gelen_data[0]*100+
gelen_data[1]*10+
gelen_data[2]*1+
gelen_data[3]*0.1+
gelen_data[4]*0.01;
FOR_ALL_INSTS() out=result;
counter=0;
}
}
}
}
}
else
{
FOR_ALL_INSTS() out = 0;
printf("Port Open Failed \n");
}
}
Thanks for your helps
Best Regards
Please Log in or Create an account to join the conversation.