using System;
using Microsoft.SPOT;

using Microsoft.SPOT.Hardware;

using System.Text;
using System.Threading;
using CPF.Profile_States;
using HWModules;
using SensorModules;
using SWModules;

namespace CPF
{
    abstract public class StateBase
    {
        private static TimeSpan SMCyclePeriod;
        private static int SMCycleSleepPeriod;
        //Delay for missionConfig.smCyclePeriod
        public static void StateMachinePacer(TimeSpan SMCycleStartTime)
        {
            SMCyclePeriod = Microsoft.SPOT.Hardware.Utility.GetMachineTime() - SMCycleStartTime;
            if (SMCyclePeriod < MissionConfig.smCyclePeriod)
            {
                SMCycleSleepPeriod = (int)((MissionConfig.smCyclePeriod.Ticks - SMCyclePeriod.Ticks) / TimeSpan.TicksPerMillisecond);

                if (SMCycleSleepPeriod < 700)
                {
                    sbTemp.Clear();
                    sbTemp.Append("State Machine Pacer Warning ^SP: ");
                    sbTemp.Append(SMCycleSleepPeriod);
                    EngrLogger.writeToColumns(sbTemp);
                }

                if (SMCycleSleepPeriod < 0)
                    SMCycleSleepPeriod = 0;
                if (SMCycleSleepPeriod > MissionConfig.smCyclePeriodMilliseconds)
                    SMCycleSleepPeriod = MissionConfig.smCyclePeriodMilliseconds;

                Thread.Sleep(SMCycleSleepPeriod);
            }
            else if (SMCyclePeriod > MissionConfig.smCyclePeriod)
            {
                if (SV.CurrentState == CPFStates.initMission) return;
                sbTemp.Clear();
                sbTemp.Append("Warning: State machine cycle time exceeded SMCyclePeriod = ");
                sbTemp.Append(SMCyclePeriod.ToString());
                EngrLogger.writeToColumns(sbTemp);
            }
        }

        #region ABSTRACT METHODS
        public abstract int doStateEntryActions();
        public abstract int doStateActions();
        public abstract CPFStates checkEvents();
        public abstract int doExitActions(bool timedOut);
        public abstract CPFStates doTimeoutAction();
        protected static int ABRetractThresholdCount = 0;
        #endregion

        #region COMMON PROPERTIES
        public int ECTimeout;// { get; protected set; }             //This is the execution constraint time out that the state must complete in
        public int nextAction { get; protected set; }
        public readonly StringBuilder stateName = new StringBuilder(32);

        protected static StringBuilder sbTemp = new StringBuilder(256);
        #endregion

        #region COMMON DEVICES
        protected CTD1 ctd1;
        protected FLBB1 flbb1;
        protected Optode1 optode1;
        protected IridiumModem1 iModem1;
        protected BTConsole btConsole;
        protected GPS1 gps1;
        protected MSC1 msc1;
        protected Radiometer1 radiometer1;

        protected BuoyancyEngine buoyancyEngine;

        protected MotherBoard motherBoard;
        protected LheBoard lheBoard;

        #endregion

        //private static RMG185_PTHSensor housingPTH;
        protected PTHSensor pthSensor;

        public static Timer instrumentTimer;
        public static TimeSpan instrumentTimerDelay = new TimeSpan(0, 0, 45);

        public StateBase()
        {
            //housingPTH = new RMG185_PTHSensor();;
            pthSensor = PTHSensor.Instance;
            ctd1 = CTD1.Instance;
            flbb1 = FLBB1.Instance;
            msc1 = MSC1.Instance;
            optode1 = Optode1.Instance;
            iModem1 = IridiumModem1.Instance;
            btConsole = BTConsole.Instance;
            buoyancyEngine = BuoyancyEngine.Instance;
            gps1 = GPS1.Instance;
            radiometer1 = Radiometer1.Instance;
            motherBoard = MotherBoard.Instance;
            lheBoard = LheBoard.Instance;
            emHotel = EnergyMonitorHotel.Instance;
            emPump = EnergyMonitorPump.Instance;

            if (instrumentTimer == null)
                instrumentTimer = new Timer(new TimerCallback(instrumentTimerCallback), null, -1, -1);

            if (underVoltageError == null)
                underVoltageError = new ErrorHandler(3, underVoltageErrorTS, underVoltageLabel, ErrorHandler.ErrorType.critical, ErrorHandler.setRecoveryMode);
        }

