Skip to content

Instantly share code, notes, and snippets.

@leha-bot
Created October 11, 2018 21:24
Show Gist options
  • Save leha-bot/896f6146124a35c73e867f5c5e3b54c2 to your computer and use it in GitHub Desktop.
Save leha-bot/896f6146124a35c73e867f5c5e3b54c2 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <stdio.h> // snprintf
#include <windows.h>
/// @example Termux Battery Info JSON Format
/// health - "COLD" | "DEAD" | "GOOD" | "OVERHEAT" | "OVER_VOLTAGE" |
/// "UNKNOWN" | "UNSPECIFIED_FAILURE" | integer
/// percentage - integer
/// plugged - "UNPLUGGED" | "PLUGGED_AC" | "PLUGGED_USB" |
/// "PLUGGED_WIRELESS" | "PLUGGED_".integer
/// status - "CHARGING" | "DISCHARGING" | "FULL" | "NOT_CHARGING" |
/// "UNKNOWN"
/// temperature - integer.
/// @group JSON Serialize functions
/// @{
/// @brief All Windows flags.
/// @see https://docs.microsoft.com/en-gb/windows/desktop/api/winbase/ns-winbase-_system_power_status
enum battery_flags {
battery_flag_charge_status_high = 0x1,
battery_flag_charge_status_low = 0x2,
battery_flag_status_critical = 0x4,
battery_flag_charge_status_charging = 0x8,
battery_flag_no_battery = 0x80,
battery_flag_unknown_status = 0xff
};
/// @brief simple struct for easy printing to avoid the C++17 variants.
struct variant_for_poormen {
union {
const char *str;
int number;
};
bool is_string;
};
std::ostream &operator <<(std::ostream &os, const variant_for_poormen &var)
{
if (var.is_string) {
os << var.str;
} else {
os << var.number;
}
return os;
}
#define CHECK_FLAG(value, flag) ( ((value) & (flag)) == (flag) )
const char *getHealthString(SYSTEM_POWER_STATUS &status)
{
auto battery_flag = status.BatteryFlag;
if (CHECK_FLAG(battery_flag, battery_flag_unknown_status)) {
// we could return "UNKNOWN", but we will use it for no_battery flag.
return "UNSPECIFIED_FAILURE";
}
if (CHECK_FLAG(battery_flag, battery_flag_status_critical)) {
return "DEAD";
}
if (CHECK_FLAG(battery_flag, battery_flag_no_battery)) {
return "UNKNOWN";
}
return "GOOD";
}
size_t getPercentageNumber(SYSTEM_POWER_STATUS &status)
{
return status.BatteryLifePercent;
}
const char *getPluggedString(SYSTEM_POWER_STATUS &status)
{
// Windows can't say us which kind of AC charge it used, so return PLUGGED_AC.
// Assume that 255 (unknown status) is "UNPLUGGED".
return status.ACLineStatus == 1 ? "PLUGGED_AC" : "UNPLUGGED";
}
const char *getStatusString(SYSTEM_POWER_STATUS &status)
{
auto battery_flag = status.BatteryFlag;
if (CHECK_FLAG(battery_flag, battery_flag_unknown_status)) {
return "UNKNOWN";
}
if (CHECK_FLAG(battery_flag, battery_flag_charge_status_charging)) {
return "CHARGING";
}
if (status.BatteryLifePercent == 100) {
return "FULL";
}
if (status.ACLineStatus == 1) {
return "NOT_CHARGING";
}
return "DISCHARGING";
}
size_t getTemperatureNumber(SYSTEM_POWER_STATUS &status)
{
// this API does not support temperature, we should send ioctl to device
// for getting its temperature. it's in TODO.
return 0;
}
/// @}
/// @brief Flushes battery info in Termux-compatible JSON format.
//
int main()
{
struct json_power_entry {
const char *key;
const char *(*value_str)(SYSTEM_POWER_STATUS&);
size_t (*value_number)(SYSTEM_POWER_STATUS&);
};
SYSTEM_POWER_STATUS status;
BOOL result = GetSystemPowerStatus(&status);
if (!result) {
return 1;
}
const json_power_entry serialize_entries[] = {
{ "health" , getHealthString },
{ "percentage" , nullptr, getPercentageNumber },
{ "plugged" , getPluggedString },
{ "status" , getStatusString },
{ "temperature", nullptr, getTemperatureNumber }
};
char delims[3] = "{\n";
for (auto &entry : serialize_entries) {
std::cout << delims;
delims[0] = ','; // replace to comma for next line delim
std::cout << "\t\"" << entry.key << "\": ";
if (entry.value_str) {
std::cout << "\"" << entry.value_str(status) << "\"";
} else {
std::cout << entry.value_number(status);
}
}
std::cout << "\n}";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment