/************************************************************************************************** * @fn npi_poll_entry * * @brief Poll Thread entry function * * input parameters * * @param ptr * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void *npi_poll_entry(void *ptr) { int ret = NPI_LNX_SUCCESS; uint8 readbuf[128]; char tmpStr[1024]; #ifndef SRDY_INTERRUPT uint8 pollStatus = FALSE; #endif //SRDY_INTERRUPT ((void)ptr); snprintf(tmpStr, sizeof(tmpStr), "[%s] Locking Mutex for Poll Thread \n", __FUNCTION__); time_printf(tmpStr); /* lock mutex in order not to lose signal */ pthread_mutex_lock(&npi_poll_mutex); snprintf(tmpStr, sizeof(tmpStr), "[%s] Poll Thread Started\n", __FUNCTION__); time_printf(tmpStr); //This lock wait for Initialization to finish (reset) pthread_mutex_lock(&npiPollLock); snprintf(tmpStr, sizeof(tmpStr), "[%s] Poll Thread Continues After Synchronization\n", __FUNCTION__); time_printf(tmpStr); #ifdef SRDY_INTERRUPT if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Lock Poll mutex (SRDY=%d) \n", __FUNCTION__, global_srdy); time_printf(tmpStr); } pthread_cond_wait(&npi_srdy_H2L_poll, &npiPollLock); if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Locked Poll mutex (SRDY=%d) \n", __FUNCTION__, global_srdy); time_printf(tmpStr); } #else pthread_mutex_unlock(&npiPollLock); #endif /* thread loop */ while(!npi_poll_terminate) { #ifndef SRDY_INTERRUPT pthread_mutex_lock(&npiPollLock); #endif if (PollLockVar) { ret = PollLockVarError(__LINE__, PollLockVar); } else { PollLockVar = 1; if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] PollLockVar set to %d\n", __FUNCTION__, PollLockVar); time_printf(tmpStr); } } //Ready SRDY Status // This Test check if RNP has asserted SRDY line because it has some Data pending. // If SRDY is not Used, then this line need to be commented, and the Poll command need // to be sent regularly to check if any data is pending. this is done every 10ms (see below npi_poll_cond) #ifndef SRDY_INTERRUPT ret = HAL_RNP_SRDY_CLR(); if(TRUE == ret) #else //Interruption case, In case of a SREQ, SRDY will go low a end generate an event. // the npiPollLock will prevent us to arrive to this test, // BUT an AREQ can immediately follow a SREQ: SRDY will stay low for the whole process // In this case, we need to check that the SRDY line is still LOW or is HIGH. if (HalGpioSrdyCheck(0) == TRUE) #endif { if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Polling received... \n", __FUNCTION__); time_printf(tmpStr); } //RNP is polling, retrieve the data *readbuf = 0; //Poll Command has zero data bytes. *(readbuf+1) = RPC_CMD_POLL; *(readbuf+2) = 0; ret = npi_i2c_pollData((npiMsgData_t *)readbuf); if (ret == NPI_LNX_SUCCESS) { //Check if polling was successful if ((readbuf[RPC_POS_CMD0] & RPC_CMD_TYPE_MASK) == RPC_CMD_AREQ) { // ((uint8 *)readbuf)[RPC_POS_CMD0] = RPC_SUBSYSTEM_MASK; ret = NPI_AsynchMsgCback((npiMsgData_t *)(readbuf)); if (ret != NPI_LNX_SUCCESS) { // Exit thread to invoke report to main thread npi_poll_terminate = 1; error_printf("%s:%d: ERROR! Terminating poll because RPC_CMD_AREQ.\n", __FUNCTION__, __LINE__); } } } else { // An error has occurred // Check what error it is, some errors are expected char *errorMsg; switch (npi_ipc_errno) { case NPI_LNX_ERROR_HAL_GPIO_WAIT_SRDY_CLEAR_POLL_TIMEDOUT: errorMsg = "npi_i2c_pollData timed out waiting for SRDY. Could be SBL which only responds to SREQ. Please check global error message\n"; NPI_LNX_IPC_NotifyError(NPI_LNX_ERROR_MODULE_MASK(NPI_LNX_ERROR_HAL_GPIO_WAIT_SRDY_CLEAR_POLL_TIMEDOUT), errorMsg); // The RNP may be in SBL or may only respond to SREQ. We should not exit POLL thread. ret = NPI_LNX_SUCCESS; break; case NPI_LNX_ERROR_HAL_I2C_READ_TIMEDOUT: // The RNP may have reset unexpectedly, keep going ret = NPI_LNX_SUCCESS; break; case NPI_LNX_ERROR_HAL_I2C_WRITE_TIMEDOUT: // The RNP may have reset unexpectedly, keep going ret = NPI_LNX_SUCCESS; break; default: // Exit clean so main knows... npi_poll_terminate = 1; error_printf("%s:%d: ERROR! Terminating poll because error return (ret=%d, npi_ipc_errno=%d).\n", __FUNCTION__, __LINE__, ret, npi_ipc_errno); break; } } if (!PollLockVar) { ret = PollLockVarError(__LINE__, !PollLockVar); } else { PollLockVar = 0; if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] PollLockVar set to %d\n", __FUNCTION__, PollLockVar); time_printf(tmpStr); } } #ifndef SRDY_INTERRUPT if ( 0 == pthread_mutex_unlock(&npiPollLock)) { pollStatus = TRUE; if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Unlock SRDY mutex \n", __FUNCTION__); time_printf(tmpStr); } } else { if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Failed to unlock SRDY mutex \n", __FUNCTION__); time_printf(tmpStr); } npi_ipc_errno = NPI_LNX_ERROR_I2C_POLL_THREAD_POLL_UNLOCK; ret = NPI_LNX_FAILURE; npi_poll_terminate = 1; error_printf("%s:%d: ERROR! Terminating poll because POLL mutex unlock failed.\n", __FUNCTION__, __LINE__); } #endif //SRDY_INTERRUPT } else { if (!PollLockVar) { ret = PollLockVarError(__LINE__, !PollLockVar); } else { PollLockVar = 0; if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] PollLockVar set to %d\n", __FUNCTION__, PollLockVar); time_printf(tmpStr); } } #ifdef SRDY_INTERRUPT if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] SRDY was not 0 when we expected!\n", __FUNCTION__); time_printf(tmpStr); } #else if ( 0 == pthread_mutex_unlock(&npiPollLock)) { if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Unlock SRDY mutex \n", __FUNCTION__); time_printf(tmpStr); } } else { if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Failed to unlock SRDY mutex \n", __FUNCTION__); time_printf(tmpStr); } npi_ipc_errno = NPI_LNX_ERROR_I2C_POLL_THREAD_POLL_UNLOCK; ret = NPI_LNX_FAILURE; npi_poll_terminate = 1; error_printf("%s:%d: ERROR! Terminating poll because POLL mutex unlock failed.\n", __FUNCTION__, __LINE__); } pollStatus = FALSE; #endif //SRDY_INTERRUPT } #ifdef SRDY_INTERRUPT if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Unlock POLL mutex by conditional wait (SRDY=%d) \n", __FUNCTION__, global_srdy); time_printf(tmpStr); } if (TRUE == HAL_RNP_SRDY_SET()) { if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Waiting for SRDY to go low\n", __FUNCTION__); time_printf(tmpStr); } int condWaitRetVal = pthread_cond_wait(&npi_srdy_H2L_poll, &npiPollLock); if (condWaitRetVal) { snprintf(tmpStr, sizeof(tmpStr), "[%s] pthread_cond_wait returned with %d (%s, %s)\n", __FUNCTION__, condWaitRetVal, strerror(condWaitRetVal), strerror(errno)); time_printf(tmpStr); if (condWaitRetVal == 1) exit(-1); } } else if (npi_poll_terminate) { // Just unlock mutex, while loop will exit next pthread_mutex_unlock(&npiPollLock); } else { if (PollLockVar) { ret = PollLockVarError(__LINE__, PollLockVar); } if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] SRDY found high after poll, poll again\n", __FUNCTION__); time_printf(tmpStr); } // After a synchronous request we need to poll RNP again. The RNP will only release SRDY after // replying with 0x00 0x00 0x00 to a poll request. } if ( __BIG_DEBUG_ACTIVE == TRUE ) { snprintf(tmpStr, sizeof(tmpStr), "[%s] Locked POLL mutex because condition was met (SRDY=%d) \n", __FUNCTION__, global_srdy); time_printf(tmpStr); } #else if (!pollStatus) //If previous poll failed, wait 10ms to do another one, else do it right away to empty the RNP queue. { struct timespec expirytime; clock_gettime(CLOCK_REALTIME, &expiryTime); expirytime.tv_nsec += 10000000; // 10ms if (expirytime.tv_nsec >= 1000000000) { expirytime.tv_nsec -= 1000000000; expirytime.tv_sec++; } pthread_cond_timedwait(&npi_poll_cond, &npi_poll_mutex, &expirytime); } #endif } error_printf("[POLL] WARNING. Thread exiting with ret=%d, npi_ipc_errno0x%x...\n", ret, npi_ipc_errno); pthread_mutex_unlock(&npi_poll_mutex); char const *errorMsg; if (ret == NPI_LNX_FAILURE) { errorMsg = "[POLL] Thread exited with error. Please check global error message\n"; } else { errorMsg = "[POLL] Thread exited without error\n"; } NPI_LNX_IPC_NotifyError(NPI_LNX_ERROR_MODULE_MASK(NPI_LNX_ERROR_I2C_POLL_THREAD_FAILED_LOCK), errorMsg); return ptr; }
/************************************************************************************************** * * @fn npi_ipc_handleThreadFunc * * @brief This function initializes RTI Surrogate * * input parameters * * @param ipAddress - path to the NPI Server Socket * * output parameters * * None. * * @return TRUE if the surrogate module started off successfully. * FALSE, otherwise. * **************************************************************************************************/ static void *npi_ipc_handleThreadFunc (void *ptr) { int done = 0, tryLockFirstTimeOnly = 0; // Handle message from socket do { if (tryLockFirstTimeOnly == 0) { // Lock mutex debug_verbose_printf("[CLIENT HANDLE][MUTEX] Lock AREQ Mutex (Handle)\n"); int mutexRet = 0, writeOnce = 0; while ( (mutexRet = pthread_mutex_trylock(&npiLnxClientAREQmutex)) == EBUSY) { if (writeOnce == 0) { debug_verbose_printf("[CLIENT HANDLE][MUTEX] AREQ Mutex (Handle) busy"); fflush(stdout); writeOnce++; } else { writeOnce++; if ( (writeOnce % 1000) == 0) { debug_verbose_printf("."); } if (writeOnce > 0xEFFFFFF0) writeOnce = 1; fflush(stdout); } } debug_verbose_printf("\n[CLIENT HANDLE][MUTEX] AREQ Lock (Handle) status: %d\n", mutexRet); tryLockFirstTimeOnly = 1; } // Conditional wait for the response handled in the AREQ handling thread, debug_verbose_printf("[CLIENT HANDLE][MUTEX] Wait for AREQ Cond (Handle) signal... (areqMsgProcessStatus = %d), effectively releasing lock\n", areqMsgProcessStatus); pthread_cond_wait(&npiLnxClientAREQcond, &npiLnxClientAREQmutex); debug_verbose_printf("[CLIENT HANDLE][MUTEX] AREQ (Handle) has lock\n"); // Walk through all received AREQ messages before releasing MUTEX areqMsg *searchList = npi_ipc_areq_proc_buf, *clearList; while (searchList != NULL) { debug_verbose_printf("\n\n[CLIENT HANDLE][DBG] Processing \t@ %p next \t@ %p\n", (void *)searchList, (void *)(searchList->nextMessage)); // Must remove command type before calling NPI_AsynchMsgCback searchList->message.subSys &= ~(RPC_CMD_TYPE_MASK); debug_verbose_printf("[CLIENT HANDLE][MUTEX] AREQ Calling NPI_AsynchMsgCback (Handle)...\n"); NPI_AsynchMsgCback((npiMsgData_t *)&(searchList->message)); debug_verbose_printf("[CLIENT HANDLE][MUTEX] AREQ (Handle) (message @ %p)...\n", (void *)searchList); clearList = searchList; // Set search list to next message searchList = searchList->nextMessage; // Free processed buffer if (clearList == NULL) { // Impossible error, must abort done = 1; printf("[CLIENT HANDLE][ERR] clearList buffer was already free\n"); break; } else { messageCount--; debug_verbose_printf("[CLIENT HANDLE][DBG] Clearing \t\t@ %p (processed %d messages)...\n", (void *)clearList, messageCount); memset(clearList, 0, sizeof(areqMsg)); free(clearList); } } debug_verbose_printf("[CLIENT HANDLE][MUTEX] AREQ Signal message(s) handled (Handle) (processed %d messages)...\n", messageCount); // Signal to the read thread that we're ready for more // pthread_cond_signal(&npiLnxClientAREQcond); areqMsgProcessStatus = NPI_MSG_AREQ_READY; debug_printf("[CLIENT HANDLE][DBG] Finished processing (processed %d messages)...\n", messageCount); } while (!done); return ptr; }