CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Using callback functions with double pointer argument

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
mjm_graco



Joined: 22 Oct 2020
Posts: 4

View user's profile Send private message

Using callback functions with double pointer argument
PostPosted: Thu Oct 22, 2020 12:28 pm     Reply with quote

compiler: PCH 5.013
chip: PIC18F67K22

I'm trying to implement a serial port command handler, adapting existing code that was written in XC8/XC32 for different/bigger PICs. That code parses an input string into separate elements in a buffer, then uses a "command table" of input strings and functions to determine the appropriate function to pass that buffer and the number of elements to, which gives the function calls the command line (argc, **argv) look.
Code:

// note:  this part is *not* CCS code 
typedef struct
{
   char *cmdString;
   void (*function)(int, char **);
} CommandTableEntry;

static const CommandTableEntry CommandTable[] = {{"?", HelpCommand},{"writeAppEE", WriteApplicationEEprom},{NULL, NULL}};

void WriteApplicationEEprom( int argc, char **argv )

I'd like to keep the command table format and the function calls (kinda the "outward facing" part of the software) the same as the existing code.
The parsing function populates these variables:
Code:
static uint8 s_InputBufferWordCount;
static char *s_InputBufferWordPtr[16];

So far, with lots of reading this forum, I've been able to call functions from a command table, but only with "conventional" arguments.
I've not been able to pass s_InputBufferWordPtr to the callback.

This works:
Code:

   typedef void (*_fptr)(int, int);

   typedef struct
   {
      // can't have this variable length - only get first character then
      char  cmdString[5];
      _fptr function;
   }CommandTableEntry;

   const CommandTableEntry CommandTable[] = {{"?", add}, {"test", sub}, {NULL, NULL}};
   _fptr temp;

   // i is the index of the match
   temp = CommandTable[i].function;
   result = (*temp)( num1, num2 );
   
   // where "add" and "sub" are simple functions (from a previous post in this forum!)
   int add( int x, int y )
   {
      return (x + y);
   }
   int sub( int x, int y )
   {
      return (x - y);
   }


But if I try to progress to this:
Code:

   typedef void (*_fptr)(int, char **);

   const CommandTableEntry CommandTable[] = {{"?", Dummy}, {"test", Test1}, {NULL,NULL}};
   
   (*temp)( s_InputBufferWordCount, &s_InputBufferWordPtr );
   
   where "Test1" looks like this:
   
   void Test1( int argc, char **argv )


I get the compiler error: "No valid assignment made to function pointer", which I can trace to s_InputBufferWordPtr.
I'm not a pointer expert, so I'm probably missing something obvious. Any thoughts?
Thanks in advance for any help.

One other note regarding s_InputBufferWordPtr:
When testing the parsing and the Test1 function (calling Test1 directly, rather than via a callback), I had to put the "&" in front s_InputBufferWordPtr to get it to work correctly. The code I'm copying/adapting does not do that when it calls the function from the command table:
Code:

   // note: also *not* CCS code
   const CommandTableEntry *pEntry = &CommandTable[0];

   /* Break up command buffer into individual words */
   TokenizeBuffer();
   if( s_InputBufferWordCount == 0 )
      return;

   while( pEntry->cmdString != NULL )
   {
      /* Find a match between the first word and a command table entry */
      if( strcmp( s_InputBufferWordPtr[0], pEntry->cmdString ) == 0 )
      {
         (pEntry->function)( s_InputBufferWordCount, s_InputBufferWordPtr );
         return;
      }
      pEntry++;
   }
jeremiah



Joined: 20 Jul 2010
Posts: 1314

View user's profile Send private message

PostPosted: Thu Oct 22, 2020 4:40 pm     Reply with quote

your
Code:

static char *s_InputBufferWordPtr[16];


means that s_InputBufferWordPtr is already a char**

when you do:

Code:

(*temp)( s_InputBufferWordCount, &s_InputBufferWordPtr );


The ampersand (&) says take another pointer level, which makes the type char ***

pointers in C can cast directly to integers, which is why the first one works, while in the second one you are trying to pass char *** into a char ** which doesn't.
mjm_graco



Joined: 22 Oct 2020
Posts: 4

View user's profile Send private message

PostPosted: Mon Oct 26, 2020 11:24 pm     Reply with quote

If I change:
Code:
(*temp)( s_InputBufferWordCount, &s_InputBufferWordPtr );

to:
Code:
(*temp)( s_InputBufferWordCount, s_InputBufferWordPtr );

I get the same compiler error.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Oct 27, 2020 1:45 am     Reply with quote

Post a test program that's compilable, except for that one error.
Then we can test it with vs. 5.096.

This means the #include for the PIC, #fuses, #use delay, global variables,
functions, main(), local variables, and the body of the program.
It should compile with only warnings or errors on the topic of your
problem. No other warnings or errors. Fix them before posting.

And make it be a short program. Example:
In this thread, the OP posts a lengthy test program. I strip it down to
to essentials. It makes it way easier to find the bug(s).
http://www.ccsinfo.com/forum/viewtopic.php?t=59015
mjm_graco



Joined: 22 Oct 2020
Posts: 4

View user's profile Send private message

PostPosted: Tue Oct 27, 2020 10:24 pm     Reply with quote

Yeah, that original post was all over the place. My apologies.

This combines the concepts of the 2 pieces of code after this one, and gives the compile error.
s_InputBufferWordPtr is a 2D array of words parsed from an input string.
Quote:
*** Error 144 "main.c" Line 24(1,1): No valid assignment made to function pointer 823 from=??0 0 SCR=1241
Code:
#include "18f67k22.h"
#use delay(clock=10M)
#use rs232(baud=9600, UART1, ERRORS)

void TestFunc(int argc, char **argv);

typedef void (*_fptr)(int, char **);

typedef struct
{
    char   cmdString[10];
    _fptr function;
}CommandTableEntry;

CommandTableEntry CommandTable[] = {{"?", TestFunc}};

void main(void)
{
    int   s_InputBufferWordCount;
    char  *s_InputBufferWordPtr[16];
    _fptr temp;
   
    temp = CommandTable[0].function;
    (*temp)(s_InputBufferWordCount, s_InputBufferWordPtr);
}

void TestFunc(int argc, char **argv)
{
    for (int i = 0; i < argc; ++i)
    {
        while(*argv[i])
        {
            printf("%u: %u\r", i, *argv[i]);
            ++argv[i];
        }
    }
}

This compiles and works (although extra code is required to show it works). Shows the callback with a conventional argument:
Code:
#include <18f67k22.h>
#use delay(clock=10M)
#use rs232(baud=9600, UART1, ERRORS)

void TestFunc(int argc);

typedef void (*_fptr)(int);

typedef struct
{
    char   cmdString[10];
    _fptr function;
}CommandTableEntry;

CommandTableEntry CommandTable[] = {{"?", TestFunc}};

void main(void)
{
   int  s_InputBufferWordCount;
   char *s_InputBufferWordPtr[16];
   _fptr temp;
   
    temp = CommandTable[0].function;
    (*temp)(s_InputBufferWordCount);

    while(1);
}

void TestFunc(int argc)
{
    printf("%u\r", argc);
}

This also compiles and works. Shows s_InputBufferWordPtr being passed to a function, but without the callback.
Code:
#include <18f67k22.h>
#use delay(clock=10M)
#use rs232(baud=9600, UART1, ERRORS)

void TestFunc(int argc, char **argv);

void main(void)
{
   int  s_InputBufferWordCount;
   char *s_InputBufferWordPtr[16];
   
    TestFunc(s_InputBufferWordCount, s_InputBufferWordPtr);
    while(1);
}

void TestFunc(int argc, char **argv)
{
    for (int i = 0; i < argc; ++i)
    {
        while(*argv[i])
        {
            printf("%u: %u\r", i, *argv[i]);
            ++argv[i];
        }
    }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Wed Oct 28, 2020 6:47 am     Reply with quote

Generally, CCS is rather restrictive with regards to handling pointer to
pointers and similar constructs. I've found that usually the best way to
avoid problems is to instead hand all values to functions as integers
(in the case of the PIC18, normally int16), and then convert these
values back to the required pointer where used.
So a fiddle like:
Code:

#include <18f67k22.h>
#use delay(clock=10M)
#use rs232(baud=9600, UART1, ERRORS)

void TestFunc(int argc, int16 argv);

typedef void (*_fptr)(int, int16);

typedef struct
{
    char   cmdString[10];
    _fptr function;
}CommandTableEntry;

CommandTableEntry CommandTable[] = {{"?", TestFunc}};
char string[] = "Test message";

void main(void)
{
   int  s_InputBufferWordCount=1;
   char *s_InputBufferWordPtr[16];
   _fptr temp;
   s_inputBufferWordPtr[0]=string;
   s_inputBufferWordPtr[1]=(char *)0;
   
    temp = CommandTable[0].function;
    (*temp)(s_InputBufferWordCount, (int16)s_InputBufferWordPtr );

    while(TRUE);
}

void TestFunc(int argc, int16 temp)
{
    char ** argv;
    argv=temp;
    printf("%u\r", argc);
    for (int i = 0; i < argc; ++i)
    {
        while(*argv[i])
        {
            printf("%u: %u\r", i, *argv[i]);
            ++argv[i];
        }
    }     
}


Ought to work (possibly...).
mjm_graco



Joined: 22 Oct 2020
Posts: 4

View user's profile Send private message

PostPosted: Wed Oct 28, 2020 7:29 am     Reply with quote

That worked. Thanks for the help - 'tis appreciated.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group