        public void instrumentTimerCallback(object o)
        {
            EngrLogger.writeToColumns("Inst timer callback, starting new SampleCycle");
            SciLogger.startNewSampleCycle(SciLogger.Instruments.AllInstruments);
        }

        #region INHERITED METHODS

        private static StringBuilder sbStateEntry = new StringBuilder("State Entry");
        protected virtual int basicStateEntry()
        {
            EngrLogger.writeToColumns(sbStateEntry);

            buoyancyEngine.stopMotor();
            SV.RunPVPID = false;
            nextAction = 0;
            SV.DoStateEntry = false;
            sendAckSBD = SbdReply.OK;


            //TODO P2 Maybe make SV.PressureTableNum into 2 variable descendTableNum and ascendTableNum and put them in descend and ascend classes
            //Start at the beginning of the pressure table unless transitioning from park
            //Added GM 2015Oct22
            if (SV.PastState != CPFStates.park)
                SV.PressureTableNum = 0;


            MessageQueue mq = MessageQueue.Instance;
            mq.processQMaxLimit();

            return (1);
        }

        private static StringBuilder sbStateTimedOut = new StringBuilder("State Timed Out");
        private static StringBuilder sbNormalStateExit = new StringBuilder("Normal State Exit");
        protected int basicStateExit(bool timedOut)
        {
            //timedOut exit actions
            if (timedOut)
                EngrLogger.writeToColumns(sbStateTimedOut);
            else
                EngrLogger.writeToColumns(sbNormalStateExit);

            SV.RunPVPID = false;
            buoyancyEngine.stopMotor();
            SV.DoStateEntry = true;

            //Check the file system before we move on
            if (FileSystemCheck.CheckSDCard() == false)
            {
                sbTemp.Clear();
                sbTemp.Append("File system check failed, forcing recovery");
                setForceRecovery(sbTemp);
            }

            return (1);
        }

        //Evaluates return code of a given action, and if successful increments currentAction. 
        //If action is incomplete, or fails, returns initial value of currentAction. 
        //Errors are to be handled higher up because this is a common and inherited method that is context agnostic.
        protected int checkActionReturn(int returnVal, int currentAction)
        {
            return (returnVal > 0) ? returnVal : currentAction;    //action has completed sucessfully, or is still in process
        }

        public void initBuoyancyEngine()
        {
            buoyancyEngine.init();
        }

        private static double bellowsPosition = double.NaN;
        public static PTHData pthData = new PTHData();
        private static StringBuilder systemDataHeader = new StringBuilder("System Data (dBar %full Volts mAmps): ");

        private static DateTime lastSystemDataSampleTime = new DateTime(2000, 1, 1);

        private static DateTime globalIssueLastRun = new DateTime(2000, 1, 1);

