
namespace PIC_Simulator.PIC
{
	class PICWatchDog
	{
		private PICProgramm programm;

		private const double TIME_OUT = 0.018; // 18ms;

		public uint Prescale = 1;

		private double time; // in s

		public bool Aktiviert = false;

		public PICWatchDog(PICProgramm p)
		{
			programm = p;
			time = 0;
		}

		public void Aktualisieren(uint cycles, float frequenz)
		{
			if (Aktiviert)
			{
				time += (1.0 / frequenz) * cycles;

				if (time > TIME_OUT * GetPreScale())
				{
					WDReset();
				}
			}
			else
			{
				time = 0;
			}
		}

		private void WDReset()
		{
			if (!programm.IsSleeping)
			{
				// >> WATCHDOG RESET <<

				time = 0;

				programm.Reset();
				programm.SetRegisterOhneBank(PICProgramm.ADDR_STATUS, PICProgramm.STATUS_BIT_TO, false);
			}
			else
			{
				// >> Wake Up <<

				time = 0;

				programm.IsSleeping = false;
			}
		}

		private uint GetPreScale()
		{
			bool prescale_mode = !programm.GetRegisterOhneBank(PICProgramm.ADDR_OPTION, PICProgramm.OPTION_BIT_PSA);

			uint scale = 0;
			scale += programm.GetRegisterOhneBank(PICProgramm.ADDR_OPTION, PICProgramm.OPTION_BIT_PS2) ? 1U : 0U;
			scale *= 2;
			scale += programm.GetRegisterOhneBank(PICProgramm.ADDR_OPTION, PICProgramm.OPTION_BIT_PS1) ? 1U : 0U;
			scale *= 2;
			scale += programm.GetRegisterOhneBank(PICProgramm.ADDR_OPTION, PICProgramm.OPTION_BIT_PS0) ? 1U : 0U;

			Prescale = prescale_mode ? 1 : (PICProgramm.SHL(1, scale));

			return Prescale;
		}

		public void Reset()
		{
			time = 0;
		}

		public double GetPerc()
		{
			return time / (TIME_OUT * Prescale);
		}
	}
}
