├── img └── ss.png ├── src ├── PiMon.rc ├── icon.ico ├── resource.h ├── version.h ├── tray.h ├── utils.h ├── listview.h ├── PiMon.exe.manifest ├── setting.h ├── data.h ├── utils.c ├── PiMon.vcxproj.filters ├── listview.c ├── tray.c ├── setting.c ├── data.c ├── main.c ├── PiMon.vcxproj └── rpiq.h ├── README.md ├── LICENSE ├── PiMon.sln ├── .gitattributes └── .gitignore /img/ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driver1998/PiMon/HEAD/img/ss.png -------------------------------------------------------------------------------- /src/PiMon.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driver1998/PiMon/HEAD/src/PiMon.rc -------------------------------------------------------------------------------- /src/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driver1998/PiMon/HEAD/src/icon.ico -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/driver1998/PiMon/HEAD/src/resource.h -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | #ifdef _UNICODE 5 | #define PIMON_APPNAME L"PiMon" 6 | #define PIMON_VERSION L"1.1.2" 7 | #else 8 | #define PIMON_APPNAME "PiMon" 9 | #define PIMON_VERSION "1.1.2" 10 | #endif 11 | 12 | #define PIMON_FILE_VERSION 1,1,2,0 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/tray.h: -------------------------------------------------------------------------------- 1 | #ifndef TRAY_H 2 | #define TRAY_H 3 | 4 | #include 5 | 6 | void AddTrayIcon(HWND hwnd, UINT id, const wchar_t* desc, HICON icon, UINT msgId); 7 | void DeleteTrayIcon(HWND hwnd, UINT id); 8 | void UpdateTrayIcon(HWND hwnd, UINT id, HICON icon, const wchar_t* desc); 9 | 10 | // Remember to destroy the icon 11 | HICON DrawTrayIcon(HWND hwnd, COLORREF bkColor, COLORREF textColor, double value); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | 6 | #define SCALE(x, dpi) ((int)((x) * (dpi / 96.0))) 7 | void ResizeWindowByClientArea(HWND hwnd, int width, int height); 8 | void MoveWindowToCenterOfScreen(HWND hwnd); 9 | 10 | // Free the string after use 11 | wchar_t* RegQueryString(HKEY hKey, LPCWSTR subKey, LPCWSTR valueName); 12 | DWORD RegQueryDword(HKEY hKey, LPCWSTR subKey, LPCWSTR valueName); 13 | 14 | int PrettyPrintUnits(double* value, const wchar_t** units, int unit_count, double unit_step); 15 | 16 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PiMon 2 | 3 | A simple hardware monitor for your Raspberry Pi running Windows. 4 | 5 | ![Screenshot](https://raw.githubusercontent.com/driver1998/PiMon/master/img/ss.png) 6 | 7 | ## Features 8 | 9 | - Detect Pi model name, processor and RAM configuration 10 | - Detect Windows and firmware version 11 | - Realtime monitoring of temperature, clocks, and voltages, via VC Mailbox. 12 | - Always on top support 13 | 14 | ## Acknowledgements 15 | 16 | - Raspberry Pi Foundation's documents on VC Mailbox 17 | - Microsoft's RPIQ driver for communicating with VC Mailbox in Windows 18 | - Icon from the Tango Desktop Project 19 | -------------------------------------------------------------------------------- /src/listview.h: -------------------------------------------------------------------------------- 1 | #ifndef LISTVIEW_H 2 | #define LISTVIEW_H 3 | 4 | #include 5 | 6 | void LVAddColumn(HWND hwnd, int pos, const wchar_t* header, int width); 7 | void LVSetColumnWidth(HWND hwnd, int iCol, int width); 8 | void LVSetItemText(HWND hwnd, int iItem, int iSubItem, const wchar_t* text); 9 | void LVSetItemGroupId(HWND hwnd, int iItem, int groupId); 10 | void LVSetItemIndent(HWND hwnd, int iItem, int indent); 11 | void LVSetItemImage(HWND hwnd, int iItem, int imageId); 12 | void LVAddGroup(HWND hwnd, int pos, const wchar_t* header, int id); 13 | int LVAddItem(HWND hwnd, int pos, const wchar_t* text); 14 | 15 | #endif -------------------------------------------------------------------------------- /src/PiMon.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | true/pm 11 | permonitorv2,permonitor 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/setting.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTING_H 2 | #define SETTING_H 3 | 4 | #include 5 | 6 | extern BOOL alwaysOnTop; 7 | extern BOOL hideOnMinimize; 8 | extern BOOL acpiThermal; 9 | extern COLORREF trayBackground; 10 | extern COLORREF trayForeground; 11 | 12 | #define CONFIG_ALWAYS_ON_TOP L"AlwaysOnTop" 13 | #define CONFIG_HIDE_ON_MINIMIZE L"HideOnMinimize" 14 | #define CONFIG_ACPI_THERMAL_ZONE L"UseAcpiThermalZone" 15 | #define CONFIG_TRAY_BACKGROUND L"TrayIconBackground" 16 | #define CONFIG_TRAY_FOREGROUND L"TrayIconForeground" 17 | 18 | INT_PTR CALLBACK SettingsDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 19 | 20 | void LoadConfig(); 21 | int ConfigGetInt(const wchar_t* section, const wchar_t* key, int default_value); 22 | BOOL ConfigSetInt(const wchar_t* section, const wchar_t* key, int value); 23 | COLORREF ConfigGetColor(const wchar_t* section, const wchar_t* key, COLORREF default_value); 24 | void ConfigSetColor(const wchar_t* section, const wchar_t* key, COLORREF value); 25 | 26 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 driver1998 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/data.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILBOX_H 2 | #define MAILBOX_H 3 | 4 | #include 5 | 6 | enum RpiProcessor { 7 | CPU_UNKNOWN = 0, 8 | CPU_BCM2835 = 1, 9 | CPU_BCM2836 = 2, 10 | CPU_BCM2837 = 3, 11 | CPU_BCM2711 = 4 12 | }; 13 | 14 | enum RpiModel { 15 | MODEL_UNKNOWN = 0, 16 | MODEL_A = 1, 17 | MODEL_B = 2, 18 | MODEL_A_PLUS = 3, 19 | MODEL_B_PLUS = 4, 20 | MODEL_2B = 5, 21 | MODEL_CM1 = 6, 22 | MODEL_3B = 7, 23 | MODEL_ZERO = 8, 24 | MODEL_CM3 = 9, 25 | MODEL_ZERO_W = 10, 26 | MODEL_3B_PLUS = 11, 27 | MODEL_3A_PLUS = 12, 28 | MODEL_CM3_PLUS = 13, 29 | MODEL_4B = 14, 30 | MODEL_PI400 = 15, 31 | MODEL_CM4 = 16 32 | }; 33 | 34 | ULONG GetBoardRevision(); 35 | ULONG GetVoltage(int voltageId); 36 | ULONG GetClock(int clockId); 37 | ULONG GetMeasuredClock(int clockId); 38 | ULONG GetTemperature(); 39 | ULONG GetTemperatureAcpi(); 40 | ULONG GetFirmwareRevision(); 41 | ULONGLONG GetSerialNumber(); 42 | ULONG GetWindowsMemory(); 43 | ULONG GetInstalledMemory(ULONG BoardRevision); 44 | enum RpiProcessor GetProcessorType(ULONG BoardRevision); 45 | enum RpiModel GetPiModel(ULONG BoardRevision); 46 | const wchar_t* GetProcessorName(ULONG BoardRevision); 47 | const wchar_t* GetPiModelName(ULONG BoardRevision); 48 | 49 | // Free the string after use 50 | wchar_t* GetBiosVersion(); 51 | wchar_t* GetWindowsVersion(); 52 | 53 | #endif -------------------------------------------------------------------------------- /PiMon.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.30413.136 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PiMon", "src\PiMon.vcxproj", "{4A8C24DD-C156-4607-9054-B8D43A541421}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|ARM = Debug|ARM 10 | Debug|ARM64 = Debug|ARM64 11 | Debug|Win32 = Debug|Win32 12 | Release|ARM = Release|ARM 13 | Release|ARM64 = Release|ARM64 14 | Release|Win32 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Debug|ARM.ActiveCfg = Debug|ARM 18 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Debug|ARM.Build.0 = Debug|ARM 19 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Debug|ARM64.ActiveCfg = Debug|ARM64 20 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Debug|ARM64.Build.0 = Debug|ARM64 21 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Debug|Win32.Build.0 = Debug|Win32 23 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Release|ARM.ActiveCfg = Release|ARM 24 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Release|ARM.Build.0 = Release|ARM 25 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Release|ARM64.ActiveCfg = Release|ARM64 26 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Release|ARM64.Build.0 = Release|ARM64 27 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Release|Win32.ActiveCfg = Release|Win32 28 | {4A8C24DD-C156-4607-9054-B8D43A541421}.Release|Win32.Build.0 = Release|Win32 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {A05FCE5B-C01D-46C2-9F06-336368E65F2C} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include "utils.h" 6 | #include "version.h" 7 | 8 | void ResizeWindowByClientArea(HWND hwnd, int width, int height) { 9 | UINT dpi = GetDpiForWindow(hwnd); 10 | int w = SCALE(width, dpi) + 11 | (GetSystemMetricsForDpi(SM_CXFRAME, dpi) + 12 | GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) * 2; 13 | int h = SCALE(height, dpi) + 14 | (GetSystemMetricsForDpi(SM_CYFRAME, dpi) + 15 | GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi)) * 2 + 16 | GetSystemMetricsForDpi(SM_CYCAPTION, dpi); 17 | SetWindowPos(hwnd, NULL, 0, 0, w, h, SWP_NOMOVE); 18 | } 19 | 20 | void MoveWindowToCenterOfScreen(HWND hwnd) { 21 | RECT rs = { 0 }; 22 | SystemParametersInfoW(SPI_GETWORKAREA, 0, &rs, 0); 23 | RECT r = { 0 }; 24 | GetWindowRect(hwnd, &r); 25 | 26 | int x = (rs.right - (r.right - r.left)) / 2; 27 | int y = (rs.bottom - (r.bottom - r.top)) / 2; 28 | 29 | SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE); 30 | } 31 | 32 | wchar_t* RegQueryString(HKEY hKey, LPCWSTR subKey, LPCWSTR valueName) { 33 | HKEY hSubKey; 34 | DWORD size = 0; 35 | DWORD type = REG_SZ; 36 | 37 | LSTATUS status = RegOpenKeyExW(hKey, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hSubKey); 38 | if (status != ERROR_SUCCESS) return NULL; 39 | 40 | RegQueryValueExW(hSubKey, valueName, NULL, &type, NULL, &size); 41 | wchar_t* str = (wchar_t*)malloc(size); 42 | 43 | status = RegQueryValueExW(hSubKey, valueName, NULL, &type, (LPBYTE)str, &size); 44 | if (status != ERROR_SUCCESS) { 45 | free(str); 46 | str = NULL; 47 | } 48 | 49 | RegCloseKey(hSubKey); 50 | return str; 51 | } 52 | 53 | DWORD RegQueryDword(HKEY hKey, LPCWSTR subKey, LPCWSTR valueName) { 54 | HKEY hSubKey; 55 | DWORD type = REG_DWORD; 56 | 57 | LSTATUS status = RegOpenKeyExW(hKey, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hSubKey); 58 | if (status != ERROR_SUCCESS) return 0; 59 | 60 | DWORD value = 0; 61 | DWORD size = sizeof(DWORD); 62 | 63 | status = RegQueryValueExW(hSubKey, valueName, NULL, &type, (LPBYTE)&value, &size); 64 | if (status != ERROR_SUCCESS) value = 0; 65 | 66 | RegCloseKey(hSubKey); 67 | return value; 68 | } 69 | 70 | int PrettyPrintUnits(double* value, const wchar_t** units, int unit_count, double unit_step) { 71 | int unit_index = 0; 72 | while (*value >= unit_step && unit_index < (unit_count - 1)) { 73 | *value /= unit_step; 74 | unit_index++; 75 | } 76 | return unit_index; 77 | } 78 | -------------------------------------------------------------------------------- /src/PiMon.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 头文件 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 头文件 29 | 30 | 31 | 头文件 32 | 33 | 34 | 头文件 35 | 36 | 37 | 头文件 38 | 39 | 40 | 头文件 41 | 42 | 43 | 44 | 45 | 源文件 46 | 47 | 48 | 源文件 49 | 50 | 51 | 源文件 52 | 53 | 54 | 源文件 55 | 56 | 57 | 源文件 58 | 59 | 60 | 源文件 61 | 62 | 63 | 64 | 65 | 资源文件 66 | 67 | 68 | 69 | 70 | 资源文件 71 | 72 | 73 | 74 | 75 | 资源文件 76 | 77 | 78 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/listview.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "listview.h" 4 | 5 | void LVAddColumn(HWND hwnd, int pos, const wchar_t* header, int width) { 6 | size_t len = wcslen(header) + 1; 7 | wchar_t* str = (wchar_t*)malloc(len * sizeof(wchar_t)); 8 | if (str == NULL) return; 9 | wcscpy_s(str, len, header); 10 | 11 | LVCOLUMNW col = { 0 }; 12 | col.mask = LVCF_TEXT | LVCF_WIDTH; 13 | col.pszText = str; 14 | col.cchTextMax = (int)wcslen(str); 15 | col.cx = width; 16 | ListView_InsertColumn(hwnd, pos, &col); 17 | 18 | free(str); 19 | } 20 | 21 | void LVSetColumnWidth(HWND hwnd, int iCol, int width) { 22 | LVCOLUMNW col = { 0 }; 23 | col.mask = LVCF_WIDTH; 24 | col.cx = width; 25 | ListView_SetColumn(hwnd, iCol, &col); 26 | } 27 | 28 | void LVSetItemText(HWND hwnd, int iItem, int iSubItem, const wchar_t* text) { 29 | size_t len = wcslen(text) + 1; 30 | wchar_t* str = (wchar_t*)malloc(len * sizeof(wchar_t)); 31 | if (str == NULL) return; 32 | wcscpy_s(str, len, text); 33 | 34 | LVITEMW item = { 0 }; 35 | item.mask = LVIF_TEXT; 36 | item.iItem = iItem; 37 | item.iSubItem = iSubItem; 38 | item.pszText = str; 39 | item.cchTextMax = (int)wcslen(str); 40 | ListView_SetItem(hwnd, &item); 41 | 42 | free(str); 43 | } 44 | 45 | void LVSetItemGroupId(HWND hwnd, int iItem, int groupId) { 46 | LVITEMW item = { 0 }; 47 | item.mask = LVIF_GROUPID; 48 | item.iItem = iItem; 49 | item.iGroupId = groupId; 50 | ListView_SetItem(hwnd, &item); 51 | } 52 | 53 | void LVSetItemIndent(HWND hwnd, int iItem, int indent) { 54 | LVITEMW item = { 0 }; 55 | item.mask = LVIF_INDENT; 56 | item.iItem = iItem; 57 | item.iIndent = indent; 58 | ListView_SetItem(hwnd, &item); 59 | } 60 | 61 | 62 | void LVSetItemImage(HWND hwnd, int iItem, int imageId) { 63 | LVITEMW item = { 0 }; 64 | item.mask = LVIF_IMAGE; 65 | item.iItem = iItem; 66 | item.iImage = imageId; 67 | ListView_SetItem(hwnd, &item); 68 | } 69 | 70 | 71 | void LVAddGroup(HWND hwnd, int pos, const wchar_t* header, int id) { 72 | size_t len = wcslen(header) + 1; 73 | wchar_t* str = (wchar_t*)malloc(len * sizeof(wchar_t)); 74 | if (str == NULL) return; 75 | wcscpy_s(str, len, header); 76 | 77 | LVGROUP group = { 0 }; 78 | group.cbSize = sizeof(LVGROUP); 79 | group.mask = LVGF_HEADER | LVGF_GROUPID; 80 | group.pszHeader = str; 81 | group.cchHeader = (int)wcslen(str); 82 | group.iGroupId = id; 83 | ListView_InsertGroup(hwnd, pos, &group); 84 | 85 | free(str); 86 | } 87 | 88 | int LVAddItem(HWND hwnd, int pos, const wchar_t* text) { 89 | int index = 0; 90 | if (pos < 0) pos = ListView_GetItemCount(hwnd); 91 | 92 | size_t len = wcslen(text) + 1; 93 | wchar_t* str = (wchar_t*)malloc(len * sizeof(wchar_t)); 94 | if (str == NULL) return index; 95 | wcscpy_s(str, len, text); 96 | 97 | LVITEMW item = { 0 }; 98 | item.mask = LVIF_TEXT; 99 | item.iItem = pos; 100 | item.pszText = str; 101 | item.cchTextMax = (int)wcslen(str); 102 | index = ListView_InsertItem(hwnd, &item); 103 | 104 | free(str); 105 | return index; 106 | } 107 | -------------------------------------------------------------------------------- /src/tray.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "tray.h" 5 | #include "utils.h" 6 | 7 | void AddTrayIcon(HWND hwnd, UINT id, const wchar_t* desc, HICON icon, UINT msgId) { 8 | NOTIFYICONDATAW nid = { 0 }; 9 | nid.cbSize = sizeof(NOTIFYICONDATAW); 10 | nid.hWnd = hwnd; 11 | nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; 12 | nid.hIcon = icon; 13 | nid.uCallbackMessage = msgId; 14 | nid.uID = id; 15 | wcscpy_s(nid.szTip, 128, desc); 16 | Shell_NotifyIconW(NIM_ADD, &nid); 17 | } 18 | 19 | void DeleteTrayIcon(HWND hwnd, UINT id) { 20 | NOTIFYICONDATAW nid = { 0 }; 21 | nid.cbSize = sizeof(NOTIFYICONDATAW); 22 | nid.hWnd = hwnd; 23 | nid.uFlags = 0; 24 | nid.uID = id; 25 | Shell_NotifyIconW(NIM_DELETE, &nid); 26 | } 27 | 28 | HICON DrawTrayIcon(HWND hwnd, COLORREF bkColor, COLORREF textColor, double value) { 29 | int dpi = GetDpiForWindow(hwnd); 30 | int size = SCALE(16, dpi); 31 | 32 | // Create Memory Bitmap 33 | HDC dc = GetDC(hwnd); 34 | HDC memDC = CreateCompatibleDC(dc); 35 | HBITMAP hcolor = CreateCompatibleBitmap(dc, size, size); 36 | SelectObject(memDC, hcolor); 37 | 38 | // Fill Background 39 | RECT r = { 0, 0, size, size }; 40 | HBRUSH brush = CreateSolidBrush(bkColor); 41 | FillRect(memDC, &r, brush); 42 | SetBkColor(memDC, bkColor); 43 | 44 | // Set Text Color 45 | SetTextColor(memDC, textColor); 46 | 47 | // Set Font 48 | LOGFONTW font = { 0 }; 49 | font.lfWeight = FW_NORMAL; 50 | font.lfPitchAndFamily = DEFAULT_PITCH; 51 | if (value < 100.0) 52 | font.lfHeight = -9 * dpi / 72; 53 | else 54 | font.lfHeight = -8 * dpi / 72; 55 | wcscpy_s(font.lfFaceName, size, L"Segoe UI"); 56 | HFONT hfont = CreateFontIndirectW(&font); 57 | SelectObject(memDC, hfont); 58 | 59 | // Determine a sane format 60 | wchar_t str[5]; 61 | const wchar_t* format; 62 | if (value < 1.0) 63 | format = L"%.1g"; 64 | else if (value < 100.0) 65 | format = L"%.2g"; 66 | else 67 | format = L"%.3g"; 68 | StringCbPrintfW(str, sizeof(str), format, value); 69 | 70 | // Draw text 71 | DrawTextW(memDC, str, (int)wcslen(str), &r, DT_SINGLELINE | DT_CALCRECT); 72 | r.left = (size - r.right) / 2; r.right += r.left; 73 | r.top = (size - r.bottom) / 2; r.bottom += r.top; 74 | DrawTextW(memDC, str, (int)wcslen(str), &r, DT_SINGLELINE); 75 | 76 | // Create Icon 77 | HBITMAP hmask = CreateBitmap(size, size, 1, 1, NULL); 78 | ICONINFO ii = { TRUE, 0, 0, hmask, hcolor }; 79 | HICON trayIcon = CreateIconIndirect(&ii); 80 | 81 | // Cleanup 82 | DeleteObject(brush); 83 | DeleteObject(hcolor); 84 | DeleteObject(hmask); 85 | DeleteObject(hfont); 86 | DeleteDC(memDC); 87 | ReleaseDC(hwnd, dc); 88 | 89 | return trayIcon; 90 | } 91 | 92 | void UpdateTrayIcon(HWND hwnd, UINT id, HICON icon, const wchar_t* desc) { 93 | NOTIFYICONDATAW nid = { 0 }; 94 | nid.cbSize = sizeof(NOTIFYICONDATAW); 95 | nid.hWnd = hwnd; 96 | nid.uFlags = NIF_TIP | NIF_ICON; 97 | nid.uID = id; 98 | nid.hIcon = icon; 99 | wcscpy_s(nid.szTip, sizeof(nid.szTip) / sizeof(wchar_t), desc); 100 | Shell_NotifyIconW(NIM_MODIFY, &nid); 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/setting.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "setting.h" 8 | #include "resource.h" 9 | #include "data.h" 10 | #include "utils.h" 11 | 12 | // Global config 13 | BOOL alwaysOnTop; 14 | BOOL hideOnMinimize; 15 | BOOL acpiThermal; 16 | COLORREF trayBackground; 17 | COLORREF trayForeground; 18 | 19 | INT_PTR CALLBACK SettingsDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 20 | static COLORREF custom_colors[16] = { 0 }; 21 | static COLORREF tmpForeground; 22 | static COLORREF tmpBackground; 23 | static BOOL tmpAcpiThermal; 24 | 25 | static HWND hwndPreview; 26 | static HWND hwndAcpiThermal; 27 | static HBRUSH bkgBrush = NULL; 28 | 29 | CHOOSECOLORW c = { 0 }; 30 | c.lStructSize = sizeof(CHOOSECOLORW); 31 | c.hwndOwner = hwnd; 32 | c.lpCustColors = custom_colors; 33 | c.Flags = CC_RGBINIT; 34 | 35 | switch (uMsg) { 36 | case WM_INITDIALOG: 37 | MoveWindowToCenterOfScreen(hwnd); 38 | hwndPreview = GetDlgItem(hwnd, IDC_PREVIEW); 39 | hwndAcpiThermal = GetDlgItem(hwnd, IDC_ACPI_THERMAL); 40 | 41 | tmpForeground = trayForeground; 42 | tmpBackground = trayBackground; 43 | tmpAcpiThermal = acpiThermal; 44 | bkgBrush = CreateSolidBrush(tmpBackground); 45 | 46 | Button_SetCheck(hwndAcpiThermal, tmpAcpiThermal ? BST_CHECKED : BST_UNCHECKED); 47 | return TRUE; 48 | case WM_CTLCOLORSTATIC: 49 | if ((HWND)lParam == hwndPreview) { 50 | SetTextColor((HDC)wParam, tmpForeground); 51 | SetBkColor((HDC)wParam, tmpBackground); 52 | return (INT_PTR)bkgBrush; 53 | } else { 54 | SetBkMode((HDC)wParam, TRANSPARENT); 55 | return (INT_PTR)GetStockObject(NULL_BRUSH); 56 | } 57 | case WM_COMMAND: 58 | switch (LOWORD(wParam)) { 59 | case IDC_FOREGROUND: 60 | c.rgbResult = tmpForeground; 61 | ChooseColorW(&c); 62 | tmpForeground = c.rgbResult; 63 | 64 | InvalidateRect(hwndPreview, NULL, TRUE); 65 | return TRUE; 66 | case IDC_BACKGROUND: 67 | c.rgbResult = tmpBackground; 68 | ChooseColorW(&c); 69 | tmpBackground = c.rgbResult; 70 | 71 | DeleteObject(bkgBrush); 72 | bkgBrush = CreateSolidBrush(tmpBackground); 73 | InvalidateRect(hwndPreview, NULL, TRUE); 74 | 75 | return TRUE; 76 | case IDC_ACPI_THERMAL: 77 | tmpAcpiThermal = (Button_GetCheck(hwndAcpiThermal) == BST_CHECKED); 78 | return TRUE; 79 | case IDOK: 80 | trayForeground = tmpForeground; 81 | ConfigSetColor(PIMON_APPNAME, CONFIG_TRAY_FOREGROUND, trayForeground); 82 | 83 | trayBackground = tmpBackground; 84 | ConfigSetColor(PIMON_APPNAME, CONFIG_TRAY_BACKGROUND, trayBackground); 85 | 86 | acpiThermal = tmpAcpiThermal; 87 | ConfigSetInt(PIMON_APPNAME, CONFIG_ACPI_THERMAL_ZONE, acpiThermal); 88 | case IDCANCEL: 89 | EndDialog(hwnd, wParam); 90 | return TRUE; 91 | } 92 | } 93 | return FALSE; 94 | } 95 | 96 | 97 | void LoadConfig() { 98 | alwaysOnTop = ConfigGetInt(PIMON_APPNAME, CONFIG_ALWAYS_ON_TOP, FALSE); 99 | hideOnMinimize = ConfigGetInt(PIMON_APPNAME, CONFIG_HIDE_ON_MINIMIZE, FALSE); 100 | acpiThermal = ConfigGetInt(PIMON_APPNAME, CONFIG_ACPI_THERMAL_ZONE, FALSE); 101 | trayBackground = ConfigGetColor(PIMON_APPNAME, CONFIG_TRAY_BACKGROUND, RGB(128, 0, 0)); 102 | trayForeground = ConfigGetColor(PIMON_APPNAME, CONFIG_TRAY_FOREGROUND, RGB(255, 255, 255)); 103 | } 104 | 105 | 106 | void GetExecutableDirectory(wchar_t* path, DWORD size) { 107 | if (!path) return; 108 | GetModuleFileNameW(NULL, path, size); 109 | PathCchRemoveFileSpec(path, size); 110 | } 111 | 112 | void GetConfigFile(wchar_t* path, DWORD size) { 113 | if (!path) return; 114 | wchar_t exeDir[MAX_PATH] = { 0 }; 115 | GetExecutableDirectory(exeDir, MAX_PATH); 116 | PathCchCombine(path, size, exeDir, PIMON_APPNAME L".ini"); 117 | } 118 | 119 | int ConfigGetInt(const wchar_t* section, const wchar_t* key, int default_value) { 120 | wchar_t configPath[MAX_PATH] = { 0 }; 121 | GetConfigFile(configPath, MAX_PATH); 122 | return GetPrivateProfileIntW(section, key, default_value, configPath); 123 | } 124 | 125 | BOOL ConfigSetInt(const wchar_t* section, const wchar_t* key, int value) { 126 | wchar_t configPath[MAX_PATH] = { 0 }; 127 | GetConfigFile(configPath, MAX_PATH); 128 | return WritePrivateProfileStringW(section, key, value ? L"1" : L"0", configPath); 129 | } 130 | 131 | COLORREF ParseColorString(const wchar_t* str) { 132 | ULONG r, g, b; 133 | if (swscanf_s(str, L"#%02X%02x%02x", &r, &g, &b) < 3) return -1; 134 | if (r > 255 || g > 255 || b > 255) return -1; 135 | return RGB(r, g, b); 136 | } 137 | 138 | void GetColorString(COLORREF color, wchar_t* str, size_t size) { 139 | if (str == NULL || size < 8 * sizeof(wchar_t)) return; 140 | BYTE r = GetRValue(color); 141 | BYTE g = GetGValue(color); 142 | BYTE b = GetBValue(color); 143 | StringCbPrintfW(str, size, L"#%02X%02X%02X", r, g, b); 144 | } 145 | 146 | COLORREF ConfigGetColor(const wchar_t* section, const wchar_t* key, COLORREF default_value) { 147 | wchar_t configPath[MAX_PATH] = { 0 }; 148 | GetConfigFile(configPath, MAX_PATH); 149 | 150 | wchar_t def[10] = { 0 }; 151 | GetColorString(default_value, def, sizeof(def)); 152 | 153 | wchar_t str[10] = { 0 }; 154 | GetPrivateProfileStringW(section, key, def, str, 10, configPath); 155 | 156 | COLORREF c = ParseColorString(str); 157 | if (c > RGB(255, 255, 255)) 158 | return default_value; 159 | else 160 | return c; 161 | } 162 | 163 | void ConfigSetColor(const wchar_t* section, const wchar_t* key, COLORREF value) { 164 | wchar_t configPath[MAX_PATH] = { 0 }; 165 | GetConfigFile(configPath, MAX_PATH); 166 | 167 | wchar_t str[10] = { 0 }; 168 | GetColorString(value, str, sizeof(str)); 169 | 170 | WritePrivateProfileStringW(section, key, str, configPath); 171 | } 172 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /src/data.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rpiq.h" 5 | #include "utils.h" 6 | #include "data.h" 7 | 8 | #ifdef _DEBUG 9 | #define DEBUGLOG(x, ...) wprintf(x, __VA_ARGS__) 10 | #else 11 | #define DEBUGLOG(x, ...) 12 | #endif 13 | 14 | static const wchar_t* RpiProcessorName[] = { 15 | [CPU_UNKNOWN] = L"Unknown", 16 | [CPU_BCM2835] = L"BCM2835 (ARM11)", 17 | [CPU_BCM2836] = L"BCM2836 (ARM Cortex-A7)", 18 | [CPU_BCM2837] = L"BCM2837 (ARM Cortex-A53)", 19 | [CPU_BCM2711] = L"BCM2711 (ARM Cortex-A72)", 20 | }; 21 | 22 | static const wchar_t* RpiModelName[] = { 23 | [MODEL_A] = L"Raspberry Pi Model A", 24 | [MODEL_B] = L"Raspberry Pi Model B", 25 | [MODEL_A_PLUS] = L"Raspberry Pi Model A+", 26 | [MODEL_B_PLUS] = L"Raspberry Pi Model B+", 27 | [MODEL_2B] = L"Raspberry Pi 2 Model B", 28 | [MODEL_CM1] = L"Raspberry Pi Compute Module 1", 29 | [MODEL_3B] = L"Raspberry Pi 3 Model B", 30 | [MODEL_ZERO] = L"Raspberry Pi Zero", 31 | [MODEL_CM3] = L"Raspberry Pi Compute Module 3", 32 | [MODEL_ZERO_W] = L"Raspberry Pi Zero W", 33 | [MODEL_3B_PLUS] = L"Raspberry Pi 3 Model B+", 34 | [MODEL_3A_PLUS] = L"Raspberry Pi 3 Model A+", 35 | [MODEL_CM3_PLUS] = L"Raspberry Pi Compute Module 3+", 36 | [MODEL_4B] = L"Raspberry Pi 4 Model B", 37 | [MODEL_PI400] = L"Raspberry Pi 400", 38 | [MODEL_CM4] = L"Raspberry Pi Compute Module 4", 39 | [MODEL_UNKNOWN] = L"Unknown Raspberry Pi Model" 40 | }; 41 | 42 | ULONG GetBoardRevision() { 43 | ULONG value = 0; 44 | 45 | HANDLE hDevice = CreateFileW( 46 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 47 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 48 | ); 49 | if (hDevice == INVALID_HANDLE_VALUE) return value; 50 | 51 | DWORD bytesReturned; 52 | 53 | MAILBOX_GET_BOARD_REVISION mailbox; 54 | INIT_MAILBOX_GET_BOARD_REVISION(&mailbox); 55 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 56 | (LPVOID)(&mailbox), sizeof(mailbox), 57 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 58 | if (status) value = mailbox.BoardRevision; 59 | 60 | CloseHandle(hDevice); 61 | return value; 62 | } 63 | 64 | ULONG GetVoltage(int voltageId) { 65 | ULONG value = 0; 66 | 67 | HANDLE hDevice = CreateFileW( 68 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 69 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 70 | ); 71 | if (hDevice == INVALID_HANDLE_VALUE) return value; 72 | 73 | DWORD bytesReturned; 74 | 75 | MAILBOX_GET_VOLTAGE mailbox; 76 | INIT_MAILBOX_GET_VOLTAGE(&mailbox, voltageId); 77 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 78 | (LPVOID)(&mailbox), sizeof(mailbox), 79 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 80 | if (status) value = mailbox.Value; 81 | 82 | CloseHandle(hDevice); 83 | return value; 84 | } 85 | 86 | ULONG GetClock(int clockId) { 87 | ULONG value = 0; 88 | 89 | HANDLE hDevice = CreateFileW( 90 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 91 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 92 | ); 93 | if (hDevice == INVALID_HANDLE_VALUE) return value; 94 | 95 | DWORD bytesReturned; 96 | 97 | MAILBOX_GET_CLOCK_RATE mailbox; 98 | INIT_MAILBOX_GET_CLOCK_RATE(&mailbox, clockId); 99 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 100 | (LPVOID)(&mailbox), sizeof(mailbox), 101 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 102 | if (status) value = mailbox.Rate; 103 | 104 | CloseHandle(hDevice); 105 | return value; 106 | } 107 | 108 | ULONG GetMeasuredClock(int clockId) { 109 | ULONG value = 0; 110 | 111 | HANDLE hDevice = CreateFileW( 112 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 113 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 114 | ); 115 | if (hDevice == INVALID_HANDLE_VALUE) return value; 116 | 117 | DWORD bytesReturned; 118 | 119 | MAILBOX_GET_MEASURED_CLOCK_RATE mailbox; 120 | INIT_MAILBOX_GET_MEASURED_CLOCK_RATE(&mailbox, clockId); 121 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 122 | (LPVOID)(&mailbox), sizeof(mailbox), 123 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 124 | if (status) value = mailbox.Rate; 125 | 126 | CloseHandle(hDevice); 127 | return value; 128 | } 129 | 130 | ULONG GetTemperature() { 131 | ULONG value = 0; 132 | 133 | HANDLE hDevice = CreateFileW( 134 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 135 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 136 | ); 137 | if (hDevice == INVALID_HANDLE_VALUE) return value; 138 | 139 | DWORD bytesReturned; 140 | 141 | MAILBOX_GET_TEMPERATURE mailbox; 142 | INIT_MAILBOX_GET_TEMPERATURE(&mailbox); 143 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 144 | (LPVOID)(&mailbox), sizeof(mailbox), 145 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 146 | if (status) value = mailbox.Value; 147 | 148 | CloseHandle(hDevice); 149 | return value; 150 | } 151 | 152 | ULONG GetFirmwareRevision() { 153 | ULONG value = 0; 154 | 155 | HANDLE hDevice = CreateFileW( 156 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 157 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 158 | ); 159 | if (hDevice == INVALID_HANDLE_VALUE) return value; 160 | 161 | DWORD bytesReturned; 162 | 163 | MAILBOX_GET_FIRMWARE_REVISION mailbox; 164 | INIT_MAILBOX_GET_FIRMWARE_REVISION(&mailbox); 165 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 166 | (LPVOID)(&mailbox), sizeof(mailbox), 167 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 168 | if (status) value = mailbox.FirmwareRevision; 169 | 170 | CloseHandle(hDevice); 171 | return value; 172 | } 173 | 174 | ULONGLONG GetSerialNumber() { 175 | ULONGLONG value = 0; 176 | 177 | HANDLE hDevice = CreateFileW( 178 | RPIQ_USERMODE_PATH, GENERIC_READ | GENERIC_WRITE, 179 | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 180 | ); 181 | if (hDevice == INVALID_HANDLE_VALUE) return value; 182 | 183 | DWORD bytesReturned; 184 | 185 | MAILBOX_GET_BOARD_SERIAL mailbox; 186 | INIT_MAILBOX_GET_BOARD_SERIAL(&mailbox); 187 | BOOL status = DeviceIoControl(hDevice, IOCTL_MAILBOX_PROPERTY, 188 | (LPVOID)(&mailbox), sizeof(mailbox), 189 | (LPVOID)(&mailbox), sizeof(mailbox), &bytesReturned, 0); 190 | if (status) { 191 | value = *(ULONGLONG*)(mailbox.BoardSerial); 192 | } 193 | 194 | CloseHandle(hDevice); 195 | return value; 196 | } 197 | 198 | ULONG GetWindowsMemory() { 199 | MEMORYSTATUSEX memStatus; 200 | memStatus.dwLength = sizeof(MEMORYSTATUSEX); 201 | GlobalMemoryStatusEx(&memStatus); 202 | 203 | return (ULONG)(memStatus.ullTotalPhys / 1048576ULL); 204 | } 205 | 206 | ULONG GetInstalledMemory(ULONG BoardRevision) { 207 | // 208 | // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 209 | // Bits [20-22] indicate the amount of memory starting with 256MB (000b) 210 | // and doubling in size for each value (001b = 512 MB, 010b = 1GB, etc.) 211 | // 212 | return 256 << ((BoardRevision >> 20) & 0x07); 213 | } 214 | 215 | enum RpiProcessor GetProcessorType(ULONG BoardRevision) 216 | { 217 | // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 218 | ULONG cpuId = (BoardRevision >> 12) & 0x0F; 219 | 220 | switch (cpuId) { 221 | case 0x00: 222 | return CPU_BCM2835; 223 | case 0x01: 224 | return CPU_BCM2836; 225 | case 0x02: 226 | return CPU_BCM2837; 227 | case 0x03: 228 | return CPU_BCM2711; 229 | default: 230 | return CPU_UNKNOWN; 231 | } 232 | } 233 | 234 | enum RpiModel GetPiModel(ULONG BoardRevision) 235 | { 236 | // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md 237 | ULONG modelId = (BoardRevision >> 4) & 0xFF; 238 | 239 | switch (modelId) { 240 | case 0x00: 241 | return MODEL_A; 242 | case 0x01: 243 | return MODEL_B; 244 | case 0x02: 245 | return MODEL_A_PLUS; 246 | case 0x03: 247 | return MODEL_B_PLUS; 248 | case 0x04: 249 | return MODEL_2B; 250 | case 0x06: 251 | return MODEL_CM1; 252 | case 0x08: 253 | return MODEL_3B; 254 | case 0x09: 255 | return MODEL_ZERO; 256 | case 0x0A: 257 | return MODEL_CM3; 258 | case 0x0C: 259 | return MODEL_ZERO_W; 260 | case 0x0D: 261 | return MODEL_3B_PLUS; 262 | case 0x0E: 263 | return MODEL_3A_PLUS; 264 | case 0x10: 265 | return MODEL_CM3_PLUS; 266 | case 0x11: 267 | return MODEL_4B; 268 | case 0x13: 269 | return MODEL_PI400; 270 | case 0x14: 271 | return MODEL_CM4; 272 | default: 273 | return MODEL_UNKNOWN; 274 | } 275 | } 276 | 277 | const wchar_t* GetProcessorName(ULONG BoardRevision) 278 | { 279 | return RpiProcessorName[GetProcessorType(BoardRevision)]; 280 | } 281 | 282 | const wchar_t* GetPiModelName(ULONG BoardRevision) 283 | { 284 | return RpiModelName[GetPiModel(BoardRevision)]; 285 | } 286 | 287 | wchar_t* GetBiosVersion() { 288 | return RegQueryString(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", L"BIOSVersion"); 289 | } 290 | 291 | wchar_t* GetWindowsVersion() { 292 | DWORD ubr = RegQueryDword(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"UBR"); 293 | wchar_t* currentBuild = RegQueryString(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuild"); 294 | wchar_t* productName = RegQueryString(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"ProductName"); 295 | 296 | // PROCESSOR_ARCHITEW6432 is the native arch when running in WOW64 297 | wchar_t arch[10]; 298 | if (!GetEnvironmentVariableW(L"PROCESSOR_ARCHITEW6432", arch, 10)) 299 | GetEnvironmentVariableW(L"PROCESSOR_ARCHITECTURE", arch, 10); 300 | 301 | wchar_t* str = (wchar_t*)malloc(100 * sizeof(wchar_t)); 302 | if (str != NULL) StringCchPrintfW(str, 100, L"%ws %ws Build %ws.%d", productName, arch, currentBuild, ubr); 303 | 304 | free(currentBuild); 305 | free(productName); 306 | return str; 307 | } 308 | 309 | 310 | ULONG GetTemperatureAcpi() { 311 | LONGLONG value = 0; 312 | ULONG status; 313 | 314 | DWORD queryId = 0; 315 | PDH_HQUERY hQuery = NULL; 316 | status = PdhOpenQueryW(NULL, (DWORD_PTR)&queryId, &hQuery); 317 | if (status != ERROR_SUCCESS) { 318 | DEBUGLOG(L"PdhOpenQuery() Failed, status=%08x", status); 319 | goto err0; 320 | } 321 | 322 | DWORD size = 0; 323 | wchar_t* pathList = NULL; 324 | const wchar_t* wildcardPath = L"\\Thermal Zone Information(*)\\High Precision Temperature"; 325 | PdhExpandWildCardPathW(NULL, wildcardPath, pathList, &size, 0); 326 | pathList = malloc(sizeof(wchar_t) * size); 327 | if (pathList == NULL) goto err1; 328 | 329 | PdhExpandWildCardPathW(NULL, wildcardPath, pathList, &size, 0); 330 | if (status != ERROR_SUCCESS) { 331 | DEBUGLOG(L"PdhExpandWildCardPath() Failed, status=%08x", status); 332 | goto err2; 333 | } 334 | 335 | // Raspberry Pi only have one thermal zone 336 | DWORD counterId = 0; 337 | PDH_HCOUNTER hCounter = NULL; 338 | const wchar_t* path = pathList; 339 | status = PdhAddCounterW(hQuery, path, (DWORD_PTR)&counterId, &hCounter); 340 | if (status != ERROR_SUCCESS) { 341 | DEBUGLOG(L"PdhAddCounter() Failed, status=%08x", status); 342 | goto err2; 343 | } 344 | 345 | status = PdhCollectQueryData(hQuery); 346 | if (status != ERROR_SUCCESS) { 347 | DEBUGLOG(L"PdhCollectQueryData() Failed, status=%08x", status); 348 | goto err2; 349 | } 350 | 351 | PDH_RAW_COUNTER raw = { 0 }; 352 | DWORD type = PERF_COUNTER_RAWCOUNT; 353 | status = PdhGetRawCounterValue(hCounter, NULL, &raw); 354 | if (status != ERROR_SUCCESS) { 355 | DEBUGLOG(L"PdhGetRawCounterValue() Failed, status=%08x", status); 356 | goto err2; 357 | } 358 | value = raw.FirstValue; 359 | 360 | err2: 361 | if (pathList != NULL) free(pathList); 362 | err1: 363 | if (hQuery != NULL) PdhCloseQuery(hQuery); 364 | err0: 365 | return (ULONG)value; 366 | } -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "resource.h" 11 | #include "version.h" 12 | #include "data.h" 13 | #include "tray.h" 14 | #include "listview.h" 15 | #include "utils.h" 16 | #include "setting.h" 17 | 18 | static HWND hwndListView; 19 | 20 | #define WNDCLASS_NAME L"HWMON_WNDCLASS" 21 | #define TRAYICON_ID 3683 22 | #define TIMER_ID 4074 23 | 24 | #define WM_TRAYICON (WM_USER + 101) 25 | UINT WM_TASKBAR_CREATE; 26 | 27 | typedef struct { 28 | const wchar_t* name; 29 | int id; 30 | ULONG data; 31 | } ItemInfo; 32 | 33 | #define GROUP_INFO 1 34 | #define ITEMS_INFO 5 35 | static ItemInfo infoItems[ITEMS_INFO] = { 36 | { L"Model" }, { L"Processor" }, { L"Memory" }, 37 | { L"Revision" }, { L"Serial Number" } 38 | }; 39 | 40 | #define GROUP_SOFT 2 41 | #define ITEMS_SOFT 3 42 | static ItemInfo softItems[ITEMS_SOFT] = { 43 | {L"Windows"}, { L"VC Firmware" }, { L"UEFI Firmware" } 44 | }; 45 | 46 | #define GROUP_TEMP 3 47 | #define ITEMS_TEMP 1 48 | static ItemInfo tempItems[ITEMS_TEMP] = { 49 | { L"System" } 50 | }; 51 | 52 | #define GROUP_CLKS 4 53 | #define ITEMS_CLKS 14 54 | static ItemInfo clockItems[ITEMS_CLKS] = { 55 | { L"EMMC" }, { L"UART" }, { L"ARM" }, { L"CORE" }, { L"V3D" }, 56 | { L"H264" }, { L"ISP" }, { L"SDRAM" }, { L"PIXEL" }, { L"PWM" }, 57 | { L"HEVC" }, { L"EMMC2" }, { L"M2MC" }, { L"PIXEL_BVB" } 58 | }; 59 | 60 | #define GROUP_VOLT 5 61 | #define ITEMS_VOLT 4 62 | static ItemInfo voltItems[ITEMS_VOLT] = { 63 | { L"CORE" }, { L"SDRAM C" }, { L"SDRAM P" }, { L"SDRAM I" } 64 | }; 65 | 66 | static const wchar_t* mem_units[] = { L"MB", L"GB" }; 67 | static const wchar_t* clk_units[] = { L"Hz", L"MHz", L"GHz" }; 68 | 69 | void RpiqError(HWND hwnd) { 70 | #ifndef _DEBUG 71 | MessageBoxW(hwnd, 72 | L"Got a board revision of zero.\n\n" 73 | PIMON_APPNAME L" is designed for Windows on Raspberry Pis only.\n" 74 | L"It will not work on generic Windows PCs.\n\n" 75 | L"If you are running on a Raspberry Pi, \n" 76 | L"the RPIQ driver might not be working properly.\n\n" 77 | L"Try updating your RPIQ driver from\n" 78 | L"https://github.com/driver1998/bsp/releases.", 79 | L"RPIQ driver issue", MB_OK | MB_ICONERROR); 80 | #endif 81 | } 82 | 83 | void GetInfo(HWND hwnd) { 84 | wchar_t str[200]; 85 | ULONG rev = GetBoardRevision(); 86 | 87 | if (rev == 0) RpiqError(hwnd); 88 | 89 | // Model Name 90 | LVSetItemText(hwndListView, infoItems[0].id, 1, GetPiModelName(rev)); 91 | 92 | // Processor Name 93 | LVSetItemText(hwndListView, infoItems[1].id, 1, GetProcessorName(rev)); 94 | 95 | // Physically installed RAM 96 | double phyRam = GetInstalledMemory(rev); 97 | int u1 = PrettyPrintUnits(&phyRam, mem_units, sizeof(mem_units) / sizeof(wchar_t*), 1024.0); 98 | 99 | // RAM available to Windows 100 | double ram = GetWindowsMemory(); 101 | int u2 = PrettyPrintUnits(&ram, mem_units, sizeof(mem_units) / sizeof(wchar_t*), 1024.0); 102 | 103 | // Memory 104 | StringCbPrintfW(str, sizeof(str), L"%.3lg %ws (%.3lg %ws Usable)", phyRam, mem_units[u1], ram, mem_units[u2]); 105 | LVSetItemText(hwndListView, infoItems[2].id, 1, str); 106 | 107 | // Revision 108 | StringCbPrintfW(str, sizeof(str), L"%X", rev); 109 | LVSetItemText(hwndListView, infoItems[3].id, 1, str); 110 | 111 | // Serial Number 112 | ULONGLONG serial = GetSerialNumber(); 113 | StringCbPrintfW(str, sizeof(str), L"%llX", serial); 114 | LVSetItemText(hwndListView, infoItems[4].id, 1, str); 115 | 116 | // Windows Version 117 | wchar_t* ver = GetWindowsVersion(); 118 | StringCbPrintfW(str, sizeof(str), ver); 119 | LVSetItemText(hwndListView, softItems[0].id, 1, str); 120 | 121 | // VC Firmware 122 | time_t firmware = (time_t)GetFirmwareRevision(); 123 | struct tm time; 124 | gmtime_s(&time, &firmware); 125 | StringCbPrintfW(str, sizeof(str), L"%04d-%02d-%02d", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday); 126 | LVSetItemText(hwndListView, softItems[1].id, 1, str); 127 | 128 | // UEFI Firmware 129 | wchar_t* biosVersion = GetBiosVersion(); 130 | LVSetItemText(hwndListView, softItems[2].id, 1, biosVersion); 131 | free(biosVersion); 132 | } 133 | 134 | void UpdateData(HWND hwnd, BOOL force) { 135 | wchar_t str[20]; 136 | 137 | // Temperature 138 | { 139 | ULONG value = acpiThermal ? GetTemperatureAcpi() : GetTemperature(); 140 | 141 | if (value != tempItems[0].data || force) { 142 | tempItems[0].data = value; 143 | double temp = acpiThermal ? (value - 2732) / 10.0 : value / 1000.0; 144 | 145 | HICON icon = DrawTrayIcon(hwnd, trayBackground, trayForeground, temp); 146 | StringCbPrintfW(str, sizeof(str), L"Temperature: %.3lg \u2103", temp); 147 | UpdateTrayIcon(hwnd, TRAYICON_ID, icon, str); 148 | DestroyIcon(icon); 149 | 150 | StringCbPrintfW(str, sizeof(str), L"%.3lg \u2103", temp); 151 | LVSetItemText(hwndListView, tempItems[0].id, 1, str); 152 | } 153 | } 154 | 155 | // Clocks 156 | for (ULONG i = 0; i < ITEMS_CLKS; i++) { 157 | ULONG value = GetMeasuredClock(i + 1); 158 | if (value != clockItems[i].data || force) { 159 | clockItems[i].data = value; 160 | double clock = value / 1000.0; 161 | int u = PrettyPrintUnits(&clock, clk_units, sizeof(clk_units) / sizeof(wchar_t*), 1000.0); 162 | 163 | StringCbPrintfW(str, sizeof(str), L"%.3lg %ws", clock, clk_units[u]); 164 | LVSetItemText(hwndListView, clockItems[i].id, 1, str); 165 | } 166 | } 167 | 168 | // Voltages 169 | for (ULONG i = 0; i < ITEMS_VOLT; i++) { 170 | ULONG value = GetVoltage(i + 1); 171 | if (value != voltItems[i].data || force) { 172 | voltItems[i].data = value; 173 | double voltage = (value / 1000000.0) * 0.025 + 1.2; 174 | 175 | StringCbPrintfW(str, sizeof(str), L"%.3lg V", voltage); 176 | LVSetItemText(hwndListView, voltItems[i].id, 1, str); 177 | } 178 | } 179 | } 180 | 181 | void About(HWND hwnd) { 182 | MessageBoxW(hwnd, 183 | PIMON_APPNAME L" Version " PIMON_VERSION L"\n" 184 | L"Copyright (c) driver1998\n\n" 185 | L"GitHub: https://github.com/driver1998/PiMon \n" 186 | L"Release under the MIT License", 187 | L"About", MB_ICONINFORMATION | MB_OK); 188 | } 189 | 190 | void SettingsDialog(HWND hwnd) { 191 | HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE); 192 | DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_CONFIG), hwnd, (DLGPROC)SettingsDialogProc); 193 | UpdateData(hwnd, TRUE); 194 | } 195 | 196 | void AlwaysOnTop(HWND hwnd, BOOL value) { 197 | alwaysOnTop = value; 198 | ConfigSetInt(PIMON_APPNAME, CONFIG_ALWAYS_ON_TOP, alwaysOnTop); 199 | 200 | HMENU menu = GetSystemMenu(hwnd, FALSE); 201 | CheckMenuItem(menu, IDM_SYS_ALWAYS_TOP, alwaysOnTop ? MF_CHECKED : MF_UNCHECKED); 202 | 203 | SetWindowPos(hwnd, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 204 | } 205 | 206 | void HideOnMinimize(HWND hwnd, BOOL value) { 207 | hideOnMinimize = value; 208 | ConfigSetInt(PIMON_APPNAME, CONFIG_HIDE_ON_MINIMIZE, hideOnMinimize); 209 | 210 | HMENU menu = GetSystemMenu(hwnd, FALSE); 211 | CheckMenuItem(menu, IDM_SYS_HIDE_MINIMIZE, hideOnMinimize ? MF_CHECKED : MF_UNCHECKED); 212 | 213 | LONG style = GetWindowLongW(hwnd, GWL_STYLE); 214 | if (hideOnMinimize && (style & WS_MINIMIZE)) { 215 | ShowWindow(hwnd, SW_HIDE); 216 | } 217 | else if (!hideOnMinimize && !(style & WS_VISIBLE)) { 218 | ShowWindow(hwnd, SW_SHOWNORMAL); 219 | } 220 | } 221 | 222 | void InitListView(HWND hwnd) { 223 | LVAddColumn(hwndListView, 0, L"Description", 120); 224 | LVAddColumn(hwndListView, 1, L"Value", 240); 225 | ListView_EnableGroupView(hwndListView, TRUE); 226 | ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); 227 | 228 | UINT dpi = GetDpiForWindow(hwnd); 229 | HIMAGELIST imageList = ImageList_Create(SCALE(16, dpi), SCALE(16, dpi), ILC_COLOR32, 2, 0); 230 | ListView_SetImageList(hwndListView, imageList, LVSIL_SMALL); 231 | 232 | // Info 233 | LVAddGroup(hwndListView, -1, L"Device Info", GROUP_INFO); 234 | for (ULONG i = 0; i < ITEMS_INFO; i++) { 235 | infoItems[i].id = LVAddItem(hwndListView, -1, infoItems[i].name); 236 | LVSetItemGroupId(hwndListView, infoItems[i].id, GROUP_INFO); 237 | } 238 | 239 | // Software Version 240 | LVAddGroup(hwndListView, -1, L"Software", GROUP_SOFT); 241 | for (ULONG i = 0; i < ITEMS_SOFT; i++) { 242 | softItems[i].id = LVAddItem(hwndListView, -1, softItems[i].name); 243 | LVSetItemGroupId(hwndListView, softItems[i].id, GROUP_SOFT); 244 | } 245 | 246 | // Temperature 247 | LVAddGroup(hwndListView, -1, L"Temperature", GROUP_TEMP); 248 | for (ULONG i = 0; i < ITEMS_TEMP; i++) { 249 | tempItems[i].id = LVAddItem(hwndListView, -1, tempItems[i].name); 250 | LVSetItemGroupId(hwndListView, tempItems[i].id, GROUP_TEMP); 251 | LVSetItemText(hwndListView, tempItems[0].id, 1, L"0 \u2103"); 252 | } 253 | 254 | // Clocks 255 | LVAddGroup(hwndListView, -1, L"Clocks", GROUP_CLKS); 256 | for (ULONG i = 0; i < ITEMS_CLKS; i++) { 257 | clockItems[i].id = LVAddItem(hwndListView, -1, clockItems[i].name); 258 | LVSetItemGroupId(hwndListView, clockItems[i].id, GROUP_CLKS); 259 | LVSetItemText(hwndListView, clockItems[i].id, 1, L"0 Hz"); 260 | } 261 | 262 | // Voltages 263 | LVAddGroup(hwndListView, -1, L"Voltages", GROUP_VOLT); 264 | for (ULONG i = 0; i < ITEMS_VOLT; i++) { 265 | voltItems[i].id = LVAddItem(hwndListView, -1, voltItems[i].name); 266 | LVSetItemGroupId(hwndListView, voltItems[i].id, GROUP_VOLT); 267 | LVSetItemText(hwndListView, voltItems[i].id, 1, L"0 V"); 268 | } 269 | } 270 | 271 | void InitTrayIcon(HWND hwnd) { 272 | HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE); 273 | HICON icon = LoadIconW(hInstance, MAKEINTRESOURCEW(10)); 274 | AddTrayIcon(hwnd, TRAYICON_ID, PIMON_APPNAME, icon, WM_TRAYICON); 275 | } 276 | 277 | void InitSysMenu(HWND hwnd) { 278 | HMENU menu = GetSystemMenu(hwnd, FALSE); 279 | AppendMenuW(menu, MF_SEPARATOR, 0, NULL); 280 | AppendMenuW(menu, MF_STRING, IDM_SYS_ALWAYS_TOP, L"Always on &Top"); 281 | AppendMenuW(menu, MF_STRING, IDM_SYS_HIDE_MINIMIZE, L"&Hide on Minimize"); 282 | AppendMenuW(menu, MF_SEPARATOR, 0, NULL); 283 | AppendMenuW(menu, MF_STRING, IDM_SYS_SETTINGS, L"S&ettings..."); 284 | AppendMenuW(menu, MF_STRING, IDM_SYS_ABOUT, L"&About..."); 285 | CheckMenuItem(menu, IDM_SYS_ALWAYS_TOP, alwaysOnTop ? MF_CHECKED : MF_UNCHECKED); 286 | CheckMenuItem(menu, IDM_SYS_HIDE_MINIMIZE, hideOnMinimize ? MF_CHECKED : MF_UNCHECKED); 287 | } 288 | 289 | void OnCreate(HWND hwnd, CREATESTRUCTW* c) { 290 | ResizeWindowByClientArea(hwnd, 460, 590); 291 | MoveWindowToCenterOfScreen(hwnd); 292 | 293 | hwndListView = CreateWindowExW( 294 | 0, 295 | WC_LISTVIEWW, 296 | L"ListView", 297 | WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | 298 | WS_TABSTOP | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | LVS_REPORT, 299 | 0, 0, 250, 500, 300 | hwnd, 301 | NULL, 302 | c->hInstance, 303 | NULL 304 | ); 305 | 306 | InitTrayIcon(hwnd); 307 | InitSysMenu(hwnd); 308 | InitListView(hwnd); 309 | 310 | GetInfo(hwnd); 311 | UpdateData(hwnd, TRUE); 312 | 313 | SetTimer(hwnd, TIMER_ID, 1000, NULL); 314 | } 315 | 316 | void OnResize(HWND hwnd, WPARAM wParam, WORD client_width, WORD client_height) { 317 | if (hideOnMinimize && wParam == SIZE_MINIMIZED) { 318 | ShowWindow(hwnd, SW_HIDE); 319 | return; 320 | } 321 | 322 | UINT dpi = GetDpiForWindow(hwnd); 323 | MoveWindow(hwndListView, 0, 0, client_width, client_height, TRUE); 324 | 325 | LVSetColumnWidth(hwndListView, 0, SCALE(120, dpi)); 326 | 327 | int valueWidth = client_width - SCALE(120, dpi) - GetSystemMetricsForDpi(SM_CXVSCROLL, dpi); 328 | LVSetColumnWidth(hwndListView, 1, valueWidth); 329 | } 330 | 331 | void OnDpiChanged(HWND hwnd, WORD dpi, RECT* r) { 332 | MoveWindow(hwnd, r->left, r->top, (r->right - r->left), (r->bottom - r->top), TRUE); 333 | } 334 | 335 | LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 336 | 337 | // Explorer restarted, add tray icon again 338 | if (uMsg == WM_TASKBAR_CREATE) { 339 | InitTrayIcon(hwnd); 340 | UpdateData(hwnd, TRUE); 341 | } 342 | 343 | switch (uMsg) { 344 | case WM_CREATE: 345 | OnCreate(hwnd, (CREATESTRUCTW*)lParam); 346 | break; 347 | case WM_SIZE: 348 | OnResize(hwnd, wParam, LOWORD(lParam), HIWORD(lParam)); 349 | break; 350 | case WM_DPICHANGED: 351 | OnDpiChanged(hwnd, HIWORD(wParam), (RECT*)lParam); 352 | break; 353 | case WM_CLOSE: 354 | PostQuitMessage(0); 355 | break; 356 | case WM_COMMAND: 357 | if (HIWORD(wParam) == 0) { 358 | switch (LOWORD(wParam)) { 359 | case IDM_ABOUT: 360 | About(hwnd); 361 | break; 362 | case IDM_SETTINGS: 363 | SettingsDialog(hwnd); 364 | break; 365 | case IDM_ALWAYS_TOP: 366 | AlwaysOnTop(hwnd, !alwaysOnTop); 367 | break; 368 | case IDM_HIDE_MINIMIZE: 369 | HideOnMinimize(hwnd, !hideOnMinimize); 370 | break; 371 | case IDM_EXIT: 372 | SendMessageW(hwnd, WM_CLOSE, 0, 0); 373 | break; 374 | } 375 | } 376 | break; 377 | case WM_TRAYICON: 378 | switch (lParam) { 379 | case WM_LBUTTONDBLCLK: { 380 | SetForegroundWindow(hwnd); 381 | LONG style = GetWindowLongW(hwnd, GWL_STYLE); 382 | if (style & WS_MINIMIZE || !(style & WS_VISIBLE)) 383 | ShowWindow(hwnd, SW_SHOWNORMAL); 384 | break; 385 | } 386 | case WM_RBUTTONUP: { 387 | HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE); 388 | POINT p; GetCursorPos(&p); 389 | 390 | HMENU menu = LoadMenuW(hInstance, MAKEINTRESOURCE(IDM_TRAY)); 391 | HMENU subMenu = GetSubMenu(menu, 0); 392 | 393 | CheckMenuItem(subMenu, IDM_ALWAYS_TOP, alwaysOnTop ? MF_CHECKED : MF_UNCHECKED); 394 | CheckMenuItem(subMenu, IDM_HIDE_MINIMIZE, hideOnMinimize ? MF_CHECKED : MF_UNCHECKED); 395 | 396 | SetForegroundWindow(hwnd); 397 | TrackPopupMenu(subMenu, TPM_BOTTOMALIGN, p.x, p.y, 0, hwnd, NULL); 398 | DestroyMenu(menu); 399 | break; 400 | } 401 | } 402 | break; 403 | case WM_SYSCOMMAND: 404 | switch (wParam) { 405 | case IDM_SYS_ABOUT: 406 | About(hwnd); 407 | break; 408 | case IDM_SYS_SETTINGS: 409 | SettingsDialog(hwnd); 410 | break; 411 | case IDM_SYS_ALWAYS_TOP: 412 | AlwaysOnTop(hwnd, !alwaysOnTop); 413 | break; 414 | case IDM_SYS_HIDE_MINIMIZE: 415 | HideOnMinimize(hwnd, !hideOnMinimize); 416 | break; 417 | } 418 | break; 419 | case WM_TIMER: 420 | UpdateData(hwnd, FALSE); 421 | break; 422 | } 423 | 424 | return DefWindowProcW(hwnd, uMsg, wParam, lParam); 425 | } 426 | 427 | _Use_decl_annotations_ 428 | int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { 429 | 430 | LoadConfig(); 431 | 432 | #ifdef _DEBUG 433 | FILE* stream; 434 | AllocConsole(); 435 | _wfreopen_s(&stream, L"CONOUT$", L"w", stdout); 436 | wprintf(PIMON_APPNAME L" v" PIMON_VERSION L"\n"); 437 | #endif 438 | 439 | // Register the Explorer restart message 440 | WM_TASKBAR_CREATE = RegisterWindowMessageW(L"TaskbarCreated"); 441 | 442 | WNDCLASS wc = { 0 }; 443 | wc.lpfnWndProc = WndProc; 444 | wc.hInstance = hInstance; 445 | wc.lpszClassName = WNDCLASS_NAME; 446 | wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 447 | wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_MAIN)); 448 | RegisterClassW(&wc); 449 | 450 | HWND hwnd = CreateWindowExW( 451 | 0, 452 | WNDCLASS_NAME, 453 | PIMON_APPNAME, 454 | WS_OVERLAPPEDWINDOW, 455 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 456 | NULL, 457 | NULL, 458 | hInstance, 459 | NULL 460 | ); 461 | if (hwnd == NULL) return -1; 462 | 463 | ShowWindow(hwnd, nCmdShow); 464 | 465 | MSG msg = { 0 }; 466 | while (GetMessageW(&msg, NULL, 0, 0)) { 467 | if (!IsDialogMessageW(hwnd, &msg)) { 468 | TranslateMessage(&msg); 469 | DispatchMessageW(&msg); 470 | } 471 | } 472 | 473 | KillTimer(hwnd, TIMER_ID); 474 | DeleteTrayIcon(hwnd, TRAYICON_ID); 475 | return 0; 476 | } -------------------------------------------------------------------------------- /src/PiMon.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | ARM64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | 30 | true 31 | 32 | 33 | true 34 | 35 | 36 | true 37 | 38 | 39 | true 40 | 41 | 42 | true 43 | 44 | 45 | true 46 | 47 | 48 | 15.0 49 | {4A8C24DD-C156-4607-9054-B8D43A541421} 50 | Win32Proj 51 | ConsoleApplication5 52 | 10.0 53 | 54 | 55 | 56 | Application 57 | true 58 | Unicode 59 | v142 60 | 61 | 62 | Application 63 | true 64 | Unicode 65 | v142 66 | 67 | 68 | Application 69 | true 70 | Unicode 71 | v142 72 | 73 | 74 | Application 75 | false 76 | true 77 | Unicode 78 | v142 79 | 80 | 81 | Application 82 | false 83 | true 84 | Unicode 85 | v142 86 | 87 | 88 | Application 89 | false 90 | true 91 | Unicode 92 | v142 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | true 120 | true 121 | 122 | 123 | true 124 | true 125 | 126 | 127 | true 128 | true 129 | 130 | 131 | false 132 | true 133 | 134 | 135 | false 136 | true 137 | 138 | 139 | false 140 | true 141 | 142 | 143 | 144 | NotUsing 145 | Level3 146 | Disabled 147 | true 148 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 149 | true 150 | MultiThreadedDebug 151 | 152 | 153 | Windows 154 | true 155 | pdh.lib;Pathcch.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 156 | 157 | 158 | false 159 | PerMonitorHighDPIAware 160 | PiMon.exe.manifest 161 | 162 | 163 | 164 | 165 | NotUsing 166 | Level3 167 | Disabled 168 | true 169 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 170 | true 171 | MultiThreadedDebug 172 | 173 | 174 | Windows 175 | true 176 | pdh.lib;Pathcch.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 177 | 178 | 179 | false 180 | PerMonitorHighDPIAware 181 | PiMon.exe.manifest 182 | 183 | 184 | 185 | 186 | NotUsing 187 | Level3 188 | Disabled 189 | true 190 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 191 | true 192 | MultiThreadedDebug 193 | 194 | 195 | Windows 196 | true 197 | pdh.lib;Pathcch.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 198 | 199 | 200 | false 201 | PerMonitorHighDPIAware 202 | 203 | 204 | 205 | 206 | 207 | 208 | NotUsing 209 | Level3 210 | MaxSpeed 211 | true 212 | true 213 | true 214 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 215 | true 216 | MultiThreaded 217 | 218 | 219 | Windows 220 | true 221 | true 222 | true 223 | pdh.lib;Pathcch.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 224 | 225 | 226 | false 227 | PerMonitorHighDPIAware 228 | PiMon.exe.manifest 229 | 230 | 231 | 232 | 233 | NotUsing 234 | Level3 235 | MaxSpeed 236 | true 237 | true 238 | true 239 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 240 | true 241 | MultiThreaded 242 | 243 | 244 | Windows 245 | true 246 | true 247 | true 248 | pdh.lib;Pathcch.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 249 | 250 | 251 | false 252 | PerMonitorHighDPIAware 253 | PiMon.exe.manifest 254 | 255 | 256 | 257 | 258 | NotUsing 259 | Level3 260 | MaxSpeed 261 | true 262 | true 263 | true 264 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 265 | true 266 | MultiThreaded 267 | 268 | 269 | Windows 270 | true 271 | true 272 | true 273 | pdh.lib;Pathcch.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 274 | 275 | 276 | false 277 | PerMonitorHighDPIAware 278 | PiMon.exe.manifest 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /src/rpiq.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // Module Name: 5 | // 6 | // rpiq.h 7 | // 8 | // Abstract: 9 | // 10 | // This file contains public header to interface with RPIQ driver. 11 | // 12 | 13 | #ifndef _RPIQ_H 14 | #define _RPIQ_H 15 | 16 | #include 17 | 18 | #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 19 | 20 | #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #define FILE_DEVICE_RPIQ 2836 27 | 28 | // 29 | // Symbolic Link 30 | // 31 | #define RPIQ_NAME L"RPIQ" 32 | #define RPIQ_SYMBOLIC_NAME L"\\DosDevices\\" RPIQ_NAME 33 | #define RPIQ_USERMODE_PATH L"\\\\.\\" RPIQ_NAME 34 | 35 | #define OFFSET_DIRECT_SDRAM 0xC0000000 // Direct Access to SDRAM 36 | 37 | // 38 | // Interface GUID 39 | // 40 | // {96d104c2-6e21-49a6-8873-80d88835f763} 41 | // 42 | DEFINE_GUID(RPIQ_INTERFACE_GUID, 0x96d104c2, 0x6e21, 0x49a6, 0x88, 0x73, 0x80, 0xd8, 0x88, 0x35, 0xf7, 0x63 ); 43 | 44 | // 45 | // RPIQ IOCTL definition 46 | // 47 | enum RPIQFunction 48 | { 49 | RPIQ_FUNC_MIN = 2000, 50 | RPIQ_FUNC_MAILBOX_POWER_MANAGEMENT = 2000, 51 | RPIQ_FUNC_MAILBOX_FRAME_BUFFER = 2001, 52 | RPIQ_FUNC_MAILBOX_VIRT_UART = 2002, 53 | RPIQ_FUNC_MAILBOX_VCHIQ = 2003, 54 | RPIQ_FUNC_MAILBOX_LED = 2004, 55 | RPIQ_FUNC_MAILBOX_BUTTONS = 2005, 56 | RPIQ_FUNC_MAILBOX_TOUCH_SCREEN = 2006, 57 | RPIQ_FUNC_MAILBOX_UNKNOWN = 2007, 58 | RPIQ_FUNC_MAILBOX_PROPERTY = 2008, 59 | RPIQ_FUNC_MAILBOX_PROPERTY_VC = 2009, 60 | 61 | RPIQ_FUNC_MAX = 4000 62 | }; 63 | 64 | #define IOCTL_MAILBOX_POWER_MANAGEMENT \ 65 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_POWER_MANAGEMENT, METHOD_BUFFERED, FILE_ANY_ACCESS) 66 | 67 | #define IOCTL_MAILBOX_FRAME_BUFFER \ 68 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_FRAME_BUFFER, METHOD_BUFFERED, FILE_ANY_ACCESS) 69 | 70 | #define IOCTL_MAILBOX_VIRT_UART \ 71 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_VIRT_UART, METHOD_BUFFERED, FILE_ANY_ACCESS) 72 | 73 | #define IOCTL_MAILBOX_VCHIQ \ 74 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_VCHIQ, METHOD_BUFFERED, FILE_ANY_ACCESS) 75 | 76 | #define IOCTL_MAILBOX_LED \ 77 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_LED, METHOD_BUFFERED, FILE_ANY_ACCESS) 78 | 79 | #define IOCTL_MAILBOX_BUTTONS \ 80 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_BUTTONS, METHOD_BUFFERED, FILE_ANY_ACCESS) 81 | 82 | #define IOCTL_MAILBOX_TOUCH_SCREEN \ 83 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_TOUCH_SCREEN, METHOD_BUFFERED, FILE_ANY_ACCESS) 84 | 85 | #define IOCTL_MAILBOX_PROPERTY \ 86 | CTL_CODE(FILE_DEVICE_RPIQ, RPIQ_FUNC_MAILBOX_PROPERTY, METHOD_BUFFERED, FILE_ANY_ACCESS) 87 | 88 | // 89 | // Tag Request 90 | // 91 | #define TAG_REQUEST 0x00000000 92 | 93 | // 94 | // Response 95 | // 96 | #define RESPONSE_SUCCESS 0x80000000 97 | #define RESPONSE_ERROR 0x80000001 98 | 99 | #include 100 | 101 | // 102 | // Mailbox Property Interface 103 | // 104 | 105 | // Standard mailbox header for all property interface 106 | typedef struct _MAILBOX_HEADER { 107 | ULONG TotalBuffer; 108 | ULONG RequestResponse; 109 | ULONG TagID; 110 | ULONG ResponseLength; 111 | ULONG Request; 112 | } MAILBOX_HEADER, *PMAILBOX_HEADER; 113 | 114 | // 115 | // Get firmware revision 116 | // 117 | // Tag : 0x00000001 118 | // Request : 119 | // Length : 0 120 | // Response : 121 | // Length : 4 122 | // Value : 123 | // u32 : firmware revision 124 | // 125 | #define TAG_ID_GET_FIRMWARE_REVISION 0x00000001 126 | 127 | typedef struct _MAILBOX_GET_FIRMWARE_REVISION { 128 | MAILBOX_HEADER Header; 129 | ULONG FirmwareRevision; 130 | ULONG EndTag; 131 | } MAILBOX_GET_FIRMWARE_REVISION, *PMAILBOX_GET_FIRMWARE_REVISION; 132 | 133 | __inline VOID INIT_MAILBOX_GET_FIRMWARE_REVISION ( 134 | _Out_ MAILBOX_GET_FIRMWARE_REVISION* PropertyMsgPtr 135 | ) 136 | { 137 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_FIRMWARE_REVISION); 138 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 139 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_FIRMWARE_REVISION; 140 | PropertyMsgPtr->Header.ResponseLength = 4; 141 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 142 | PropertyMsgPtr->FirmwareRevision = 0; 143 | PropertyMsgPtr->EndTag = 0; 144 | } 145 | 146 | // 147 | // Get board revision 148 | // 149 | // Tag : 0x00010001 150 | // Request : 151 | // Length : 0 152 | // Response : 153 | // Length : 4 154 | // Value : 155 | // u32 : Board model 156 | // 157 | #define TAG_ID_GET_BOARD_MODEL 0x00010001 158 | 159 | typedef struct _MAILBOX_GET_BOARD_MODEL 160 | { 161 | MAILBOX_HEADER Header; 162 | ULONG BoardModel; 163 | ULONG EndTag; 164 | } MAILBOX_GET_BOARD_MODEL, *PMAILBOX_GET_BOARD_MODEL; 165 | 166 | __inline VOID INIT_MAILBOX_GET_BOARD_MODEL ( 167 | _Out_ MAILBOX_GET_BOARD_MODEL* PropertyMsgPtr 168 | ) 169 | { 170 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_BOARD_MODEL); 171 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 172 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_BOARD_MODEL; 173 | PropertyMsgPtr->Header.ResponseLength = 4; 174 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 175 | PropertyMsgPtr->BoardModel = 0; 176 | PropertyMsgPtr->EndTag = 0; 177 | } 178 | 179 | // 180 | // Get board revision 181 | // 182 | // Tag : 0x00010002 183 | // Request : 184 | // Length : 0 185 | // Response : 186 | // Length : 4 187 | // Value : 188 | // u32 : Board revision 189 | // 190 | #define TAG_ID_GET_BOARD_REVISION 0x00010002 191 | 192 | typedef struct _MAILBOX_GET_BOARD_REVISION { 193 | MAILBOX_HEADER Header; 194 | ULONG BoardRevision; 195 | ULONG EndTag; 196 | } MAILBOX_GET_BOARD_REVISION, *PMAILBOX_GET_BOARD_REVISION; 197 | 198 | __inline VOID INIT_MAILBOX_GET_BOARD_REVISION ( 199 | _Out_ MAILBOX_GET_BOARD_REVISION* PropertyMsgPtr 200 | ) 201 | { 202 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_BOARD_REVISION); 203 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 204 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_BOARD_REVISION; 205 | PropertyMsgPtr->Header.ResponseLength = 4; 206 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 207 | PropertyMsgPtr->BoardRevision = 0; 208 | PropertyMsgPtr->EndTag = 0; 209 | } 210 | 211 | // 212 | // Get board MAC address 213 | // 214 | // Tag : 0x00010003 215 | // Request : 216 | // Length : 0 217 | // Response : 218 | // Length : 6 219 | // Value : 220 | // u8 : MAC Address 221 | // 222 | #define TAG_ID_GET_BOARD_MAC_ADDRESS 0x00010003 223 | 224 | typedef struct _MAILBOX_GET_MAC_ADDRESS { 225 | MAILBOX_HEADER Header; 226 | BYTE MACAddress[6]; 227 | BYTE Padding[2]; 228 | ULONG EndTag; 229 | } MAILBOX_GET_MAC_ADDRESS, *PMAILBOX_GET_MAC_ADDRESS; 230 | 231 | __inline VOID INIT_MAILBOX_GET_BOARD_MAC_ADDRESS ( 232 | _Out_ MAILBOX_GET_MAC_ADDRESS* PropertyMsgPtr 233 | ) 234 | { 235 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_MAC_ADDRESS); 236 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 237 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_BOARD_MAC_ADDRESS; 238 | PropertyMsgPtr->Header.ResponseLength = 6; 239 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 240 | PropertyMsgPtr->Padding[0] = 0; 241 | PropertyMsgPtr->Padding[1] = 0; 242 | PropertyMsgPtr->EndTag = 0; 243 | } 244 | 245 | // 246 | // Get board board serial 247 | // 248 | // Tag : 0x00010004 249 | // Request : 250 | // Length : 0 251 | // Response : 252 | // Length : 8 253 | // Value : 254 | // u64 : Board serial 255 | // 256 | #define TAG_ID_GET_BOARD_SERIAL 0x00010004 257 | 258 | typedef struct _MAILBOX_GET_BOARD_SERIAL { 259 | MAILBOX_HEADER Header; 260 | BYTE BoardSerial[8]; 261 | ULONG EndTag; 262 | } MAILBOX_GET_BOARD_SERIAL, *PMAILBOX_GET_BOARD_SERIAL; 263 | 264 | __inline VOID INIT_MAILBOX_GET_BOARD_SERIAL ( 265 | _Out_ MAILBOX_GET_BOARD_SERIAL* PropertyMsgPtr 266 | ) 267 | { 268 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_BOARD_SERIAL); 269 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 270 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_BOARD_SERIAL; 271 | PropertyMsgPtr->Header.ResponseLength = 8; 272 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 273 | PropertyMsgPtr->EndTag = 0; 274 | } 275 | 276 | // 277 | // Get ARM memory 278 | // 279 | // Tag : 0x00010005 280 | // Request : 281 | // Length : 0 282 | // Response : 283 | // Length : 8 284 | // Value : 285 | // u32 : Base address in bytes 286 | // u32 : Size in bytes 287 | // 288 | #define TAG_ID_GET_ARM_MEMORY 0x00010005 289 | 290 | typedef struct _MAILBOX_GET_ARM_MEMORY { 291 | MAILBOX_HEADER Header; 292 | ULONG BaseAddress; 293 | ULONG Size; 294 | ULONG EndTag; 295 | } MAILBOX_GET_ARM_MEMORY, *PMAILBOX_GET_ARM_MEMORY; 296 | 297 | __inline VOID INIT_MAILBOX_GET_ARM_MEMORY ( 298 | _Out_ MAILBOX_GET_ARM_MEMORY* PropertyMsgPtr 299 | ) 300 | { 301 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_ARM_MEMORY); 302 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 303 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_ARM_MEMORY; 304 | PropertyMsgPtr->Header.ResponseLength = 8; 305 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 306 | PropertyMsgPtr->BaseAddress = 0; 307 | PropertyMsgPtr->Size = 0; 308 | PropertyMsgPtr->EndTag = 0; 309 | } 310 | 311 | // 312 | // Get VC memory 313 | // 314 | // Tag : 0x00010006 315 | // Request : 316 | // Length : 0 317 | // Response : 318 | // Length : 8 319 | // Value : 320 | // u32 : Base address in bytes 321 | // u32 : Size in bytes 322 | // 323 | #define TAG_ID_GET_VC_MEMORY 0x00010006 324 | 325 | typedef struct _MAILBOX_GET_VC_MEMORY { 326 | MAILBOX_HEADER Header; 327 | ULONG BaseAddress; 328 | ULONG Size; 329 | ULONG EndTag; 330 | } MAILBOX_GET_VC_MEMORY, *PMAILBOX_GET_VC_MEMORY; 331 | 332 | __inline VOID INIT_MAILBOX_GET_VC_MEMORY ( 333 | _Out_ MAILBOX_GET_VC_MEMORY* PropertyMsgPtr 334 | ) 335 | { 336 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_VC_MEMORY); 337 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 338 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_VC_MEMORY; 339 | PropertyMsgPtr->Header.ResponseLength = 8; 340 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 341 | PropertyMsgPtr->BaseAddress = 0; 342 | PropertyMsgPtr->Size = 0; 343 | PropertyMsgPtr->EndTag = 0; 344 | } 345 | 346 | // 347 | // Mailbox Clock Id 348 | // 349 | 350 | #define MAILBOX_CLOCK_ID_RESERVED 0x00000000 351 | #define MAILBOX_CLOCK_ID_EMMC 0x00000001 352 | #define MAILBOX_CLOCK_ID_UART 0x00000002 353 | #define MAILBOX_CLOCK_ID_ARM 0x00000003 354 | #define MAILBOX_CLOCK_ID_CORE 0x00000004 355 | #define MAILBOX_CLOCK_ID_V3D 0x00000005 356 | #define MAILBOX_CLOCK_ID_H264 0x00000006 357 | #define MAILBOX_CLOCK_ID_ISP 0x00000007 358 | #define MAILBOX_CLOCK_ID_SDRAM 0x00000008 359 | #define MAILBOX_CLOCK_ID_PIXEL 0x00000009 360 | #define MAILBOX_CLOCK_ID_PWM 0x0000000A 361 | 362 | // 363 | // Get Clock Rate 364 | // 365 | // Tag : 0x00030002 366 | // Request : 367 | // Length : 4 368 | // Value : 369 | // u32 : clock id 370 | // Response : 371 | // Length : 8 372 | // Value : 373 | // u32 : clock id 374 | // u32 : rate (in Hz) 375 | // 376 | #define TAG_ID_GET_CLOCK_RATE 0x00030002 377 | 378 | typedef struct _MAILBOX_GET_CLOCK_RATE { 379 | MAILBOX_HEADER Header; 380 | ULONG ClockId; 381 | ULONG Rate; 382 | ULONG EndTag; 383 | } MAILBOX_GET_CLOCK_RATE, *PMAILBOX_GET_CLOCK_RATE; 384 | 385 | __inline VOID INIT_MAILBOX_GET_CLOCK_RATE ( 386 | _Out_ MAILBOX_GET_CLOCK_RATE* PropertyMsgPtr, 387 | _In_ ULONG ClockId 388 | ) 389 | { 390 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_CLOCK_RATE); 391 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 392 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_CLOCK_RATE; 393 | PropertyMsgPtr->Header.ResponseLength = 8; 394 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 395 | PropertyMsgPtr->ClockId = ClockId; 396 | PropertyMsgPtr->Rate = 0; 397 | PropertyMsgPtr->EndTag = 0; 398 | } 399 | 400 | // 401 | // Get Measured Clock Rate 402 | // 403 | // Tag : 0x00030047 404 | // Request : 405 | // Length : 4 406 | // Value : 407 | // u32 : clock id 408 | // Response : 409 | // Length : 8 410 | // Value : 411 | // u32 : clock id 412 | // u32 : rate (in Hz) 413 | // 414 | #define TAG_ID_GET_MEASURED_CLOCK_RATE 0x00030047 415 | 416 | typedef struct _MAILBOX_GET_MEASURED_CLOCK_RATE { 417 | MAILBOX_HEADER Header; 418 | ULONG ClockId; 419 | ULONG Rate; 420 | ULONG EndTag; 421 | } MAILBOX_GET_MEASURED_CLOCK_RATE, * PMAILBOX_GET_MEASURED_CLOCK_RATE; 422 | 423 | __inline VOID INIT_MAILBOX_GET_MEASURED_CLOCK_RATE( 424 | _Out_ MAILBOX_GET_MEASURED_CLOCK_RATE* PropertyMsgPtr, 425 | _In_ ULONG ClockId 426 | ) 427 | { 428 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_MEASURED_CLOCK_RATE); 429 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 430 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_MEASURED_CLOCK_RATE; 431 | PropertyMsgPtr->Header.ResponseLength = 8; 432 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 433 | PropertyMsgPtr->ClockId = ClockId; 434 | PropertyMsgPtr->Rate = 0; 435 | PropertyMsgPtr->EndTag = 0; 436 | } 437 | 438 | // 439 | // Set Clock Rate 440 | // 441 | // Tag : 0x00038002 442 | // Request : 443 | // Length : 12 444 | // Value : 445 | // u32 : clock id 446 | // u32 : rate (in Hz) 447 | // u32 : skip setting turbo 448 | // Response : 449 | // Length : 8 450 | // Value : 451 | // u32 : clock id 452 | // u32 : rate (in Hz) 453 | // 454 | #define TAG_ID_SET_CLOCK_RATE 0x00038002 455 | 456 | typedef struct _MAILBOX_SET_CLOCK_RATE { 457 | MAILBOX_HEADER Header; 458 | ULONG ClockId; 459 | ULONG Rate; 460 | ULONG SkipSettingTurbo; 461 | ULONG EndTag; 462 | } MAILBOX_SET_CLOCK_RATE, *PMAILBOX_SET_CLOCK_RATE; 463 | 464 | __inline VOID INIT_MAILBOX_SET_CLOCK_RATE ( 465 | _Out_ MAILBOX_SET_CLOCK_RATE* PropertyMsgPtr, 466 | _In_ ULONG ClockId, 467 | _In_ ULONG Rate, 468 | _In_ ULONG SkipSettingTurbo 469 | ) 470 | { 471 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_SET_CLOCK_RATE); 472 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 473 | PropertyMsgPtr->Header.TagID = TAG_ID_SET_CLOCK_RATE; 474 | PropertyMsgPtr->Header.ResponseLength = 8; 475 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 476 | PropertyMsgPtr->ClockId = ClockId; 477 | PropertyMsgPtr->Rate = Rate; 478 | PropertyMsgPtr->SkipSettingTurbo = SkipSettingTurbo; 479 | PropertyMsgPtr->EndTag = 0; 480 | } 481 | 482 | // 483 | // Get Max Clock Rate 484 | // 485 | // Tag : 0x00030004 486 | // Request : 487 | // Length : 4 488 | // Value : 489 | // u32 : clock id 490 | // Response : 491 | // Length : 8 492 | // Value : 493 | // u32 : clock id 494 | // u32 : rate (in Hz) 495 | // 496 | #define TAG_ID_GET_MAX_CLOCK_RATE 0x00030004 497 | 498 | __inline VOID INIT_MAILBOX_GET_MAX_CLOCK_RATE ( 499 | _Out_ MAILBOX_GET_CLOCK_RATE* PropertyMsgPtr, 500 | _In_ ULONG ClockId 501 | ) 502 | { 503 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_CLOCK_RATE); 504 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 505 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_MAX_CLOCK_RATE; 506 | PropertyMsgPtr->Header.ResponseLength = 8; 507 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 508 | PropertyMsgPtr->ClockId = ClockId; 509 | PropertyMsgPtr->Rate = 0; 510 | PropertyMsgPtr->EndTag = 0; 511 | } 512 | 513 | // 514 | // Get Min Clock Rate 515 | // 516 | // Tag : 0x00030007 517 | // Request : 518 | // Length : 4 519 | // Value : 520 | // u32 : clock id 521 | // Response : 522 | // Length : 8 523 | // Value : 524 | // u32 : clock id 525 | // u32 : rate (in Hz) 526 | // 527 | #define TAG_ID_GET_MIN_CLOCK_RATE 0x00030007 528 | 529 | __inline VOID INIT_MAILBOX_GET_MIN_CLOCK_RATE ( 530 | _Out_ MAILBOX_GET_CLOCK_RATE* PropertyMsgPtr, 531 | _In_ ULONG ClockId 532 | ) 533 | { 534 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_CLOCK_RATE); 535 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 536 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_MIN_CLOCK_RATE; 537 | PropertyMsgPtr->Header.ResponseLength = 8; 538 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 539 | PropertyMsgPtr->ClockId = ClockId; 540 | PropertyMsgPtr->Rate = 0; 541 | PropertyMsgPtr->EndTag = 0; 542 | } 543 | 544 | // 545 | // Set V3D power state 546 | // 547 | // Tag : 0x00030012 548 | // Request : 549 | // Length : 4 550 | // Value : 551 | // u32 : V3D power state 552 | // Response : 553 | // Length : 4 554 | // Value : 555 | // u32 : V3D power state 556 | // 557 | #define TAG_ID_SET_POWER_VC4 0x00030012 558 | 559 | typedef struct _MAILBOX_SET_POWER_VC4 { 560 | MAILBOX_HEADER Header; 561 | ULONG PowerOn; 562 | ULONG EndTag; 563 | } MAILBOX_SET_POWER_VC4, *PMAILBOX_SET_POWER_VC4; 564 | 565 | __inline VOID INIT_MAILBOX_SET_POWER_VC4 ( 566 | _Out_ MAILBOX_SET_POWER_VC4* PropertyMsgPtr, 567 | _In_ ULONG PowerOn 568 | ) 569 | { 570 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_SET_POWER_VC4); 571 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 572 | PropertyMsgPtr->Header.TagID = TAG_ID_SET_POWER_VC4; 573 | PropertyMsgPtr->Header.ResponseLength = 4; 574 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 575 | PropertyMsgPtr->PowerOn = PowerOn; 576 | PropertyMsgPtr->EndTag = 0; 577 | } 578 | 579 | // 580 | // Allocate Memory 581 | // 582 | // Tag : 0x0003000c 583 | // Request : 584 | // Length : 12 585 | // Value : 586 | // u32 : size 587 | // u32 : alignment 588 | // u32 : flags 589 | // Response : 590 | // Length : 4 591 | // Value : 592 | // u32 : handle 593 | // 594 | #define TAG_ID_ALLOC_MEM 0x0003000c 595 | #define ALIGN_4K 4*1024 596 | typedef struct _MAILBOX_ALLOC_MEM { 597 | MAILBOX_HEADER Header; 598 | ULONG Size; 599 | ULONG Aligment; 600 | ULONG Flag; 601 | ULONG EndTag; 602 | } MAILBOX_ALLOC_MEM, *PMAILBOX_ALLOC_MEM; 603 | 604 | __inline VOID INIT_MAILBOX_ALLOC_MEM ( 605 | _Out_ MAILBOX_ALLOC_MEM* PropertyMsgPtr, 606 | _In_ ULONG Size, 607 | _In_ ULONG Aligment 608 | ) 609 | { 610 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_ALLOC_MEM); 611 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 612 | PropertyMsgPtr->Header.TagID = TAG_ID_ALLOC_MEM; 613 | PropertyMsgPtr->Header.ResponseLength = 12; 614 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 615 | PropertyMsgPtr->Size = Size; 616 | PropertyMsgPtr->Aligment = Aligment; 617 | PropertyMsgPtr->Flag = 0x0000000C; 618 | PropertyMsgPtr->EndTag = 0; 619 | } 620 | 621 | // 622 | // Lock memory 623 | // 624 | // Tag : 0x0003000d 625 | // Request : 626 | // Length : 4 627 | // Value : 628 | // u32 : handle 629 | // Response : 630 | // Length : 4 631 | // Value : 632 | // u32 : bus Address 633 | // 634 | #define TAG_ID_LOCK_MEM 0x0003000d 635 | typedef struct _MAILBOX_LOCK_MEM { 636 | MAILBOX_HEADER Header; 637 | ULONG Handle; 638 | ULONG EndTag; 639 | } MAILBOX_LOCK_MEM, *PMAILBOX_LOCK_MEM; 640 | 641 | __inline VOID INIT_MAILBOX_LOC_MEM ( 642 | _Out_ MAILBOX_LOCK_MEM* PropertyMsgPtr, 643 | _In_ ULONG Handle 644 | ) 645 | { 646 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_LOCK_MEM); 647 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 648 | PropertyMsgPtr->Header.TagID = TAG_ID_LOCK_MEM; 649 | PropertyMsgPtr->Header.ResponseLength = 4; 650 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 651 | PropertyMsgPtr->Handle = Handle; 652 | PropertyMsgPtr->EndTag = 0; 653 | } 654 | 655 | // 656 | // Get EDID block 657 | // 658 | // Tag : 0x00030020 659 | // Request : 660 | // Length : 4 661 | // Value : 662 | // u32 : block number 663 | // Response : 664 | // Length : 136 665 | // Value : 666 | // u32 : block number 667 | // u32 : status (keep requesting blocks until this is nonzero) 668 | // 128 bytes: EDID block 669 | // 670 | #define TAG_ID_GET_EDID 0x00030020 671 | typedef struct _MAILBOX_GET_EDID { 672 | MAILBOX_HEADER Header; 673 | ULONG BlockNumber; 674 | ULONG Status; 675 | BYTE Edid[128]; 676 | ULONG EndTag; 677 | } MAILBOX_GET_EDID, *PMAILBOX_GET_EDID; 678 | 679 | __inline VOID INIT_MAILBOX_GET_EDID ( 680 | _Out_ MAILBOX_GET_EDID* PropertyMsgPtr, 681 | _In_ ULONG BlockNumber 682 | ) 683 | { 684 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_EDID); 685 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 686 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_EDID; 687 | PropertyMsgPtr->Header.ResponseLength = 136; 688 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 689 | PropertyMsgPtr->BlockNumber = BlockNumber; 690 | PropertyMsgPtr->EndTag = 0; 691 | } 692 | 693 | // 694 | // Get virtual (buffer) width/height 695 | // 696 | // Tag : 0x00040004 697 | // Request : 698 | // Length : 0 699 | // Response : 700 | // Length : 8 701 | // Value : 702 | // u32 : width in pixels 703 | // u32 : height in pixels 704 | // 705 | #define TAG_ID_GET_VIRTUAL_BUFFER_SIZE 0x00040004 706 | typedef struct _MAILBOX_GET_VIRTUAL_BUFFER_SIZE { 707 | MAILBOX_HEADER Header; 708 | ULONG WidthPixels; 709 | ULONG HeightPixels; 710 | ULONG EndTag; 711 | } MAILBOX_GET_VIRTUAL_BUFFER_SIZE, *PMAILBOX_GET_VIRTUAL_BUFFER_SIZE; 712 | 713 | __inline VOID INIT_MAILBOX_GET_VIRTUAL_BUFFER_SIZE ( 714 | _Out_ MAILBOX_GET_VIRTUAL_BUFFER_SIZE* PropertyMsgPtr 715 | ) 716 | { 717 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_VIRTUAL_BUFFER_SIZE); 718 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 719 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_VIRTUAL_BUFFER_SIZE; 720 | PropertyMsgPtr->Header.ResponseLength = 8; 721 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 722 | PropertyMsgPtr->EndTag = 0; 723 | } 724 | 725 | // 726 | // Set Cursor Info 727 | // 728 | // Tag: 0x00008010 Error in wiki documentation. Correct value define here 729 | // https://github.com/raspberrypi/linux/blob/e50d6adf1df06a1d4f8e5938c23ed7c3502ed02d/arch/arm/mach-bcm2708/include/mach/vcio.h 730 | // Request : 731 | // Length : 24 732 | // Value : 733 | // u32 : Width 734 | // u32 : Height 735 | // u32 : (unused) 736 | // u32 : pointer to pixels 737 | // u32 : hotspotX 738 | // u32 : hotspotY 739 | // Response : 740 | // Length : 4 741 | // Value : 742 | // u32 : 0 = valid, 1 = invalid 743 | // 744 | #define TAG_ID_SET_CURSOR_INFO 0x00008010 745 | #define MAX_CURSOR_WIDTH 64 746 | #define MAX_CURSOR_HEIGHT 64 747 | #define CURSOR_BPP 4 748 | #define MAX_CURSOR_MEMORY MAX_CURSOR_WIDTH * MAX_CURSOR_HEIGHT * PropertyMsgPtrURSOR_BPP 749 | 750 | typedef struct _MAILBOX_SET_CURSOR_INFO { 751 | MAILBOX_HEADER Header; 752 | ULONG Width; 753 | ULONG Height; 754 | ULONG Unused; 755 | ULONG PointerToPixel; 756 | ULONG HotspotX; 757 | ULONG HotspotY; 758 | ULONG EndTag; 759 | } MAILBOX_SET_CURSOR_INFO; 760 | 761 | __inline VOID INIT_MAILBOX_CURSOR_INFO ( 762 | _Out_ MAILBOX_SET_CURSOR_INFO* PropertyMsgPtr, 763 | _In_ ULONG Width, 764 | _In_ ULONG Height, 765 | _In_ ULONG Address 766 | ) 767 | { 768 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_SET_CURSOR_INFO); 769 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 770 | PropertyMsgPtr->Header.TagID = TAG_ID_SET_CURSOR_INFO; 771 | PropertyMsgPtr->Header.ResponseLength = 24; 772 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 773 | PropertyMsgPtr->Width = Width; 774 | PropertyMsgPtr->Height = Height; 775 | PropertyMsgPtr->Unused = 0; 776 | PropertyMsgPtr->PointerToPixel = Address; 777 | PropertyMsgPtr->HotspotX = 0; 778 | PropertyMsgPtr->HotspotY = 0; 779 | PropertyMsgPtr->EndTag = 0; 780 | } 781 | 782 | // 783 | // Set Cursor State 784 | // 785 | // Tag : 0x00008011 Error in wiki documentation. Correct value define here 786 | // https://github.com/raspberrypi/linux/blob/e50d6adf1df06a1d4f8e5938c23ed7c3502ed02d/arch/arm/mach-bcm2708/include/mach/vcio.h 787 | // Request : 788 | // Length : 16 789 | // Value : 790 | // u32 : enable(1 = visible, 0 = invisible) 791 | // u32 : x 792 | // u32 : y 793 | // u32 : flags 794 | // Response : 795 | // Length : 4 796 | // Value : 797 | // u32 : 0 = valid, 1 = invalid 798 | // 799 | #define TAG_ID_SET_CURSOR_STATE 0x00008011 800 | typedef struct _MAILBOX_SET_CURSOR_STATE { 801 | MAILBOX_HEADER Header; 802 | ULONG Enable; 803 | ULONG HotspotX; 804 | ULONG HotspotY; 805 | ULONG Flags; 806 | ULONG EndTag; 807 | } MAILBOX_SET_CURSOR_STATE, *PMAILBOX_SET_CURSOR_STATE; 808 | 809 | __inline VOID INIT_MAILBOX_CURSOR_STATE ( 810 | _Out_ MAILBOX_SET_CURSOR_STATE* PropertyMsgPtr, 811 | _In_ ULONG Enable, 812 | _In_ ULONG HotspotX, 813 | _In_ ULONG HotspotY 814 | ) 815 | { 816 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_SET_CURSOR_STATE); 817 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 818 | PropertyMsgPtr->Header.TagID = TAG_ID_SET_CURSOR_STATE; 819 | PropertyMsgPtr->Header.ResponseLength = 16; 820 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 821 | PropertyMsgPtr->Enable = Enable; 822 | PropertyMsgPtr->HotspotX = HotspotX; 823 | PropertyMsgPtr->HotspotY = HotspotY; 824 | PropertyMsgPtr->EndTag = 0; 825 | } 826 | 827 | // 828 | // GPIO Expander 829 | // Tag: 0x00030041 and 0x00038041 830 | // Request : 831 | // Length : 8 832 | // Value : 833 | // u32 : Gpio id 834 | // u32 : Gpio Set State 835 | // Response : 836 | // Length : 8 837 | // Value : 838 | // u32 : Gpio id 839 | // u32 : Gpio State 840 | // 841 | #define TAG_ID_GET_GPIO_EXPANDER 0x00030041 842 | #define TAG_ID_SET_GPIO_EXPANDER 0x00038041 843 | typedef struct _MAILBOX_GET_SET_GPIO_EXPANDER 844 | { 845 | MAILBOX_HEADER Header; 846 | ULONG GpioId; 847 | ULONG GpioState; 848 | ULONG EndTag; 849 | } MAILBOX_GET_SET_GPIO_EXPANDER, *PMAILBOX_GET_SET_GPIO_EXPANDER; 850 | 851 | __inline VOID INIT_MAILBOX_GET_GPIO_EXPANDER ( 852 | _Out_ MAILBOX_GET_SET_GPIO_EXPANDER* PropertyMsgPtr, 853 | _In_ ULONG GpioId) 854 | { 855 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_SET_GPIO_EXPANDER); 856 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 857 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_GPIO_EXPANDER; 858 | PropertyMsgPtr->Header.ResponseLength = 8; 859 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 860 | PropertyMsgPtr->GpioId = GpioId; 861 | PropertyMsgPtr->EndTag = 0; 862 | } 863 | 864 | __inline VOID INIT_MAILBOX_SET_GPIO_EXPANDER ( 865 | _Out_ MAILBOX_GET_SET_GPIO_EXPANDER* PropertyMsgPtr, 866 | _In_ ULONG GpioId, 867 | _In_ ULONG GpioState) 868 | { 869 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_SET_GPIO_EXPANDER); 870 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 871 | PropertyMsgPtr->Header.TagID = TAG_ID_SET_GPIO_EXPANDER; 872 | PropertyMsgPtr->Header.ResponseLength = 8; 873 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 874 | PropertyMsgPtr->GpioId = GpioId; 875 | PropertyMsgPtr->GpioState = GpioState; 876 | PropertyMsgPtr->EndTag = 0; 877 | } 878 | 879 | // Get touch buffer 880 | // Tag: 0x0004000f 881 | // Request : 882 | // Length : 4 bytes 883 | // Value : null 884 | // Response : 885 | // Length : 4 bytes 886 | // Value : UINT32 887 | // u32 : Touch buffer address if any, null otherwise 888 | // 889 | #define TAG_ID_GET_TOUCHBUF 0x0004000f // RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF=0x0004000f 890 | typedef struct _MAILBOX_GET_TOUCH_BUF 891 | { 892 | MAILBOX_HEADER Header; 893 | ULONG TouchBuffer; 894 | ULONG EndTag; 895 | } MAILBOX_GET_TOUCH_BUF; 896 | 897 | __inline VOID INIT_MAILBOX_GET_TOUCH_BUFF ( 898 | _Out_ MAILBOX_GET_TOUCH_BUF* PropertyMsgPtr, 899 | _In_ ULONG InTouchBuffer) 900 | { 901 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_TOUCH_BUF); 902 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 903 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_TOUCHBUF; 904 | PropertyMsgPtr->Header.ResponseLength = 4; 905 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 906 | PropertyMsgPtr->TouchBuffer = InTouchBuffer; 907 | PropertyMsgPtr->EndTag=0; 908 | } 909 | 910 | 911 | #define TAG_ID_GET_TEMPERATURE 0x00030006 912 | typedef struct _MAILBOX_GET_TEMPERATURE 913 | { 914 | MAILBOX_HEADER Header; 915 | ULONG TemperatureId; 916 | ULONG Value; 917 | ULONG EndTag; 918 | } MAILBOX_GET_TEMPERATURE; 919 | 920 | __inline VOID INIT_MAILBOX_GET_TEMPERATURE( 921 | _Out_ MAILBOX_GET_TEMPERATURE* PropertyMsgPtr) 922 | { 923 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_TEMPERATURE); 924 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 925 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_TEMPERATURE; 926 | PropertyMsgPtr->Header.ResponseLength = 8; 927 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 928 | PropertyMsgPtr->TemperatureId = 0; 929 | PropertyMsgPtr->Value = 0; 930 | PropertyMsgPtr->EndTag = 0; 931 | } 932 | 933 | 934 | #define TAG_ID_GET_VOLTAGE 0x00030003 935 | 936 | typedef struct _MAILBOX_GET_VOLTAGE 937 | { 938 | MAILBOX_HEADER Header; 939 | ULONG VoltageId; 940 | ULONG Value; 941 | ULONG EndTag; 942 | } MAILBOX_GET_VOLTAGE; 943 | 944 | __inline VOID INIT_MAILBOX_GET_VOLTAGE ( 945 | _Out_ MAILBOX_GET_VOLTAGE* PropertyMsgPtr, 946 | _In_ ULONG VoltageId) 947 | { 948 | PropertyMsgPtr->Header.TotalBuffer = sizeof(MAILBOX_GET_VOLTAGE); 949 | PropertyMsgPtr->Header.RequestResponse = TAG_REQUEST; 950 | PropertyMsgPtr->Header.TagID = TAG_ID_GET_VOLTAGE; 951 | PropertyMsgPtr->Header.ResponseLength = 8; 952 | PropertyMsgPtr->Header.Request = TAG_REQUEST; 953 | PropertyMsgPtr->VoltageId = VoltageId; 954 | PropertyMsgPtr->Value = 0; 955 | PropertyMsgPtr->EndTag = 0; 956 | } 957 | 958 | #define MAILBOX_VOLTAGE_ID_CORE 0x000000001 959 | #define MAILBOX_VOLTAGE_ID_SDRAM_C 0x000000002 960 | #define MAILBOX_VOLTAGE_ID_SDRAM_P 0x000000003 961 | #define MAILBOX_VOLTAGE_ID_SDRAM_I 0x000000004 962 | 963 | #include 964 | 965 | #ifdef __cplusplus 966 | } // extern "C" 967 | #endif // __cplusplus 968 | 969 | #endif // NTDDI_VERSION >= NTDDI_WINTHRESHOLD 970 | 971 | #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 972 | 973 | #endif //_RPIQ_H --------------------------------------------------------------------------------