        public CPFStates checkGlobalIssues()
        {
            EngrLogger.Comment("Checking Global Issues");
            ////run once a second
            //if (DateTime.Now - globalIssueLastRun < Literals.TsOneSecond)
            //    return SV.NextState;

            ////update timer
            //globalIssueLastRun = DateTime.Now;

            //Check depth limit
            if (ctd1.SBE41LPF.RawPressure > Mission.stdMaxPressure)
            {
                sbTemp.Clear().Append("Too deep. Moving to RECOVERY MODE");
                EngrLogger.writeToColumns(sbTemp);
                return (CPFStates.recovery);
            }

            //Check mission timeout
            if (!SV.MissionTimedOut)
            {
                if (DateTime.Now - SV.MissionStartTime > SV.MissionTimeoutTS)
                {
                    SV.MissionTimedOut = true;
                    sbTemp.Clear().Append("Mission timed out. Moving to RECOVERY MODE");
                    EngrLogger.writeToColumns(sbTemp);
                    return (CPFStates.recovery);
                }
            }

            #region Check bellows limits
            EngrLogger.writeToColumns("CGI getBellowsPositionStringPot()");
            bellowsPosition = buoyancyEngine.getBellowsPositionStringPot();
            if ((SV.CurrentState != CPFStates.initMission) && (SV.CurrentState != CPFStates.exit))
            {
                if ((bellowsPosition > MissionConfig.IBFillUpperLimit) || (bellowsPosition < MissionConfig.IBFillLowerLimit))
                {

                    sbTemp.Clear();
                    sbTemp.Append("GI: Bellows position exceeds limits, Pos = ");
                    sbTemp.Append(bellowsPosition.ToString());

                    if (bellowsPosition > MissionConfig.IBFillUpperLimit && buoyancyEngine.decreasingBuoyancy)
                    {
                        sbTemp.Append("  *Trying to pass upper bellows limit, stopping motor");
                        buoyancyEngine.stopMotor();
                        SV.RunPVPID = false;

                    }

                    else if (bellowsPosition < MissionConfig.IBFillLowerLimit && buoyancyEngine.increasingBuoyancy)
                    {
                        sbTemp.Append("  *Trying to pass bellows lower limit, stopping motor");
                        buoyancyEngine.stopMotor();
                        SV.RunPVPID = false;

                    }

                    if (bellowsPosition > MissionConfig.IBFillUpperLimit)
                        SV.BellowsAtUpperLimit = true;
                    else
                        SV.BellowsAtLowerLimit = true;

                    EngrLogger.writeToColumns(sbTemp);
                }
                else
                {
                    SV.BellowsAtUpperLimit = false;
                    SV.BellowsAtLowerLimit = false;
                }
            }
            #endregion


            if (SV.ForceRecoveryState)
            {
                //buoyancyEngine.stopMotor();  Removed by GM 2022 Apr 18 to prevent no pumping in recovery mode
                //SV.RunPVPID = false;
                sbTemp.Clear();
                sbTemp.Append("CheckGlobalIssues forcing recovery");
                setForceRecovery(sbTemp);
                return (CPFStates.recovery);
            }

            checkSystemData();

            #region Check Stuck Pressure
            if (ctd1.powerCycleCount > 3)
            {
                //buoyancyEngine.stopMotor();
                //SV.RunPVPID = false;
                SV.SurfaceOpsGo = false;
                ctd1.powerCycleCount = 0;

                EngrLogger.Comment("[ERROR] Pressure isn't changing, power cycling CTD didn't work, moving to RECOVERY MODE");
                return (CPFStates.recovery);
            }
            #endregion


            //TODO P2 Check if float surfaced when in "underwater" state

            //TODO P2 check for large delta in internal housing pressure

            return (SV.NextState);
        }

        protected static StringBuilder sbdwtMessage = new StringBuilder(1920);
        protected enum SbdReply { ACK, NAK, OK }; // ACK = 1, NAK ==
        protected SbdReply sendAckSBD = SbdReply.OK; // ACK = 1, NAK ==
        protected const int MAX_SBDIX_ATTEMPTS = 5;

