Hi Paul,

IMO Option 1 seems like the best option here. I don't think the special
command processing code will require a lot of work. Of course, if you think
that Option 2 is better for your use case you can implement it and submit a
PR.

BR
Michał Narajowski

pon., 25 cze 2018 o 04:10 p...@wrada.com <p...@wrada.com> napisał(a):

> 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