mirror of
				https://github.com/RangeNetworks/openbts.git
				synced 2025-11-04 05:43:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**@file Declarations for Circuit Switched State Machine and related classes. */
 | 
						|
/*
 | 
						|
* Copyright 2013 Range Networks, Inc.
 | 
						|
*
 | 
						|
* This software is distributed under multiple licenses;
 | 
						|
* see the COPYING file in the main directory for licensing
 | 
						|
* information for this specific distribuion.
 | 
						|
*
 | 
						|
* This use of this software may be subject to additional restrictions.
 | 
						|
* See the LEGAL file in the main directory for details.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
// TODO: To avoid bugs where the state machines get stuck,
 | 
						|
// send a HARDRELEASE from L3 when mT3109 expires, which is the uplink activity counter in XCCHL1Decoder,
 | 
						|
// which is used for TCHFACCHL1Decoder, SDDCHL1Decoder and SACCHL1Decoder.
 | 
						|
// Technique is similar to: if (mUpstream!=NULL) mUpstream->writeLowSide(L2Frame(ESTABLISH));
 | 
						|
// Currently, the TCH handler in Control dir polls radioFailure() which eventually checks mT3109.
 | 
						|
// For SDCCH, the ch just gets reused after mT3109 expiry, and L3 is not notified - we just hope it is no longer in use after 30s.
 | 
						|
 | 
						|
 | 
						|
#ifndef CSL3STATEMACHINE_H
 | 
						|
#define CSL3STATEMACHINE_H
 | 
						|
 | 
						|
#include <map>
 | 
						|
 | 
						|
#include <Logger.h>
 | 
						|
#include <Interthread.h>
 | 
						|
#include <Timeval.h>
 | 
						|
 | 
						|
 | 
						|
#include <GSMTransfer.h>
 | 
						|
#include "ControlCommon.h"
 | 
						|
#include "L3Utils.h"
 | 
						|
//#include <GSML3CommonElements.h>
 | 
						|
//#include <GSML3MMElements.h>
 | 
						|
//#include <GSML3CCElements.h>
 | 
						|
//#include <GSML3Message.h>		// Doesnt this poor L3Message get lonely?  When apparently there are multiple L3MMMessages and L3CCMessages?
 | 
						|
#include <GSML3MMMessages.h>
 | 
						|
#include <GSML3CCMessages.h>
 | 
						|
#include <GSML3RRMessages.h>
 | 
						|
//#include <SIPDialog.h>
 | 
						|
namespace SIP { class SipDialog; };
 | 
						|
 | 
						|
// These are only for use inside state machines:
 | 
						|
#define PROCLOG(level) LOG(level)<<machText()
 | 
						|
#define PROCLOG2(level,state) LOG(level) <<LOGHEX(state)<<machText()<<" "
 | 
						|
 | 
						|
namespace Control {
 | 
						|
using namespace GSM;
 | 
						|
class TranEntry;
 | 
						|
class MMContext;
 | 
						|
extern void L3DCCHLoop(L3LogicalChannel*dcch, L3Frame *frame);
 | 
						|
 | 
						|
#if UNUSED_BUT_SAVE_FOR_UMTS
 | 
						|
typedef InterthreadQueue<GenericL3Msg> CSL3StateMachineFifo;
 | 
						|
#endif
 | 
						|
 | 
						|
// This is a return state from a state machine.
 | 
						|
 | 
						|
struct MachineStatus {
 | 
						|
	// There are only 4 things a state machine procedure can do on return.
 | 
						|
	// Any error returns have to map to one of these four.
 | 
						|
	enum MachineStatusCode {
 | 
						|
		MachineCodeOK,			// continue the procedure, meaning return to L3 message handler and wait for the next message.
 | 
						|
		MachineCodePopMachine,	// return to previous procedure on stack
 | 
						|
		MachineCodeQuitTran,		// Pop all machines from stack and remove the transaction.  This is the normal exit from a completed procedure.
 | 
						|
		// NOTE: MachineCodeQuitChannel does not close the channel - The user must call closeChannel or equivalent first.
 | 
						|
		MachineCodeQuitChannel,		// Drop the channel, which kills all transactions on this channel.
 | 
						|
		// All these others are error conditions.  They all terminate like MachineCodeQuit, but they are different
 | 
						|
		// so we can print a more informative diagnostic message.
 | 
						|
		//MachineCodeUnexpectedMessage,	// The MS sent a message that was not anticipated by the state machine running the Transaction.
 | 
						|
		//MachineCodeUnexpectedPrimitive,	/** Thrown when the control layer gets the wrong primitive */	// Not sure this happens.
 | 
						|
		MachineCodeUnexpectedState,		// Unexpected message or state was not handled by the current state machine.
 | 
						|
		//MachineCodeAuthorizationFail,	// Self explanatory.
 | 
						|
	};
 | 
						|
	MachineStatusCode mCode;
 | 
						|
	//GSM::RRCause mRRCause;
 | 
						|
	//string mSomeMessage;
 | 
						|
	bool operator==(MachineStatus &other) { return mCode == other.mCode; }
 | 
						|
	bool operator!=(MachineStatus &other) { return mCode != other.mCode; }
 | 
						|
	MachineStatus(MachineStatusCode code) { mCode = code; /*mRRCause = GSM::L3RRCause::NormalEvent;*/ }
 | 
						|
 | 
						|
};
 | 
						|