        protected void buildSBDMsg()
        {
            try
            {
                sbdwtMessage.Clear();

                sbdwtMessage.Append(DateTime.Now.ToString("yyyy-MM-dd"));
                sbdwtMessage.Append("T");
                sbdwtMessage.Append(DateTime.Now.ToString("HH:mm:ss"));
                sbdwtMessage.Append("Z,");

                //Position
                sbdwtMessage.Append(",Lat,");
                sbdwtMessage.Append(gps1.latestPosition.latSB).Append(',');
                sbdwtMessage.Append(",Lon,");
                sbdwtMessage.Append(gps1.latestPosition.lonSB);
                sbdwtMessage.Append(",GPS TOF,");
                sbdwtMessage.Append(gps1.latestPosition.gpsTimeOfFix);
                sbdwtMessage.Append(",Num Sats,");
                sbdwtMessage.Append(gps1.latestPosition.numSats.ToString());
                sbdwtMessage.Append(',');
                sbdwtMessage.Append(SV.CurrentStateName.ToString());
                sbdwtMessage.Append(',');
                sbdwtMessage.Append(SV.ForceRecoveryReason.ToString());
                sbdwtMessage.Append(",ProfileNum,");
                sbdwtMessage.Append(SV.ProfileNum.ToString());

                switch (sendAckSBD)
                {
                    case SbdReply.OK:
                        sbdwtMessage.Append(",OK SBD");
                        break;
                    case SbdReply.NAK:
                        sbdwtMessage.Append(",NAK SBD");
                        break;
                    case SbdReply.ACK:
                        sbdwtMessage.Append(",ACK SBD");
                        break;
                }

                sbdwtMessage.Append(",SQ,");
                sbdwtMessage.Append(NAL_A3LAR.SignalQuality.ToString());

                sbdwtMessage.Append(",MO Stat,-,");

                //Mission parameters
                sbdwtMessage.Append(",Mission TO,");
                sbdwtMessage.Append(SV.MissionTimeoutTS.ToString());

                sbdwtMessage.Append(",Park Time,");
                sbdwtMessage.Append(Mission.descendTable[0].parkTime.ToString());

                sbdwtMessage.Append(",Park P,");
                sbdwtMessage.Append(Mission.descendTable[0].pressure.ToString());

                //Status
                sbdwtMessage.Append(",Prof Num,");
                sbdwtMessage.Append(SV.ProfileNum.ToString());
                sbdwtMessage.Append(" of ");
                sbdwtMessage.Append(SV.MaxProfiles.ToString());

                sbdwtMessage.Append(",Max P,");
                sbdwtMessage.Append(Program.maxPressureThisProfile.ToString("f3"));

                sbdwtMessage.Append(",BBVolts,");
                sbdwtMessage.Append(systemVICEData.hotelVolts.ToString("f3"));

                sbdwtMessage.Append(",Can P,");
                sbdwtMessage.Append(pthData.canPressure.ToString("f1"));

                sbdwtMessage.Append(",Can Hum,");
                sbdwtMessage.Append(pthData.canHumidity.ToString("f1"));

                sbdwtMessage.Append(",BBHealth,").Append(lheBoard.BatteryHealth.ToString("x4"));
            }
            catch
            {
                sbdwtMessage.Clear();
                sbdwtMessage.Append("[ERROR] in buildSBDMsg");
                sbdwtMessage.Append(sbdwtMessage);
            }
            EngrLogger.writeToColumns(sbdwtMessage);
        }

        public void setForceRecovery(StringBuilder reason)
        {
            SV.ForceRecoveryState = true;
            SV.ForceRecoveryReason.Clear();
            SV.ForceRecoveryReason.Append(reason);

            sbTemp.Clear();
            sbTemp.Append("[ERROR] ");
            sbTemp.Append(SV.ForceRecoveryReason);
            EngrLogger.Comment(sbTemp.ToString());
        }

        public void stopMotor()
        {
            buoyancyEngine.stopMotor();
        }

        public static EnergyMonitorLTC2946.SystemVICE systemVICEData;
        public static EnergyMonitorLTC2946.emIVWTCE pumpIVWTCEData;
        public static EnergyMonitorLTC2946.emIVWTCE hotelIVWTCEData;

