/* Reads the next action from the script file, verify correctness and return its individual elements */ McpBtsSpStatus _MCP_BTS_SP_GetNextAction(McpBtsSpContext *context, McpU16 *actionDataActualLen, McpBtsSpScriptActionType *actionType, McpU8 *actionData, McpU16 actionDataMaxLen, McpBool *moreActions) { McpBtsSpStatus spStatus; MCP_BTS_SP_ScriptActionHeader actionHeader; /* Read the action header */ spStatus = _MCP_BTS_SP_ReadActionHeader(context, &actionHeader); if (spStatus != MCP_BTS_SP_STATUS_SUCCESS) { MCP_LOG_FATAL(("_MCP_BTS_SP_GetNextAction: Failed reading action header (%s)", _MCP_BTS_SP_DebugStatusStr(spStatus))); return spStatus; } /* Parse action header. The format is: [ToDo] How is the binary data represented? Do we need to handle endianity? */ *actionType = actionHeader.actionType; *actionDataActualLen = actionHeader.actionDataLen; /* Verify that actual action data len doesn't exceed the action data buffer max size */ if (*actionDataActualLen > actionDataMaxLen) { MCP_LOG_FATAL(("_MCP_BTS_SP_GetNextAction: Action Data is too long (%d), Max: %d.", *actionDataActualLen, actionDataMaxLen)); return MCP_BTS_SP_STATUS_INVALID_SCRIPT; } /* Read the action data */ spStatus = _MCP_BTS_SP_ReadScript(context, actionData, *actionDataActualLen); if (spStatus != MCP_BTS_SP_STATUS_SUCCESS) { MCP_LOG_FATAL(("_MCP_BTS_SP_GetNextAction: Failed reading action Data (%s)", _MCP_BTS_SP_DebugStatusStr(spStatus))); return spStatus; } /* If we completed reading the entire script it means there are no more actions (we just read the last one) */ if (context->scriptProcessingPos >= context->scriptSize) { *moreActions = MCP_FALSE; } else { *moreActions = MCP_TRUE; } return spStatus; }
void MCP_BTS_SP_HciCmdCompleted(McpBtsSpContext *context, McpU8 *eventParms, McpU8 eventParmsLen) { MCP_UNUSED_PARAMETER(eventParms); MCP_UNUSED_PARAMETER(eventParmsLen); /* [ToDo] The eventParms currentl doens't include the HCI opcode, event status, etc. Only the HCI return parms Need to see how to handle this in FMC_Transport */ #if 0 McpBtsSpStatus spStatus; /* Initialize to an invalid event status (in case there is no status available in the event parameters) */ McpBtsSpHciEventStatus eventStatus = (McpBtsSpHciEventStatus)0xFF; /* Extract event status from parms */ if (eventParmsLen >= MCP_BTS_SP_HCI_EVENT_STATUS_OFFSET) { eventStatus = eventParms[MCP_BTS_SP_HCI_EVENT_STATUS_OFFSET]; } if (eventType != MCP_BTS_SP_HCI_EVENT_COMMAND_COMPLETE) { MCP_LOG_FATAL(("MCP_BTS_SP_HciCmdCompleted: Unexpected HCI Event (%d), Status: %d", eventType, eventStatus)); _MCP_BTS_SP_CompleteExecution(context, MCP_BTS_SP_STATUS_EXECUTION_FAILED_UNEXPECTED_HCI_EVENT); return; } /* Now we know we have the expected command complete event */ /* verify that the command completed successfully */ if (eventStatus != MCP_BTS_SP_HCI_EVENT_STATUS_SUCCESS) { MCP_LOG_FATAL(("MCP_BTS_SP_HciCmdCompleted: Command completed unsuccessfully (%d)", eventStatus)); _MCP_BTS_SP_CompleteExecution(context, MCP_BTS_SP_STATUS_EXECUTION_FAILED_COMMAND_FAILED); return; } #endif /* [ToDo] - Pass the command complete status as the event data (instead of the 3rd argument) */ _MCP_BTS_SP_ProcessScriptCommands(context, MCP_BTS_SP_PROCESSING_EVENT_COMMAND_COMPLETE, NULL); }
/* This function is called to complete script execution from all possible execution paths. */ void _MCP_BTS_SP_CompleteExecution(McpBtsSpContext *context, McpBtsSpStatus executionStatus) { if (executionStatus == MCP_BTS_SP_STATUS_SUCCESS) { MCP_LOG_INFO(("_MCP_BTS_SP_CompleteExecution: SCRIPT EXECUTION SUCCESSFULLY COMPLETED")); } else if (executionStatus == MCP_BTS_SP_STATUS_EXECUTION_ABORTED) { MCP_LOG_INFO(("_MCP_BTS_SP_CompleteExecution: SCRIPT EXECUTION ABORTED")); } else { MCP_LOG_FATAL(("_MCP_BTS_SP_CompleteExecution: SCRIPT EXECUTION FAILED (%s)", _MCP_BTS_SP_DebugStatusStr(executionStatus))); } /* Close script file ([ToDo] - Memory scripts ) */ _MCP_BTS_SP_CloseScript(context); /* If execution completed asynchronously, notify the callback on execution completion status */ if (context->asyncExecution == MCP_TRUE) { (context->cbData.execCompleteCb)(context, executionStatus); } }
/* This function is called when transport on failed */ _CcmImStatus _CCM_IM_BtTranSm_HandlerTranOnFailed(_CcmIm_BtTranSm_Obj *thisObj, void *eventData) { MCP_UNUSED_PARAMETER(eventData); MCP_LOG_FATAL(("_CCM_IM_BtTranSm_HandlerTranOnFailed: Tran On Failed")); return _CCM_IM_BtTranSm_PerformCompletion(thisObj, _CCM_IM_BT_TRAN_SM_COMPLETED_EVENT_TRAN_ON_COMPLETED, _CCM_IM_STATUS_FAILED); }
McpBtsSpStatus _MCP_BTS_SP_ProcessNextScriptAction(McpBtsSpContext *context, McpBool *moreActions) { McpBtsSpStatus spStatus; McpBtsSpScriptActionDataLenType actionDataActualLen; McpBtsSpScriptActionType actionType; /* [ToDo] - Check the need for the mopreCommand and its usage This condition should be true when the script contains no actions (just a header) => the test may be moved elsewhere, and tested only once, after reading the header */ if (context->scriptProcessingPos >= context->scriptSize) { *moreActions = MCP_FALSE; return MCP_BTS_SP_STATUS_SUCCESS; } /* Read next action from script and parse it */ spStatus = _MCP_BTS_SP_GetNextAction(context, &actionDataActualLen, &actionType, context->scriptActionData, MCP_BTS_SP_MAX_SCRIPT_ACTION_DATA_LEN, moreActions); if (spStatus != MCP_BTS_SP_STATUS_SUCCESS) { MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessNextScriptAction: _MCP_BTS_SP_GetNextAction Failed (%s)", _MCP_BTS_SP_DebugStatusStr(spStatus))); return spStatus; } /* Handle actions according to their type */ /* [ToDo] Detect the case where 2 commands are sent without waiting for an event in-between */ switch (actionType) { case MCP_BTS_SP_SCRIPT_ACTION_SEND_COMMAND: { /* Prepare Send HCI Command parameters */ /* [ToDo] Define HCI command structure / define symbolic constants for offsets */ McpU8 hciParmLen = context->scriptActionData[3]; McpU16 hciOpcode; McpU8 *hciParms = &context->scriptActionData[4]; /*[ToDo Zvi] We should use utils general function here */ hciOpcode = (McpU16)( ((McpU16) *(&context->scriptActionData[1]+1) << 8) | ((McpU16) *&context->scriptActionData[1]) ); /* Send the HCI command via the client's supplied callback function */ spStatus = (context->cbData.sendHciCmdCb)( context, hciOpcode, hciParms, hciParmLen); /* We return pending only when waiting for a command complete. Otherwise, we should be called again by the caller of this function */ if (spStatus == MCP_BTS_SP_STATUS_PENDING) { spStatus = MCP_BTS_SP_STATUS_SUCCESS; } else { /* [ToDo] - FATAL may be too severe as an uncoditional handling of errors */ MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessNextScriptAction: Failed sending HCI Command via the callback (%d)", _MCP_BTS_SP_DebugStatusStr(spStatus))); } } break; case MCP_BTS_SP_SCRIPT_ACTION_WAIT_FOR_COMMAND_COMPLETE: /* Nothing more to do, wait for client to call MCP_BTS_SP_HciCmdCompleted to continue processing */ spStatus = MCP_BTS_SP_STATUS_PENDING; break; /* Invalid action for Software scripts */ case MCP_BTS_SP_SCRIPT_ACTION_SERIAL_PORT_PARMS: { MCP_BTS_SP_ActionSerialPortParameters *pParams = (MCP_BTS_SP_ActionSerialPortParameters *)&context->scriptActionData[0]; spStatus = (context->cbData.setTranParmsCb)(context, pParams->baudRate, pParams->flowControl); if (spStatus != MCP_BTS_SP_STATUS_SUCCESS) { /* [ToDo] - FATAL may be too severe as an uncoditional handling of errors */ MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessNextScriptAction: Setting Speed Callback Failed (%d)", _MCP_BTS_SP_DebugStatusStr(spStatus))); } } break; /* Invalid action for Software scripts */ case MCP_BTS_SP_SCRIPT_ACTION_RUN_SCRIPT: MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessNextScriptAction: Run Script action Disallowed in BTS File")); spStatus = MCP_BTS_SP_STATUS_INVALID_SCRIPT; break; case MCP_BTS_SP_SCRIPT_ACTION_SLEEP: { /* Delay action - sleep for the specified amount of time */ MCP_BTS_SP_ActionSleep *pParams = (MCP_BTS_SP_ActionSleep*)&context->scriptActionData[0]; MCP_HAL_OS_Sleep(pParams->nDurationInMillisec); } break; case MCP_BTS_SP_SCRIPT_ACTION_REMARK: /* Nothing to do */ spStatus = MCP_BTS_SP_STATUS_SUCCESS; break; /* Invalid action type detected */ default: MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessNextScriptAction: Invalid Action (%d) in BTS File", actionType)); spStatus = MCP_BTS_SP_STATUS_INVALID_SCRIPT; break; } return spStatus; }
/* The main state machine of the script processor */ McpBtsSpStatus _MCP_BTS_SP_ProcessScriptCommands(McpBtsSpContext *context, McpBtsSpProcessingEvent processingEvent, void *eventData) { McpBtsSpStatus spStatus = MCP_BTS_SP_STATUS_SUCCESS; McpBool keepProcessing; MCP_UNUSED_PARAMETER(eventData); MCP_LOG_INFO(("_MCP_BTS_SP_ProcessScriptCommands: Processing Event: %d", processingEvent)); keepProcessing = MCP_TRUE; while ((keepProcessing == MCP_TRUE) && (context->abortRequested == MCP_FALSE)) { keepProcessing = MCP_FALSE; MCP_LOG_INFO(("_MCP_BTS_SP_ProcessScriptCommands: State = %d", context->processingState)); switch (context->processingState) { case MCP_BTS_SP_PROCESSING_STATE_NONE: if (processingEvent == MCP_BTS_SP_PROCESSING_EVENT_START) { context->processingState = MCP_BTS_SP_PROCESSING_STATE_PROCESS_NEXT_ACTION; } else { MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessScriptCommands: Unexpected Processing Event (%d)", processingEvent)); context->processingState = MCP_BTS_SP_PROCESSING_STATE_DONE; spStatus = MCP_BTS_SP_STATUS_INTERNAL_ERROR; } keepProcessing = MCP_TRUE; break; case MCP_BTS_SP_PROCESSING_STATE_PROCESS_NEXT_ACTION: { McpBool moreActions; /* Process next script action as long as we do not have to wait for a command complete event */ do { spStatus = _MCP_BTS_SP_ProcessNextScriptAction(context, &moreActions); } while ((spStatus == MCP_BTS_SP_STATUS_SUCCESS) && (moreActions == MCP_TRUE)); /* [ToDo] - Handle the case of the last actio in the script being a "Send Command" (illegal) */ if (spStatus == MCP_BTS_SP_STATUS_PENDING) { /* The first time we wait for a command complete event we will record that fact */ context->asyncExecution = MCP_TRUE; /* */ if (moreActions == MCP_TRUE) { context->processingState = MCP_BTS_SP_PROCESSING_STATE_WAIT_FOR_COMMAND_COMPLETE; } else { context->processingState = MCP_BTS_SP_PROCESSING_STATE_WAIT_FOR_LAST_COMMAND_COMPLETE; } } else { /* We get here in 2 cases: 1. script processing error 2. Last script action was not a "Send Command" action In that case we terminate. spStatus stores the completion status */ context->processingState = MCP_BTS_SP_PROCESSING_STATE_DONE; keepProcessing = MCP_TRUE; } } break; case MCP_BTS_SP_PROCESSING_STATE_WAIT_FOR_COMMAND_COMPLETE: if (processingEvent == MCP_BTS_SP_PROCESSING_EVENT_COMMAND_COMPLETE) { context->processingState = MCP_BTS_SP_PROCESSING_STATE_PROCESS_NEXT_ACTION; } else { MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessScriptCommands: Unexpected Processing Event (%d)", processingEvent)); context->processingState = MCP_BTS_SP_PROCESSING_STATE_DONE; spStatus = MCP_BTS_SP_STATUS_INTERNAL_ERROR; } keepProcessing = MCP_TRUE; break; case MCP_BTS_SP_PROCESSING_STATE_WAIT_FOR_LAST_COMMAND_COMPLETE: if (processingEvent == MCP_BTS_SP_PROCESSING_EVENT_COMMAND_COMPLETE) { spStatus = MCP_BTS_SP_STATUS_SUCCESS; context->processingState = MCP_BTS_SP_PROCESSING_STATE_DONE; } else { MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessScriptCommands: Unexpected Processing Event (%d)", processingEvent)); context->processingState = MCP_BTS_SP_PROCESSING_STATE_DONE; spStatus = MCP_BTS_SP_STATUS_INTERNAL_ERROR; } keepProcessing = MCP_TRUE; break; case MCP_BTS_SP_PROCESSING_STATE_DONE: MCP_LOG_INFO(("_MCP_BTS_SP_ProcessScriptCommands: Completed (%s)", _MCP_BTS_SP_DebugStatusStr(spStatus))); _MCP_BTS_SP_CompleteExecution(context, spStatus); break; default: MCP_LOG_FATAL(("_MCP_BTS_SP_ProcessScriptCommands: Invalid Processing State (%s)", context->processingState)); context->processingState = MCP_BTS_SP_PROCESSING_STATE_DONE; spStatus = MCP_BTS_SP_STATUS_INTERNAL_ERROR; keepProcessing = MCP_TRUE; } } if (context->abortRequested == MCP_TRUE) { _MCP_BTS_SP_CompleteExecution(context, MCP_BTS_SP_STATUS_EXECUTION_ABORTED); } return spStatus; }