I’m writing an extremely simple kernel for an embedded systems class. The board is the TI Stellaris EKI-LM3S8962. It runs C and has an OLED display. I am having issues with void pointers and de-referencing them. Any help is much appreciated.
My very small initial goal is to prove the concept of passing function pointers and struct pointers around. Is this the way that I access the var batteryState pointed to by the pointer batteryStatePtr which is part of the data struct passed in?
void status (void* taskDataPtr) {
// make a temporary pointer to a Status Data Struct type
SDS* data;
// set data equal to the void* taskDataPtr now cast as a SDS pointer
data = (SDS*)(taskDataPtr);
(*data->batteryStatePtr)--;
...
Here is a very stripped down version of my code, the important region can be located by ctrl-f “HERE IS”
struct MyStruct {
void (*taskPtr)(void*);
void* taskDataPtr;
};
typedef struct MyStruct TCB;
The taskPtr points to a function that takes a void* as an arg and has a void* to a data struct. As a proof of concept I’m starting as small as possible. There are two functions, status and display.
typedef struct DisplayDataStruct {
uint* batteryStatePtr;
} DDS;
DDS DisplayData;
typedef struct StatusDataStruct {
uint* batteryStatePtr;
} SDS;
SDS StatusData;
Status decrements the global variable batteryState through the taskDataPtr it is given. Display concatenates it onto a string and shows it on the OLED.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
void status (void* taskDataPtr);
void display (void* taskDataPtr);
void delay(uint msDelay);
// Declare a TCB structure
struct MyStruct {
void (*taskPtr)(void*);
void* taskDataPtr;
};
typedef struct MyStruct TCB;
// status var
uint batteryState = 200;
typedef struct DisplayDataStruct {
uint* batteryStatePtr;
} DDS;
DDS DisplayData;
typedef struct StatusDataStruct {
uint* batteryStatePtr;
} SDS;
SDS StatusData;
void main(void)
{
DisplayData.batteryStatePtr = &batteryState;
StatusData.batteryStatePtr = &batteryState;
int i = 0; // queue index
TCB* aTCBPtr;
TCB* queue[2];
TCB StatusTCB;
TCB DisplayTCB;
StatusTCB.taskPtr = status;
StatusTCB.taskDataPtr = (void*)&StatusData;
DisplayTCB.taskPtr = display;
DisplayTCB.taskDataPtr = (void*)&DisplayData;
// Initialize the task queue
queue[0] = &StatusTCB;
queue[1] = &DisplayTCB;
// schedule and dispatch the tasks
while(1)
{
for (i = 0; i < 2; i++) {
aTCBPtr = queue[i];
aTCBPtr->taskPtr( (void*)(aTCBPtr->taskDataPtr) );
}
systemState = (systemState + 1) % 100;
delay(50);
}
}
void status (void* taskDataPtr) {
// return if systemState != 0 aka run once every 5 sec
if (systemState) {
return;
}
// make a temporary pointer to a Status Data Struct type
SDS* data;
// set data equal to the void* taskDataPtr now cast as a SDS pointer
data = (SDS*)(taskDataPtr);
// HERE IS where I am stumped. Is (*data->batteryStatePtr)-- the way you do this????
// access the batteryStatePtr through the struct data
// then dereference the whole thing to get at batteryState
if ((*(data->batteryStatePtr)) > 0) {
// decrement batteryState
(*(data->batteryStatePtr))--;
}
return;
}
void display (void* taskDataPtr) {
// run once every 5 sec
if (systemState) {
return;
}
DDS* data;
data = (DDS*) taskDataPtr;
char hold[12] = "Batt: ";
char numHold[4];
sprintf(numHold, "%u", (*(data->batteryStatePtr)));
strcat(hold, numHold);
// display the string hold
RIT128x96x4StringDraw(hold, 15, 44, 15);
return;
}
// use for loops to waste cycles, delay taken in ms
void delay(uint msDelay)
{
// when i == 60000 and j == 100 function delays for ~ 7.6 sec
msDelay = msDelay * 150 / 19;
volatile unsigned long i = 0;
volatile unsigned int j = 0;
for (i = msDelay; i > 0; i--) {
for (j = 0; j < 100; j++);
}
return;
}
The way of getting at the value batteryState through the void* structure is correct. For clarity, here it is:
The data structure called data has a member called batteryStatusPtr. After getting the ptr, dereference it to get at what it is pointing at. Add more parenthesis for order of operations. (not 100% sure if those are necessary, but it allows me to sleep at night. Finally decrement it by 1.
In one line the problem was after using sprintf() to convert it to a string, and sending it to a display function, the value became corrupted with some strange garbage number. I don’t know why, but sprintf() was the cause. I wrote my own uint to string function and the problem was solved. The sprintf worked fine on my linux box, but the Texas Instruments LM3S8962 Lumninary Evaluation Board did not like it.
Here is a stripped down, commented version of the code. As I’m a bit of a noob (in school, have a year of programming experience in Javascript, not C), I will take no responsibility for any errors. This is to the best of my knowledge. Perhaps in the process of stripping it is broken so I apologize in advance.