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.
Hi All. I'm becoming more familiar with C51's various memory models, but I could use some confirmation on one issue. Here's a code snippet:
char CODE_B = 'B'; char CODE_C = 'C'; ... void TaskShow( void ) { OStypeMsgP msgP; InitPORT(); PORT = 0x00; for (;;) { OS_WaitMsg(MSG_UPDATE_PORT_P, &msgP, OSNO_TIMEOUT, TaskShow1); if ( *(char *)msgP == CODE_C ) { PORT &= ~0xFE; PORT |= ( counter >> 8 ) & 0xFE; } else PORT ^= 0x01; } }
if ( *(char xdata *)msgP == CODE_C ) {
Hi Mark. Thanks for your reply. It (and a subsequent review of the Cx51 manual) answered all of my questions. The "generic" nature of these message pointers is what I was looking for. Should a user wish to reduce the RAM associated with the message pointers, then they can use a Salvo configuration option, e.g.
#define OSMESSAGE_TYPE data *
#define OSMESSAGE_TYPE data * #define? That's what typedef's are for. AFAIK, the casting of l-values as above is unavoidable if one wants a single message pointer type that i) can be used to point to anything and ii) can be processed by the messaging functions like OSSignalMsg() and OS_WaitMsg(). Not true, we're using an optimizing compiler here. There is no penalty for temporary variables.
void TaskShow(void) { OStypeMsgP msgP; InitPORT(); PORT = 0x00; for (;;) { /* Treat it like it is, C51 won't penalize you for this var. */ char *pTemp = (char *) msgP; OS_WaitMsg(MSG_UPDATE_PORT_P, &msgP, OSNO_TIMEOUT, TaskShow1); if (CODE_C == *pTemp) { PORT = (PORT & ~0xFE) | counter >> 8 & 0xFE; } else { PORT ^= 0x01; } } }
Hi Mark. Thanks for your continued interest in this thread. (The #define is ugly, I know, but it is there for historical reasons to support other non-Keil compilers. Perhaps I can find an elegant way to remove it and use only the typedef ...) Anyway, I see your point re the use of a local var to avoid casting the lvalue, but how is that any different from
if ( CODE_C == *(char *)msgP ) {
support other non-Keil compilers. Perhaps I can find an elegant way to remove it and use only the typedef ...) The common way is to do #ifdef __WIN32__ blah #elif __C51__ blix #endif Anyway, I see your point re the use of a local var to avoid casting the lvalue, but how is that any different from if ( CODE_C == *(char *)msgP ) { ? Isn't that effectively the same thing? Yes it is. I screwed up on the l-value. L-values are "left hand side of equates" or "linker resoved" whereas r-values are "right hand side of equates" or "run-time resolved". Since the dereference of msgP is a run-time resolved value it is an r-value. Thus it's not a problem. My apologies. I confused it with:
*(char *) msgP = 'a';
Hi Mark. Here's the general reason why we use a #define instead of a typedef in certain places of the Salvo code (we already test for compilers using their defined symbols, etc. -- it's not for that reason). Before this thread expires :-) I thought I'd pester you on your thoughts for a a more elegant solution ... Let's assume that, by default, we want our message pointers to be of type
void *
typedef void * OStypeMsgP;
#ifndef OSMESSAGE_TYPE #define OSMESSAGE_TYPE void #endif typedef OSMESSAGE_TYPE * OStypeMsgP;
#define OSMESSAGE_TYPE data
#ifndef OSOVERRIDE_MESSAGE_POINTER_TYPE typedef void * OStypeMsgP; #endif
#define OSOVERRIDE_MESSAGE_POINTER_TYPE TRUE typedef data * OStypeMsgP
Andrew, I'm afraid I don't have much to add here. I'd have done the message object a bit differently to avoid the 8051 data space specifier conundrum but as I'm sure you're well aware, there's not much you can do with a typedef once you've declared it except use it. For the message object I'd simply forgo the pointer version and supply the base type letting user create a pointer from it. E.g.
typedef enum MsgTypes { MSG_COMPLEX, MSG_A, MSG_B, MSG_C, NUM_MSGS } MsgTypes; typedef struct o_complex { int var; char arr[5]; } o_complex; typedef struct o_msg { MsgTypes type; union MsgBody { o_complex complex; unsigned long apple; unsigned int butter; unsigned char cheese; } body; } o_msg; int main(void) { /* Pointer resides in IDATA but points only to DATA space */ o_msg idata * data pMsg; pMsg->type = MSG_A; pMsg->body.cheese = 'a'; /* blah, blah, blah... */ for (;;); return 0; }
Ahem, off-line is tough without an email address, eh? mark@embeddedfw.com
maybe we should take it off-line That'd be a shame. Then all of us Salvo users couldn't see what you guys are up to ;-) I've always found it beneficial to follow a problem as it is worked through to its eventual solution.
I just don't want to turn Keil's website into a Salvo discussion forum, they have their own already. Regards, - Mark
I just don't want to turn Keil's website into a Salvo discussion forum, they have their own already. Agreed. This is Keil's web space, after all. I'm pretty happy with the way we do message pointers -- anything more explicit invariably leads to cross-platform portability problems and increased maintenance headaches. It does work well, once users get the hang of it. And it can be quite efficient. Thanks again, Mark, for your help and interest in my original query. It has helped me in my understanding of the pointer situation with Cx51. Regards,