We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I am trying to convert an unmaintainable user interface driver over to something that uses data structures to define the menu organization (This example is stripped down to the bare minimum from my actual app).
Picture an array of screens, selectable by the user's activation of some arrow keys:
Col 0 Col 1 +-----------+ Row 0 | Screen 1a | +-----------+ /\ || \/ +-----------+ +-----------+ Row 1 | Screen 2a | <===> | Screen 2b | +-----------+ +-----------+
I define a function to output each screen (in the code below, they also change the row & column indices):
void f1a(void) { outputScreen1a(); if(r > 0) r++; return; } /* ============= */ void f2a(void) { outputScreen2a(); if(c < 1) c++; return; } /* ============= */ void f2b(void) { outputScreen2b(); r = c = 0; return; }
These are called by the main() function, using a function pointer table:
static code const void (* code menuFunc[2][2])(void) = { { f1a, NULL }, { f2a, f2b } }; unsigned char r, c; void main(void) { unsigned char i; SFRPAGE = 0; /* Go to default page */ WDTCN = 0xDE; /* Disable watchdog timer */ WDTCN = 0xAD; IE = 0; /* Disable all interrupts */ i = 0; r = c = 0; while (1) { if(i < 70) { i++; } else { i = 0; (*menuFunc[r][c])(); } } /* END while (TRUE) */ } /* END main() */
As presented above, the source file will compile without error. But my application is quite a bit more complex than what I present here, the table is assymetrical (marked by the NULL pointer) and I want to guantee I do not inadvertently dereference it, so I add a qualification to the main control loop:
while (1) { if(i < 70) { i++; } else { i = 0; if((menuFunc[r][c])() != NULL) (*menuFunc[r][c])(); } } /* END while (TRUE) */
C51 does not like this. It flags the statement where I check for NULL:
?????.C:(56): error C193: '!=' : illegal conversion from/to 'void'
NULL is defined in stdio.h:
#define NULL ((void *) 0)
K&R doesn't state it explicitly, but seems to assume that void is an object type, that (void *) can only point to an object, and never uses NULL as a pointer to a function.
So the question is, if I can't use NULL to mark an uncallable function in the table, is there a null function pointer I could use instead?
============================================================ Gary Lynch | To send mail, no$pam in domain name lynchg@no$pam.com | must be changed to stacoenergy. ============================================================
On 25-Oct-2008 06:21; Hans-Bernhard Broeker wrote: > > So what's keeping you from copying and modifying a > personally adjusted default project (including Lint > settings) instead of creating new ones all the time? > I promised to report my findings on the feasibility of that suggestion. First I need to explain how I structure projects.
The file containing the main() function has a 3-part naming convention:
- The name of the application (in current project, that is the same as what uV3 calls the 'Target', - A symbol denoting configuration for products that get sliced into many different one-of-a-kind special configurations, - The revision number.
Thus, the file that started this dialog is named:
RectCtlDelta2_0.c ------- --- | ----- | | | | The MCU that ----+ | +--- Rev 2.0 controls the | rectifier The designation section of for 'plain, vanilla', the UPS i.e. non-special
If you let everything default, C51 will translate this into an object file with the same name and extension .obj, and if you specify that module first to BL51, it will create absolute object in a file with the same name and no extension.
I create a project file called RectCtlDelta2_0.uv2 to hold all the build details, and that is (I hope) what Herr Broeker wanted me to clone. It creates a self-documenting trail from executable back to source, with the most critical parameters visible in the (shared) file name.
Let's say we move from Rev 2.0 to 2.1, and I copy:
- RectCtlDelta2_0.c to RectCtlDelta2_1.c, & - RectCtlDelta2_0.uv2 to RectCtlDelta2_1.uv2
Under dialog box Project\Options for Target 'RectifierCtl' I discovered most of the parameters on the 'Listing' tab did not copy through, reverting to their defaults. I snooped around and found file RectCtlDelta2_0.opt, created by uV3 when I run a build held them, so I tried cloning it as well:
- RectCtlDelta2_0.opt to RectCtlDelta2_1.opt.
Now I have most of the attributes of the old project assigned to the new, but I'm not through yet. As I mentioned earlier, tab 'BL51 Misc' contains data for the OVERLAY directive, and that references a constant, code segment from the module holding the FSM and main(), so I must edit its revision number:
?PR?onRect?RectCtlDelta2_0 ~ ?CO?RectCtlDelta2_0, ?PR?onNoBattery?RectCtlDelta2_0 ~ ?CO?RectCtlDelta2_0
must become:
?PR?onRect?RectCtlDelta2_1 ~ ?CO?RectCtlDelta2_1, ?PR?onNoBattery?RectCtlDelta2_1 ~ ?CO?RectCtlDelta2_1
I could eliminate that by moving the FSM to another source file--one not containing the revision number, but there's more.
The 'BL51 Misc' tab also contains a 'Linker control string' field with the name of the target file for my absolute object module:
TO "RectCtlDelta2_0"
I need to change that, but BL51 will not let me edit it in the dialog box.
In the positive column, after I configured PC-lint from the Tools\ menu, it remained configured in the new project.
That's all the investigation I have time for today, but it's not looking like a time-saving approach.
I create a project file called RectCtlDelta2_0.uv2 to hold all the build details, and that is (I hope) what Herr Broeker wanted me to clone.
I'm afraid you took this ball and ran it with much further and faster than I meant you to.
Your original problem was that the PC-Lint configuration has to be re-done after every "Project->New Project". The solution to that issue is to have a default project that is exactly the same as a virgin "New Project", but with PC-Lint configured. You can then copy that around instead of using "New Project".
That said, I think you need to step back a bit and review your naming strategy a bit. I rather much doubt that you're doing yourself any kind of favour by putting the project version number into the source file names. Version number tags belong into your revision control system, not in file names. File name modifications just create change all over the place (section names, e.g.) that only get in the way instead of being helpful. Whether or not the same applies to the other two parts of the file name is for you to decide, so I'll just say that I don't to see any reason why the file containing main() should not be called main.c.
But if you really must, I would suggest you try an automated text search-and-replace tool on the copied uV2 and opt files to apply all changes related to the filename change to the project.
That one's pretty easy. Find the project options, and go to the "Output" tab. Change the executable's name there. (The text substitution step mentioned before could take care of that automatically).
And you may want to consider using multiple targets in a single project instead of creating a whole new project for every minor version of your program.
Generally speaking, it feels like you need to relax and re-read the entire documentation on uVision --- at the moment, you appear to fighting it instead of letting it help you.
That's certainly the way it looks to me!
I think it is, unfortunately, one of those cases where the best way to get to where you want to be is not to start from where you are!