I'm checking with the group on how folks have done this in the past in case I 
am missing something. Also proposing how I would solve the problem looking for 
feedback.

I have a module that you may want to instantiate more than once (create two or 
more objects). For example suppose I have a device driver that may instantiate 
multiple times but with different context.

I’m trying to determine how I will provide shell commands for them. I have a 
few options.

  1.  use the first argument of the shell command as the object instance and 
queue the object onto some list that I can search in the command to execute the 
command on the right object
  2.  Try to modify the the shell command to include a void * somewhere in the 
registration and have the shell commands pass it back during execution.
  3.  Have the callback return the module name string which I can cast back or 
search for combining the flexibility of #1 and #2

In the first option I would queue my instance objects on a queue and then 
search for them by name or number

  *   foo 0 reset
  *   foo 1 reset

When there is only once instance (most typical) then the command has the burden 
of carrying the extra notation or I have to provide provisional processing to 
do some default behavior when the number is left out of the command. For this 
functionality I need to queue the objects which is not currently necessary (its 
only a few bytes for an SLIST).

In the second choice I could have the following changes to shell

  *   include a void * in  the shell_register that is passed in the callback 
like
     *   typedef int (*shell_cmd_func_t)(int argc, char *argv[], void *arg);

  *   int shell_register(const char *shell_name,  const struct shell_cmd 
*shell_commands, void *arg)

     *   shell_register(“sample_object0", cmd, (void*) &obj0)

     *   shell_register(“sample_object1", cmd, (void*) &obj1)
  *   Modify the internal definition of the shell module to have
     *   struct shell_module {
     *       const char *name;
     *       const struct shell_cmd *commands;
     *       void *arg;
     *   };

In this method the commands would look like this

  *   foo0 reset
  *   foo1 reset

Of course, the first instance of this could also just be called foo and then 
the latter could have numbers

  *   Foo reset
  *   foo1 reset
  *   foo2 reset

NOTE: because of mempools, logs and stats I already keep a char *name in the 
object to differentiate each instance (e.g. foo0 foo1 etc).  So I already have 
the means to pass the name.

In the 3rd option, it would not change any of the APIs to register or any of 
the internal structures , but will still require a change to the callback to 
pass the string back to the caller like this

  *   typedef int (*shell_cmd_func_t)(int argc, char *argv[], const char 
*shell_name);

And I could cast that back to my object using something like

Struct foo {
/* blah blah */
char name[32];
};

Struct foo *pf = (struct foo*) ( (uint8_t*)  shell_name  - (int) ((struct foo 
*) 0)->name))

Or I could keep them on a list and search the list for a matching string in 
shell_name.

In short

  *   Option 1 — requires no change to shell API.  Requires queueing objects 
and some special command processing code
  *   Option 2 — simple to use, but requires API change and an extra void * 
storage for each shell module
  *   Option 3 — more complicated to use, requires API change but does not 
require extra storage for each shell module







Reply via email to