        public void checkSystemData(bool doTimeCheck = true)
        {
            if (doTimeCheck)
            {
                timeNow = DateTime.Now;
                if ((timeNow - lastSystemDataSampleTime) < MissionConfig.SystemDataSamplePeriod)
                    return;
            }

            EngrLogger.Comment("CSD getPTH()");
            pthData = pthSensor.getPTH(false);
            EngrLogger.Comment("CSD get pump and hotel IVWTCE()");
            pumpIVWTCEData = emPump.getIVWTCE();
            hotelIVWTCEData = emHotel.getIVWTCE();
            EngrLogger.Comment("CSD getBellowsPositionStringPot()");
            bellowsPosition = buoyancyEngine.getBellowsPositionStringPot();

            EngrLogger.writeToColumns(-1, EngrLiterals.ColumnNums.dateTime, timeNow,
                        EngrLiterals.ColumnNums.state, SV.CurrentState,
                        EngrLiterals.ColumnNums.comment, systemDataHeader,
                        EngrLiterals.ColumnNums.pressure, SV.Pressure,
                        EngrLiterals.ColumnNums.bellowsPosition, bellowsPosition,
  
                        EngrLiterals.ColumnNums.LPS331Pressure, pthData.canPressure,
                        EngrLiterals.ColumnNums.LPS331Temperature, pthData.canP_Temperature,
                        EngrLiterals.ColumnNums.SHT21Humidity, pthData.canHumidity,
                        EngrLiterals.ColumnNums.SHT21Temperature, pthData.canH_Temperature,

                        EngrLiterals.ColumnNums.pumpMilliamps, pumpIVWTCEData.milliAmps,
                        EngrLiterals.ColumnNums.pumpVolts, pumpIVWTCEData.volts,
                        EngrLiterals.ColumnNums.pumpUWatts, pumpIVWTCEData.uWatts,
                        EngrLiterals.ColumnNums.pumpVolts, pumpIVWTCEData.milliSeconds,
                        EngrLiterals.ColumnNums.pumpUCoulombs, pumpIVWTCEData.uCoulombs,
                        EngrLiterals.ColumnNums.pumpMilliJoules, pumpIVWTCEData.milliJoules,

                        EngrLiterals.ColumnNums.hotelMilliamps, pumpIVWTCEData.milliAmps,
                        EngrLiterals.ColumnNums.hotelVolts, pumpIVWTCEData.volts,
                        EngrLiterals.ColumnNums.hotelVolts, pumpIVWTCEData.uWatts,
                        EngrLiterals.ColumnNums.hotelVolts, pumpIVWTCEData.milliSeconds,
                        EngrLiterals.ColumnNums.hotelUCoulombs, pumpIVWTCEData.uCoulombs,
                        EngrLiterals.ColumnNums.hotelMilliJoules, pumpIVWTCEData.milliJoules);

            if (lheBoard.isPumpPowerNotFaulted == 1)
                EngrLogger.writeToColumns(0, "Pump motor not faulted");
            else
                EngrLogger.writeToColumns("***FAULT: Pump motor faulted");
            buoyancyEngine.getPumpMotorStats();

            sbTemp.Clear();
            sbTemp.Append(Literals.crlfString);
            sbTemp.Append("System Check, State: ");
            sbTemp.Append(SV.CurrentStateName);
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("CTD Pressure (dBar): ");
            sbTemp.Append(SV.Pressure.ToString("f1"));
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Can Pressure (mBar): ");
            sbTemp.Append(pthData.canPressure.ToString("f1"));
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Can Humidity (%RH): ");
            sbTemp.Append(pthData.canHumidity.ToString("f1"));
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Battery Bus Voltage: ");
            sbTemp.Append(systemVICEData.hotelVolts.ToString("f2"));
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Battery Bus Current (mA): ");
            sbTemp.Append(systemVICEData.hotelMilliamps.ToString("f1"));
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Inner Bellows Position (% full) ");
            sbTemp.Append(bellowsPosition.ToString("f1"));
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Profile num: ");
            sbTemp.Append(SV.ProfileNum.ToString());
            sbTemp.Append(" of ");
            sbTemp.Append(SV.MaxProfiles);
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Park/Anchor Period ([d.]hh:mm:ss): ");
            sbTemp.Append(Mission.descendTable[0].parkTime);
            sbTemp.Append(Literals.crlfString);

            sbTemp.Append("Mission time ([d.]hh:mm:ss): ");
            sbTemp.Append((DateTime.Now - SV.MissionStartTime));
            sbTemp.Append(" of ");
            sbTemp.Append(SV.MissionTimeoutTS);
            sbTemp.Append(Literals.crlfString);

            btConsole.SendLine(sbTemp);

            lastSystemDataSampleTime = timeNow;

        }

        private EnergyMonitorLTC2946.EM_VICE emVICE;
        private EnergyMonitorLTC2946.SystemVICE systemVIE;