std::ostream& operator<<(std::ostream& os, MachineStatus::MachineStatusCode state);
 | 
						|
 | 
						|
// These ones have no arguments so they might as well be constants.
 | 
						|
extern MachineStatus MachineStatusOK, MachineStatusPopMachine, MachineStatusQuitTran, MachineStatusQuitChannel, MachineStatusAuthorizationFail;
 | 
						|
extern MachineStatus MachineStatusAuthorizationFail, MachineStatusUnexpectedState;
 | 
						|
 | 
						|
 | 
						|
struct MachineStatusQuitTran : MachineStatus {
 | 
						|
	//MachineStatusQuitTran(GSM::CCCause wcause) : MachineStatus(MachineCodeQuitTran) { mCCCause = wCCcause; }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
// A base class for the individual Procedure state machines.
 | 
						|
// Formerly this contained state so had to be unique for each state machine.
 | 
						|
DEFINE_MEMORY_LEAK_DETECTOR_CLASS(MachineBase,MemCheckMachineBase)
 | 
						|
class MachineBase : public MemCheckMachineBase
 | 
						|
{
 | 
						|
	friend class TranEntry;
 | 
						|
	friend class ProcCommon;
 | 
						|
	protected:
 | 
						|
	int mPopState; // If we push into a procedure, save the return location here.
 | 
						|
	public:
 | 
						|
	// Args are the L3Procedure we are calling and the state in the current procedure to which we will return when nextProcedure is popped.
 | 
						|
	MachineStatus machPush( MachineBase*wCalledProcedure, int wNextState);
 | 
						|
 | 
						|
	// The one and only TranEntry that is running this procedure.
 | 
						|
	// The CallHold and CallWaiting will have multiple TransactionEntries and multiple procedures.
 | 
						|
	private: TranEntry *mTran;
 | 
						|
 | 
						|
	// No TranEntry yet?  Then no L3Procedure can be started.
 | 
						|
	protected:
 | 
						|
	MachineBase(TranEntry *wTran): mTran(wTran) {
 | 
						|
		mPopState = 0;		// unnecessary but neat.
 | 
						|
	}
 | 
						|
	void setTran(TranEntry *wTran) { mTran = wTran; }
 | 
						|
	TranEntry *tran() const { return mTran; }
 | 
						|
	MMContext *getContext() const;
 | 
						|
	MachineBase *currentProcedure() { return this; }
 | 
						|
 | 
						|
	MachineStatus callMachStart(MachineBase* wProc, unsigned startState=0);
 | 
						|
 | 
						|
	void timerStart(L3TimerId tid, unsigned val, int nextState);	// Executes nextState on expiry.
 | 
						|
	void timerStop(L3TimerId tid);
 | 
						|
	void timerStopAll();
 | 
						|
	bool timerExpired(L3TimerId tid);		// Is it expired?
 | 
						|
 | 
						|
	public:
 | 
						|
	virtual ~MachineBase() {}	// Must be virtual to allow derived L3Procedures to delete themselves properly.
 | 
						|
	void machText(std::ostream&) const;
 | 
						|
	string machText() const;
 | 
						|
 | 
						|
	// accessors
 | 
						|
	L3LogicalChannel *channel() const; 	// may be SDCCH or FACCH.
 | 
						|
	CallState getGSMState() const;
 | 
						|
	void setGSMState(CallState);
 | 
						|
	SIP::SipDialog *getDialog() const;
 | 
						|
	void setDialog(SIP::SipDialog*dialog);
 | 
						|
	unsigned getL3TI() const;
 | 
						|
	bool isL3TIValid() const;
 | 
						|
	virtual const char *debugName() const = 0;
 | 
						|
	MachineStatus unexpectedState(int state, const L3Message*l3msg);
 | 
						|
	MachineStatus closeChannel(L3RRCause cause,Primitive prim);
 | 
						|
	void machineErrorMessage(int level, int state, const L3Message *l3msg, const SIP::DialogMessage *sipmsg, const char *format);
 | 
						|
 | 
						|
	virtual void handleTerminationRequest() {}	// Procedure can over-ride this to do nicer cleanup.
 | 
						|
 | 
						|
	// Methods for Procedure States.
 | 
						|
	// The primary entry point for the state machine at the specified state.
 | 
						|
	// State 0 is always reserved as the initial start state.
 | 
						|
	// If this invocation is due to a message arrival, it is included as an argument.
 | 
						|
	// The other possibilities are: timeout, popProcedure, or initial invocation in state 0.
 | 
						|
 | 
						|
	// The state machine must implement one of the following methods, depending on how much control it wants over its input.
 | 
						|
	virtual MachineStatus machineRunState(int state, const GSM::L3Message *l3msg=NULL, const SIP::DialogMessage *sipmsg=NULL);
 | 
						|
	virtual MachineStatus machineRunState1(int state, const GSM::L3Frame *frame=NULL, const GSM::L3Message *l3msg=NULL, const SIP::DialogMessage *sipmsg=NULL);
 | 
						|
 | 
						|
	//virtual MachineStatus procRunSipMsg(const SIP::DialogMessage *sipmsg) = 0;
 | 
						|
 | 
						|
	MachineStatus dispatchSipDialogMsg(const SIP::DialogMessage *msg);
 | 
						|
	MachineStatus dispatchL3Msg(const GSM::L3Message *msg);
 | 
						|
	MachineStatus dispatchTimeout(L3Timer *timer);
 | 
						|
	MachineStatus dispatchFrame(const L3Frame *frame, const L3Message *l3msg);
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
#if UNUSED_BUT_SAVE_FOR_UMTS
 | 
						|
// TODO: This class could go away.  I am keeping it around to see if it is useful for UMTS.
 | 
						|
// This is the outer layer state machine to process CS L3 Messages.
 | 
						|
// CS [Circuit Switched] L3 messages are specified in 3GPP 4.08, as opposed to PS [Packet Switched] L3 messages handled by the SGSN.
 | 
						|
// This is part of the L3 rewrite.
 | 
						|
class CSL3StateMachine
 | 
						|
{
 | 
						|
	CSL3StateMachineFifo mCSL3Fifo;
 | 
						|
	Thread* mCSL3Thread;
 | 
						|
 | 
						|
	public:
 | 
						|
	CSL3StateMachine();
 | 
						|
	//void csl3ServiceLoop();
 | 
						|
	//void csl3Start();
 | 
						|
	// Put a message on the queue of messages to process.
 | 
						|
	//bool csl3Write(GenericL3Msg *msg);		// return TRUE if the message was handled.
 | 
						|
};
 | 
						|
extern CSL3StateMachine gCSL3StateMachine;
 | 
						|
#endif
 | 
						|
 | 
						|
};	// namespace Control
 | 
						|
 | 
						|
#endif
 | 
						|
 |