/*************************************************************************** * Copyright (c) 2003-2008, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: message filtering module * ***************************************************************************/ #include "bapp_task.h" #include "bapp_util.h" #include "bsettop_smessage.h" #include "nexus_pid_channel.h" #include "nexus_parser_band.h" #include "nexus_message.h" #include "nexus_memory.h" BDBG_MODULE(smsg); #define MSG_VERBOSE 0 #if MSG_VERBOSE & 1 #define BDBG_MSG_1(x) BDBG_MSG(x) #else #define BDBG_MSG_1(x) BDBG_NOP() #endif #define MAX_PIDS 24 #define MAX_FILTERS 24 #define START_PID_CHANNEL 8 #define B_INVALID_PID 0xFFFF #define B_INVALID_PID_CHANNEL SMESSAGE_INVALID_CHANNEL #define B_INVALID_BAND ((int)(-1)) #define FILTER_SIZE 16 #define TS_PACKET_SIZE 188 #define SM_MAGIC 0xBADBABE0 #define SM_BUFFER_SIZE (188 * 512) #define SM_WAIT (-1) #define SM_POLL_INTERVAL 50 #define MAX_CAP 4 #define FILTER_CAP 0 enum sm_task_state_t { STS_DONE, STS_RUN }; struct smessage_stream { BLST_S_ENTRY(smessage_stream) next; struct smessage_pid * sm_pid; smessage_callback callback; smessage_callback overflow; void * context; void *priv; uint16_t pid; NEXUS_PidChannelHandle pidChannel; NEXUS_MessageHandle msg; NEXUS_MessageStartSettings startSettings; void * buffer; size_t buffer_size; smessage_format format; }; BLST_S_HEAD(smessage_stream_list_t, smessage_stream); struct smessage_state { uint32_t magic; int band; bapp_task_t task; bapp_task_mutex_t lock; enum sm_task_state_t task_state; struct smessage_stream_list_t free_filter; struct smessage_stream_list_t started_filter; struct smessage_stream sm[MAX_FILTERS]; }; static struct smessage_state sm_st; #define SM_STACK_SIZE 0x400 #define SM_PRIORITY 16 static uint32_t sm_stack[SM_STACK_SIZE]; static char * sm_task_name = "msg"; static void bsettop_smessage_parser_task(void * param); /* Summary: Initialize the message system. */ bresult smessage_init(void *data) { int i; bapp_task_params t_param; bapp_result_t bres = eBAPP_RESULT_OK; BAPP_UNUSED(data); BDBG_MSG_1(("%s", __PRETTY_FUNCTION__)); memset(&sm_st, 0, sizeof(struct smessage_stream)); BLST_S_INIT(&sm_st.free_filter); BLST_S_INIT(&sm_st.started_filter); for (i = 0; i < MAX_FILTERS; i ++) { BLST_S_INSERT_HEAD(&sm_st.free_filter, &sm_st.sm[i], next); } bres = bapp_task_create_mutex(&sm_st.lock); if (eBAPP_RESULT_OK != bres) { goto ExitFunc; } sm_st.task_state = STS_RUN; t_param.priority = SM_PRIORITY; t_param.stack_size = SM_STACK_SIZE; t_param.stack = sm_stack; t_param.name = sm_task_name; bres = bapp_task_start_task(&sm_st.task, &t_param, bsettop_smessage_parser_task, NULL); sm_st.magic = SM_MAGIC; ExitFunc: return bres; } /* Summary: Cleanup the messages system */ bresult smessage_uninit(void) { sm_st.magic = 0; return eBAPP_RESULT_OK; } /* Summary: Open a message stream for a particular format of data */ smessage_stream_t smessage_open(smessage_format format) { smessage_stream_t st; bapp_result_t result = eBAPP_RESULT_FAILURE; st = NULL; switch (format) { case smessage_format_ts: break; case smessage_format_tsc: case smessage_format_psi: result = bapp_task_acquire_mutex(sm_st.lock, SM_WAIT); if (eBAPP_RESULT_OK != result) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); break; } st = BLST_S_FIRST(&sm_st.free_filter); if (NULL != st) { BLST_S_REMOVE_HEAD(&sm_st.free_filter, next); st->format = format; bapp_task_release_mutex(sm_st.lock); } else { BDBG_ERR(("%s:%d st - NULL",__FILE__, __LINE__)); bapp_task_release_mutex(sm_st.lock); } default: break; } return st; } /* Summary: Close a message stream */ void smessage_close(smessage_stream_t stream) { bapp_result_t result = eBAPP_RESULT_FAILURE; result = smessage_stop(stream); if (eBAPP_RESULT_OK != result) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); } BLST_S_INSERT_HEAD(&sm_st.free_filter, stream, next); } /* Summary: Initialize parameters structure */ void smessage_stream_params_init( smessage_stream_params_t *params, smessage_stream_t stream) { int i; BAPP_UNUSED(stream); if (NULL != params) { memset(params, 0, sizeof(smessage_stream_params_t)); params->band = B_INVALID_BAND; params->pid = B_INVALID_PID; params->pid_channel = B_INVALID_PID_CHANNEL; for (i = 0; i < FILTER_SIZE; i++) { params->filter.mask[i] = 0xFF; params->filter.excl[i] = 0xFF; } } } /* Summary: Capture message according to the parameters */ bresult smessage_start(const smessage_stream_params_t * params, smessage_stream_t stream) { bapp_result_t result = eBAPP_RESULT_FAILURE; NEXUS_ParserBandSettings parserBandSettings; NEXUS_MessageSettings settings; NEXUS_MemoryAllocationSettings memSettings; NEXUS_PidChannelSettings pidChannelSettings; BDBG_ASSERT(NULL != stream); BDBG_ASSERT(NULL != params); BDBG_ASSERT(params->buffer); if (((stream->format != smessage_format_psi) && (stream->format != smessage_format_tsc) ) || (B_INVALID_BAND == params->band) || (NULL != stream->msg) || (NULL != stream->pidChannel) || (0 == params->buffer_size)) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); BDBG_ERR(("stream->msg = 0x%08x",stream->msg)); BDBG_ERR(("stream->pidChannel = 0x%08x",stream->pidChannel)); BDBG_ERR(("params->pid = 0x%08x",params->pid)); BDBG_ERR(("stream->format = %d",stream->format)); BDBG_ERR(("params->band = %d",params->band)); BDBG_ERR(("params->buffer_size = %d",params->buffer_size)); goto ExitFunc; } NEXUS_Memory_GetDefaultAllocationSettings(&memSettings); result = bapp_task_acquire_mutex(sm_st.lock, SM_WAIT); if (eBAPP_RESULT_OK != result) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); goto ExitFunc; } NEXUS_ParserBand_GetSettings((NEXUS_ParserBand)params->band, &parserBandSettings); parserBandSettings.sourceType = NEXUS_ParserBandSourceType_eInputBand; NEXUS_ParserBand_SetSettings((NEXUS_ParserBand)params->band, &parserBandSettings); stream->pid = params->pid; NEXUS_PidChannel_GetDefaultSettings(&pidChannelSettings); stream->pidChannel = NEXUS_PidChannel_Open((NEXUS_ParserBand)params->band, params->pid, &pidChannelSettings); if (stream->pidChannel == NULL) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); goto ExitUnlock; } NEXUS_Message_GetDefaultSettings(&settings); settings.maxContiguousMessageSize = 4096; settings.bufferSize = 0; /* don't have Message alloc the buffer. recommended for maximum flexibility. */ stream->msg = NEXUS_Message_Open(&settings); NEXUS_Message_GetDefaultStartSettings(stream->msg, &stream->startSettings); memSettings.alignment = 4; if (NEXUS_Memory_Allocate(params->buffer_size,&memSettings,&stream->startSettings.buffer) != BERR_SUCCESS) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); NEXUS_Message_Close(stream->msg); stream->msg = NULL; goto ExitUnlock; } stream->buffer = params->buffer; stream->startSettings.bufferSize = params->buffer_size; switch (stream->format) { case smessage_format_tsc: stream->startSettings.format = NEXUS_MessageFormat_eTs; break; case smessage_format_psi: default: stream->startSettings.format = NEXUS_MessageFormat_ePsi; break; } stream->startSettings.psfCrcDisabled = true; /* disable CRC check on short packets */ stream->buffer_size = params->buffer_size; /* use the default filter for any data */ memcpy(stream->startSettings.filter.coefficient, params->filter.coef, FILTER_SIZE); memcpy(stream->startSettings.filter.mask, params->filter.mask, FILTER_SIZE); memcpy(stream->startSettings.filter.exclusion, params->filter.excl, FILTER_SIZE); stream->startSettings.pidChannel = stream->pidChannel; if (NEXUS_Message_Start(stream->msg, &stream->startSettings) != NEXUS_SUCCESS) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); NEXUS_Message_Close(stream->msg); stream->msg = NULL; NEXUS_Memory_Free(stream->startSettings.buffer); stream->startSettings.buffer = NULL; goto ExitUnlock; } stream->callback = params->data_ready_callback; stream->overflow = params->overflow; stream->context = params->callback_context; stream->priv = params->priv; BLST_S_INSERT_HEAD(&sm_st.started_filter, stream, next); result = eBAPP_RESULT_OK; ExitUnlock: if (eBAPP_RESULT_OK != bapp_task_release_mutex(sm_st.lock)) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); } ExitFunc: return result; } bresult smessage_stop(smessage_stream_t stream) { bapp_result_t result = eBAPP_RESULT_FAILURE; BDBG_ASSERT(NULL != stream); result = bapp_task_acquire_mutex(sm_st.lock, SM_WAIT); if (eBAPP_RESULT_OK != result) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); goto ExitFunc; } if (stream->msg == NULL) /* Already closed */ { if (eBAPP_RESULT_OK != bapp_task_release_mutex(sm_st.lock)) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); } return eBAPP_RESULT_OK; } if (stream->pidChannel != NULL) /* Already closed */ { NEXUS_PidChannel_Close(stream->pidChannel); stream->pidChannel = NULL; } if (stream->msg) { NEXUS_Message_Stop(stream->msg); NEXUS_Message_Close(stream->msg); stream->msg = NULL; } if (stream->startSettings.buffer) { NEXUS_Memory_Free(stream->startSettings.buffer); stream->startSettings.buffer = NULL; } BLST_S_REMOVE(&sm_st.started_filter, stream, smessage_stream, next); result = eBAPP_RESULT_OK; if (eBAPP_RESULT_OK != bapp_task_release_mutex(sm_st.lock)) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); } ExitFunc: return result; } bresult smessage_get_buffer(smessage_stream_t stream, const void ** pbuffer, size_t * plength) { bapp_result_t result; result = bapp_task_acquire_mutex(sm_st.lock, SM_WAIT); if (eBAPP_RESULT_OK != result) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); goto ExitFunc; } if (NEXUS_Message_GetBuffer(stream->msg, (const void **)pbuffer, plength) != NEXUS_SUCCESS) { result = eBAPP_RESULT_FAILURE; } if (eBAPP_RESULT_OK != bapp_task_release_mutex(sm_st.lock)) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); } ExitFunc: return result; } bresult smessage_read_complete(smessage_stream_t stream, size_t consumed) { bapp_result_t result; result = bapp_task_acquire_mutex(sm_st.lock, SM_WAIT); if (eBAPP_RESULT_OK != result) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); goto ExitFunc; } NEXUS_Message_ReadComplete(stream->msg, consumed); if (eBAPP_RESULT_OK != bapp_task_release_mutex(sm_st.lock)) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); } ExitFunc: return result; } static void DBG_HEXDUMP(unsigned char* ptr, unsigned long len) { unsigned long i; for (i=0; icallback || !stream->buffer) continue; size = 0; if (NEXUS_Message_GetBuffer(stream->msg, (const void **)&buffer, &size) == NEXUS_SUCCESS) { if (size <= 0) continue; /* BDBG_ERR(("%s:%d(0x%08x,%d)",__FILE__, __LINE__,buffer,size)); DBG_HEXDUMP(buffer,size); */ bapp_util_memcpy(stream->buffer,buffer,size); /* use the app-allocated buffer. */ stream->buffer = stream->callback(stream->context,size); NEXUS_Message_ReadComplete(stream->msg, size); if (stream->buffer == NULL) { bapp_task_release_mutex(sm_st.lock); smessage_stop(stream); if (bapp_task_acquire_mutex(sm_st.lock, SM_WAIT) != eBAPP_RESULT_OK) { BDBG_ERR(("%s:%d",__FILE__, __LINE__)); break; } } } } bapp_task_release_mutex(sm_st.lock); bapp_task_sleep(SM_POLL_INTERVAL); } }