I have huge difficulties setting up a proper I2C master-driven connection to a slave BNO055 sensor. I have tried using the plain registers as suggested in many previous posts but to no avail and the debugging the application was quite awful.
Anyway, my application has many states in the TaskHandler (as switch cases) and almost all have some read/write function calls to BNO055 sensor. I have managed to get the connection working by separating every read/write in their separate states. However, since I want to minimize the number of states and make the code less gibberish and clearer I would like to combine the logically same application states.
The HAL open, read/write and close functions are located in readBno055 and writeBno055. When trying to combine two calls of these functions in the same application state, there isn't enough time for the I2C packet to be closed by the callback function before the second call for (example) writeBno055 fails. I suppose delaying the application to wait for this callback by using _delay_ms is not good. My question is, is it even possible to have multiple read/write operations in the same switch case of the TaskHandler? The developer guide for BitCloud 3.3.0 regarding these HAL I2C function is a bit misleading and on the sequence diagram it even has an error. Below my code of app.c:
/**************************************************************************//** \file app.c \brief App that reads sensor values of BNO055 9-axis sensor. \author tozamimoza ******************************************************************************/ #include <appTimer.h> #include <zdo.h> #include <app.h> #include <sysTaskManager.h> #include <usartManager.h> #include <i2cPacket.h> #include <bspLeds.h> #include <util/delay.h> #include <string.h> #include <stdlib.h> bool debugMode; bool isPacketClosed=false; bool avoidReset=false; bool isReadingQuat= false; static AppState_t appstate = APP_INIT; // timers static HAL_AppTimer_t initDelayTimer; static HAL_AppTimer_t quaterTimer; static HAL_AppTimer_t resetDelayTimer; static HAL_AppTimer_t calibTimer; static HAL_AppTimer_t eulerTimer; // timer initializations static void initQuaterTimer(void); static void initInitDelayTimer(void); static void initResetDelayTimer(void); static void initCalibTimer(void); static void initEulerTimer(void); // timer callbacks static void quaterTimerFired(void); static void initDelayTimerFired(void); static void resetDelayTimerFired(void); static void calibTimerFired(void); static void eulerTimerFired(void); void printLineToUSART(char*); void printTextToUSART(uint8_t*); // help function for concatenating strings (used in printToUSART functions) char* concat(const char *s1, const char *s2); uint8_t readQuatCtr=0; uint8_t readOneByteData[1]; uint8_t writeTwoBytesData[2]; uint8_t writeOneByteData[1]; uint8_t readData[1]={0x00}; uint8_t readDataQ[8]; uint8_t readDataC[1]={0x00}; uint8_t readEightBytesData[8]; uint8_t readEuelerData[6]; uint8_t output[] = "0xXX"; uint8_t outputStr[] = "XXX"; int16_t quat_w, quat_x, quat_y, quat_z; uint8_t tempZ[] = "000000"; uint8_t tempY[] = "000000"; uint8_t tempX[] = "000000"; uint8_t tempW[] = "000000"; const double scale = (1.0 / (1<<14)); static void writeDone(bool result); static void readDone(bool result); static inline bool checkIfPacketIsClosed(void); static HAL_I2cDescriptor_t i2cdescriptor={ .tty = TWI_CHANNEL_0, .clockRate = I2C_CLOCK_RATE_125, .id = BNO055_I2C_ADDRESS, }; /** * \brief Method for writing values to a BNO055 register. It should be also used for selecting registers for read. * * \param numOfBytes number of bytes to write. If 1, last argument of this function can be set to an arbitrary value and will not be used. * \param regAddr register address * \param val value to write * * \return int control value for success/fail. -1 is fail of opening/writing an I2C packet, -2 is for invalid numOfBytes argument */ int writeBno055(uint8_t numOfBytes, uint8_t regAddr, uint8_t val){ if(-1 == HAL_OpenI2cPacket(&i2cdescriptor)){ printLineToUSART(ERROR_I2C_OPEN); printLineToUSART("Error in writeBno055!"); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); return -1; }else{ // set isPacketClosed to false since it's open isPacketClosed=false; } if (numOfBytes==1) { writeOneByteData[0]=regAddr; i2cdescriptor.f = writeDone; i2cdescriptor.data = writeOneByteData; i2cdescriptor.length = 1; }else if(numOfBytes==2){ writeTwoBytesData[0]= regAddr; writeTwoBytesData[1]= val; i2cdescriptor.f = writeDone; i2cdescriptor.data = writeTwoBytesData; i2cdescriptor.length = 2; }else{ // invalid numOfBytes argument return -2; } if(-1 == HAL_WriteI2cPacket(&i2cdescriptor)){ printLineToUSART(ERROR_I2C_WRITE); printLineToUSART(" IN WRITE FUNCTION FOR BNO055!"); appstate = APP_NOTHING; SYS_PostTask(APL_TASK_ID); return -1; } // the packet is closed in the callback function writeDone return 0; } /** * \brief Reads values from already selected register (with previous write function). * * \param numOfBytes specifies how much bytes of data are to be read starting from the previously selected register address. * \param readData pointer to an array for read data to be stored. * * \return int control integer */ int readBno055(uint8_t numOfBytes, uint8_t* readData){ // ------------------------------------------------ READ -------------------------------------------------------- if(-1 == HAL_OpenI2cPacket(&i2cdescriptor)){ printLineToUSART(ERROR_I2C_OPEN); printLineToUSART("Error in readBno055!"); return -1; }else{ // set isPacketClosed to false since it's open isPacketClosed=false; } i2cdescriptor.f = readDone; i2cdescriptor.data = readData; i2cdescriptor.length = numOfBytes; if(-1 == HAL_ReadI2cPacket(&i2cdescriptor)){ printLineToUSART(ERROR_I2C_READ); printLineToUSART("Error in readBno055!"); appstate = APP_NOTHING; SYS_PostTask(APL_TASK_ID); return -1; } return 0; } /** * \brief Prints a line to UART interface in the same way as appWriteDataToUsart function but more convenient. * * \param text text to be printed * * \return void */ void printLineToUSART(char* text){ const char suffix[]="\n\r"; char* result=concat(text, suffix); uint8_t* uintArr = (uint8_t*)result; uint8_t len = strlen(uintArr); appWriteDataToUsart(uintArr,len); free(result); } /** * \brief Prints text to UART interface in the same way as appWriteDataToUsart function but more convenient. * * \param text text to be printed * * \return void */ void printTextToUSART(uint8_t* text){ uint8_t len = strlen(text); appWriteDataToUsart(text,len); } /** * \brief Function for concatenating two strings. * * \param s1 argument 1 to be concatenated * \param s2 argument 2 to be concatenated * * \return char* concatenated string result. */ char* concat(const char *s1, const char *s2) { char *result = malloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator // in real code you would check for errors in malloc here strcpy(result, s1); strcat(result, s2); return result; } void APL_TaskHandler(void){ switch(appstate){ case APP_INIT: debugMode=true; avoidReset=true; isReadingQuat=false; appInitUsartManager(); if(debugMode){ printLineToUSART("---------------------------"); printLineToUSART("STATE: APP_INIT"); } //appWriteDataToUsart((uint8_t*)"STATE_APP_INIT\n\r",sizeof("STATE_APP_INIT\n\r")-1); //Timer init initQuaterTimer(); initInitDelayTimer(); initResetDelayTimer(); initCalibTimer(); initEulerTimer(); appstate = APP_READ_BATTERY; SYS_PostTask(APL_TASK_ID); break; case APP_READ_BATTERY: appstate = APP_RESET_BNO055; SYS_PostTask(APL_TASK_ID); break; case APP_NOTHING : if(debugMode){ printLineToUSART("----------------------------"); printLineToUSART("STATE: APP_NOTHING"); } break; case APP_RESET_BNO055: if(!avoidReset){ if(debugMode){ printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_RESET_BNO055"); } if(-1==writeBno055(2, SYS_TRIGGER_ADDRESS, RST_SYS)){ printLineToUSART(ERROR_SET_SYS_RESET); appstate=APP_SET_OP_MODE_NDOF; SYS_PostTask(APL_TASK_ID); } HAL_StartAppTimer(&resetDelayTimer); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } else{ if(debugMode){ printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_RESET_BNO055"); printLineToUSART("Reset AVOIDED!"); } appstate=APP_SET_ID_REG; SYS_PostTask(APL_TASK_ID); } break; case APP_SET_ID_REG: if (debugMode) { printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_SET_ID_REG"); } if(-1 == writeBno055(1, BNO055_ID_REG, 0x00)){ printLineToUSART(ERROR_I2C_WRITE); } appstate=APP_READ_ID_REG; SYS_PostTask(APL_TASK_ID); break; case APP_READ_ID_REG: if (debugMode) { printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_SET_ID_REG"); } readBno055(1, readOneByteData); if (readOneByteData!=BNO055_ID) { printLineToUSART("Not the same ID!"); } appstate=APP_SET_OP_MODE_CONFIG; SYS_PostTask(APL_TASK_ID); break; //NDOF MODE Siehe Datenblatt case APP_SET_OP_MODE_NDOF: if(debugMode){ printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_SET_OP_MODE_NDOF"); } //appWriteDataToUsart((uint8_t*)"STATE_APP_SET_NDOF\n\r",sizeof("STATE_APP_SET_NDOF\n\r")-1); if(-1 == writeBno055(2, OPR_MODE_ADDRESS, BNO055_OPERATION_MODE_NDOF)){ printLineToUSART(ERROR_I2C_WRITE); printLineToUSART(" It is caused in APP_SET_OP_MODE_NDOF."); appstate=APP_SET_OP_MODE_NDOF; SYS_PostTask(APL_TASK_ID); } appstate = APP_SET_CALIBRATION_REG; SYS_PostTask(APL_TASK_ID); break; case APP_SET_OP_MODE_CONFIG: if(debugMode){ printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_SET_OP_MODE_CONFIG"); } if(-1==writeBno055(2, OPR_MODE_ADDRESS, BNO055_OPERATION_MODE_CONFIG)){ printLineToUSART(ERROR_SET_MODE_CONF); printLineToUSART("Caused in OP MODE CONFIG!"); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } appstate=APP_SET_PAGEID; SYS_PostTask(APL_TASK_ID); break; /* This is done automatically at start-up! case APP_SET_POWER_MODE_NORMAL: if(debugMode){ printLineToUSART("---------------------------------"); printLineToUSART("STATE: APP_SET_POWER_MODE_NORMAL"); } if(-1 == writeBno055(2, BNO055_PWR_MODE_REG, PWR_MODE_NORMAL)){ printLineToUSART(ERROR_SET_PWR_NORMAL); } appstate = APP_SET_PAGEID; SYS_PostTask(APL_TASK_ID); break; */ //Page ID wird auf 0 gesetzt um den Sensor zu nutzen case APP_SET_PAGEID: if(debugMode){ printLineToUSART("---------------------------"); printLineToUSART("STATE: APP_SET_PAGEID"); } if(-1 == writeBno055(2, PAGE_ID_ADDRESS, PAGE0)){ printLineToUSART(ERROR_I2C_WRITE); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } appstate = APP_SET_SYS_TRIGGER_REG; SYS_PostTask(APL_TASK_ID); break; // SYS_TRIGGER auf CLK_SEL case APP_SET_SYS_TRIGGER_REG: if(debugMode){ printLineToUSART("-------------------------------------"); printLineToUSART("STATE: APP_SET_SYS_TRIGGER_REG"); } if(-1 == writeBno055(2, SYS_TRIGGER_ADDRESS, CLK_SEL)){ printLineToUSART(ERROR_SEL_REG_SYS_TRIGGER); printLineToUSART("IN SET SYS TRIGGER REG STATE!"); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } appstate = APP_SET_OP_MODE_NDOF; SYS_PostTask(APL_TASK_ID); break; //Register für kalibrierung laden case APP_SET_CALIBRATION_REG: if(debugMode){ printLineToUSART("------------------------------"); printLineToUSART("STATE: APP_SET_CALIBRATION_REG"); } // select calibration register if(-1 == writeBno055(1, CALIB_STAT_ADDR, 0x00)){ printLineToUSART(ERROR_SEL_REG_CAL); printLineToUSART("Caused in SET CALIB REG!"); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } appstate = APP_READ_CALIBRATION_REG; SYS_PostTask(APL_TASK_ID); break; //kalibrierung aUSLESEN UND IN READDATAC SPEICHERN case APP_READ_CALIBRATION_REG: if (debugMode){ printLineToUSART("--------------------------------"); printLineToUSART("STATE: APP_READ_CALIBRATION_REG"); } if (-1==readBno055(1, readDataC)) { printLineToUSART(ERROR_I2C_READ); printLineToUSART("Caused by READ CALIB REG STATE!"); HAL_StartAppTimer(&calibTimer); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); }else{ if(readDataC[0]!=0xFF){ printLineToUSART("Not ready yet. Calibrating..."); printTextToUSART("Value: "); uint8_to_hexstr(output,sizeof(output),readDataC[0],2); printTextToUSART(output); printTextToUSART(" "); uint32_to_str(outputStr,sizeof(outputStr),readDataC[0],0,3); printTextToUSART(outputStr); printLineToUSART(" "); HAL_StartAppTimer(&calibTimer); appstate = APP_NOTHING; SYS_PostTask(APL_TASK_ID); } // calibrated, proceed else{ if (isReadingQuat) { appstate = APP_SET_QUATERNION_REG; }else{ appstate = APP_SET_EULER_REG; } SYS_PostTask(APL_TASK_ID); } } /* if(-1 == HAL_OpenI2cPacket(&i2cdescriptor)){ appWriteDataToUsart((uint8_t*)"APP_READ_CALIBRATION_REG Fail\r\n",sizeof("APP_READ_CALIBRATION_REG")-1); } //appWriteDataToUsart((uint8_t*)"APP_READ_CALIBRATION_REG\n\r",sizeof("APP_READ_CALIBRATION_REG\n\r")-1); i2cdescriptor.f = readDone; i2cdescriptor.data = readDataC; i2cdescriptor.length = 1; if(-1 == HAL_ReadI2cPacket(&i2cdescriptor)){ appWriteDataToUsart((uint8_t*)"Read Fail\r\n",sizeof("Read Fail\r\n")-1); } */ break; case APP_SET_EULER_REG: if(debugMode){ printLineToUSART("------------------------------"); printLineToUSART("STATE: APP_SET_EULER_REG"); } if(-1 == writeBno055(1, EUL_HEADING_LSB, 0x00)){ printLineToUSART(ERROR_SEL_REG_EULER); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } appstate = APP_READ_EULER; SYS_PostTask(APL_TASK_ID); break; //Register W für die Quaterionen laden case APP_SET_QUATERNION_REG: if(debugMode){ printLineToUSART("------------------------------"); printLineToUSART("STATE: APP_SET_QUAT_REG"); } if(-1 == writeBno055(1, QUATERNION_DATA_W_LSB_ADDR, 0x00)){ printLineToUSART(ERROR_SEL_REG_QUA); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); } HAL_StartAppTimer(&quaterTimer); appstate=APP_NOTHING; SYS_PostTask(APL_TASK_ID); break; case APP_READ_EULER: if(debugMode){ printLineToUSART("--------------------------------"); printLineToUSART("STATE: APP_READ_EULER"); } readBno055(6, readEuelerData); //printLineToUSART("is READ"); // display read results { char buffer[30]; uint16_t heading = readEuelerData[0] << 8 | readEuelerData[1]; uint16_t roll = readEuelerData[2] << 8 | readEuelerData[3]; uint16_t pitch = readEuelerData[4] << 8 | readEuelerData[5]; printTextToUSART(itoa(heading,buffer,10)); printTextToUSART(" / "); printTextToUSART(itoa(roll,buffer,10)); printTextToUSART(" / "); printLineToUSART(itoa(pitch,buffer,10)); } HAL_StartAppTimer(&eulerTimer); appstate = APP_NOTHING; SYS_PostTask(APL_TASK_ID); break; //Quaterionen auslesen W,X,Y,Z wegen length 8 direkt die andeeren Register von X,Y,Z mitauslesen case APP_READ_QUATERNION: if(debugMode){ printLineToUSART("--------------------------------"); printLineToUSART("STATE: APP_READ_QUATERNION"); } readBno055(8, readDataQ); //printLineToUSART("is READ"); appstate = APP_STORE_QUATERNION; SYS_PostTask(APL_TASK_ID); break; case APP_STORE_QUATERNION: if(debugMode){ printLineToUSART("--------------------------------"); printLineToUSART("STATE: APP_STORE_QUATERNION"); } quat_w = (((uint16_t)readDataQ[1]) << 8) | ((uint16_t)readDataQ[0]); quat_w = scale * quat_w; quat_x = (((uint16_t)readDataQ[3]) << 8) | ((uint16_t)readDataQ[2]); quat_x = scale * quat_x; quat_y = (((uint16_t)readDataQ[5]) << 8) | ((uint16_t)readDataQ[4]); quat_y = scale * quat_y; quat_z = (((uint16_t)readDataQ[7]) << 8) | ((uint16_t)readDataQ[6]); quat_z = scale * quat_z; /* //wenn nicht fertig kalibriert if(readDataC[0] != 0xFF){ //printTextToUSART("Calibration reg val: "); uint8_to_hexstr(output,sizeof(output),readDataC[0],2); printTextToUSART(output); printTextToUSART(" "); uint32_to_str(outputStr,sizeof(outputStr),readDataC[0],0,3); printTextToUSART(outputStr); printLineToUSART(" "); //HAL_StartAppTimer(&calibTimer); _delay_ms(100); appstate = APP_SET_CALIBRATION_REG; SYS_PostTask(APL_TASK_ID); } */ //wenn fertig kalibriert //else{ { char* buffer[4]; //printLineToUSART((char*)readDataQ); int32_to_str(tempW,sizeof(tempW), quat_w, 0, 6); //printTextToUSART(tempW); printTextToUSART(itoa(quat_w, buffer, 10)); printTextToUSART(" "); int32_to_str(tempX,sizeof(tempX), quat_x, 0, 6); printTextToUSART(itoa(quat_x, buffer, 10)); printTextToUSART(" "); int32_to_str(tempY,sizeof(tempY), quat_y, 0, 6); printTextToUSART(tempY); printTextToUSART(" "); //appWriteDataToUsart(tempY,sizeof(tempY)); int32_to_str(tempZ,sizeof(tempZ), quat_z, 0, 6); //appWriteDataToUsart(tempZ,sizeof(tempZ)); printTextToUSART(tempZ); printLineToUSART(" "); //appWriteDataToUsart((uint8_t*)"else\n\r",sizeof("else\n\r")-1); HAL_StartAppTimer(&quaterTimer); appstate = APP_NOTHING; SYS_PostTask(APL_TASK_ID); } //} break; } } // TIMER INITIALIZATION FUNCTIONS static void initInitDelayTimer(void) { initDelayTimer.interval = INIT_DELAY; initDelayTimer.mode = TIMER_ONE_SHOT_MODE; initDelayTimer.callback = initDelayTimerFired; } static void initResetDelayTimer(void){ resetDelayTimer.interval = RESET_DELAY; resetDelayTimer.mode = TIMER_ONE_SHOT_MODE; resetDelayTimer.callback = resetDelayTimerFired; } static void initCalibTimer(void){ calibTimer.interval=CALIB_READ_INTERVAL; calibTimer.mode = TIMER_ONE_SHOT_MODE; calibTimer.callback = calibTimerFired; } static void initQuaterTimer(void){ quaterTimer.interval = QUAT_READ_INTERVAL; // Timer interval quaterTimer.mode = TIMER_ONE_SHOT_MODE; // Timer-Mode quaterTimer.callback = quaterTimerFired; // Callback function } static void initEulerTimer(void){ eulerTimer.interval = EULER_READ_INTERVAL; // Timer interval eulerTimer.mode = TIMER_ONE_SHOT_MODE; // Timer-Mode eulerTimer.callback = eulerTimerFired; // Callback function } // TIMER CALLBACKS void calibTimerFired(void){ appstate = APP_READ_CALIBRATION_REG; SYS_PostTask(APL_TASK_ID); } void resetDelayTimerFired(void){ appstate = APP_SET_OP_MODE_CONFIG; SYS_PostTask(APL_TASK_ID); } void initDelayTimerFired(void){ appstate = APP_SET_PAGEID; SYS_PostTask(APL_TASK_ID); } /** * \brief Timer callback function for the timer representing an interval between quaternion reads. Application state is changed to read state for quaternions. * * * \return void */ static void quaterTimerFired(){ appstate = APP_READ_QUATERNION; SYS_PostTask(APL_TASK_ID); } static void eulerTimerFired(){ appstate = APP_READ_EULER; SYS_PostTask(APL_TASK_ID); } static inline bool checkIfPacketIsClosed(void){ return isPacketClosed; } /** * \brief Callback function for I2C descriptor (write). * * \param result a boolean indicating a successful/unsuccessful write operation * * \return void */ static void writeDone(bool result){ if(result == false){ printLineToUSART(ERROR_I2C_WRITE); appstate = APP_NOTHING; }else{ // succesful write, now close the packet if(-1 == HAL_CloseI2cPacket(&i2cdescriptor)){ printLineToUSART(ERROR_I2C_CLOSE); appstate = APP_NOTHING; }else{ // set isPacketClosed to true isPacketClosed=true; } } SYS_PostTask(APL_TASK_ID); } /** * \brief Callback function for I2C descriptor (read). * * \param result a boolean indicating a successful/unsuccessful read operation * * \return void */ static void readDone(bool result){ if(result == false){ printLineToUSART(ERROR_I2C_READ); appstate = APP_NOTHING; }else{ // succesful read, now close the packet if(-1 == HAL_CloseI2cPacket(&i2cdescriptor)){ printLineToUSART(ERROR_I2C_CLOSE); appstate = APP_NOTHING; }else{ // set isPacketClosed to true isPacketClosed=true; } } SYS_PostTask(APL_TASK_ID); } /******************************************************************************* \brief The function is called by the stack to notify the application about various network-related events. See detailed description in API Reference. Mandatory function: must be present in any application. \param[in] nwkParams - contains notification type and additional data varying an event \return none *******************************************************************************/ void ZDO_MgmtNwkUpdateNotf(ZDO_MgmtNwkUpdateNotf_t *nwkParams) { nwkParams = nwkParams; // Unused parameter warning prevention } /******************************************************************************* \brief The function is called by the stack when the node wakes up by timer. When the device starts after hardware reset the stack posts an application task (via SYS_PostTask()) once, giving control to the application, while upon wake up the stack only calls this indication function. So, to provide control to the application on wake up, change the application state and post an application task via SYS_PostTask(APL_TASK_ID) from this function. Mandatory function: must be present in any application. \return none *******************************************************************************/ void ZDO_WakeUpInd(void) { } #ifdef _BINDING_ /*********************************************************************************** \brief The function is called by the stack to notify the application that a binding request has been received from a remote node. Mandatory function: must be present in any application. \param[in] bindInd - information about the bound device \return none ***********************************************************************************/ void ZDO_BindIndication(ZDO_BindInd_t *bindInd) { (void)bindInd; } /*********************************************************************************** \brief The function is called by the stack to notify the application that a binding request has been received from a remote node. Mandatory function: must be present in any application. \param[in] unbindInd - information about the unbound device \return none ***********************************************************************************/ void ZDO_UnbindIndication(ZDO_UnbindInd_t *unbindInd) { (void)unbindInd; } #endif //_BINDING_ /**********************************************************************//** \brief The entry point of the program. This function should not be changed by the user without necessity and must always include an invocation of the SYS_SysInit() function and an infinite loop with SYS_RunTask() function called on each step. \return none **************************************************************************/ int main(void) { //Initialization of the System Environment SYS_SysInit(); //The infinite loop maintaing task management for(;;) { //Each time this function is called, the task //scheduler processes the next task posted by one //of the BitCloud components or the application SYS_RunTask(); } } //eof app.c