/*
 *   lowbat.c
 *
 *   This file is part of Emu48
 *
 *   Copyright (C) 2006 Christoph Gießelink
 *
 */
#include "pch.h"
#include "Emu48.h"
#include "io.h"								// I/O definitions

#define BAT_FREQ	(60*1000)				// bat update time in ms (real machine = 60us, HP28C = 60s)

static HANDLE hCThreadBat = NULL;
static HANDLE hEventBat;

static DWORD WINAPI LowBatThread(LPVOID pParam)
{
	BOOL bLBI,bVLBI;

	do
	{
		GetBatteryState(&bLBI,&bVLBI);		// get battery state

		// very low bat detection
		bVLBI = bVLBI && (Chipset.IORam[LPE] & EVLBI) != 0;

		IOBit(LPD,VLBI,bVLBI);				// set VLBI
		IOBit(SRQ1,VSRQ,bVLBI);				// and service bit

		if (bVLBI)							// VLBI detected
		{
			Chipset.SoftInt = TRUE;
			bInterrupt = TRUE;

			if (Chipset.Shutdn)				// CPU shut down
			{
				Chipset.bShutdnWake = TRUE;	// wake up from SHUTDN mode
				SetEvent(hEventShutdn);		// wake up emulation thread
			}
		}
	}
	while (WaitForSingleObject(hEventBat,BAT_FREQ) == WAIT_TIMEOUT);

	return 0;
	UNREFERENCED_PARAMETER(pParam);
}

VOID StartBatMeasure(VOID)
{
	if (hCThreadBat)						// Bat measuring thread running
		return;								// -> quit

	// event to cancel Bat refresh loop
	hEventBat = CreateEvent(NULL,FALSE,FALSE,NULL);

	VERIFY(hCThreadBat = CreateThread(NULL,0,&LowBatThread,NULL,0,NULL));
	return;
}

VOID StopBatMeasure(VOID)
{
	if (hCThreadBat == NULL)				// thread stopped
		return;								// -> quit

	SetEvent(hEventBat);					// leave Bat update thread
	WaitForSingleObject(hCThreadBat,INFINITE);
	CloseHandle(hCThreadBat);
	hCThreadBat = NULL;						// set flag Bat update stopped
	CloseHandle(hEventBat);					// close Bat event
	return;
}

VOID GetBatteryState(BOOL *pbLBI, BOOL *pbVLBI)
{
	SYSTEM_POWER_STATUS_EX sSps;

	*pbLBI = FALSE;							// no battery warning
	*pbVLBI = FALSE;

	VERIFY(GetSystemPowerStatusEx(&sSps,FALSE));

	// battery powered
	if (sSps.ACLineStatus == AC_LINE_OFFLINE)
	{
		// on critical battery state make sure that lowbat flag is also set
		if ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0)
			sSps.BatteryFlag |= BATTERY_FLAG_LOW;

		// low bat detection
		*pbLBI = ((sSps.BatteryFlag & BATTERY_FLAG_LOW) != 0);

		// very low bat detection
		*pbVLBI = ((sSps.BatteryFlag & BATTERY_FLAG_CRITICAL) != 0);
	}
	return;
}

