loadusr command with multiple instance

More
23 Feb 2015 22:31 #56239 by mdurna
Dear all,

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.

More
23 Feb 2015 23:18 - 23 Feb 2015 23:24 #56242 by dgarrett
With a recent linuxCNC version (i tested with recent 2.7), you can try the following
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
Last edit: 23 Feb 2015 23:24 by dgarrett.
The following user(s) said Thank You: mdurna

Please Log in or Create an account to join the conversation.

More
24 Feb 2015 00:44 - 24 Feb 2015 01:09 #56245 by ArcEye
Hi

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

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.
Last edit: 24 Feb 2015 01:09 by ArcEye.
The following user(s) said Thank You: mdurna, Fuzzy_Mind

Please Log in or Create an account to join the conversation.

More
24 Feb 2015 01:16 #56246 by ArcEye

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: 
The following user(s) said Thank You: mdurna, Fuzzy_Mind

Please Log in or Create an account to join the conversation.

More
24 Feb 2015 01:24 - 24 Feb 2015 02:35 #56247 by ArcEye
ArcEye wrote:

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,

undefined reference to 'get_count'

so no use there, may be a rt only option or may just be that you have to provide the function yourself.

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+
Last edit: 24 Feb 2015 02:35 by ArcEye.
The following user(s) said Thank You: mdurna

Please Log in or Create an account to join the conversation.

More
02 Mar 2015 15:11 #56394 by Fuzzy_Mind
Hi

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.

More
02 Mar 2015 17:21 - 02 Mar 2015 17:23 #56396 by ArcEye

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
Last edit: 02 Mar 2015 17:23 by ArcEye.
The following user(s) said Thank You: Fuzzy_Mind

Please Log in or Create an account to join the conversation.

More
02 Mar 2015 17:41 #56398 by Fuzzy_Mind
I finally solved this stupid problem :cheer: . My solution is easy but it works.

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
Attachments:

Please Log in or Create an account to join the conversation.

Time to create page: 0.102 seconds
Powered by Kunena Forum