        private EnergyMonitorLTC2946.SystemVICE getSystemVICE()
        {
            systemVIE.hotelVolts = double.NaN;
            systemVIE.hotelMilliamps = double.NaN;
            systemVIE.hotelCoulombs = double.NaN;
            systemVIE.hotelJoules = double.NaN;
            systemVIE.pumpVolts = double.NaN;
            systemVIE.pumpMilliamps = double.NaN;
            systemVIE.pumpCoulombs = double.NaN;
            systemVIE.pumpJoules = double.NaN;

            emVICE.volts = double.NaN;
            emVICE.milliAmps = double.NaN;
            emVICE.milliJoules = double.NaN;

            emVICE = emHotel.getVICE();
            systemVIE.hotelVolts = emVICE.volts;
            systemVIE.hotelCoulombs = emVICE.uCoulombs;
            systemVIE.hotelMilliamps = emVICE.milliAmps;
            systemVIE.hotelJoules = emVICE.milliJoules;

            emVICE.volts = double.NaN;
            emVICE.milliAmps = double.NaN;
            emVICE.milliJoules = double.NaN;

            emVICE = emPump.getVICE();
            systemVIE.pumpVolts = emVICE.volts;
            systemVIE.pumpMilliamps = emVICE.milliAmps;
            systemVIE.pumpCoulombs = emVICE.uCoulombs;
            systemVIE.pumpJoules = emVICE.milliJoules;

            if (SV.CurrentState != CPFStates.SMNotRunning)       //TODO P3 might not need to check state as this might only be called after state machine starts
            {
                if (systemVIE.hotelVolts < busVoltageEndMissionThreshold)
                    underVoltageError.logError();
            }

            return (systemVIE);
        }

        public void resetEMAccumulators()
        {
            emPump.ResetAccumulators();
            emHotel.ResetAccumulators();
        }

        private EnergyMonitorHotel emHotel;
        private EnergyMonitorPump emPump;
        private static TimeSpan underVoltageErrorTS = new TimeSpan(10000, 0, 0);
        private static StringBuilder underVoltageLabel = new StringBuilder("Bat Bus Under Voltage Error");
        private static ErrorHandler underVoltageError;

        public static EnergyMonitorLTC2946.EM_VandI batteryBusData;

        private const double busVoltageEndMissionThreshold = 26.5;

        //public EnergyMonitorLTC2946.EM_VandI checkVandI()
        //{
        //    batteryBusData = EMBatteryBus.getVandI();
        //    SV.busVoltage = batteryBusData.volts;
        //    SV.busAmps = batteryBusData.amps;

        //    if (SV.CurrentState != CPFStates.SMNotRunning)       //TODO P3 might not need to check state as this might only be called after state machine starts
        //    {
        //        if (batteryBusData.volts < busVoltageEndMissionThreshold)
        //            underVoltageError.logError();
        //    }
        //    return batteryBusData;
        //}        

        private static DateTime timeNow = new DateTime();
        public void writeSystemStateMessage()
        {
            timeNow = DateTime.Now;
            sbTemp.Clear();

            if (SV.RunPVPID)
                sbTemp.Append("PID On, ");
            else
                sbTemp.Append("PID Off, ");

            if (buoyancyEngine.increasingBuoyancy)
                sbTemp.Append("BE Ext'g, ");
            if (buoyancyEngine.decreasingBuoyancy)
                sbTemp.Append("BE Ret'g, ");
            if (buoyancyEngine.motorStopped)
                sbTemp.Append("Motor Stopped, ");
            if (buoyancyEngine.isValveOpen())
                sbTemp.Append("Valve Open, ");
            else
                sbTemp.Append("Valve Closed, ");

            if (SV.CurrentState == CPFStates.park)
                sbTemp.Append("Park, ");

            sbTemp.Append("depthNum = ");
            sbTemp.Append(SV.PressureTableNum.ToString());

            sbTemp.Append("  Pres, BP, BatV, BatI: ");

            //TODO P2 either 1) get rid of system state message and add basic data to all engLogger messages or
            //TODO P2 2) make it more effective and don't send all engrLogger messages to bluetooth console

            //EngrLogger.writeToColumns(EngrLiterals.ColumnNums.dateTime, timeNow,
            //                            EngrLiterals.ColumnNums.state, SV.CurrentState,
            //                            EngrLiterals.ColumnNums.comment, sbTemp,
            //                            EngrLiterals.ColumnNums.pressure, ctd1.SBE41LPF.RawPressure,
            //                            EngrLiterals.ColumnNums.bellowsPosition, buoyancyEngine.bellowsPosition,
            //                            EngrLiterals.ColumnNums.batteryBusVolts, batteryBusData.voltage,
            //                            EngrLiterals.ColumnNums.batteryBusAmps, batteryBusData.current);
        }

        //       //TODO P2 maybe this should go in a constructor somewhere
        //       public void initPTHSensor()
        //       {
        //           housingPTH.init();
        //       }

        #endregion
    }
}
