// This callback occurs when running as a listener and data is available. bool openavbMapNullRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen) { AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL); if (pMediaQ && pData) { U8 *pHdr = pData; media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ); if (pMediaQItem) { // Get the timestamp and place it in the media queue item. U32 timestamp = ntohl(*(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32])); openavbAvtpTimeSetToTimestamp(pMediaQItem->pAvtpTime, timestamp); // Set timestamp valid and timestamp uncertain flags openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TV1] & 0x01) ? TRUE : FALSE); openavbAvtpTimeSetTimestampUncertain(pMediaQItem->pAvtpTime, (pHdr[HIDX_AVTP_HIDE7_TU1] & 0x01) ? TRUE : FALSE); pMediaQItem->dataLen = 0; // Regardless of what is sent nullify the data to the interface. openavbMediaQHeadPush(pMediaQ); AVB_TRACE_LINE(AVB_TRACE_MAP_LINE); AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL); return TRUE; } else { AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL); return FALSE; // Media queue full } } AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL); return FALSE; }
/* Talker Listener thread function that talks primarily with the endpoint */ void* openavbTLThreadFn(void *pv) { AVB_TRACE_ENTRY(AVB_TRACE_TL); tl_state_t *pTLState = (tl_state_t *)pv; while (pTLState->bRunning) { AVB_TRACE_LINE(AVB_TRACE_TL_DETAIL); int endpointHandle = openavbEptClntOpenSrvrConnection(pTLState); if (endpointHandle == AVB_ENDPOINT_HANDLE_INVALID) { // error connecting to endpoint, already logged } else { pTLState->endpointHandle = endpointHandle; // Validate the AVB version for TL and Endpoint are the same before continuing pTLState->AVBVerState = OPENAVB_TL_AVB_VER_UNKNOWN; pTLState->bConnected = openavbEptClntRequestVersionFromServer(pTLState->endpointHandle); while (pTLState->bRunning && pTLState->bConnected && pTLState->AVBVerState == OPENAVB_TL_AVB_VER_UNKNOWN) { // Check for endpoint version message. Timeout in 50 msec. if (!openavbEptClntService(pTLState->endpointHandle, 50)) { AVB_LOG_WARNING("Lost connection to endpoint, will retry"); pTLState->bConnected = FALSE; pTLState->endpointHandle = 0; } } if (pTLState->AVBVerState == OPENAVB_TL_AVB_VER_INVALID) { AVB_LOG_ERROR("AVB core version is different than Endpoint AVB core version. Streams will not be started. Will reconnect to the endpoint and check again."); } if (pTLState->bConnected && pTLState->AVBVerState == OPENAVB_TL_AVB_VER_VALID) { if (pTLState->cfg.role == AVB_ROLE_TALKER) { openavbTLRunTalker(pTLState); } else { openavbTLRunListener(pTLState); } } // Close the endpoint connection. unless connection already gone in which case the socket could already be reused. if (pTLState->bConnected) { openavbEptClntCloseSrvrConnection(endpointHandle); pTLState->bConnected = FALSE; pTLState->endpointHandle = 0; } } if (pTLState->bRunning) { SLEEP(1); } } THREAD_JOINABLE(pTLState->TLThread); AVB_TRACE_EXIT(AVB_TRACE_TL); return NULL; }
// This talker callback will be called for each AVB observation interval. tx_cb_ret_t openavbMapNullTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen) { AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL); if (pMediaQ && pData && dataLen) { U8 *pHdr = pData; pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo; if (!pPvtData) { AVB_LOG_ERROR("Private mapping module data not allocated."); return TX_CB_RET_PACKET_NOT_READY; } media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE); if (pMediaQItem) { // PTP walltime already set in the interface module. Just add the max transit time. openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec); // Set timestamp valid flag if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) pHdr[HIDX_AVTP_HIDE7_TV1] |= 0x01; // Set else { pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01; // Clear } // Set timestamp uncertain flag if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime)) pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear *(U32 *)(&pHdr[HIDX_AVTP_TIMESPAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime)); pHdr[HIDX_OPENAVB_FORMAT8] = MAP_NULL_OPENAVB_FORMAT; pHdr[HIDX_OPENAVB_RESERVEDA8] = 0x00; pHdr[HIDX_OPENAVB_RESERVEDB8] = 0x00; pHdr[HIDX_OPENAVB_RESERVEDC8] = 0x00; *(U32 *)(&pHdr[HIDX_OPENAVB_FORMAT_SPEC32]) = 0x00000000; *dataLen = TOTAL_HEADER_SIZE; // No data openavbMediaQTailPull(pMediaQ); AVB_TRACE_LINE(AVB_TRACE_MAP_LINE); AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL); return TX_CB_RET_PACKET_READY; } else { AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL); return TX_CB_RET_PACKET_NOT_READY; // Media queue empty } } AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL); return TX_CB_RET_PACKET_NOT_READY; }
void openavbAcmpSMControllerStateMachine() { AVB_TRACE_ENTRY(AVB_TRACE_ACMP); openavb_acmp_InflightCommand_t *pInflightActive = NULL; // The inflight command for the current state openavb_acmp_sm_controller_state_t state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING; // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses. ACMP_SM_LOCK(); while (bRunning) { switch (state) { case OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING: AVB_TRACE_LINE(AVB_TRACE_ACMP); AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING"); openavbAcmpSMControllerVars.rcvdResponse = FALSE; // Calculate timeout for inflight commands // Start is a arbitrary large time out. struct timespec timeout; CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout); timeout.tv_sec += 60; // At most will timeout after 60 seconds // Look for soonest inflight command timeout openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight); while (node) { openavb_acmp_InflightCommand_t *pInflight = openavbListData(node); if ((openavbTimeTimespecCmp(&pInflight->timer, &timeout) < 0)) { timeout.tv_sec = pInflight->timer.tv_sec; timeout.tv_nsec = pInflight->timer.tv_nsec; } node = openavbListIterNext(openavbAcmpSMControllerVars.inflight); } ACMP_SM_UNLOCK(); U32 timeoutMSec = 0; struct timespec now; CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now); timeoutMSec = openavbTimeUntilMSec(&now, &timeout); SEM_ERR_T(err); SEM_TIMEDWAIT(openavbAcmpSMControllerSemaphore, timeoutMSec, err); ACMP_SM_LOCK(); if (!SEM_IS_ERR_NONE(err)) { if (SEM_IS_ERR_TIMEOUT(err)) { struct timespec now; CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now); // Look for a timed out inflight command openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight); while (node) { openavb_acmp_InflightCommand_t *pInflight = openavbListData(node); if ((openavbTimeTimespecCmp(&now, &pInflight->timer) >= 0)) { // Found a timed out command state = OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT; pInflightActive = pInflight; break; } node = openavbListIterNext(openavbAcmpSMControllerVars.inflight); } } } else { if (openavbAcmpSMControllerVars.doTerminate) { bRunning = FALSE; } else if (openavbAcmpSMControllerVars.rcvdResponse && memcmp(pRcvdCmdResp->controller_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) { // Look for a corresponding inflight command openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight); while (node) { openavb_acmp_InflightCommand_t *pInflight = openavbListData(node); if (pRcvdCmdResp->sequence_id == pInflight->command.sequence_id && pRcvdCmdResp->message_type == pInflight->command.message_type + 1) { // Found a corresponding command state = OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE; pInflightActive = pInflight; break; } node = openavbListIterNext(openavbAcmpSMControllerVars.inflight); } } break; case OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT: { AVB_TRACE_LINE(AVB_TRACE_ACMP); AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT"); if (pInflightActive) { if (pInflightActive->retried) { openavbAcmpSMController_removeInflight(&pInflightActive->command); } else { openavbAcmpSMController_txCommand(pInflightActive->command.message_type, &pInflightActive->command, TRUE); } } pInflightActive = NULL; state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING; } break; case OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE: { AVB_TRACE_LINE(AVB_TRACE_ACMP); AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE"); if (pInflightActive) { openavbAcmpSMController_cancelTimeout(pRcvdCmdResp); openavbAcmpSMController_processResponse(pRcvdCmdResp); openavbAcmpSMController_removeInflight(pRcvdCmdResp); } pInflightActive = NULL; state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING; } break; } } } ACMP_SM_UNLOCK(); AVB_TRACE_EXIT(AVB_TRACE_ACMP); }