diff --git a/src/detection/battery/battery.h b/src/detection/battery/battery.h index 8165d1961..91ca8d37b 100644 --- a/src/detection/battery/battery.h +++ b/src/detection/battery/battery.h @@ -7,6 +7,7 @@ typedef struct FFBatteryResult { FFstrbuf manufacturer; + FFstrbuf manufacturerDate; FFstrbuf modelName; FFstrbuf technology; FFstrbuf status; diff --git a/src/detection/battery/battery_android.c b/src/detection/battery/battery_android.c index 6ddf3bbfe..b3b08dee1 100644 --- a/src/detection/battery/battery_android.c +++ b/src/detection/battery/battery_android.c @@ -40,6 +40,7 @@ static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results) ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); + ffStrbufInit(&battery->manufacturerDate); battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage")); ffStrbufAppendS(&battery->status, yyjson_get_str(yyjson_obj_get(root, "status"))); diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index c0d0ec8a6..4c5be2edf 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -29,6 +29,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) ffStrbufInit(&battery->serial); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); + ffStrbufInit(&battery->manufacturerDate); battery->capacity = 0.0/0.0; int currentCapacity, maxCapacity; diff --git a/src/detection/battery/battery_bsd.c b/src/detection/battery/battery_bsd.c index cb1e3090e..ff6367547 100644 --- a/src/detection/battery/battery_bsd.c +++ b/src/detection/battery/battery_bsd.c @@ -40,6 +40,7 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->serial); + ffStrbufInit(&battery->manufacturerDate); battery->capacity = battio.battinfo.cap; if(battio.battinfo.state == ACPI_BATT_STAT_INVALID) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index e10484dcf..536f1995d 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -83,6 +83,8 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount; } + ffStrbufInit(&result->manufacturerDate); + result->temperature = FF_BATTERY_TEMP_UNSET; if (options->temp) { diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 81e78162e..4866f49cd 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -1,6 +1,7 @@ #include "battery.h" #include "util/windows/unicode.h" #include "util/mallocHelper.h" +#include "util/smbiosHelper.h" #undef WIN32_LEAN_AND_MEAN #include @@ -75,19 +76,19 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results); if(memcmp(bi.Chemistry, "PbAc", 4) == 0) - ffStrbufInitS(&battery->technology, "Lead Acid"); + ffStrbufInitStatic(&battery->technology, "Lead Acid"); else if(memcmp(bi.Chemistry, "LION", 4) == 0 || memcmp(bi.Chemistry, "Li-I", 4) == 0) - ffStrbufInitS(&battery->technology, "Lithium Ion"); + ffStrbufInitStatic(&battery->technology, "Lithium Ion"); else if(memcmp(bi.Chemistry, "NiCd", 4) == 0) - ffStrbufInitS(&battery->technology, "Nickel Cadmium"); + ffStrbufInitStatic(&battery->technology, "Nickel Cadmium"); else if(memcmp(bi.Chemistry, "NiMH", 4) == 0) - ffStrbufInitS(&battery->technology, "Nickel Metal Hydride"); + ffStrbufInitStatic(&battery->technology, "Nickel Metal Hydride"); else if(memcmp(bi.Chemistry, "NiZn", 4) == 0) - ffStrbufInitS(&battery->technology, "Nickel Zinc"); + ffStrbufInitStatic(&battery->technology, "Nickel Zinc"); else if(memcmp(bi.Chemistry, "RAM\0", 4) == 0) - ffStrbufInitS(&battery->technology, "Rechargeable Alkaline-Manganese"); + ffStrbufInitStatic(&battery->technology, "Rechargeable Alkaline-Manganese"); else - ffStrbufInitS(&battery->technology, "Unknown"); + ffStrbufInitStatic(&battery->technology, "Unknown"); { ffStrbufInit(&battery->modelName); @@ -105,6 +106,14 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results ffStrbufSetWS(&battery->manufacturer, name); } + { + ffStrbufInit(&battery->manufacturerDate); + bqi.InformationLevel = BatteryManufactureDate; + BATTERY_MANUFACTURE_DATE date; + if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL)) + ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day); + } + { ffStrbufInit(&battery->serial); bqi.InformationLevel = BatterySerialNumber; @@ -121,7 +130,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results bqi.InformationLevel = BatteryTemperature; ULONG temp; if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &temp, sizeof(temp), &dwOut, NULL)) - battery->temperature = temp; + battery->temperature = temp / 10.0 - 273.15; } { @@ -148,6 +157,83 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results return NULL; } + + +typedef struct FFSmbiosPortableBattery +{ + FFSmbiosHeader Header; + + // 2.1+ + uint8_t Location; // string + uint8_t Manufacturer; // string + uint8_t ManufactureDate; // string + uint8_t SerialNumber; // string + uint8_t DeviceName; // string + uint8_t DeviceChemistry; // enum + uint16_t DesignCapacity; // varies + uint16_t DesignVoltage; // varies + uint8_t SbdsVersionNumber; // string + uint8_t MaximumErrorInBatteryData; // varies + + // 2.2+ + uint16_t SbdsSerialNumber; // varies + uint16_t SbdsManufactureDate; // varies + uint8_t SbdsDeviceChemistry; // string + uint8_t DesignCapacityMultiplier; // varies + uint16_t OEMSpecific; // varies +} FFSmbiosPortableBattery; + +const char* detectBySmbios(FFBatteryResult* battery) +{ + const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PORTABLE_BATTERY]; + if (!data) + return "Portable battery section is not found in SMBIOS data"; + + const char* strings = (const char*) data + data->Header.Length; + + ffStrbufSetStatic(&battery->modelName, ffSmbiosLocateString(strings, data->DeviceName)); + ffCleanUpSmbiosValue(&battery->modelName); + ffStrbufSetStatic(&battery->manufacturer, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&battery->manufacturer); + + if (data->ManufactureDate) + { + ffStrbufSetStatic(&battery->manufacturerDate, ffSmbiosLocateString(strings, data->ManufactureDate)); + ffCleanUpSmbiosValue(&battery->manufacturerDate); + } + else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate)) + { + uint16_t day = data->SbdsManufactureDate & 0b11111; + uint16_t month = (data->SbdsManufactureDate >> 5) & 0b1111; + uint16_t year = (data->SbdsManufactureDate >> 9) + 1800; + ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + } + + switch (data->DeviceChemistry) + { + case 0x01: ffStrbufSetStatic(&battery->technology, "Other"); break; + case 0x02: ffStrbufSetStatic(&battery->technology, "Unknown"); break; + case 0x03: ffStrbufSetStatic(&battery->technology, "Lead Acid"); break; + case 0x04: ffStrbufSetStatic(&battery->technology, "Nickel Cadmium"); break; + case 0x05: ffStrbufSetStatic(&battery->technology, "Nickel metal hydride"); break; + case 0x06: ffStrbufSetStatic(&battery->technology, "Lithium-ion"); break; + case 0x07: ffStrbufSetStatic(&battery->technology, "Zinc air"); break; + case 0x08: ffStrbufSetStatic(&battery->technology, "Lithium Polymer"); break; + } + + if (data->SerialNumber) + { + ffStrbufSetStatic(&battery->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&battery->serial); + } + else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsSerialNumber)) + { + ffStrbufSetF(&battery->serial, "%4X", data->SbdsSerialNumber); + } + + return NULL; +} + static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) { SYSTEM_BATTERY_STATE info; @@ -156,6 +242,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results); ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->manufacturer); + ffStrbufInit(&battery->manufacturerDate); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); ffStrbufInit(&battery->serial); @@ -171,6 +258,9 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF } else if(info.Discharging) ffStrbufAppendS(&battery->status, "Discharging"); + + detectBySmbios(battery); + return NULL; } return "NtPowerInformation(SystemBatteryState) failed"; @@ -178,7 +268,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { - return true + return options->useSetupApi ? detectWithSetupApi(options, results) : detectWithNtApi(options, results); } diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 733983d20..3fad65c54 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -72,6 +72,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin {FF_FORMAT_ARG_TYPE_DOUBLE, &result->temperature}, {FF_FORMAT_ARG_TYPE_UINT, &result->cycleCount}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->serial}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturerDate}, }); } } @@ -97,6 +98,8 @@ void ffPrintBattery(FFBatteryOptions* options) ffStrbufDestroy(&result->modelName); ffStrbufDestroy(&result->technology); ffStrbufDestroy(&result->status); + ffStrbufDestroy(&result->serial); + ffStrbufDestroy(&result->manufacturerDate); } if(results.length == 0) ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, "No batteries found"); @@ -192,6 +195,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_obj_add_real(doc, obj, "capacity", battery->capacity); yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &battery->manufacturer); + yyjson_mut_obj_add_strbuf(doc, obj, "manufacturerDate", &battery->manufacturerDate); yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &battery->modelName); yyjson_mut_obj_add_strbuf(doc, obj, "status", &battery->status); yyjson_mut_obj_add_strbuf(doc, obj, "technology", &battery->technology); @@ -203,6 +207,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, FF_LIST_FOR_EACH(FFBatteryResult, battery, results) { ffStrbufDestroy(&battery->manufacturer); + ffStrbufDestroy(&battery->manufacturerDate); ffStrbufDestroy(&battery->modelName); ffStrbufDestroy(&battery->technology); ffStrbufDestroy(&battery->status); @@ -221,6 +226,7 @@ void ffPrintBatteryHelpFormat(void) "Battery temperature", "Battery cycle count", "Battery serial number", + "Battery manufactorDate", }); }