using System;
using Microsoft.SPOT;

using System.Text;
using Microsoft.SPOT.Hardware;
using System.Threading;
using GHI.Utilities;

namespace CPF
{
    class EnergyMonitor
    {
        public struct EnergyMonitorData
        {
            public double voltage;
            public double current;
        }

        private static I2CDevice.Configuration config2946 = new I2CDevice.Configuration(0x6F, 400);
        private static I2CDevice.I2CTransaction[] xActions2946 = new I2CDevice.I2CTransaction[2];

        private static int xActionReturn;

        private static byte[] LTC2946_VIN_MSB_REG = new byte[1] { 0x1E };
        private static byte[] LTC2946_VIN_LSB_REG = new byte[1] { 0x1F };

        private static byte[] LTC2946_DELTA_SENSE_MSB_REG = new byte[1] { 0x14 };
        private static byte[] LTC2946_DELTA_SENSE_LSB_REG = new byte[1] { 0x15 };

        private static byte[] registerBytes2 = new byte[2];

        private static double Rsense = 0.020;

        private static EnergyMonitorData EMData = new EnergyMonitorData();

        private static TimeSpan underVoltageErrorTS = new TimeSpan(10000, 0, 0);
        private static StringBuilder underVoltageLabel = new StringBuilder("Bat Bus Under Voltage Error");
        private static ErrorHandler underVoltageError = new ErrorHandler(3, underVoltageErrorTS, underVoltageLabel, ErrorHandler.ErrorType.critical);
        private const double minVoltage = 26.5;

        static EnergyMonitor()
        {
            underVoltageError.criticalErrorHandler += new ErrorHandler.CriticalErrorHandler(ErrorHandler.setRecoveryMode);
        }

        public static EnergyMonitorData readEM()
        {
            Program.g400I2C.Config = config2946;

            EMData.current = double.NaN;
            EMData.voltage = double.NaN;

            // create write buffer to read voltage
            xActions2946[0] = I2CDevice.CreateWriteTransaction(LTC2946_VIN_MSB_REG);

            // create read buffer to read the returned data
            xActions2946[1] = I2CDevice.CreateReadTransaction(registerBytes2);

            //startTime = Utility.GetMachineTime();
            xActionReturn = Program.g400I2C.Execute(xActions2946, 500);
            //endTime = Utility.GetMachineTime();
            //diffTime = endTime - startTime;
            //Debug.Print("I2C Transaction Done, time diff = " + diffTime.ToString());

            if (xActionReturn == 0)
            {
                EngrLogger.writeToColumns("Error executing 2946 Transaction = " + xActionReturn.ToString());
            }
            else
            {
                //Debug.Print(registerBytes2[0].ToString() + " " + registerBytes2[1].ToString());

                EMData.voltage = 0.025 * ((registerBytes2[0] * 16) + (registerBytes2[1] >> 4));

                if (Program.CurrentState != Program.CPFStates.SMNotRunning)
                {
                    if (EMData.voltage < minVoltage)
                        underVoltageError.logError();
                }

                //Debug.Print("Voltage = " + voltage.ToString());
            }

            // create write buffer to read voltage
            xActions2946[0] = I2CDevice.CreateWriteTransaction(LTC2946_DELTA_SENSE_MSB_REG);

            //startTime = Utility.GetMachineTime();
            xActionReturn = Program.g400I2C.Execute(xActions2946, 500);
            //endTime = Utility.GetMachineTime();
            //diffTime = endTime - startTime;
            //Debug.Print("I2C Transaction Done, time diff = " + diffTime.ToString());

            if (xActionReturn == 0)
            {
                EngrLogger.writeToColumns("Error executing 2946 Transaction = " + xActionReturn.ToString());
            }
            else
            {
                //Debug.Print(registerBytes2[0].ToString() + " " + registerBytes2[1].ToString());

                EMData.current = (0.000025 * ((registerBytes2[0] * 16) + (registerBytes2[1] >> 4))) / Rsense;
                //Debug.Print("Current = " + current.ToString());
            }
            return (EMData);
        }
    }
}
