Example #1
0
// 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;
}
Example #3
0
// 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);
}