|
|
View previous topic :: View next topic |
Author |
Message |
mjm_graco
Joined: 22 Oct 2020 Posts: 4
|
Using callback functions with double pointer argument |
Posted: Thu Oct 22, 2020 12:28 pm |
|
|
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: 1349
|
|
Posted: Thu Oct 22, 2020 4:40 pm |
|
|
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
|
|
Posted: Mon Oct 26, 2020 11:24 pm |
|
|
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
|
|
Posted: Tue Oct 27, 2020 1:45 am |
|
|
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
|
|
Posted: Tue Oct 27, 2020 10:24 pm |
|
|
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: 19515
|
|
Posted: Wed Oct 28, 2020 6:47 am |
|
|
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
|
|
Posted: Wed Oct 28, 2020 7:29 am |
|
|
That worked. Thanks for the help - 'tis appreciated. |
|
|
|
|
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
|