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