Compare commits
193 Commits
cpp_OLD
...
764dd1a4a9
| Author | SHA1 | Date | |
|---|---|---|---|
| 764dd1a4a9 | |||
| 244213f396 | |||
| 74362a0dad | |||
| f46e7df5f3 | |||
| ddf0868c9e | |||
| 159406d327 | |||
| f8046918c6 | |||
| 3ecdc57309 | |||
| 739c62effa | |||
| a53fc1b33f | |||
| 34173674d8 | |||
| 7b37b2052d | |||
| 7043284dcb | |||
| c748e60915 | |||
| e6170fc9cc | |||
| f74af3122c | |||
| 70eaad2f5a | |||
| ad6e378340 | |||
| 81cfc2ce0d | |||
| 901d5b53d9 | |||
| 1103434857 | |||
| 8bac9bde42 | |||
| 78a77164fb | |||
| 1f70f2ead2 | |||
| cd06d047d5 | |||
| 31cd2ef211 | |||
| df6f9f3986 | |||
| 046cff01f8 | |||
| cf203edc32 | |||
| 2d3c115703 | |||
| ddb9ea7173 | |||
| e4e7c4bbc2 | |||
| 73a9b4303d | |||
| 8c2296ca1f | |||
| b2af4630b9 | |||
| 6a24d54a6c | |||
| a89e227d95 | |||
| e816a7d8ee | |||
| c31c3d6e67 | |||
| 7b74e69759 | |||
| c693e892d0 | |||
| c2f19b83f4 | |||
| 7caef9c744 | |||
| 9419230747 | |||
| 116eb7201f | |||
| 27b083f388 | |||
| 42620b3577 | |||
| f4503370fd | |||
| de500dc5e5 | |||
| 3f0a96ef7f | |||
| 4ecce5c4d0 | |||
| 12135f0a33 | |||
| 7bb7281df8 | |||
| c2d53ad334 | |||
| 988a44b8f4 | |||
| 7eaa63a1aa | |||
| 816698f2a5 | |||
| 9a9ecc644c | |||
| 92ce83ab4f | |||
| b3397abe90 | |||
| 9afef7fbd8 | |||
| 5a055fb03e | |||
| 5609ae5055 | |||
| 88387704e1 | |||
| 6920f9f34f | |||
| 6b035a0b81 | |||
| d883bdc6ff | |||
| 7f6ef12201 | |||
| 13e658087b | |||
| 7b89645114 | |||
| e270aa3ac5 | |||
| e439831fb0 | |||
| 4858feb4c7 | |||
| 1d2095261f | |||
| a0bbc71cd8 | |||
| 2f8d08a1f9 | |||
| 3d869b5169 | |||
| 96a55076f6 | |||
| 29c14dc56f | |||
| 86da8434bd | |||
| 782b57cbb5 | |||
| ea05923bc7 | |||
| 735ad9cdff | |||
| 9011767f76 | |||
| 43d7f0ed4a | |||
| f7ed895f3b | |||
| 42f702ca1b | |||
| 0352675e79 | |||
| 1099bb6688 | |||
| b46f457afc | |||
| 2a75c9eb24 | |||
| 4875fa4093 | |||
| c4e80fbb69 | |||
| 804e477d50 | |||
| 8bea9be551 | |||
| d4d12cc3c1 | |||
| d44683a991 | |||
| 0cd7520cf4 | |||
| 3d40ebeb84 | |||
| 0bcc340d75 | |||
| 2b6a72fcb2 | |||
| 2cac64c448 | |||
| 2bfef862ce | |||
| 03c426195e | |||
| 85f87677d7 | |||
| f74d9bf539 | |||
| f9272f8d1c | |||
| 6d8b74ce3d | |||
| 21d897886c | |||
| 4a80e795b2 | |||
| 29d2385bd1 | |||
| 07f391d8f2 | |||
| 632abb467d | |||
| e01748808a | |||
| da8aec78a8 | |||
| 920600b294 | |||
| a28da52f8a | |||
| b46731a9e1 | |||
| 13e2c083cb | |||
| 1db30f2eba | |||
| 5e54828b65 | |||
| b6ac658974 | |||
| 542bd6f36c | |||
| 000b0bd543 | |||
| 4189148abc | |||
| d0faf1d84a | |||
| 9de7379f45 | |||
| 5bfdda4b21 | |||
| 952e984f65 | |||
| e083dcc447 | |||
| 5686dcdbf6 | |||
| 4478df4f24 | |||
| b2e98f27f5 | |||
| a6a1a58bcf | |||
| 6524ce346f | |||
| e9ca7d1691 | |||
| c3d1efbc01 | |||
| f25a361bb0 | |||
| 415310603e | |||
| e7a42c92c9 | |||
| 9cee96a64c | |||
| 35aba48c48 | |||
| a247e8ecf6 | |||
| 4777d51107 | |||
| b17c02127e | |||
| 39174cb5f2 | |||
| d903566362 | |||
| 74bcbb6486 | |||
| 8c2f95b2b6 | |||
| 54c178e3f5 | |||
| 8c21c37b84 | |||
| 4650c178ff | |||
| 8ff87d2600 | |||
| ffc1d55fde | |||
| 77f5494dd9 | |||
| 00656d4ba3 | |||
| 07a8ecddf9 | |||
| 00b06ef6c1 | |||
| cc4605f528 | |||
| 72587c72a8 | |||
| 1dd46c8761 | |||
| 3d00f10b77 | |||
| 0a19965657 | |||
| aa57cdf651 | |||
| 574f59b8f5 | |||
| c26ccba813 | |||
| 5b8708ad0c | |||
| 9b62096d5e | |||
| 938b3af523 | |||
| ac75332680 | |||
| c1fd1f706e | |||
| c93ae21114 | |||
| c44365d78b | |||
| 88c6db07c2 | |||
| 694b496282 | |||
| 169ca4b59b | |||
| f0dc384d37 | |||
| 88764a8900 | |||
| 9bd2357b96 | |||
| f28cd4c31a | |||
| 39193cdc9f | |||
| ebd96aa8fb | |||
| fd0a53f789 | |||
| 35e2e83862 | |||
| 3833c9be6b | |||
| 8e2d2e04de | |||
| 4be515392d | |||
| 110c012587 | |||
| 6c8739ecd5 | |||
| cab3c32c63 | |||
| a82fdd3d33 | |||
| a90a65ba96 | |||
| 96e14ed6ea |
@@ -1,4 +1,56 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 0
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Indentation (Linux kernel style)
|
||||
UseTab: Always
|
||||
TabWidth: 8
|
||||
IndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
|
||||
# Keep parameters on one line as much as possible
|
||||
BinPackParameters: true
|
||||
BinPackArguments: true
|
||||
|
||||
# Allow long lines (important!)
|
||||
ColumnLimit: 0 # or set to something large like 120
|
||||
|
||||
# Prevent breaking after return type / before function name
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
|
||||
# Keep function declarations/definitions on one line if possible
|
||||
PenaltyBreakBeforeFirstCallParameter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
|
||||
# Braces: K&R style everywhere, INCLUDING functions (your modification)
|
||||
BreakBeforeBraces: Attach
|
||||
|
||||
# Control specific brace wrapping behavior
|
||||
BraceWrapping:
|
||||
AfterFunction: false # <-- key change (same line for functions)
|
||||
AfterControlStatement: false
|
||||
AfterStruct: false
|
||||
AfterEnum: false
|
||||
AfterUnion: false
|
||||
AfterClass: false
|
||||
BeforeElse: false
|
||||
|
||||
# Spaces
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
|
||||
# Pointer alignment (kernel prefers this style)
|
||||
PointerAlignment: Right
|
||||
|
||||
# Keep simple statements compact
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
|
||||
# For-loop style similar to kernel
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
|
||||
# Don't align weirdly
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
|
||||
SortIncludes: CaseSensitive
|
||||
10
.idea/.gitignore
generated
vendored
10
.idea/.gitignore
generated
vendored
@@ -1,10 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
105
.idea/codeStyles/Project.xml
generated
105
.idea/codeStyles/Project.xml
generated
@@ -1,105 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<RiderCodeStyleSettings>
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
|
||||
</RiderCodeStyleSettings>
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
</clangFormatSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
7
.idea/dictionaries/project.xml
generated
7
.idea/dictionaries/project.xml
generated
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="project">
|
||||
<words>
|
||||
<w>drath</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
345
.idea/editor.xml
generated
345
.idea/editor.xml
generated
@@ -1,345 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="BackendCodeEditorSettings">
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||
</component>
|
||||
</project>
|
||||
11
.idea/inspectionProfiles/Project_Default.xml
generated
11
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,11 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="GrazieInspection" enabled="false" level="GRAMMAR_ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
2
.idea/linuxSmartie.iml
generated
2
.idea/linuxSmartie.iml
generated
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CIDR" type="CPP_MODULE" version="4" />
|
||||
7
.idea/misc.xml
generated
7
.idea/misc.xml
generated
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakePythonSetting">
|
||||
<option name="pythonIntegrationState" value="YES" />
|
||||
</component>
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/linuxSmartie.iml" filepath="$PROJECT_DIR$/.idea/linuxSmartie.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,54 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(linuxSmartie
|
||||
VERSION 1.0
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
# Use C++20
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Collect sources
|
||||
file(GLOB SOURCES
|
||||
src/*.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
# Define executable
|
||||
add_executable(linuxSmartie ${SOURCES})
|
||||
|
||||
# Include directories
|
||||
target_include_directories(linuxSmartie
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
# Compiler warnings
|
||||
target_compile_options(linuxSmartie
|
||||
PRIVATE
|
||||
-O2
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Werror
|
||||
-fdiagnostics-color=always
|
||||
)
|
||||
|
||||
find_package(libwebsockets QUIET)
|
||||
find_package(ZLIB QUIET)
|
||||
|
||||
if(libwebsockets_FOUND)
|
||||
target_link_libraries(linuxSmartie PRIVATE websockets)
|
||||
target_compile_definitions(linuxSmartie PRIVATE ENABLE_HOME_ASSISTANT)
|
||||
else()
|
||||
message(STATUS "no libwebsockets found, disabling hass")
|
||||
endif()
|
||||
|
||||
if(ZLIB_FOUND)
|
||||
target_link_libraries(linuxSmartie PRIVATE z)
|
||||
target_compile_definitions(linuxSmartie PRIVATE ENABLE_ZLIB)
|
||||
else()
|
||||
message(STATUS "no zlib found, disabling saving logs to gz")
|
||||
endif()
|
||||
95
Makefile
95
Makefile
@@ -1,27 +1,92 @@
|
||||
# wrapper around cmake, see CMakeLists.txt for compile options
|
||||
.PHONY: configure build clean nuke install install_service
|
||||
CC := cc
|
||||
PKG_CONFIG := pkg-config
|
||||
|
||||
BUILD_DIR ?= build
|
||||
TARGET := build/linuxSmartie
|
||||
|
||||
build: configure
|
||||
cmake --build ${BUILD_DIR} -j
|
||||
BITCHY_ERRORS := \
|
||||
-Wconversion \
|
||||
-Wsign-conversion \
|
||||
-Wshadow \
|
||||
-Wformat=2 \
|
||||
-Wundef \
|
||||
-Wstrict-prototypes \
|
||||
-Wmissing-prototypes \
|
||||
-Wold-style-definition \
|
||||
-Wwrite-strings \
|
||||
-Wvla \
|
||||
-Wcast-qual \
|
||||
-Wcast-align \
|
||||
-Wpointer-arith \
|
||||
-Wswitch-enum \
|
||||
|
||||
configure:
|
||||
cmake -S . -B ${BUILD_DIR}
|
||||
CFLAGS := \
|
||||
-std=c23 \
|
||||
-Iinclude \
|
||||
-Ibuild \
|
||||
-D_GNU_SOURCE \
|
||||
-D_POSIX_C_SOURCE=200809L \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wpedantic \
|
||||
-Werror \
|
||||
-pedantic-errors \
|
||||
-MMD -MP \
|
||||
-O2 \
|
||||
$(BITCHY_ERRORS)
|
||||
|
||||
|
||||
LDLIBS := \
|
||||
$(shell $(PKG_CONFIG) --libs libusb-1.0) \
|
||||
-lm
|
||||
|
||||
SOURCES := $(wildcard src/*.c)
|
||||
OBJECTS := $(patsubst src/%.c,build/src/%.o,$(SOURCES))
|
||||
DEPS := $(OBJECTS:.o=.d)
|
||||
|
||||
VERSION_H := build/version.h
|
||||
|
||||
# glowny target, linkuje linuxSmartie, potrzebuje ${OBJECTS}, jest na samej górze wiec jest domyslny
|
||||
$(TARGET): $(OBJECTS) $(VERSION_H)
|
||||
$(CC) $(OBJECTS) -o $@ $(LDLIBS)
|
||||
|
||||
# Compile source files
|
||||
build/src/%.o: src/%.c $(VERSION_H)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Generate version.h from Git
|
||||
$(VERSION_H): include/version.h.in
|
||||
@mkdir -p $(dir $@)
|
||||
@version=$$(git describe --always --long --dirty 2>/dev/null || echo unknown); \
|
||||
sed "s/@VCS_TAG@/$$version/" $< > $@.tmp; \
|
||||
if ! cmp -s $@.tmp $@ 2>/dev/null; then \
|
||||
mv $@.tmp $@; \
|
||||
else \
|
||||
rm -f $@.tmp; \
|
||||
fi
|
||||
|
||||
# Include automatically generated header dependencies
|
||||
-include $(DEPS)
|
||||
|
||||
.PHONY: all clean install uninstall debug
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
debug: CFLAGS += -O0 -g
|
||||
debug: $(TARGET)
|
||||
|
||||
clean:
|
||||
cmake --build $(BUILD_DIR) --target clean
|
||||
rm -rf build
|
||||
|
||||
nuke: clean
|
||||
rm -rf $(BUILD_DIR)
|
||||
install: $(TARGET)
|
||||
install -Dm755 $(TARGET) $(DESTDIR)$(HOME)/.local/bin/linuxSmartie
|
||||
|
||||
install: build
|
||||
mkdir -p ${HOME}/.local/bin
|
||||
install ${BUILD_DIR}/linuxSmartie ${HOME}/.local/bin
|
||||
|
||||
install_service: install
|
||||
service_install: install
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cp linuxSmartie.service ~/.config/systemd/user/linuxSmartie.service
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable linuxSmartie
|
||||
systemctl --user start linuxSmartie
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(HOME)/.local/bin/linuxSmartie
|
||||
40
README.md
40
README.md
@@ -1,29 +1,23 @@
|
||||
# linuxSmartie
|
||||
Alphanumeric LCD controller software for Linux (kind of LCDSmartie for Windows but no GUI, no config file, no plugins, no Windows).
|
||||
Alphanumeric LCD controller software for Linux (kind of LCDSmartie for Windows but no GUI, no config file, no plugins, no Windows).
|
||||
|
||||
~~Written with C++26 (`-std=c++2c`), will need at least gcc 14 to compile.~~ Uhm actually written with C++20 now, I was only really using `std::print` from 26. Let us not fall for memes. Will need gcc 10 to compile. GCC actually made C++20 the default since v16.
|
||||
|
||||
We can't go lower than C++20, we use too much shit introduced by it (std::format, std::chrono stuff mostly).
|
||||
|
||||
Hardcoded to work with 4x40 character display because that's what I have and I don't plan on using anything else. Uses Matrix Orbital protocol over serial. Should work with most other display sizes by modifying `src/LCDDisplay.cpp`. Best of luck if you try to make it work with anything else.
|
||||
|
||||
Vaguely inspired by suckless software philosophy, as in:
|
||||
- Hardcoded to work with 4x40 character display because that's what I have. Uses Matrix Orbital protocol over serial. Should work with most other display sizes by modifying `src/lcd.c`. If you're trying to make it work with anything else, good luck.
|
||||
- Originally written in C++26, then in C++20, and now finally in C23 because GOD C++ IS A MESS. Used to be vaguely C99 at some point but meson didn't like it and ig writing C23 I'm consistent with esp-idf v6.0.
|
||||
- Vaguely inspired by suckless software philosophy, as in:
|
||||
|
||||
## The config is the source code
|
||||
Same as plugins. Just write in more features scrub, learn some C++, damn
|
||||
Same as plugins. Just write in more features scrub, learn some C, damn
|
||||
|
||||
## TODOs
|
||||
- Use `std::string_view` or `const std::string &` when possible, its faster, no copy
|
||||
- GPU power is jumpy, average? Use accumulator instead?
|
||||
- Extra screens support perhaps? just halt sensors monitoring thread and print another struct on display if needed, have a semaphore or sth
|
||||
- Maybe not even screens, keep the 1st line and change lines 2-4
|
||||
- Media playback screen (use mpris, get playback info with mpris)
|
||||
- In the LCDDisplay lib, reimplement all the features I have in picoSmartie + maybe finally add keypad support for both so I can toggle backlight (?) or change screens if I want any
|
||||
- In the lcd lib, reimplement all the features I have in picoSmartie + maybe finally add keypad support for both so I can toggle backlight (?) or change screens if I want any
|
||||
- Screens could be automatic tbh, like if it detects media playing it switches to media screen, if in media screen and GPU power > 80W it switches to main (hwmon) screen
|
||||
- Try to be C++, avoid globals, wrap in namespaces, use naming conventions, use classes, avoid pure C way of doing things unless it makes more sense (which it often does tbh, better for reading small files)
|
||||
- **FUCK C++, HUGE REWRITE FROM SCRATCH IN C LIKE GOD ALWAYS INTENDED** but fuuuuck display thread would be so painful without std::string. And I really would need to start a whole ass project from a clean slate since I made it a point to use a lot of C++ features which now bite me in the ass.
|
||||
- Fuck it man, nvm let's leave it. Make it C++17 or 20 or sth so it compiles on yo mama or sth.
|
||||
|
||||
## LCD layout
|
||||
## LCD layout (on Windows)
|
||||
|
||||
It looks something like this
|
||||
```
|
||||
****************************************
|
||||
@@ -33,7 +27,6 @@ It looks something like this
|
||||
1,200V 1186MHz 3150 2/9MHz 0,112V
|
||||
****************************************
|
||||
```
|
||||
(on LCDSmartie)
|
||||
|
||||
### Ok but what does it all mean
|
||||
In general left side is CPU/system stuff, right side is GPU stuff
|
||||
@@ -59,20 +52,19 @@ Text04="$dll(hwinfo,1,Vcore,3)V $Right($dll(hwinfo,1,Average Effective Clock,a)M
|
||||
|
||||
### So what's still missing
|
||||
- Per-core CPU load, doable but annoying
|
||||
- FPS counter, maybe possible?
|
||||
- Active core count, probably impossible but loadAvg is better?
|
||||
- FPS counter, maybe possible? Not really on wayland, by design
|
||||
- Active core count, probably impossible but loadAvg is better
|
||||
- GPU board power, probably impossible, it was estimated on windows anyway
|
||||
- CPU cache/iod, likely impossible, zenpower doesnt show it
|
||||
- GPU clock limit, probably impossible, gpu_metrics doesnt show it?
|
||||
|
||||
### Shit needed to compile on Debian 13
|
||||
|
||||
V simple:
|
||||
```bash
|
||||
sudo apt install build-essential cmake libwebsockets-dev nlohmann-json3-dev
|
||||
make configure
|
||||
make build
|
||||
sudo apt install build-essential meson libusb-1.0-0-dev pkgconf zlib1g-dev
|
||||
make -j
|
||||
```
|
||||
You're probably on some meme immutable distro so use Debian 13 on distrobox. Ubuntu 24.04 should also work. Might set up a distrobox container file, with distrobox-assemble (?)
|
||||
You're probably on some meme immutable distro so use Debian 13 on distrobox. Any distro with GCC and cmake should work tbh.
|
||||
|
||||
### Additional notes
|
||||
|
||||
@@ -80,4 +72,4 @@ You're probably on some meme immutable distro so use Debian 13 on distrobox. Ubu
|
||||
- On Fedora Workstation it can be added by appending it to `/etc/kernel/cmdline`.
|
||||
- On atomic desktops (Silverblue/Kinoite), `rpm-ostree kargs --append-if-missing=acpi_enforce_resources=lax`
|
||||
- You need to be able to read RAPL as user. Create in `/etc/tmpfiles.d/intelrapl.conf` with content `z- /sys/class/powercap/intel-rapl:0/energy_uj 0440 root uucp - -`. Adjust uucp to whatever group applicable, like `dialout`.
|
||||
- `compile_commands.json` is so clang understands this project, so we can edit it with helix/neovim. Generated with `bear -- make`, make sure to run `make clean` beforehand.
|
||||
- ModemManager might steal the port sometimes. Either disable the service or setup an udev rule: `SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", ENV{ID_MM_DEVICE_IGNORE}="1"`
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[linuxsmartie]
|
||||
additional_packages="build-essential cmake"
|
||||
additional_packages="libwebsockets-dev nlohmann-json3-dev"
|
||||
image=debian-toolbox:13
|
||||
additional_packages="build-essential libusb-1.0-0-dev pkgconf zlib1g-dev"
|
||||
image=quay.io/toolbx-images/debian-toolbox:13
|
||||
init=false
|
||||
replace=true
|
||||
start_now=true
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#ifndef LCDDISPLAY_HPP
|
||||
#define LCDDISPLAY_HPP
|
||||
|
||||
#define LCD_LINES 4
|
||||
#define LCD_COLS 40
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class LCDDisplay {
|
||||
private:
|
||||
int lcd = -1;
|
||||
uint32_t baud = 0;
|
||||
std::string dev;
|
||||
std::array<char, LCD_LINES * LCD_COLS + 8> writebuf{}; // 4x40 chars + 2x4 setcursor commands
|
||||
static constexpr bool dualDisp = (LCD_LINES * LCD_COLS > 80); // is it dual display device or not, evauluated from the size at compile time
|
||||
|
||||
int open(bool reopen = false);
|
||||
void write(const uint8_t* cmdbuf, uint8_t len);
|
||||
void close();
|
||||
|
||||
// we avoid using these, use buffer (even if these are faster for small writes, perhaps a rewrite is in order)
|
||||
void writeStr(const std::string& str);
|
||||
void writeStr(uint8_t row, uint8_t col, const std::string& str);
|
||||
|
||||
public:
|
||||
explicit LCDDisplay(const std::string& dev, uint32_t baud = 0010002); // from termios-baud.h, B115200
|
||||
~LCDDisplay();
|
||||
|
||||
int Init();
|
||||
void clear();
|
||||
void setContrast(uint8_t contrast);
|
||||
void setBacklight(bool enabled);
|
||||
void setBacklight(uint8_t brightness);
|
||||
void setCursor(uint8_t row, uint8_t col);
|
||||
void setCustomChar(uint8_t index, std::array<uint8_t, 8> cchar);
|
||||
|
||||
void writeBuf(uint8_t row, uint8_t col, const std::string& str);
|
||||
void clearBuf();
|
||||
void flushBuf();
|
||||
char bar(uint8_t char_id, double value);
|
||||
|
||||
// returns custom char no. c, small enough to define in header
|
||||
static constexpr char cc(const uint8_t c) { return static_cast<char>(c % 8); }
|
||||
};
|
||||
|
||||
#endif
|
||||
67
include/aio.h
Normal file
67
include/aio.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef LINUXSMARTIE_AIO_H
|
||||
#define LINUXSMARTIE_AIO_H
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#define AIO_USB_VID 0x1b1cU
|
||||
#define AIO_USB_PID 0x0c13U
|
||||
|
||||
#define AIO_COLOR_CYAN { 0, 255, 255 }
|
||||
#define AIO_COLOR_WHITE { 255, 255, 255 }
|
||||
#define AIO_COLOR_OFF { 0, 0, 0 }
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
struct aio_params_t {
|
||||
struct {
|
||||
uint8_t min_duty;
|
||||
uint8_t max_duty;
|
||||
bool fan_stop;
|
||||
float setpoint;
|
||||
struct {
|
||||
float Ki;
|
||||
float Kd;
|
||||
} ctrl;
|
||||
} fans;
|
||||
};
|
||||
|
||||
enum aio_pump_mode_t {
|
||||
AIO_PUMP_MODE_QUIET,
|
||||
AIO_PUMP_MODE_BALANCED,
|
||||
AIO_PUMP_MODE_EXTREME,
|
||||
AIO_PUMP_MODE_UNKNOWN
|
||||
};
|
||||
|
||||
enum aio_color_mode_t : uint8_t {
|
||||
AIO_COLOR_PULSE,
|
||||
AIO_COLOR_SHIFT,
|
||||
AIO_COLOR_FIXED,
|
||||
AIO_COLOR_BLINKING
|
||||
};
|
||||
|
||||
struct rgb_t {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
};
|
||||
|
||||
struct curve_point_t {
|
||||
uint8_t temp;
|
||||
uint8_t duty;
|
||||
};
|
||||
|
||||
struct aio_t {
|
||||
libusb_device_handle* handle;
|
||||
enum aio_pump_mode_t pump_mode;
|
||||
float water_temp;
|
||||
int16_t pump_counter;
|
||||
uint16_t pump_speed;
|
||||
uint16_t fan_speed[2];
|
||||
};
|
||||
|
||||
void aio_detect(struct aio_t *aio);
|
||||
void aio_update(struct aio_t *aio);
|
||||
void aio_close(const struct aio_t *aio);
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
#ifndef APP_HPP
|
||||
#define APP_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <cpu.hpp>
|
||||
#include <gpu.hpp>
|
||||
#include <mutex>
|
||||
#include <semaphore>
|
||||
#include <stop_token>
|
||||
#include <sys.hpp>
|
||||
#include <thread>
|
||||
|
||||
class Application {
|
||||
public:
|
||||
struct Config {
|
||||
struct Lcd {
|
||||
uint16_t refresh_interval_ms;
|
||||
uint8_t contrast;
|
||||
std::string port;
|
||||
};
|
||||
struct HomeAssistant {
|
||||
std::string url;
|
||||
std::string entity;
|
||||
std::string token;
|
||||
};
|
||||
Lcd lcd;
|
||||
HomeAssistant hass;
|
||||
std::string cpu_pciaddr;
|
||||
std::string gpu_pciaddr;
|
||||
std::string sys_sensor;
|
||||
std::string sys_ifname;
|
||||
std::string home_dir;
|
||||
};
|
||||
|
||||
explicit Application(Config config);
|
||||
~Application();
|
||||
int Run();
|
||||
|
||||
private:
|
||||
struct Sensors {
|
||||
sys::TimeDate td;
|
||||
double loadavg[3] = {0.0f};
|
||||
sys::Memory ram;
|
||||
sys::Disk home;
|
||||
sys::Network net;
|
||||
sys::sysSensors sys;
|
||||
cpu::cpuSensors cpu;
|
||||
gpu::gpuSensors gpu;
|
||||
double hass_state = 0.0f;
|
||||
};
|
||||
|
||||
struct Control {
|
||||
std::binary_semaphore display{0};
|
||||
std::mutex sensors; // making sure the sensors struct isnt accessed by multiple threads at once
|
||||
sigset_t sigset;
|
||||
};
|
||||
|
||||
pid_t m_mainPid{};
|
||||
int m_ret = 0;
|
||||
Config m_config{}; // m_ is prefix for member variable
|
||||
Control m_control{};
|
||||
Sensors m_sensors{};
|
||||
|
||||
void hassThread(const std::stop_token& st);
|
||||
void sensorsThread(const std::stop_token& st);
|
||||
void displayThread(const std::stop_token& st);
|
||||
|
||||
void Crash(int ret);
|
||||
};
|
||||
|
||||
#endif
|
||||
30
include/cpu.h
Normal file
30
include/cpu.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef LINUXSMARTIE_CPU_H
|
||||
#define LINUXSMARTIE_CPU_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum cpu_module_t : uint8_t {
|
||||
unknown,
|
||||
k10temp,
|
||||
zenpower
|
||||
};
|
||||
|
||||
struct cpu_sensors_t {
|
||||
enum cpu_module_t module;
|
||||
uint8_t num_cores;
|
||||
int16_t tdie;
|
||||
int16_t tctl;
|
||||
int16_t tccd1;
|
||||
// double pcore;
|
||||
// double psoc;
|
||||
float ptotal;
|
||||
// double vcore;
|
||||
// double vsoc;
|
||||
uint32_t avg_freq;
|
||||
char hwmon[64];
|
||||
};
|
||||
|
||||
void cpu_detect(struct cpu_sensors_t *t, const char *pci_dev);
|
||||
void cpu_update(struct cpu_sensors_t *c);
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef CPU_HPP
|
||||
#define CPU_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace cpu {
|
||||
|
||||
enum Module : uint8_t { unknown,
|
||||
k10temp,
|
||||
zenpower };
|
||||
|
||||
struct cpuSensors {
|
||||
Module module = unknown;
|
||||
uint8_t num_cores = 0;
|
||||
int16_t tdie = 0;
|
||||
int16_t tctl = 0;
|
||||
int16_t tccd1 = 0;
|
||||
// double pcore = 0.0;
|
||||
// double psoc = 0.0;
|
||||
float ptotal = 0.0;
|
||||
// double vcore = 0.0;
|
||||
// double vsoc = 0.0;
|
||||
uint32_t avg_freq = 0;
|
||||
std::string hwmon;
|
||||
};
|
||||
|
||||
int detect(cpuSensors* target, const std::string& pci);
|
||||
void update(cpuSensors* c);
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif
|
||||
41
include/gpu.h
Normal file
41
include/gpu.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef LINUXSMARTIE_GPU_H
|
||||
#define LINUXSMARTIE_GPU_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct gpu_sensors_t {
|
||||
uint64_t vram_used;
|
||||
// uint64_t vram_total = 0;
|
||||
|
||||
float vcore;
|
||||
|
||||
uint16_t clock_core;
|
||||
uint16_t clock_mem;
|
||||
|
||||
// uint8_t fan_pwm = 0;
|
||||
uint16_t fan_speed;
|
||||
|
||||
uint16_t power_avg;
|
||||
uint16_t power_cap;
|
||||
// uint16_t power_cap_max = 0;
|
||||
|
||||
uint8_t temp_edge;
|
||||
uint8_t temp_hotspot;
|
||||
uint8_t temp_mem;
|
||||
uint8_t temp_vrm_gfx;
|
||||
uint8_t temp_vrm_soc;
|
||||
uint8_t temp_vrm_mem;
|
||||
|
||||
bool has_gpu_metrics;
|
||||
|
||||
uint8_t usage_core;
|
||||
uint8_t usage_media;
|
||||
uint8_t usage_umc;
|
||||
|
||||
char hwmon[64];
|
||||
};
|
||||
|
||||
void gpu_detect(struct gpu_sensors_t *t, const char *pci);
|
||||
void gpu_update(struct gpu_sensors_t *g);
|
||||
|
||||
#endif
|
||||
@@ -1,85 +0,0 @@
|
||||
#ifndef GPU_HPP
|
||||
#define GPU_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
/* clean abstraction for gpu_metrics or metrics in filesystem in sane units */
|
||||
|
||||
namespace gpu {
|
||||
|
||||
struct gpuSensors {
|
||||
uint64_t vram_used = 0;
|
||||
// uint64_t vram_total = 0;
|
||||
|
||||
float vcore = 0.0f;
|
||||
|
||||
uint16_t clock_core = 0;
|
||||
uint16_t clock_mem = 0;
|
||||
|
||||
// uint8_t fan_pwm = 0;
|
||||
uint16_t fan_speed = 0;
|
||||
|
||||
uint16_t power_avg = 0;
|
||||
uint16_t power_cap = 0;
|
||||
// uint16_t power_cap_max = 0;
|
||||
|
||||
uint8_t temp_edge = 0;
|
||||
uint8_t temp_hotspot = 0;
|
||||
uint8_t temp_mem = 0;
|
||||
uint8_t temp_vrm_gfx = 0;
|
||||
uint8_t temp_vrm_soc = 0;
|
||||
uint8_t temp_vrm_mem = 0;
|
||||
|
||||
bool hasGpuMetrics = false;
|
||||
|
||||
uint8_t usage_core = 0;
|
||||
uint8_t usage_media = 0;
|
||||
uint8_t usage_umc = 0;
|
||||
|
||||
std::string hwmon;
|
||||
};
|
||||
|
||||
int detect(gpuSensors* target, const std::string& pci);
|
||||
void update(gpuSensors* g);
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
// class ThrottleStatus(IntFlag):
|
||||
// # linux/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
|
||||
// PPT0 = 1 << 0
|
||||
// PPT1 = 1 << 1
|
||||
// PPT2 = 1 << 2
|
||||
// PPT3 = 1 << 3
|
||||
// SPL = 1 << 4
|
||||
// FPPT = 1 << 5
|
||||
// SPPT = 1 << 6
|
||||
// SPPT_APU = 1 << 7
|
||||
// TDC_GFX = 1 << 16
|
||||
// TDC_SOC = 1 << 17
|
||||
// TDC_MEM = 1 << 18
|
||||
// TDC_VDD = 1 << 19
|
||||
// TDC_CVIP = 1 << 20
|
||||
// EDC_CPU = 1 << 21
|
||||
// EDC_GFX = 1 << 22
|
||||
// APCC = 1 << 23
|
||||
// TEMP_GPU = 1 << 32
|
||||
// TEMP_CORE = 1 << 33
|
||||
// TEMP_MEM = 1 << 34
|
||||
// TEMP_EDGE = 1 << 35
|
||||
// TEMP_HOTSPOT = 1 << 36
|
||||
// TEMP_SOC = 1 << 37
|
||||
// TEMP_VR_GFX = 1 << 38
|
||||
// TEMP_VR_SOC = 1 << 39
|
||||
// TEMP_VR_MEM0 = 1 << 40
|
||||
// TEMP_VR_MEM1 = 1 << 41
|
||||
// TEMP_LIQUID0 = 1 << 42
|
||||
// TEMP_LIQUID1 = 1 << 43
|
||||
// VRHOT0 = 1 << 44
|
||||
// VRHOT1 = 1 << 45
|
||||
// PROCHOT_CPU = 1 << 46
|
||||
// PROCHOT_GFX = 1 << 47
|
||||
// PPM = 1 << 56
|
||||
// FIT = 1 << 57
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
#ifndef HASS_HPP
|
||||
#define HASS_HPP
|
||||
|
||||
#ifdef ENABLE_HOME_ASSISTANT
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class HomeAssistant {
|
||||
public:
|
||||
struct Config {
|
||||
std::string address;
|
||||
std::string entity;
|
||||
std::string token;
|
||||
};
|
||||
explicit HomeAssistant(const Config& config);
|
||||
~HomeAssistant();
|
||||
|
||||
float state = 0.0f;
|
||||
int connect();
|
||||
void disconnect() const;
|
||||
void service(int timeout_ms = 0) const;
|
||||
|
||||
private:
|
||||
uint16_t id = 2;
|
||||
std::string tx;
|
||||
lws_context* context = nullptr;
|
||||
lws* websock = nullptr;
|
||||
void event_handler(lws* wsi, lws_callback_reasons reason, char* in);
|
||||
static int callback(lws* wsi, lws_callback_reasons reason, void* user, void* in, size_t len);
|
||||
Config m_config;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
34
include/lcd.h
Normal file
34
include/lcd.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef LINUXSMARTIE_LCD_H
|
||||
#define LINUXSMARTIE_LCD_H
|
||||
|
||||
#define LCD_LINES 4
|
||||
#define LCD_COLS 40
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct lcd_t {
|
||||
int fd;
|
||||
uint32_t baud;
|
||||
struct {
|
||||
char cchar[8][11]; // 8 custom chars, each 11 bytes (3 byte command + 8 byte glyph)
|
||||
char text[LCD_LINES * LCD_COLS + 8]; // number of chars on the lcd + 2*4 byte set cursor commands
|
||||
} writebuf;
|
||||
char port[96];
|
||||
};
|
||||
|
||||
typedef uint8_t lcd_glyph_t[8];
|
||||
|
||||
void lcd_close(struct lcd_t *lcd);
|
||||
void lcd_clear(struct lcd_t *lcd);
|
||||
void lcd_set_contrast(struct lcd_t *lcd, uint8_t contrast);
|
||||
void lcd_set_backlight(struct lcd_t *lcd, bool enabled);
|
||||
void lcd_set_cursor(struct lcd_t *lcd, uint8_t row, uint8_t col);
|
||||
void lcd_set_custom_char(struct lcd_t *lcd, uint8_t index, const lcd_glyph_t *glyph);
|
||||
void lcd_write_buf(struct lcd_t *lcd, uint8_t row, uint8_t col, const char *str);
|
||||
void lcd_writef(struct lcd_t *lcd, uint8_t x, uint8_t y, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
|
||||
void lcd_clear_buf(struct lcd_t *lcd);
|
||||
void lcd_flush_buf(struct lcd_t *lcd);
|
||||
char lcd_bar(struct lcd_t *lcd, uint8_t char_id, double value);
|
||||
int lcd_init(struct lcd_t *lcd);
|
||||
|
||||
#endif
|
||||
36
include/log.h
Normal file
36
include/log.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef LINUXSMARTIE_LOG_H
|
||||
#define LINUXSMARTIE_LOG_H
|
||||
|
||||
/* ── kill switch ────────────────────────────────────────────────────────── */
|
||||
/* comment out to disable all logging */
|
||||
#define APPLOG_ENABLED
|
||||
|
||||
/* ─────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
#ifdef APPLOG_ENABLED
|
||||
|
||||
typedef enum {
|
||||
LOG_INF,
|
||||
LOG_WRN,
|
||||
LOG_ERR,
|
||||
LOG_DBG,
|
||||
LOG_START,
|
||||
} log_level_t;
|
||||
|
||||
/* __PRETTY_FUNCTION__ is a GCC/Clang extension that gives the full
|
||||
signature: "voi*d foo(int x)" — same thing source_location gave you.
|
||||
Falls back to plain __func__ (C99) if somehow unavailable. */
|
||||
#define applog(level, fmt, ...) \
|
||||
log_write(level, __func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
/* format attribute gives compile-time printf format checking —
|
||||
better than wha*t std::format gave you at runtime */
|
||||
void log_write(log_level_t level, const char *func, const char *fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
#else /* APPLOG_ENABLED not defined */
|
||||
|
||||
#define applog(...) ((void)0)
|
||||
|
||||
#endif /* APPLOG_ENABLED */
|
||||
#endif /* LINUXSMARTIE_LOG_H */
|
||||
@@ -1,96 +0,0 @@
|
||||
#ifndef LOG_HPP
|
||||
#define LOG_HPP
|
||||
|
||||
// comment out to disable logging in general
|
||||
|
||||
#define applog(level, fmt, ...) utils::log(level, std::source_location::current(), fmt, ##__VA_ARGS__)
|
||||
|
||||
// comment out to disable logging to file
|
||||
// #define LOG_FILE_LOCATION "linuxSmartie.log.gz"
|
||||
|
||||
#ifdef applog
|
||||
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef LOG_FILE_LOCATION
|
||||
#include <zlib.h>
|
||||
inline std::mutex fmtx; // file logging mutex
|
||||
#endif
|
||||
|
||||
enum class LOG { INF, WRN, ERR, DBG, START };
|
||||
|
||||
namespace utils {
|
||||
inline std::mutex cmtx; // console logging mutex
|
||||
|
||||
constexpr std::string pFname(std::string_view full) {
|
||||
if (const auto pos = full.find(' '); pos != std::string_view::npos)
|
||||
full.remove_prefix(pos + 1);
|
||||
|
||||
if (const auto pos = full.rfind('('); pos != std::string_view::npos)
|
||||
full.remove_suffix(full.size() - pos);
|
||||
|
||||
return std::string(full);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void log(const LOG level, const std::source_location& loc, std::format_string<Args...> str, Args&&... args) {
|
||||
constexpr std::string_view reset = "\033[0m";
|
||||
constexpr std::string_view pattern = "[{}{}{}] ";
|
||||
std::string_view color;
|
||||
|
||||
switch (level) {
|
||||
case LOG::INF:
|
||||
color = "\033[1;32m";
|
||||
break; // bold; green
|
||||
case LOG::WRN:
|
||||
color = "\033[1;33m"; // bold; yellow
|
||||
break;
|
||||
case LOG::ERR:
|
||||
color = "\033[1;31m"; // bold; red
|
||||
break;
|
||||
case LOG::DBG:
|
||||
break;
|
||||
case LOG::START:
|
||||
color = "\033[1;3;36m"; // bold; blinking; cyan
|
||||
break;
|
||||
}
|
||||
|
||||
/* log to console */
|
||||
{
|
||||
std::scoped_lock lock(cmtx);
|
||||
std::cout << std::format(pattern, color, pFname(loc.function_name()), reset);
|
||||
std::cout << std::format(str, std::forward<Args>(args)...) << std::endl;
|
||||
}
|
||||
|
||||
#ifdef LOG_FILE_LOCATION
|
||||
/* log to file */
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto local = std::chrono::current_zone()->to_local(now);
|
||||
std::string msg = std::format("{:%x %H:%M:%S }", floor<std::chrono::milliseconds>(local)); // timestamp
|
||||
std::format_to(std::back_inserter(msg), pattern, color, pFname(loc.function_name()), reset); // tag
|
||||
std::format_to(std::back_inserter(msg), str, std::forward<Args>(args)...); // actual log message
|
||||
|
||||
std::scoped_lock lock(fmtx);
|
||||
gzFile file = gzopen(LOG_FILE_LOCATION, "ab");
|
||||
if (file) {
|
||||
gzprintf(file, "%s\n", msg.c_str());
|
||||
gzclose(file);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // namespace utils
|
||||
|
||||
#else
|
||||
|
||||
#define applog(...)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
56
include/sys.h
Normal file
56
include/sys.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef LINUXSMARTIE_SYS_H
|
||||
#define LINUXSMARTIE_SYS_H
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SYS_GET_TIME_STR(t) sys_get_time_string((char[16]){0}, 16, t)
|
||||
#define SYS_GET_DATE_STR(t) sys_get_date_string((char[16]){0}, 16, t)
|
||||
|
||||
struct memory_t {
|
||||
uint64_t free;
|
||||
uint64_t used;
|
||||
uint64_t total;
|
||||
};
|
||||
|
||||
struct disk_t {
|
||||
struct memory_t usage;
|
||||
char mountpoint[64];
|
||||
};
|
||||
|
||||
struct network_t {
|
||||
uint32_t download;
|
||||
uint32_t upload;
|
||||
sensor_file_t f_rx;
|
||||
sensor_file_t f_tx;
|
||||
char device[16];
|
||||
};
|
||||
|
||||
struct syssensors_t {
|
||||
char hwmon[64];
|
||||
// uint16_t fan_speed[1]; // just one fan (pump) we monitor
|
||||
int16_t t_sensor; // ntc temp sensor
|
||||
};
|
||||
|
||||
char *sys_get_time_string(char *buf, size_t bufsz, time_t t);
|
||||
|
||||
char *sys_get_date_string(char *buf, size_t bufsz, time_t t);
|
||||
|
||||
void sys_get_load_avg(double *load_avg);
|
||||
|
||||
void sys_get_distro(char* name, char* ver_str);
|
||||
|
||||
void sys_get_ram(struct memory_t *ram);
|
||||
|
||||
void sys_get_disk(struct disk_t *disk);
|
||||
|
||||
void sys_get_network(struct network_t *network);
|
||||
|
||||
void sys_netdev_detect(struct network_t *network);
|
||||
|
||||
void sys_detect(struct syssensors_t *s, const char *platform);
|
||||
|
||||
void sys_update_sensors(const struct syssensors_t *s);
|
||||
|
||||
#endif // LINUXSMARTIE_SYS_H
|
||||
@@ -1,49 +0,0 @@
|
||||
#ifndef SYS_HPP
|
||||
#define SYS_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace sys {
|
||||
|
||||
constexpr char months[][4] = {"sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paz", "lis", "gru"};
|
||||
constexpr char wdays[][4] = {"Nie", "Pon", "Wto", "Sro", "Czw", "Pia", "Sob"};
|
||||
|
||||
struct sysSensors {
|
||||
std::string hwmon;
|
||||
uint16_t fan_speed[2] = {0}; // left and right cpu fans
|
||||
int16_t t_sensor = 0; // ntc temp sensor
|
||||
std::byte _pad[2];
|
||||
};
|
||||
|
||||
struct Memory {
|
||||
uint64_t free = 0;
|
||||
uint64_t used = 0;
|
||||
uint64_t total = 0;
|
||||
};
|
||||
|
||||
struct Disk {
|
||||
std::string mountpoint;
|
||||
Memory usage;
|
||||
};
|
||||
|
||||
struct TimeDate {
|
||||
std::string time;
|
||||
std::string date;
|
||||
};
|
||||
|
||||
struct Network {
|
||||
uint32_t download = 0;
|
||||
uint32_t upload = 0;
|
||||
};
|
||||
|
||||
void getTimeDate(TimeDate* td);
|
||||
void getDisk(Disk* disk);
|
||||
void getRam(Memory* mem);
|
||||
void getNetwork(Network* net, const std::string& device);
|
||||
int detect(sysSensors* s, const std::string& platform);
|
||||
void updateSensors(sysSensors* s);
|
||||
|
||||
} // namespace sys
|
||||
|
||||
#endif
|
||||
60
include/utils.h
Normal file
60
include/utils.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef LINUXSMARTIE_UTILS_H
|
||||
#define LINUXSMARTIE_UTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h> // NOLINT yes its, needed for ssize_t
|
||||
|
||||
#if __STDC_VERSION__ >= 202000L
|
||||
#define C_STD "C23"
|
||||
#elif __STDC_VERSION__ >= 201710L
|
||||
#define C_STD "C17"
|
||||
#elif __STDC_VERSION__ >= 201112L
|
||||
#define C_STD "C11"
|
||||
#elif __STDC_VERSION__ >= 199901L
|
||||
#define C_STD "C99"
|
||||
#else
|
||||
#define C_STD "C89"
|
||||
#endif
|
||||
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define P_BYTES(bytes, start) pretty_bytes((bytes), (start), (char[16]){0}, 16)
|
||||
#define P_NUM(num) pretty_num((num), (char[16]){0}, 16)
|
||||
|
||||
typedef enum : uint8_t {
|
||||
SENSOR_I16,
|
||||
SENSOR_U8,
|
||||
SENSOR_U16,
|
||||
SENSOR_U64,
|
||||
SENSOR_FLOAT,
|
||||
} sensor_type_t;
|
||||
|
||||
typedef struct {
|
||||
sensor_type_t type;
|
||||
int fd;
|
||||
void* value;
|
||||
uint32_t divider;
|
||||
} sensor_file_t;
|
||||
|
||||
int get_instance_lock();
|
||||
|
||||
void timespec_add_ms(struct timespec *ts, uint16_t ms);
|
||||
|
||||
int64_t timespec_diff_us(const struct timespec *a, const struct timespec *b);
|
||||
|
||||
char *pretty_num(double num, char *buf, size_t bufsz);
|
||||
|
||||
char *pretty_bytes(uint64_t bytes, int8_t start_suffix, char *buf, size_t bufsz);
|
||||
|
||||
int get_hwmon_dir(char *path, size_t bufsz);
|
||||
|
||||
void open_sensor(sensor_file_t* s, const char* dir, const char *file, void* value, uint32_t divider, sensor_type_t type);
|
||||
|
||||
void fast_read_sensor_into_mem(const sensor_file_t *s, void* val);
|
||||
|
||||
void fast_read_sensor(const sensor_file_t *s);
|
||||
|
||||
void close_sensor(const sensor_file_t* s);
|
||||
|
||||
#endif
|
||||
@@ -1,80 +0,0 @@
|
||||
#ifndef UTILS_HPP
|
||||
#define UTILS_HPP
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <log.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
constexpr char fill_char = ' ';
|
||||
enum just : uint8_t { right, left };
|
||||
|
||||
std::string pad(std::string s, uint8_t len, just j = right);
|
||||
std::string center(std::string str, uint8_t len);
|
||||
std::string getFirstDir(const std::string_view& path);
|
||||
|
||||
inline std::string pNum(const auto num, const uint8_t decs = 0) {
|
||||
static std::array<char, 20> buf;
|
||||
auto [ptr, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), static_cast<double>(num), std::chars_format::fixed, decs);
|
||||
return {buf.data(), ptr};
|
||||
}
|
||||
|
||||
/* converts large number in (k)bytes to human-readable numer with suffix and sane decimal */
|
||||
std::string pBytes(const auto bytes, const bool isKbytes = false) {
|
||||
double bytes_d = bytes;
|
||||
for (constexpr std::array suffix_list = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'}; const auto& suffix : suffix_list) {
|
||||
if (suffix == 'K' && isKbytes) continue; // skip first loop if already in Kbytes
|
||||
bytes_d /= 1024.0;
|
||||
if (bytes_d < 1024) {
|
||||
if (bytes_d > 100) return pNum(bytes_d) + suffix;
|
||||
if (bytes_d > 10) return pNum(bytes_d, 1) + suffix;
|
||||
return pNum(bytes_d, 2) + suffix;
|
||||
}
|
||||
}
|
||||
return "++++";
|
||||
}
|
||||
|
||||
/* reads file into a std::array buffer */
|
||||
template <size_t N>
|
||||
inline ssize_t readFile(const std::string& path, std::array<char, N>& buffer) {
|
||||
const int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
applog(LOG::ERR, "Error reading {}", path);
|
||||
return 0;
|
||||
}
|
||||
const ssize_t len = read(fd, buffer.data(), buffer.size());
|
||||
if (len >= 0) buffer[len] = '\0';
|
||||
close(fd);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* reads a number fast and divides it if needed */
|
||||
template <uint32_t Divider = 1, typename T, size_t N>
|
||||
inline void fastReadNum(const std::string& path, std::array<char, N>& buf, T& result) {
|
||||
readFile(path, buf);
|
||||
if constexpr (Divider == 1) {
|
||||
std::from_chars(buf.data(), buf.data() + N, result);
|
||||
return;
|
||||
}
|
||||
uint64_t temp{};
|
||||
std::from_chars(buf.data(), buf.data() + N, temp);
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
result = temp / static_cast<T>(Divider);
|
||||
else
|
||||
result = static_cast<T>(temp / Divider);
|
||||
}
|
||||
|
||||
inline bool fileExists(const std::string_view& path) {
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif
|
||||
2
include/version.h.in
Normal file
2
include/version.h.in
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define GIT_HASH "@VCS_TAG@"
|
||||
@@ -5,6 +5,7 @@ Description=HD44780 display service (linuxSmartie)
|
||||
Type=simple
|
||||
ExecStart=%h/.local/bin/linuxSmartie
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
WantedBy=graphical-session.target
|
||||
20
main.cpp
20
main.cpp
@@ -1,20 +0,0 @@
|
||||
#include <app.hpp>
|
||||
|
||||
int main() {
|
||||
Application::Config config;
|
||||
|
||||
config.lcd.port = "/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00"; // tis a symlink, can also be just /dev/ttyACM0)
|
||||
config.lcd.refresh_interval_ms = 500;
|
||||
config.lcd.contrast = 215;
|
||||
config.cpu_pciaddr = "0000:00:18.3";
|
||||
config.gpu_pciaddr = "0000:0a:00.0";
|
||||
config.sys_sensor = "nct6775.656";
|
||||
config.sys_ifname = "enp7s0";
|
||||
config.home_dir = "/home/drath";
|
||||
config.hass.url = "home.drath.win";
|
||||
config.hass.entity = "sensor.gniazdko_komputer_moc";
|
||||
config.hass.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI0MzUxMTZiY2VjNTg0MTI3OGI4YmU0NTY4ZGQ5MzIyYiIsImlhdCI6MTc1NzQzMDI0MCwiZXhwIjoyMDcyNzkwMjQwfQ.6wKTlxEA0FLWfv-qW35vewUSvTxdVrZWqFwHT5Khu6E";
|
||||
|
||||
Application App(config);
|
||||
return App.Run();
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
#include "LCDDisplay.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <log.hpp>
|
||||
#include <string>
|
||||
|
||||
/* lcd size hardcoded to 4x40 idgaf */
|
||||
LCDDisplay::LCDDisplay(const std::string& dev, const uint32_t baud) {
|
||||
this->dev = dev;
|
||||
this->baud = baud;
|
||||
}
|
||||
|
||||
LCDDisplay::~LCDDisplay() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
int LCDDisplay::Init() {
|
||||
if (const int ret = this->open(); ret < 0) {
|
||||
this->close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct termios term{};
|
||||
// Setup the serial port 8 data bits, no parity, 1 stopbit, no flow control
|
||||
term.c_cflag = baud | CS8 | CSTOPB | CLOCAL | CREAD;
|
||||
term.c_iflag = 0;
|
||||
term.c_oflag = 0;
|
||||
term.c_lflag = 0;
|
||||
tcflush(lcd, TCIFLUSH);
|
||||
tcsetattr(lcd, TCSANOW, &term);
|
||||
|
||||
// init linebuf to spaces
|
||||
this->clearBuf();
|
||||
|
||||
// disable underline and block cursor
|
||||
constexpr uint8_t cmdbuf[] = {254, 75, 254, 84};
|
||||
const ssize_t ret = ::write(lcd, &cmdbuf, sizeof(cmdbuf));
|
||||
(void)ret;
|
||||
|
||||
// clear display and set cursor home
|
||||
this->clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LCDDisplay::open(const bool reopen) {
|
||||
applog(LOG::INF, "Opening serial port at \"{}\"", dev);
|
||||
if (lcd < 0 || reopen)
|
||||
lcd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); // ::open calls the global open() instead of LCDDisplay::open()
|
||||
if (lcd < 0) {
|
||||
applog(LOG::ERR, "Error opening serial port \"{}\"", dev); // err
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LCDDisplay::close() {
|
||||
if (lcd >= 0) {
|
||||
::close(lcd);
|
||||
applog(LOG::INF, "LCD port closed");
|
||||
}
|
||||
lcd = -1;
|
||||
}
|
||||
|
||||
void LCDDisplay::write(const uint8_t* cmdbuf, const uint8_t len) {
|
||||
if (::write(lcd, cmdbuf, len) != len) {
|
||||
applog(LOG::ERR, "failed to execute ::write, lost access to port?");
|
||||
this->open(true);
|
||||
}
|
||||
}
|
||||
|
||||
void LCDDisplay::clear() {
|
||||
constexpr uint8_t cmdbuf[] = {254, 88};
|
||||
this->write(cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
void LCDDisplay::setContrast(const uint8_t contrast) {
|
||||
applog(LOG::INF, "Set contrast to {}", contrast);
|
||||
const uint8_t cmdbuf[] = {254, 80, contrast};
|
||||
this->write(cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
void LCDDisplay::setBacklight(const bool enabled) {
|
||||
applog(LOG::INF, "Set backlight to {}", enabled);
|
||||
const uint8_t cmdbuf[] = {254, static_cast<uint8_t>(enabled ? 66 : 70), 255};
|
||||
this->write(cmdbuf, enabled ? 3 : 2);
|
||||
}
|
||||
|
||||
/* still doesnt work? */
|
||||
void LCDDisplay::setBacklight(const uint8_t brightness) {
|
||||
applog(LOG::INF, "Set backlight brightness to {}", brightness);
|
||||
const uint8_t cmdbuf[] = {254, static_cast<uint8_t>(brightness ? 66 : 70), 255, brightness}; // 3rd char is timer, 4th is brightness
|
||||
this->write(cmdbuf, brightness ? 4 : 2);
|
||||
}
|
||||
|
||||
void LCDDisplay::setCursor(const uint8_t row, const uint8_t col) {
|
||||
const uint8_t cmdbuf[] = {254, 71, static_cast<uint8_t>(col + 1), static_cast<uint8_t>(row + 1)};
|
||||
this->write(cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
/* reconsider so im not writing every time. prepend custom chars to the write buffer? */
|
||||
void LCDDisplay::setCustomChar(const uint8_t index, const std::array<uint8_t, 8> cchar) {
|
||||
uint8_t cmdbuf[] = {254, 78, index, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
std::memcpy(&cmdbuf[3], &cchar, sizeof(cchar));
|
||||
this->write(cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
/* immediately writes string to the lcd at current cursor pos */
|
||||
void LCDDisplay::writeStr(const std::string& str) {
|
||||
this->write(reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
|
||||
}
|
||||
|
||||
/* immediately writes string to the lcd at given cursor pos */
|
||||
void LCDDisplay::writeStr(const uint8_t row, const uint8_t col, const std::string& str) {
|
||||
this->setCursor(row, col);
|
||||
this->write(reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
|
||||
}
|
||||
|
||||
/* writes string to write buffer at calculated pos */
|
||||
void LCDDisplay::writeBuf(const uint8_t row, const uint8_t col, const std::string& str) {
|
||||
const size_t len = std::min(str.size(), writebuf.size() - col);
|
||||
uint8_t pos = 4 + col + (LCD_COLS * (row % 2)); // skip 4 bytes to leave room for set cursor command
|
||||
if (row >= 2) pos += 2 * LCD_COLS + 4; // if we're writing to disp2, skip another 4 bytes for set cursor command and 2*40 bytes of disp 1
|
||||
std::memcpy(&writebuf[pos], str.c_str(), len);
|
||||
}
|
||||
|
||||
/* initializes the write buffer to spaces */
|
||||
void LCDDisplay::clearBuf() {
|
||||
std::memset(writebuf.data(), ' ', writebuf.size());
|
||||
}
|
||||
|
||||
/* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */
|
||||
void LCDDisplay::flushBuf() {
|
||||
constexpr uint8_t setDisp[] = {254, 71, 1, 1}; // set cursor to char 1, line 1
|
||||
std::memcpy(&writebuf[0], setDisp, 4);
|
||||
std::memcpy(&writebuf[2 * LCD_COLS + 4], setDisp, 4);
|
||||
writebuf[2 * LCD_COLS + 7] = 3; // overwrite set cursor c1 l1 to c1 l3
|
||||
this->write(reinterpret_cast<uint8_t*>(writebuf.data()), writebuf.size());
|
||||
}
|
||||
|
||||
// i have a whole flushbuf func to avoid too many writes, but im writing on every bar, need to rethink this.
|
||||
// we could have a separate pre-char buffer and put all the setCustomChar commands to that?
|
||||
char LCDDisplay::bar(const uint8_t char_id, const double value) {
|
||||
std::array<uint8_t, 8> b{};
|
||||
b.fill(0b01110);
|
||||
for (uint8_t i = 0; i < (1.0 - value) * 8; i++)
|
||||
b[i] = 0;
|
||||
this->setCustomChar(char_id, b);
|
||||
return cc(char_id);
|
||||
}
|
||||
255
src/aio.c
Normal file
255
src/aio.c
Normal file
@@ -0,0 +1,255 @@
|
||||
#include "aio.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static constexpr uint16_t usb_timeout = 250;
|
||||
static constexpr uint8_t buf_size = 32; // needs 32 bc of overflow issue on these aios?
|
||||
static constexpr uint8_t max_curve_points = 7;
|
||||
|
||||
static uint8_t req[buf_size], resp[buf_size];
|
||||
|
||||
static const struct curve_point_t fan_curve[] = {
|
||||
{ .temp = 35, .duty = 25 }, // ~350rpm
|
||||
{ .temp = 40, .duty = 40 },
|
||||
{ .temp = 46, .duty = 60 },
|
||||
{ .temp = 50, .duty = 100 }
|
||||
};
|
||||
|
||||
static void aio_usb_claim(libusb_device_handle *dev) {
|
||||
int ret = libusb_claim_interface(dev, 0);
|
||||
if (ret != 0) {
|
||||
applog(LOG_ERR, "failed to claim AIO device: %s", libusb_error_name(ret));
|
||||
return;
|
||||
}
|
||||
ret = libusb_control_transfer(dev, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), 0x02, 0x02, 0, nullptr, 0, usb_timeout);
|
||||
if (ret < 0)
|
||||
applog(LOG_ERR, "AIO clear-to-send failed: %s", libusb_error_name(ret));
|
||||
}
|
||||
|
||||
static void aio_usb_release(libusb_device_handle *dev) {
|
||||
libusb_release_interface(dev, 0);
|
||||
}
|
||||
|
||||
static int aio_post(libusb_device_handle *dev, const int req_len, const int resp_len) {
|
||||
// applog(LOG_DBG, "writing to aio reg 0x%02x", req[0]);
|
||||
int ret = 0;
|
||||
ret += libusb_bulk_transfer(dev, 0x01, req, req_len, nullptr, usb_timeout);
|
||||
ret += libusb_bulk_transfer(dev, 0x81, resp, resp_len, nullptr, usb_timeout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static float aio_get_water_temp(libusb_device_handle *dev) {
|
||||
req[0] = 0xa9;
|
||||
aio_post(dev, 1, 6);
|
||||
return (float)resp[3] + (float)resp[4] / 10.0f;
|
||||
}
|
||||
|
||||
static uint16_t aio_get_pump_speed(libusb_device_handle *dev) {
|
||||
req[0] = 0x31;
|
||||
if (aio_post(dev, 1, 5) != 0)
|
||||
return UINT16_MAX;
|
||||
return (uint16_t)(resp[3] << 8 | resp[4]);
|
||||
}
|
||||
|
||||
static enum aio_pump_mode_t aio_get_pump_mode(libusb_device_handle *dev) {
|
||||
req[0] = 0x33;
|
||||
if (aio_post(dev, 1, 4) != 0)
|
||||
return AIO_PUMP_MODE_UNKNOWN;
|
||||
return (enum aio_pump_mode_t)resp[3];
|
||||
}
|
||||
|
||||
static void aio_get_fan_speed(libusb_device_handle *dev, uint16_t *speeds) {
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
req[0] = 0x41;
|
||||
req[1] = i;
|
||||
if (aio_post(dev, 2, 6) != 0)
|
||||
speeds[i] = UINT16_MAX;
|
||||
speeds[i] = (uint16_t)(resp[4] << 8 | resp[5]);
|
||||
}
|
||||
}
|
||||
|
||||
static void aio_set_fan_duty(libusb_device_handle *dev, const uint8_t *duty) {
|
||||
if (duty == nullptr)
|
||||
return;
|
||||
static uint8_t last_duty = 255;
|
||||
if (duty[0] == last_duty)
|
||||
return;
|
||||
req[0] = 0x42;
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
req[1] = i;
|
||||
req[2] = MIN(MAX(duty[i], 0), 100);
|
||||
if (aio_post(dev, 3, buf_size) == 0)
|
||||
last_duty = req[2];
|
||||
}
|
||||
}
|
||||
|
||||
static char *aio_get_firmware_version(libusb_device_handle *dev, char *buf) {
|
||||
req[0] = 0xaa;
|
||||
aio_post(dev, 1, buf_size);
|
||||
sprintf(buf, "%d.%d.%d.%d", resp[3], resp[4], resp[5], resp[6]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void aio_set_pump_mode(libusb_device_handle *dev, const enum aio_pump_mode_t mode) {
|
||||
static enum aio_pump_mode_t last_mode = AIO_PUMP_MODE_UNKNOWN;
|
||||
if (mode == last_mode)
|
||||
return;
|
||||
applog(LOG_DBG, "setting pump to %u", mode);
|
||||
req[0] = 0x32;
|
||||
req[1] = (uint8_t)mode;
|
||||
if (aio_post(dev, 2, 6) == 0)
|
||||
last_mode = mode;
|
||||
}
|
||||
|
||||
static void aio_set_color(libusb_device_handle *dev, const enum aio_color_mode_t mode, const uint8_t speed, const struct rgb_t *colors, const uint8_t color_count) {
|
||||
if (colors == nullptr) // NOLINT no its not
|
||||
return;
|
||||
|
||||
constexpr uint8_t modes[] = {0x52, 0x55, 0x55, 0x58};
|
||||
|
||||
|
||||
req[0] = 0x56;
|
||||
req[1] = color_count;
|
||||
|
||||
// sort out and send color table
|
||||
memcpy(&req[2], colors, color_count * 3);
|
||||
if (color_count < 2 || mode == AIO_COLOR_FIXED) {
|
||||
memcpy(&req[5], colors, 3); // copy the same color to the 2nd pos in the table
|
||||
req[1] = 2;
|
||||
}
|
||||
aio_post(dev, 2 + req[1] * 3, buf_size);
|
||||
|
||||
// send speed, skip if fixed color
|
||||
if (mode != AIO_COLOR_FIXED) {
|
||||
constexpr uint8_t speed_shift[] = {0x46, 0x28, 0x0F};
|
||||
constexpr uint8_t speed_pulse[] = {0x50, 0x37, 0x1E};
|
||||
req[0] = 0x53;
|
||||
req[1] = mode == AIO_COLOR_SHIFT ? speed_shift[speed] : speed_pulse[speed];
|
||||
aio_post(dev,2, buf_size);
|
||||
}
|
||||
|
||||
// actually set the aio to desired mode
|
||||
req[0] = modes[mode];
|
||||
req[1] = 0x01;
|
||||
aio_post(dev, 2, buf_size);
|
||||
}
|
||||
|
||||
static void aio_set_fan_curve(libusb_device_handle *dev, const struct curve_point_t *curve, const uint8_t count) {
|
||||
if (curve == nullptr)
|
||||
return;
|
||||
|
||||
if (count < 1 || count > max_curve_points) {
|
||||
applog(LOG_ERR, "aio: curve must have 1-%d points", max_curve_points);
|
||||
return;
|
||||
}
|
||||
|
||||
struct curve_point_t padded[max_curve_points];
|
||||
for (int i = 0; i < max_curve_points; i++)
|
||||
padded[i] = (i < count) ? curve[i] : curve[count - 1];
|
||||
|
||||
req[0] = 0x40;
|
||||
|
||||
// setup request
|
||||
for (int i = 0; i < max_curve_points; i++)
|
||||
req[2 + i] = padded[i].temp;
|
||||
for (int i = 0; i < max_curve_points; i++)
|
||||
req[9 + i] = padded[i].duty;
|
||||
|
||||
// set curve for both fans
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
req[1] = i;
|
||||
aio_post(dev, 16, sizeof(resp));
|
||||
}
|
||||
applog(LOG_INF, "set up AIO fan curve");
|
||||
}
|
||||
|
||||
void aio_detect(struct aio_t *aio) {
|
||||
libusb_init(nullptr);
|
||||
aio->handle = libusb_open_device_with_vid_pid(nullptr, AIO_USB_VID, AIO_USB_PID);
|
||||
if (aio->handle == nullptr) {
|
||||
applog(LOG_ERR, "Can't open AIO USB device %x:%x", AIO_USB_VID, AIO_USB_PID);
|
||||
return;
|
||||
}
|
||||
|
||||
/* detaches other software that might take the device? */
|
||||
if (libusb_kernel_driver_active(aio->handle, 0))
|
||||
libusb_detach_kernel_driver(aio->handle, 0);
|
||||
|
||||
aio_usb_claim(aio->handle);
|
||||
applog(LOG_INF, "found Corsair AIO device at %04x:%04x, fw ver: %s", AIO_USB_VID, AIO_USB_PID, aio_get_firmware_version(aio->handle, (char[16]){0}));
|
||||
aio_set_fan_duty(aio->handle, nullptr); // so it doenst complain the func is unused
|
||||
aio_set_fan_curve(aio->handle, fan_curve, sizeof(fan_curve) / sizeof(fan_curve[0]));
|
||||
aio_set_pump_mode(aio->handle, AIO_PUMP_MODE_QUIET); // needed for init ig?
|
||||
aio_set_color(aio->handle, AIO_COLOR_FIXED, 0, nullptr, 0); // so it doenst complain the func is unused
|
||||
aio_usb_release(aio->handle);
|
||||
}
|
||||
|
||||
void aio_update(struct aio_t *aio) {
|
||||
if (aio->handle == nullptr)
|
||||
return;
|
||||
|
||||
aio_usb_claim(aio->handle);
|
||||
|
||||
aio->water_temp = aio_get_water_temp(aio->handle);
|
||||
aio->pump_speed = aio_get_pump_speed(aio->handle);
|
||||
aio->pump_mode = aio_get_pump_mode(aio->handle);
|
||||
aio_get_fan_speed(aio->handle, aio->fan_speed);
|
||||
|
||||
const uint16_t avg_rpm = (uint16_t)((aio->fan_speed[0] + aio->fan_speed[1]) / 2);
|
||||
switch (aio->pump_mode) {
|
||||
case AIO_PUMP_MODE_QUIET:
|
||||
if (avg_rpm > 400)
|
||||
aio->pump_counter++;
|
||||
else
|
||||
aio->pump_counter = 0;
|
||||
|
||||
if (aio->pump_counter >= 300) {
|
||||
aio->pump_counter = 0;
|
||||
aio_set_pump_mode(aio->handle, AIO_PUMP_MODE_BALANCED);
|
||||
}
|
||||
break;
|
||||
case AIO_PUMP_MODE_BALANCED:
|
||||
if (avg_rpm >= 700)
|
||||
aio->pump_counter++;
|
||||
else if (avg_rpm <= 375)
|
||||
aio->pump_counter--;
|
||||
else
|
||||
aio->pump_counter = 0;
|
||||
|
||||
if (aio->pump_counter >= 300) {
|
||||
aio->pump_counter = 0;
|
||||
aio_set_pump_mode(aio->handle, AIO_PUMP_MODE_EXTREME);
|
||||
}
|
||||
if (aio->pump_counter <= -300) {
|
||||
aio->pump_counter = 0;
|
||||
aio_set_pump_mode(aio->handle, AIO_PUMP_MODE_QUIET);
|
||||
}
|
||||
break;
|
||||
case AIO_PUMP_MODE_EXTREME:
|
||||
if (avg_rpm <= 500)
|
||||
aio->pump_counter--;
|
||||
else
|
||||
aio->pump_counter = 0;
|
||||
|
||||
if (aio->pump_counter <= -300) {
|
||||
aio->pump_counter = 0;
|
||||
aio_set_pump_mode(aio->handle, AIO_PUMP_MODE_BALANCED);
|
||||
}
|
||||
break;
|
||||
case AIO_PUMP_MODE_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
aio_usb_release(aio->handle);
|
||||
}
|
||||
|
||||
void aio_close(const struct aio_t *aio) {
|
||||
aio_set_pump_mode(aio->handle, AIO_PUMP_MODE_BALANCED);
|
||||
libusb_attach_kernel_driver(aio->handle, 0); // reattach so liquidctl still works
|
||||
libusb_close(aio->handle);
|
||||
libusb_exit(nullptr);
|
||||
applog(LOG_INF, "AIO device closed");
|
||||
}
|
||||
209
src/app.cpp
209
src/app.cpp
@@ -1,209 +0,0 @@
|
||||
#include <LCDDisplay.hpp>
|
||||
#include <app.hpp>
|
||||
#include <chrono>
|
||||
#include <cpu.hpp>
|
||||
#include <csignal>
|
||||
#include <functional>
|
||||
#include <gpu.hpp>
|
||||
#include <hass.hpp>
|
||||
#include <log.hpp>
|
||||
#include <mutex>
|
||||
#include <stop_token>
|
||||
#include <string>
|
||||
#include <sys.hpp>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <utils.hpp>
|
||||
#include <vector>
|
||||
|
||||
Application::Application(Config config) {
|
||||
m_config = std::move(config);
|
||||
// set up signals
|
||||
sigemptyset(&m_control.sigset);
|
||||
sigaddset(&m_control.sigset, SIGINT);
|
||||
sigaddset(&m_control.sigset, SIGTERM);
|
||||
applog(LOG::START, "Application initialized");
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
auto level = LOG::START;
|
||||
if (m_ret < 0) level = LOG::WRN;
|
||||
applog(level, "Application destroyed");
|
||||
}
|
||||
|
||||
int Application::Run() {
|
||||
int sig;
|
||||
m_mainPid = getpid();
|
||||
pthread_sigmask(SIG_BLOCK, &m_control.sigset, nullptr);
|
||||
|
||||
{
|
||||
std::vector<std::jthread> threads;
|
||||
|
||||
std::function<void(std::stop_token)> funcs[] = {
|
||||
[this](const std::stop_token& st) { displayThread(st); },
|
||||
[this](const std::stop_token& st) { sensorsThread(st); },
|
||||
[this](const std::stop_token& st) { hassThread(st); },
|
||||
};
|
||||
|
||||
// start threads in order
|
||||
for (auto& f : funcs) {
|
||||
threads.emplace_back(f);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // start threads with delay so displayThread can quit the app if theres no lcd
|
||||
}
|
||||
|
||||
// waits for signal, the threads are stopped when we go out of scope
|
||||
sigwait(&m_control.sigset, &sig);
|
||||
applog(LOG::WRN, "got stop signal, shutting down...");
|
||||
}
|
||||
return m_ret;
|
||||
}
|
||||
|
||||
void Application::Crash(const int ret) {
|
||||
m_ret = ret;
|
||||
kill(m_mainPid, SIGINT);
|
||||
}
|
||||
|
||||
|
||||
void Application::hassThread(const std::stop_token& st) { //NOLINT
|
||||
applog(LOG::START, "Thread started");
|
||||
#ifdef ENABLE_HOME_ASSISTANT
|
||||
static double power;
|
||||
HomeAssistant::Config config;
|
||||
config.address = m_config.hass.url;
|
||||
config.entity = m_config.hass.entity;
|
||||
config.token = m_config.hass.token;
|
||||
HomeAssistant pc_power(config);
|
||||
|
||||
pc_power.connect();
|
||||
while (!st.stop_requested()) {
|
||||
pc_power.service();
|
||||
if (power != pc_power.state) {
|
||||
power = pc_power.state;
|
||||
{
|
||||
std::lock_guard lock(m_control.sensors);
|
||||
m_sensors.hass_state = power;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
#else
|
||||
(void)st;
|
||||
applog(LOG::WRN, "feature disabled at compile time, probably no libwebsockets on host. exiting thread");
|
||||
{
|
||||
std::lock_guard lock(m_control.sensors);
|
||||
m_sensors.hass_state = -1.0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::sensorsThread(const std::stop_token& st) {
|
||||
applog(LOG::START, "Thread started, poll interval {} ms", m_config.lcd.refresh_interval_ms);
|
||||
int ret = cpu::detect(&m_sensors.cpu, m_config.cpu_pciaddr);
|
||||
ret += gpu::detect(&m_sensors.gpu, m_config.gpu_pciaddr);
|
||||
ret += sys::detect(&m_sensors.sys, m_config.sys_sensor);
|
||||
m_sensors.home.mountpoint = m_config.home_dir;
|
||||
if (ret < 0)
|
||||
applog(LOG::ERR, "Failed to detect some sensors");
|
||||
|
||||
while (!st.stop_requested()) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
{
|
||||
std::lock_guard lock(m_control.sensors);
|
||||
|
||||
sys::getTimeDate(&m_sensors.td);
|
||||
getloadavg(m_sensors.loadavg, 3);
|
||||
sys::getRam(&m_sensors.ram);
|
||||
sys::getDisk(&m_sensors.home);
|
||||
sys::getNetwork(&m_sensors.net, m_config.sys_ifname);
|
||||
sys::updateSensors(&m_sensors.sys);
|
||||
cpu::update(&m_sensors.cpu);
|
||||
gpu::update(&m_sensors.gpu);
|
||||
}
|
||||
|
||||
// log(LOG::DBG, "took {} microseconds", std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count());
|
||||
m_control.display.release(); // unlocks display loop
|
||||
std::this_thread::sleep_until(start + std::chrono::milliseconds(m_config.lcd.refresh_interval_ms));
|
||||
}
|
||||
applog(LOG::INF, "Thread stopped");
|
||||
}
|
||||
|
||||
void Application::displayThread(const std::stop_token& st) {
|
||||
std::stop_callback cb(st, [&] { m_control.display.release(); });
|
||||
applog(LOG::START, "Thread started");
|
||||
// init internal variables of LCDDisplay class
|
||||
LCDDisplay lcd(m_config.lcd.port);
|
||||
if (const int ret = lcd.Init(); ret < 0) {
|
||||
applog(LOG::ERR, "Failed to initialize LCDDisplay");
|
||||
this->Crash(ret);
|
||||
return;
|
||||
}
|
||||
|
||||
// basic lcd setup
|
||||
lcd.setContrast(m_config.lcd.contrast);
|
||||
lcd.setBacklight(true);
|
||||
lcd.setCustomChar(0, {16, 6, 9, 8, 8, 9, 6, 0}); // celcius
|
||||
lcd.setCustomChar(1, {0, 0, 4, 10, 10, 17, 31, 0}); // delta
|
||||
lcd.setCustomChar(2, {0, 0, 8, 21, 21, 2, 0, 0}); // home (tilde)
|
||||
lcd.setCustomChar(3, {4, 14, 21, 4, 4, 4, 0}); // up arrow
|
||||
lcd.setCustomChar(4, {4, 4, 4, 21, 14, 4, 0}); // down arrow
|
||||
|
||||
// welcome msg
|
||||
lcd.writeBuf(2, 0, utils::center("Waiting for sensors...", 40));
|
||||
lcd.flushBuf();
|
||||
lcd.clearBuf();
|
||||
|
||||
// actual main display loop
|
||||
while (!st.stop_requested()) {
|
||||
m_control.display.try_acquire_for(std::chrono::milliseconds(static_cast<int>(m_config.lcd.refresh_interval_ms * 1.25))); // holds the loop until sensor data is ready, max 1.25x of the loop time
|
||||
if (st.stop_requested()) break; // needed, otherwise it wont quit correctly
|
||||
{
|
||||
std::lock_guard lock(m_control.sensors);
|
||||
|
||||
// prepare some tricky sensors
|
||||
std::string gpu_temps = std::to_string(m_sensors.gpu.temp_edge);
|
||||
if (m_sensors.gpu.temp_hotspot) {
|
||||
const auto delta = m_sensors.gpu.temp_hotspot - m_sensors.gpu.temp_edge;
|
||||
gpu_temps.append("/" + std::to_string(m_sensors.gpu.temp_hotspot));
|
||||
gpu_temps.insert(0, LCDDisplay::cc(1) + std::to_string(delta) + LCDDisplay::cc(0) + " ");
|
||||
}
|
||||
|
||||
uint16_t cpu_fan = 0;
|
||||
for (const auto& fan : m_sensors.sys.fan_speed)
|
||||
cpu_fan += fan;
|
||||
cpu_fan /= 2;
|
||||
|
||||
// write to display buffer
|
||||
lcd.writeBuf(0, 0, utils::pad(m_sensors.td.date, 11, utils::just::left) + " " + m_sensors.td.time + lcd.bar(7, m_sensors.gpu.usage_core / 100.0));
|
||||
lcd.writeBuf(0, 26, utils::pNum(m_sensors.loadavg[0], m_sensors.loadavg[0] > 10 ? 1 : 2));
|
||||
lcd.writeBuf(0, 31, utils::pNum(m_sensors.loadavg[1], m_sensors.loadavg[1] > 10 ? 1 : 2));
|
||||
lcd.writeBuf(0, 36, utils::pNum(m_sensors.loadavg[2], m_sensors.loadavg[2] > 10 ? 1 : 2));
|
||||
|
||||
lcd.writeBuf(1, 0, utils::pad(std::to_string(m_sensors.cpu.tctl) + "/" + std::to_string(m_sensors.cpu.tccd1) + LCDDisplay::cc(0), 8, utils::just::left));
|
||||
lcd.writeBuf(1, 7, utils::pad(utils::pBytes(m_sensors.ram.used, true), 6, utils::just::left));
|
||||
if (m_sensors.hass_state >= 0)
|
||||
lcd.writeBuf(1, 13, utils::pad(utils::pNum(m_sensors.hass_state) + "W", 4));
|
||||
lcd.writeBuf(1, 19, std::to_string(m_sensors.sys.t_sensor) + LCDDisplay::cc(0)); // t_sensor temp
|
||||
lcd.writeBuf(1, 32 - gpu_temps.size(), utils::pad(utils::pBytes(m_sensors.gpu.vram_used), 6));
|
||||
lcd.writeBuf(1, 39 - gpu_temps.size(), gpu_temps + LCDDisplay::cc(0));
|
||||
|
||||
lcd.writeBuf(2, 0, utils::pad(std::to_string(static_cast<int>(m_sensors.cpu.ptotal)) + "W", 8, utils::just::left));
|
||||
lcd.writeBuf(2, m_sensors.cpu.ptotal < 100 ? 4 : 5, std::to_string(cpu_fan) + "R"); // avg fan speed
|
||||
lcd.writeBuf(2, 12, LCDDisplay::cc(3) + utils::pBytes(m_sensors.net.upload));
|
||||
lcd.writeBuf(2, 19, LCDDisplay::cc(4) + utils::pBytes(m_sensors.net.download));
|
||||
lcd.writeBuf(2, 26, utils::pad(std::to_string(m_sensors.gpu.fan_speed) + "R", 5));
|
||||
lcd.writeBuf(2, 31, utils::pad(std::to_string(m_sensors.gpu.power_avg) + "/" + std::to_string(m_sensors.gpu.power_cap) + "W", 9));
|
||||
|
||||
lcd.writeBuf(3, 0, std::to_string(m_sensors.cpu.avg_freq) + "MHz");
|
||||
lcd.writeBuf(3, 14, utils::pad(LCDDisplay::cc(2) + utils::pBytes(m_sensors.home.usage.free), 6));
|
||||
lcd.writeBuf(3, 21, utils::pad(std::to_string(m_sensors.gpu.clock_core) + "/" + std::to_string(m_sensors.gpu.clock_mem) + "MHz ", 13));
|
||||
lcd.writeBuf(3, 34, utils::pad(utils::pNum(m_sensors.gpu.vcore, 3) + "V", 5));
|
||||
}
|
||||
|
||||
lcd.flushBuf();
|
||||
lcd.clearBuf();
|
||||
}
|
||||
|
||||
// goodbye msg
|
||||
lcd.writeBuf(2, 0, utils::center("Goodbye", 40));
|
||||
lcd.flushBuf();
|
||||
}
|
||||
105
src/cpu.c
Normal file
105
src/cpu.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "cpu.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static sensor_file_t* sensors;
|
||||
static sensor_file_t* cpu_freqs;
|
||||
static constexpr uint64_t max_energy_range_uj = 65532610987;
|
||||
|
||||
void cpu_detect(struct cpu_sensors_t *t, const char *pci_dev) {
|
||||
t->module = unknown;
|
||||
t->num_cores = (uint8_t)sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
snprintf(t->hwmon, sizeof(t->hwmon), "/sys/bus/pci/devices/%s/hwmon", pci_dev);
|
||||
const int ret = get_hwmon_dir(t->hwmon, sizeof(t->hwmon));
|
||||
if (ret != 0) {
|
||||
t->hwmon[0] = '\0';
|
||||
applog(LOG_WRN, "Detected %d cores, module enum #%d. Can't get hwmon path, skipping", t->num_cores, t->module);
|
||||
return;
|
||||
}
|
||||
|
||||
// fast_read_num_u64("/sys/class/powercap/intel-rapl:0/", "max_energy_range_uj", buf, &max_energy_range_uj, 1);
|
||||
// t->module = read_file(t->hwmon, "/in1_input", nullptr, 0) ? zenpower : k10temp; // if we can read zenpower file then zenpower. idk if this is reliable, we're trying to avoid just reading the name
|
||||
t->module = k10temp; // just assume its k10temp until we figure out a better way to detect it
|
||||
applog(LOG_INF, "Detected %d cores, module enum #%d in path %s", t->num_cores, t->module, t->hwmon);
|
||||
|
||||
cpu_freqs = malloc(sizeof(sensor_file_t) * t->num_cores);
|
||||
sensors = malloc(sizeof(sensor_file_t) * (t->module == zenpower ? 4 : 3));
|
||||
|
||||
for (uint8_t i = 0; i < t->num_cores; i++) {
|
||||
char p[128];
|
||||
sprintf(p, "/sys/devices/system/cpu/cpu%d/cpufreq/", i);
|
||||
open_sensor(&cpu_freqs[i], p, "cpuinfo_avg_freq", nullptr, 1000, SENSOR_U64);
|
||||
}
|
||||
|
||||
if (max_energy_range_uj != 0)
|
||||
open_sensor(&sensors[0], "/sys/class/powercap/intel-rapl:0/", "energy_uj", nullptr, 1, SENSOR_U64);
|
||||
|
||||
if (t->module == k10temp) {
|
||||
open_sensor(&sensors[1], t->hwmon, "/temp1_input", &t->tctl, 1000, SENSOR_I16);
|
||||
open_sensor(&sensors[2], t->hwmon, "/temp3_input", &t->tccd1, 1000, SENSOR_I16);
|
||||
} else if (t->module == zenpower) {
|
||||
open_sensor(&sensors[1], t->hwmon, "/temp1_input", &t->tdie, 1000, SENSOR_I16);
|
||||
open_sensor(&sensors[2], t->hwmon, "/temp2_input", &t->tctl, 1000, SENSOR_I16);
|
||||
open_sensor(&sensors[3], t->hwmon, "/temp3_input", &t->tccd1, 1000, SENSOR_I16);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_update(struct cpu_sensors_t *c) {
|
||||
struct energy_t {
|
||||
struct timespec ts;
|
||||
uint64_t energy;
|
||||
};
|
||||
|
||||
static struct energy_t prev;
|
||||
struct energy_t curr = {};
|
||||
uint64_t energy_delta;
|
||||
|
||||
// read power from intel-rapl? works on amd too, btop uses this trick, seems accurate
|
||||
// it tracks with "socket power" in hwinfo on windows, its actually the same thing i had in lcdsmartie
|
||||
clock_gettime(CLOCK_MONOTONIC, &curr.ts);
|
||||
fast_read_sensor_into_mem(&sensors[0], &curr.energy);
|
||||
|
||||
if (curr.energy >= prev.energy)
|
||||
energy_delta = curr.energy - prev.energy;
|
||||
else
|
||||
energy_delta = (max_energy_range_uj - prev.energy) + curr.energy;
|
||||
|
||||
c->ptotal = (float)energy_delta / (float)timespec_diff_us(&curr.ts, &prev.ts);
|
||||
|
||||
if (c->ptotal > 500.0f || c->ptotal < 0.0f)
|
||||
c->ptotal = 0.0f;
|
||||
else
|
||||
prev = curr;
|
||||
|
||||
// lots of reads but still faster than reading /proc/cpuinfo
|
||||
c->avg_freq = 0;
|
||||
for (uint8_t i = 0; i < c->num_cores; i++) {
|
||||
uint64_t t = 0;
|
||||
fast_read_sensor_into_mem(&cpu_freqs[i], &t);
|
||||
c->avg_freq += (uint32_t)t;
|
||||
}
|
||||
c->avg_freq /= (c->num_cores > 1) ? c->num_cores : 1;
|
||||
|
||||
if (c->module == unknown)
|
||||
return;
|
||||
|
||||
if (c->module == k10temp) {
|
||||
fast_read_sensor(&sensors[1]);
|
||||
fast_read_sensor(&sensors[2]);
|
||||
}
|
||||
|
||||
// commented out unused values so its faster
|
||||
if (c->module == zenpower) {
|
||||
fast_read_sensor(&sensors[1]);
|
||||
fast_read_sensor(&sensors[2]);
|
||||
fast_read_sensor(&sensors[3]);
|
||||
// utils::fastReadNum<1000>(c->hwmon + "/in1_input", buf, c->vcore);
|
||||
// utils::fastReadNum<1000>(c->hwmon + "/in2_input", buf, c->vsoc);
|
||||
}
|
||||
}
|
||||
72
src/cpu.cpp
72
src/cpu.cpp
@@ -1,72 +0,0 @@
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cpu.hpp>
|
||||
#include <cstdint>
|
||||
#include <log.hpp>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utils.hpp>
|
||||
|
||||
namespace cpu {
|
||||
|
||||
int detect(cpuSensors* target, const std::string& pci) {
|
||||
const std::string path = "/sys/bus/pci/devices/" + pci + "/hwmon";
|
||||
|
||||
try {
|
||||
target->hwmon = utils::getFirstDir(path);
|
||||
} catch (...) {
|
||||
applog(LOG::ERR, "NO CPU HWMON KERNEL MODULE DETECTED");
|
||||
return -1;
|
||||
}
|
||||
|
||||
target->module = utils::fileExists(target->hwmon + "/in1_input") ? zenpower : k10temp; // idk if this is reliable, we're trying to avoid just reading the name
|
||||
target->num_cores = std::thread::hardware_concurrency();
|
||||
applog(LOG::INF, "Detected {} cores, module enum #{} in path \"{}\"", target->num_cores, static_cast<uint8_t>(target->module), target->hwmon);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void update(cpuSensors* c) {
|
||||
static std::array<char, 32> buf;
|
||||
struct EnergyTs {
|
||||
uint64_t energy = 0;
|
||||
std::chrono::time_point<std::chrono::steady_clock> ts;
|
||||
};
|
||||
|
||||
static EnergyTs prev;
|
||||
EnergyTs curr;
|
||||
|
||||
// read power from intel-rapl? works on amd too, btop uses this trick, seems accurate
|
||||
// it tracks with "socket power" in hwinfo on windows, its actually the same thing i had in lcdsmartie
|
||||
curr.ts = std::chrono::steady_clock::now();
|
||||
utils::fastReadNum("/sys/class/powercap/intel-rapl:0/energy_uj", buf, curr.energy);
|
||||
c->ptotal = static_cast<float>(curr.energy - prev.energy) / static_cast<float>(std::chrono::duration_cast<std::chrono::microseconds>(curr.ts - prev.ts).count());
|
||||
prev = curr;
|
||||
|
||||
// lots of reads but still faster than reading /proc/cpuinfo
|
||||
c->avg_freq = 0;
|
||||
for (uint8_t i = 0; i < c->num_cores; i++) {
|
||||
uint32_t t = 0;
|
||||
utils::fastReadNum<1000>("/sys/devices/system/cpu/cpu" + std::to_string(i) + "/cpufreq/cpuinfo_avg_freq", buf, t);
|
||||
c->avg_freq += t;
|
||||
}
|
||||
c->avg_freq /= (c->num_cores > 1) ? c->num_cores : 1;
|
||||
|
||||
if (c->hwmon.empty())
|
||||
return;
|
||||
|
||||
// commented out unused values so its faster
|
||||
if (c->module == zenpower) {
|
||||
utils::fastReadNum<1000>(c->hwmon + "/temp1_input", buf, c->tdie);
|
||||
utils::fastReadNum<1000>(c->hwmon + "/temp2_input", buf, c->tctl);
|
||||
utils::fastReadNum<1000>(c->hwmon + "/temp3_input", buf, c->tccd1);
|
||||
// utils::fastReadNum<1000>(c->hwmon + "/in1_input", buf, c->vcore);
|
||||
// utils::fastReadNum<1000>(c->hwmon + "/in2_input", buf, c->vsoc);
|
||||
}
|
||||
|
||||
if (c->module == k10temp) {
|
||||
utils::fastReadNum<1000>(c->hwmon + "/temp1_input", buf, c->tctl);
|
||||
utils::fastReadNum<1000>(c->hwmon + "/temp3_input", buf, c->tccd1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
136
src/gpu.c
Normal file
136
src/gpu.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#include "gpu.h"
|
||||
|
||||
#include "gpu_metrics.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static constexpr char rel_metrics_path[] = "/../../gpu_metrics"; // gpu_metrics path relative to hwmon path
|
||||
static constexpr uint16_t max_metrics_length = 512; // length of the metrics buffer
|
||||
|
||||
static sensor_file_t* sensors;
|
||||
static int gpu_metrics_fd;
|
||||
|
||||
void gpu_detect(struct gpu_sensors_t *t, const char *pci) {
|
||||
snprintf(t->hwmon, sizeof(t->hwmon), "/sys/bus/pci/devices/%s/hwmon", pci);
|
||||
const int ret = get_hwmon_dir(t->hwmon, sizeof(t->hwmon));
|
||||
if (ret != 0) {
|
||||
t->hwmon[0] = '\0';
|
||||
applog(LOG_WRN, "Detected GPU hwmon");
|
||||
return;
|
||||
}
|
||||
|
||||
t->has_gpu_metrics = false;
|
||||
char p[160];
|
||||
char *nt = stpcpy(p, t->hwmon);
|
||||
strcpy(nt, rel_metrics_path);
|
||||
gpu_metrics_fd = open(p, O_RDONLY | O_CLOEXEC);
|
||||
if (gpu_metrics_fd > 0) {
|
||||
t->has_gpu_metrics = true;
|
||||
char raw_metrics[max_metrics_length];
|
||||
read(gpu_metrics_fd, raw_metrics, sizeof(raw_metrics));
|
||||
const struct metrics_table_header *header = (struct metrics_table_header *)raw_metrics;
|
||||
applog(LOG_INF, "Found gpu_metrics_v%d_%d", header->format_revision, header->content_revision);
|
||||
}
|
||||
|
||||
sensors = malloc(sizeof(sensor_file_t) * (t->has_gpu_metrics ? 10 : 5));
|
||||
|
||||
// we always open these
|
||||
open_sensor(&sensors[0], t->hwmon, "/in0_input", &t->vcore, 1000, SENSOR_FLOAT);
|
||||
open_sensor(&sensors[1], t->hwmon, "/fan1_input", &t->fan_speed, 1, SENSOR_U16);
|
||||
open_sensor(&sensors[2], t->hwmon, "/power1_cap", &t->power_cap, 1000000, SENSOR_U16);
|
||||
open_sensor(&sensors[3], t->hwmon, "/power1_average", &t->power_avg, 1000000, SENSOR_U16);
|
||||
open_sensor(&sensors[4], t->hwmon, "/../../mem_info_vram_used", &t->vram_used, 1, SENSOR_U64);
|
||||
|
||||
if (t->has_gpu_metrics == false) {
|
||||
open_sensor(&sensors[5], t->hwmon, "/freq1_input", &t->clock_core, 1000000, SENSOR_U16);
|
||||
open_sensor(&sensors[6], t->hwmon, "/freq2_input", &t->clock_mem, 1000000, SENSOR_U16);
|
||||
open_sensor(&sensors[7], t->hwmon, "/power1_input",&t->power_avg, 1000000, SENSOR_U16);
|
||||
open_sensor(&sensors[8], t->hwmon, "/temp1_input", &t->temp_edge, 1000, SENSOR_U8);
|
||||
open_sensor(&sensors[9], t->hwmon, "/../../gpu_busy_percent", &t->usage_core, 1, SENSOR_U8);
|
||||
}
|
||||
}
|
||||
|
||||
/* some metrics are missing in gpu_metrics, we always fill them from fs, unused metrics are commented out */
|
||||
static void fill_missing_metrics() {
|
||||
// g->fan_pwm = std::stoi(readFile(g->hwmon + "/pwm1", 4)) * 100 / 256;
|
||||
// utils::fastReadNum(g->hwmon + "/power1_cap_max", g->power_cap_max) / 1000000;
|
||||
// utils::fastReadNum(g->hwmon + "/../../mem_info_vram_total", g->vram_total);
|
||||
for (uint8_t i = 0; i < 5; i++)
|
||||
fast_read_sensor(&sensors[i]);
|
||||
}
|
||||
|
||||
/* get sensors for pre-vega cards (rx480/580) */
|
||||
static void update_from_fs() {
|
||||
for (uint8_t i = 5; i < 10; i++)
|
||||
fast_read_sensor(&sensors[i]);
|
||||
}
|
||||
|
||||
static void update_from_metrics(struct gpu_sensors_t *g) {
|
||||
char raw_metrics[max_metrics_length];
|
||||
lseek(gpu_metrics_fd, 0, SEEK_SET);
|
||||
read(gpu_metrics_fd, raw_metrics, sizeof(raw_metrics));
|
||||
const struct metrics_table_header *header = (struct metrics_table_header *)raw_metrics;
|
||||
|
||||
switch (header->format_revision * 10 + header->content_revision) {
|
||||
|
||||
/* rx5700xt, rx7800xt, rx9070xt */
|
||||
case 13: {
|
||||
const struct gpu_metrics_v1_3 *metrics = (struct gpu_metrics_v1_3 *)raw_metrics;
|
||||
g->usage_core = (uint8_t)metrics->average_gfx_activity;
|
||||
g->usage_umc = (uint8_t)metrics->average_umc_activity;
|
||||
g->usage_media = (uint8_t)metrics->average_mm_activity;
|
||||
|
||||
g->temp_edge = (uint8_t)metrics->temperature_edge;
|
||||
g->temp_hotspot = (uint8_t)metrics->temperature_hotspot;
|
||||
g->temp_mem = (uint8_t)metrics->temperature_mem;
|
||||
|
||||
g->temp_vrm_gfx = (uint8_t)metrics->temperature_vrgfx;
|
||||
g->temp_vrm_soc = (uint8_t)metrics->temperature_vrsoc;
|
||||
g->temp_vrm_mem = (uint8_t)metrics->temperature_vrmem;
|
||||
// g->power_avg = metrics->average_socket_power; // jumpy on 9070xt
|
||||
g->fan_speed = metrics->current_fan_speed;
|
||||
|
||||
g->clock_core = metrics->average_gfxclk_frequency;
|
||||
g->clock_mem = metrics->average_uclk_frequency; // mem controller clock, needs to be 2x on 5700xt for some reason
|
||||
|
||||
// hacks for rx7800xt
|
||||
// g->clock_core = metrics->average_vclk1_frequency; // why not gfxclock?
|
||||
// g->clock_mem = metrics->average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping
|
||||
break;
|
||||
}
|
||||
|
||||
/* ryzen 5 5600g */
|
||||
case 22: {
|
||||
const struct gpu_metrics_v2_2 *metrics = (struct gpu_metrics_v2_2 *)raw_metrics;
|
||||
g->temp_edge = (uint8_t)(metrics->temperature_gfx / 100);
|
||||
break;
|
||||
}
|
||||
|
||||
/* werid hardware i probably dont like, maybe fallback to reading from fs? */
|
||||
default: {
|
||||
applog(LOG_WRN, "Unsupported gpu_metrics_v%d_%d", header->format_revision, header->content_revision);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* reads values from system and updates the target gpu_sensors_t struct */
|
||||
void gpu_update(struct gpu_sensors_t *g) {
|
||||
const bool hwmon_valid = g->hwmon[0] != '\0';
|
||||
|
||||
if (hwmon_valid)
|
||||
fill_missing_metrics();
|
||||
if (g->has_gpu_metrics)
|
||||
update_from_metrics(g);
|
||||
else if (hwmon_valid)
|
||||
update_from_fs();
|
||||
if (g->fan_speed > 9999)
|
||||
g->fan_speed = 9999; // sanity check fan speed
|
||||
}
|
||||
123
src/gpu.cpp
123
src/gpu.cpp
@@ -1,123 +0,0 @@
|
||||
#include <array>
|
||||
#include <gpu.hpp>
|
||||
#include <gpu_metrics.hpp>
|
||||
#include <log.hpp>
|
||||
#include <string>
|
||||
#include <utils.hpp>
|
||||
|
||||
/* maybe have a read pp_table function */
|
||||
/* would be neat to wrap it in a class but eh namespace is good enough */
|
||||
|
||||
namespace gpu {
|
||||
|
||||
const std::string rel_metrics_path = "/../../gpu_metrics"; // gpu_metrics path relative to hwmon path
|
||||
constexpr uint16_t max_metrics_length = 512; // length of the metrics buffer
|
||||
|
||||
/* takes pointer to a target gpu::sensors struct and updates its hwmon path and detects gpu_metrics */
|
||||
int detect(gpuSensors* target, const std::string& pci) {
|
||||
try {
|
||||
target->hwmon = utils::getFirstDir("/sys/bus/pci/devices/" + pci + "/hwmon");
|
||||
} catch (...) {
|
||||
applog(LOG::ERR, "Couldn't find GPU hwmon");
|
||||
return -1;
|
||||
}
|
||||
applog(LOG::INF, "Detected path \"{}\"", target->hwmon);
|
||||
|
||||
if (utils::fileExists(target->hwmon + rel_metrics_path)) {
|
||||
std::array<char, max_metrics_length> raw_metrics{};
|
||||
if (!utils::readFile(target->hwmon + rel_metrics_path, raw_metrics))
|
||||
return -1;
|
||||
const auto header = reinterpret_cast<metrics::metrics_table_header*>(raw_metrics.data());
|
||||
|
||||
applog(LOG::INF, "Found gpu_metrics_v{}_{}", header->format_revision, header->content_revision);
|
||||
target->hasGpuMetrics = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* some metrics are missing in gpu_metrics, we always fill them from fs, unused metrics are commented out */
|
||||
void fillMissingMetrics(gpuSensors* g) {
|
||||
static std::array<char, 32> buf;
|
||||
utils::fastReadNum<1000>(g->hwmon + "/in0_input", buf, g->vcore);
|
||||
// g->fan_pwm = std::stoi(readFile(g->hwmon + "/pwm1", 4)) * 100 / 256;
|
||||
utils::fastReadNum(g->hwmon + "/fan1_input", buf, g->fan_speed);
|
||||
utils::fastReadNum<1000000>(g->hwmon + "/power1_cap", buf, g->power_cap);
|
||||
// utils::fastReadNum(g->hwmon + "/power1_cap_max", g->power_cap_max) / 1000000;
|
||||
utils::fastReadNum(g->hwmon + "/../../mem_info_vram_used", buf, g->vram_used);
|
||||
// utils::fastReadNum(g->hwmon + "/../../mem_info_vram_total", g->vram_total);
|
||||
}
|
||||
|
||||
/* get sensors for pre-vega cards (rx480/580) */
|
||||
void updateFromFs(gpuSensors* g) {
|
||||
static std::array<char, 32> buf;
|
||||
utils::fastReadNum<1000000>(g->hwmon + "/freq1_input", buf, g->clock_core);
|
||||
utils::fastReadNum<1000000>(g->hwmon + "/freq2_input", buf, g->clock_mem);
|
||||
utils::fastReadNum<1000000>(g->hwmon + "/power1_input", buf, g->power_avg);
|
||||
utils::fastReadNum<1000>(g->hwmon + "/temp1_input", buf, g->temp_edge);
|
||||
utils::fastReadNum(g->hwmon + "/../../gpu_busy_percent", buf, g->usage_core);
|
||||
}
|
||||
|
||||
/* get sensors for vega and newer (rx5700xt, rx7800xt [*]) */
|
||||
void updateFromMetrics(gpuSensors* g) {
|
||||
std::array<char, max_metrics_length> raw_metrics{};
|
||||
if (!utils::readFile(g->hwmon + rel_metrics_path, raw_metrics)) return;
|
||||
|
||||
switch (const auto header = reinterpret_cast<metrics::metrics_table_header*>(raw_metrics.data()); header->format_revision * 10 + header->content_revision) {
|
||||
/* rx5700xt, rx7800xtx rx9070xt */
|
||||
case 13: {
|
||||
const auto metrics = reinterpret_cast<metrics::gpu_metrics_v1_3*>(raw_metrics.data());
|
||||
g->usage_core = metrics->average_gfx_activity;
|
||||
g->usage_umc = metrics->average_umc_activity;
|
||||
g->usage_media = metrics->average_mm_activity;
|
||||
|
||||
g->temp_edge = metrics->temperature_edge;
|
||||
g->temp_hotspot = metrics->temperature_hotspot;
|
||||
g->temp_mem = metrics->temperature_mem;
|
||||
|
||||
g->temp_vrm_gfx = metrics->temperature_vrgfx;
|
||||
g->temp_vrm_soc = metrics->temperature_vrsoc;
|
||||
g->temp_vrm_mem = metrics->temperature_vrmem;
|
||||
g->power_avg = metrics->average_socket_power;
|
||||
g->fan_speed = metrics->current_fan_speed;
|
||||
|
||||
// hacks for rx7800xt
|
||||
// g->clock_core = metrics->average_vclk1_frequency; // why not gfxclock?
|
||||
// g->clock_mem = metrics->average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping
|
||||
|
||||
// hacks for rx5700xt
|
||||
g->clock_core = metrics->average_gfxclk_frequency;
|
||||
g->clock_mem = metrics->average_uclk_frequency; // mem controller clock, needs to be 2x on 5700xt for some reason
|
||||
break;
|
||||
}
|
||||
|
||||
/* ryzen 5 5600g */
|
||||
case 22: {
|
||||
const auto metrics = reinterpret_cast<metrics::gpu_metrics_v2_2*>(raw_metrics.data());
|
||||
g->temp_edge = metrics->temperature_gfx / 100;
|
||||
break;
|
||||
}
|
||||
|
||||
/* werid hardware i probably dont like, maybe fallback to reading from fs? */
|
||||
default: {
|
||||
applog(LOG::WRN, "Unsupported gpu_metrics_v{}_{}", header->format_revision, header->content_revision);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* reads values from system and updates the target gpu::sensors struct */
|
||||
void update(gpuSensors* g) {
|
||||
const bool hwmon_valid = !g->hwmon.empty();
|
||||
if (hwmon_valid)
|
||||
fillMissingMetrics(g);
|
||||
|
||||
if (g->hasGpuMetrics)
|
||||
updateFromMetrics(g);
|
||||
else
|
||||
if (hwmon_valid)
|
||||
updateFromFs(g);
|
||||
|
||||
if (g->fan_speed > 9999) g->fan_speed = 9999; // sanity check fan speed
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
163
src/hass.cpp
163
src/hass.cpp
@@ -1,163 +0,0 @@
|
||||
#ifdef ENABLE_HOME_ASSISTANT
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <hass.hpp>
|
||||
#include <log.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
|
||||
HomeAssistant::HomeAssistant(const Config& config) {
|
||||
m_config = config;
|
||||
}
|
||||
|
||||
HomeAssistant::~HomeAssistant() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void HomeAssistant::event_handler(lws* wsi, const lws_callback_reasons reason, char* in) {
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
|
||||
applog(LOG::ERR, "websocket conn error: {}", in ? in : "(null)");
|
||||
return;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE: {
|
||||
nlohmann::json json = nlohmann::json::parse(in);
|
||||
const std::string ha_type = json["type"].get<std::string>();
|
||||
|
||||
if (ha_type == "auth_required") {
|
||||
json.clear();
|
||||
json["type"] = "auth";
|
||||
json["access_token"] = m_config.token;
|
||||
tx = json.dump();
|
||||
break;
|
||||
}
|
||||
|
||||
if (ha_type == "auth_ok") {
|
||||
applog(LOG::INF, "subscribing to entity \"{}\"", m_config.entity);
|
||||
json.clear();
|
||||
json["id"] = id++;
|
||||
json["type"] = "subscribe_entities";
|
||||
json["entity_ids"][0] = m_config.entity.c_str();
|
||||
tx = json.dump();
|
||||
break;
|
||||
}
|
||||
|
||||
if (ha_type == "result") {
|
||||
if (json["success"].get<bool>() != true)
|
||||
applog(LOG::ERR, "api said success was \"false\" on message id {}", id - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ha_type == "event") {
|
||||
json = json["event"];
|
||||
if (json.contains("a"))
|
||||
state = std::stof(json["a"][m_config.entity]["s"].get<std::string>());
|
||||
if (json.contains("c"))
|
||||
state = std::stof(json["c"][m_config.entity]["+"]["s"].get<std::string>());
|
||||
break;
|
||||
}
|
||||
|
||||
applog(LOG::WRN, "unhandled event: {}", static_cast<char*>(in));
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED: {
|
||||
applog(LOG::INF, "Websocket connected");
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CLOSED: {
|
||||
applog(LOG::INF, "Websocket closed");
|
||||
return;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE: {
|
||||
/* skip whole callback if there's no tx to send */
|
||||
if (!tx.empty()) {
|
||||
const size_t msgLen = LWS_PRE + tx.size();
|
||||
auto* buf = static_cast<unsigned char*>(malloc(msgLen));
|
||||
if (buf) {
|
||||
memcpy(&buf[LWS_PRE], tx.c_str(), tx.size());
|
||||
lws_write(wsi, &buf[LWS_PRE], tx.size(), LWS_WRITE_TEXT);
|
||||
tx = "";
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int HomeAssistant::callback(lws* wsi, const lws_callback_reasons reason, void* user, void* in, size_t) {
|
||||
auto* self = static_cast<HomeAssistant*>(user);
|
||||
self->event_handler(wsi, reason, static_cast<char*>(in));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HomeAssistant::connect() {
|
||||
lws_client_connect_info i{};
|
||||
lws_context_creation_info info{};
|
||||
|
||||
lws_set_log_level(LLL_ERR | LLL_WARN, lwsl_emit_syslog);
|
||||
|
||||
std::memset(&i, 0, sizeof(i));
|
||||
std::memset(&info, 0, sizeof info);
|
||||
|
||||
static constexpr lws_protocols protocols[] = {
|
||||
{"lws-minimal-client", callback, sizeof(void*), 0, 0, nullptr, 0},
|
||||
LWS_PROTOCOL_LIST_TERM};
|
||||
|
||||
static constexpr lws_extension extensions[] = {
|
||||
{"permessage-deflate",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"permessage-deflate"
|
||||
"; client_no_context_takeover"
|
||||
"; client_max_window_bits"},
|
||||
{nullptr, nullptr, nullptr}};
|
||||
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = protocols;
|
||||
info.fd_limit_per_thread = 1 + 1 + 1;
|
||||
info.extensions = extensions;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
applog(LOG::ERR, "error creating context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i.context = context;
|
||||
i.port = 443;
|
||||
i.address = m_config.address.c_str();
|
||||
i.path = "/api/websocket";
|
||||
i.host = i.address;
|
||||
i.origin = i.address;
|
||||
i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_PRIORITIZE_READS;
|
||||
i.protocol = nullptr;
|
||||
i.userdata = this;
|
||||
i.local_protocol_name = "lws-minimal-client";
|
||||
|
||||
websock = lws_client_connect_via_info(&i);
|
||||
if (!websock) {
|
||||
applog(LOG::ERR, "error creating lws client");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HomeAssistant::service(const int timeout_ms) const {
|
||||
lws_callback_on_writable(websock);
|
||||
lws_service(context, timeout_ms);
|
||||
}
|
||||
|
||||
void HomeAssistant::disconnect() const {
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
#endif
|
||||
141
src/lcd.c
Normal file
141
src/lcd.c
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "lcd.h"
|
||||
#include "log.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static int lcd_open(struct lcd_t *lcd, const bool reopen) {
|
||||
applog(LOG_INF, "Opening serial port at %s", lcd->port);
|
||||
if (lcd->fd <= 0 || reopen)
|
||||
lcd->fd = open(lcd->port, O_WRONLY | O_NOCTTY);
|
||||
if (lcd->fd <= 0) {
|
||||
applog(LOG_ERR, "Error opening serial port %s", lcd->port); // err
|
||||
return -1;
|
||||
}
|
||||
struct termios term = {};
|
||||
term.c_cflag = lcd->baud | CS8 | CLOCAL | CREAD;
|
||||
tcflush(lcd->fd, TCIFLUSH);
|
||||
tcsetattr(lcd->fd, TCSANOW, &term);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lcd_close(struct lcd_t *lcd) {
|
||||
if (lcd->fd >= 0) {
|
||||
close(lcd->fd);
|
||||
applog(LOG_INF, "LCD port closed");
|
||||
}
|
||||
lcd->fd = -1;
|
||||
}
|
||||
|
||||
static void lcd_write(struct lcd_t *lcd, const uint8_t *cmdbuf, const uint16_t len) {
|
||||
if (write(lcd->fd, cmdbuf, len) <= 0) {
|
||||
applog(LOG_ERR, "failed to execute write(), lost access to port?");
|
||||
lcd_close(lcd);
|
||||
lcd_open(lcd, true);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_clear(struct lcd_t *lcd) {
|
||||
constexpr uint8_t cmdbuf[] = {0xFE, 88};
|
||||
lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
void lcd_set_contrast(struct lcd_t *lcd, const uint8_t contrast) {
|
||||
applog(LOG_INF, "Set contrast to %d", contrast);
|
||||
const uint8_t cmdbuf[] = {0xFE, 80, contrast};
|
||||
lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
void lcd_set_backlight(struct lcd_t *lcd, const bool enabled) {
|
||||
applog(LOG_INF, "Set backlight to %s", enabled ? "true" : "false");
|
||||
const uint8_t cmdbuf[] = {0xFE, (enabled ? 66 : 70), 255};
|
||||
lcd_write(lcd, cmdbuf, enabled ? 3 : 2);
|
||||
}
|
||||
|
||||
void lcd_set_cursor(struct lcd_t *lcd, const uint8_t row, const uint8_t col) {
|
||||
const uint8_t cmdbuf[] = {0xFE, 71, col + 1, row + 1};
|
||||
lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
|
||||
}
|
||||
|
||||
void lcd_set_custom_char(struct lcd_t *lcd, const uint8_t index, const lcd_glyph_t *glyph) {
|
||||
memcpy(lcd->writebuf.cchar[index] + 3, glyph, sizeof(lcd_glyph_t)); // we prepare the command in init, so we can just copy the glyph after the command
|
||||
}
|
||||
|
||||
/* writes string to write buffer at calculated pos, we trust it to be null terminated */
|
||||
void lcd_write_buf(struct lcd_t *lcd, const uint8_t row, const uint8_t col, const char *str) {
|
||||
size_t len = 0;
|
||||
while (str[len] != '\0')
|
||||
len++;
|
||||
|
||||
len = MIN(len, sizeof(lcd->writebuf) - col);
|
||||
int pos = 4 + col + (LCD_COLS * (row % 2)); // skip 4 bytes to leave room for set cursor command
|
||||
if (row >= 2)
|
||||
pos += 2 * LCD_COLS + 4; // if we're writing to disp2, skip another 4 bytes for set cursor command and 2*40 bytes of disp 1
|
||||
memcpy(lcd->writebuf.text + pos, str, len);
|
||||
}
|
||||
|
||||
/* hyperoptimized function to write a formatted string to lcd buffer. */
|
||||
/* we cant just snprintf to the buffer directly bc it null terminates */
|
||||
void lcd_writef(struct lcd_t *lcd, const uint8_t x, const uint8_t y, const char *fmt, ...) {
|
||||
char tmp[LCD_COLS + 1];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int len = vsnprintf(tmp, sizeof(tmp), fmt, ap); // print fmt and ap to a temporary buffer
|
||||
va_end(ap);
|
||||
len = MIN(len, LCD_COLS - x);
|
||||
int pos = 4 + x + (LCD_COLS * (y % 2)); // skip 4 bytes to leave room for set cursor command
|
||||
if (y >= 2)
|
||||
pos += 2 * LCD_COLS + 4; // if we're writing to disp2, skip another 4 bytes for set cursor command and 2*40 bytes of disp 1
|
||||
memcpy(lcd->writebuf.text + pos, tmp, (size_t)len); // copy to lcd writebuffer address + whatever pos is
|
||||
}
|
||||
|
||||
inline void lcd_clear_buf(struct lcd_t *lcd) {
|
||||
memset(lcd->writebuf.text, ' ', sizeof(lcd->writebuf.text));
|
||||
// prepare commands for custom chars
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
const uint8_t charbuf[] = {0xFE, 78, i};
|
||||
memcpy(lcd->writebuf.cchar[i], charbuf, sizeof(charbuf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */
|
||||
void lcd_flush_buf(struct lcd_t *lcd) {
|
||||
constexpr uint8_t set_disp[] = {0xFE, 71, 1, 1}; // set cursor to char 1, line 1
|
||||
memcpy(&lcd->writebuf.text[0], set_disp, 4);
|
||||
memcpy(&lcd->writebuf.text[2 * LCD_COLS + 4], set_disp, 4);
|
||||
lcd->writebuf.text[2 * LCD_COLS + 7] = 3; // overwrite set cursor c1 l1 to c1 l3
|
||||
lcd_write(lcd, (const uint8_t *)&lcd->writebuf, sizeof(lcd->writebuf));
|
||||
}
|
||||
|
||||
// i have a whole flushbuf func to avoid too many writes, but im writing on every bar, need to rethink this.
|
||||
// we could have a separate pre-char buffer and put all the setCustomChar commands to that?
|
||||
inline char lcd_bar(struct lcd_t *lcd, const uint8_t char_id, const double value) {
|
||||
uint8_t b[8];
|
||||
memset(b, 0b01110, sizeof(b));
|
||||
for (uint8_t i = 0; i < (1.0 - value) * 8; i++)
|
||||
b[i] = 0;
|
||||
lcd_set_custom_char(lcd, char_id, &b);
|
||||
return (char)char_id;
|
||||
}
|
||||
|
||||
int lcd_init(struct lcd_t *lcd) {
|
||||
const int ret = lcd_open(lcd, false);
|
||||
if (ret < 0) {
|
||||
lcd_close(lcd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lcd_clear_buf(lcd);
|
||||
constexpr uint8_t cmdbuf[] = {0xFE, 75, 0xFE, 84};
|
||||
lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
|
||||
|
||||
lcd_clear(lcd);
|
||||
return 0;
|
||||
}
|
||||
73
src/log.c
Normal file
73
src/log.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "log.h"
|
||||
|
||||
#ifdef APPLOG_ENABLED
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static pthread_mutex_t cmtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Replicates pFname: strips return type and parameters from __PRETTY_FUNCTION__
|
||||
* "void myFunc(int x)" → "myFunc"
|
||||
* "int other_func(void)" → "other_func"
|
||||
*/
|
||||
static void fmt_funcname(const char *pretty, char *out, size_t outsz) {
|
||||
const char *start = pretty;
|
||||
|
||||
const char *space = strchr(pretty, ' ');
|
||||
if (space)
|
||||
start = space + 1;
|
||||
|
||||
const char *paren = strrchr(start, '(');
|
||||
size_t len = paren ? (size_t)(paren - start) : strlen(start);
|
||||
if (len >= outsz)
|
||||
len = outsz - 1;
|
||||
|
||||
memcpy(out, start, len);
|
||||
out[len] = '\0';
|
||||
}
|
||||
|
||||
void log_write(const log_level_t level, const char *func, const char *fmt, ...) {
|
||||
static const char *reset = "\033[0m";
|
||||
const char *color;
|
||||
|
||||
switch (level) {
|
||||
case LOG_INF:
|
||||
color = "\033[1;32m";
|
||||
break; /* bold green */
|
||||
case LOG_WRN:
|
||||
color = "\033[1;33m";
|
||||
break; /* bold yellow */
|
||||
case LOG_ERR:
|
||||
color = "\033[1;31m";
|
||||
break; /* bold red */
|
||||
case LOG_DBG:
|
||||
color = "";
|
||||
break;
|
||||
case LOG_START:
|
||||
color = "\033[1;3;36m";
|
||||
break; /* bold italic cyan */
|
||||
default:
|
||||
color = "";
|
||||
break;
|
||||
}
|
||||
|
||||
char funcname[128];
|
||||
fmt_funcname(func, funcname, sizeof(funcname));
|
||||
|
||||
/* ── console ─────────────────────────────────────────────────────── */
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
pthread_mutex_lock(&cmtx);
|
||||
fprintf(stderr, "[%s%s%s] ", color, funcname, reset);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fputc('\n', stderr);
|
||||
pthread_mutex_unlock(&cmtx);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* APPLOG_ENABLED */
|
||||
239
src/main.c
Normal file
239
src/main.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "aio.h"
|
||||
#include "cpu.h"
|
||||
#include "gpu.h"
|
||||
#include "lcd.h"
|
||||
#include "log.h"
|
||||
#include "sys.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
static constexpr uint8_t lcd_contrast = 250;
|
||||
static constexpr uint16_t refresh_interval_ms = 1000;
|
||||
static constexpr char netif[] = "enp7s0";
|
||||
static constexpr char cpu_pcidev[] = "0000:00:18.3";
|
||||
static constexpr char gpu_pcidev[] = "0000:0a:00.0";
|
||||
|
||||
static struct {
|
||||
pthread_mutex_t sensors_mtx;
|
||||
pthread_cond_t sensors_ready;
|
||||
atomic_bool running;
|
||||
} control;
|
||||
|
||||
struct sensors_t { // NOLINT stfu
|
||||
time_t ts;
|
||||
struct memory_t ram;
|
||||
struct disk_t home;
|
||||
struct disk_t gry;
|
||||
struct network_t net;
|
||||
struct syssensors_t sys;
|
||||
struct cpu_sensors_t cpu;
|
||||
struct gpu_sensors_t gpu;
|
||||
struct aio_t aio;
|
||||
double loadavg[3];
|
||||
};
|
||||
|
||||
static void *sensors_thread(void *arg) {
|
||||
applog(LOG_START, "sensors thread started, refresh interval is %dms", refresh_interval_ms);
|
||||
struct sensors_t *sensors = arg;
|
||||
|
||||
struct timespec next;
|
||||
clock_gettime(CLOCK_REALTIME, &next);
|
||||
|
||||
/* set up paths for the sensors */
|
||||
strcpy(sensors->home.mountpoint, "/home/drath");
|
||||
strcpy(sensors->gry.mountpoint, "/var/mnt/gry");
|
||||
strcpy(sensors->net.device, netif);
|
||||
cpu_detect(&sensors->cpu, cpu_pcidev);
|
||||
gpu_detect(&sensors->gpu, gpu_pcidev);
|
||||
sys_detect(&sensors->sys, "nct6775.656");
|
||||
sys_netdev_detect(&sensors->net);
|
||||
aio_detect(&sensors->aio);
|
||||
|
||||
/* main sensor loop */
|
||||
applog(LOG_START, "reached sensors main loop");
|
||||
while (control.running) { // NOLINT
|
||||
pthread_mutex_lock(&control.sensors_mtx);
|
||||
|
||||
{
|
||||
sensors->ts = time(nullptr);
|
||||
sys_get_load_avg(sensors->loadavg);
|
||||
sys_get_ram(&sensors->ram);
|
||||
sys_get_disk(&sensors->home);
|
||||
sys_get_disk(&sensors->gry);
|
||||
sys_get_network(&sensors->net);
|
||||
sys_update_sensors(&sensors->sys);
|
||||
cpu_update(&sensors->cpu);
|
||||
gpu_update(&sensors->gpu);
|
||||
aio_update(&sensors->aio);
|
||||
}
|
||||
|
||||
pthread_cond_signal(&control.sensors_ready);
|
||||
pthread_mutex_unlock(&control.sensors_mtx);
|
||||
|
||||
timespec_add_ms(&next, refresh_interval_ms);
|
||||
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next, nullptr);
|
||||
}
|
||||
|
||||
aio_close(&sensors->aio);
|
||||
applog(LOG_WRN, "sensors thread stopped");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void *display_thread(void *arg) {
|
||||
applog(LOG_START, "display thread started");
|
||||
const struct sensors_t *sensors = arg;
|
||||
|
||||
/* lcd setup */
|
||||
struct lcd_t lcd = {
|
||||
.port = "/dev/serial/by-id/usb-Drath_Technologies_Serial_Display_Controller_00002-if00",
|
||||
.baud = 0010002, // from termios-baud.h, B115200
|
||||
};
|
||||
lcd_init(&lcd);
|
||||
lcd_set_backlight(&lcd, true);
|
||||
lcd_set_contrast(&lcd, lcd_contrast);
|
||||
|
||||
char name[64], ver[64];
|
||||
sys_get_distro(name, ver);
|
||||
lcd_writef(&lcd, 0, 0, "%s %s", name, ver);
|
||||
lcd_writef(&lcd, 0, 3, "linuxSmartie %s", GIT_HASH);
|
||||
lcd_flush_buf(&lcd);
|
||||
lcd_clear_buf(&lcd);
|
||||
struct timespec next;
|
||||
clock_gettime(CLOCK_REALTIME, &next);
|
||||
timespec_add_ms(&next, refresh_interval_ms);
|
||||
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next, nullptr);
|
||||
|
||||
/* setup custom chars */
|
||||
lcd_set_custom_char(&lcd, 0, &(lcd_glyph_t){16, 6, 9, 8, 8, 9, 6, 0}); // celcius
|
||||
lcd_set_custom_char(&lcd, 1, &(lcd_glyph_t){0, 0, 4, 10, 10, 17, 31, 0}); // delta
|
||||
lcd_set_custom_char(&lcd, 2, &(lcd_glyph_t){0, 0, 8, 21, 21, 2, 0, 0}); // home (tilde)
|
||||
lcd_set_custom_char(&lcd, 3, &(lcd_glyph_t){4, 14, 21, 4, 4, 4, 0}); // up arrow
|
||||
lcd_set_custom_char(&lcd, 4, &(lcd_glyph_t){4, 4, 4, 21, 14, 4, 0}); // down arrow
|
||||
lcd_set_custom_char(&lcd, 5, &(lcd_glyph_t){0, 0, 15, 21, 21, 17, 15, 0}); // games (steam?)
|
||||
|
||||
/* main display loop */
|
||||
applog(LOG_START, "reached display main loop");
|
||||
while (control.running) { // NOLINT its updated globally bud
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
timespec_add_ms(&ts, (uint16_t)(refresh_interval_ms * 1.25));
|
||||
pthread_mutex_lock(&control.sensors_mtx); // lock sensor struct
|
||||
pthread_cond_timedwait(&control.sensors_ready, &control.sensors_mtx, &ts); // wait until data ready
|
||||
|
||||
{
|
||||
// prepare some tricky sensors
|
||||
constexpr char modes[] = "QBE";
|
||||
const uint16_t avg_fan_speed = (uint16_t)((sensors->aio.fan_speed[0] + sensors->aio.fan_speed[1]) / 2);
|
||||
|
||||
char gpudelta[5];
|
||||
const uint8_t delta = sensors->gpu.temp_hotspot - sensors->gpu.temp_edge;
|
||||
snprintf(gpudelta, sizeof(gpudelta), "%c%d", 1, delta);
|
||||
const uint8_t gpu_pos = delta >= 10 ? 3 : 2;
|
||||
|
||||
char gpuclock[16];
|
||||
snprintf(gpuclock, sizeof(gpuclock), "%d/%dMHz", sensors->gpu.clock_core, sensors->gpu.clock_mem);
|
||||
|
||||
lcd_writef(&lcd, 0, 0, "%c%s", 2, P_BYTES(sensors->home.usage.free, 1));
|
||||
lcd_writef(&lcd, 7, 0, "%c%s", 5, P_BYTES(sensors->gry.usage.free, 1));
|
||||
lcd_writef(&lcd, 15, 0, "%s%c", SYS_GET_TIME_STR(sensors->ts), lcd_bar(&lcd, 6, sensors->gpu.usage_core / 100.0));
|
||||
lcd_writef(&lcd, 26, 0, "%s %s %s", P_NUM(sensors->loadavg[0]), P_NUM(sensors->loadavg[1]), P_NUM(sensors->loadavg[2]));
|
||||
|
||||
lcd_writef(&lcd, 0, 1, "%d/%d%c", sensors->cpu.tctl, sensors->cpu.tccd1, 0);
|
||||
lcd_writef(&lcd, 7, 1, "%s", P_BYTES(sensors->ram.used, 0));
|
||||
lcd_writef(&lcd, 13, 1, "%.1f%c", (double)sensors->aio.water_temp, 0);
|
||||
lcd_writef(&lcd, 18, 1, "%3d%c", sensors->sys.t_sensor, 0);
|
||||
lcd_writef(&lcd, 28, 1, "%4s%c", gpudelta, 0);
|
||||
lcd_writef(&lcd, 25 - gpu_pos, 1, "%6s", P_BYTES(sensors->gpu.vram_used, 1));
|
||||
lcd_writef(&lcd, 34, 1, "%d/%d%c", sensors->gpu.temp_edge, sensors->gpu.temp_hotspot, 0);
|
||||
|
||||
lcd_writef(&lcd, 0, 2, "%.0fW", (double)sensors->cpu.ptotal);
|
||||
lcd_writef(&lcd, 5, 2, "%dR", avg_fan_speed);
|
||||
lcd_writef(&lcd, 12, 2, "%5s%c", P_BYTES(sensors->net.upload, 1), 3);
|
||||
lcd_writef(&lcd, 19, 2, "%c%s", 4, P_BYTES(sensors->net.download, 1));
|
||||
lcd_writef(&lcd, 26, 2, "%4dR", sensors->gpu.fan_speed);
|
||||
lcd_writef(&lcd, 32, 2, "%3d/%3dW", sensors->gpu.power_avg, sensors->gpu.power_cap);
|
||||
|
||||
lcd_writef(&lcd, 0, 3, "%uMHz", sensors->cpu.avg_freq);
|
||||
lcd_writef(&lcd, 8, 3, "%4dR-%c %d", sensors->aio.pump_speed, modes[sensors->aio.pump_mode], sensors->aio.pump_counter);
|
||||
lcd_writef(&lcd, 21, 3, "%12s", gpuclock);
|
||||
lcd_writef(&lcd, 34, 3, "%.3fV", (double)sensors->gpu.vcore);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&control.sensors_mtx); // unlock sensor struct
|
||||
lcd_flush_buf(&lcd);
|
||||
lcd_clear_buf(&lcd);
|
||||
}
|
||||
|
||||
lcd_write_buf(&lcd, 2, 16, "Goodbye"); // center
|
||||
lcd_set_backlight(&lcd, false);
|
||||
lcd_flush_buf(&lcd);
|
||||
lcd_close(&lcd);
|
||||
applog(LOG_WRN, "display thread stopped");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int main() {
|
||||
applog(LOG_START, "linuxSmartie %s starting", GIT_HASH);
|
||||
applog(LOG_DBG, "Compiled with %s", C_STD);
|
||||
|
||||
/* see if another instance is up, quit if it is */
|
||||
if (get_instance_lock() < 0) {
|
||||
applog(LOG_ERR, "Another instance is already running. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* malloc memory for the struct */
|
||||
struct sensors_t *sensors = malloc(sizeof(struct sensors_t)); // no actual point in mallocing but its cool
|
||||
if (sensors == nullptr) {
|
||||
applog(LOG_ERR, "can't allocate mem for the sensor struct. You don't got %lu bytes bro?", sizeof(*sensors));
|
||||
free(sensors);
|
||||
return 1;
|
||||
}
|
||||
applog(LOG_INF, "sensor struct allocated, size is %lu bytes", sizeof(*sensors));
|
||||
|
||||
/* signal setup */
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGINT);
|
||||
sigaddset(&sigset, SIGTERM);
|
||||
sigaddset(&sigset, SIGQUIT);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
|
||||
struct signalfd_siginfo info;
|
||||
const int sfd = signalfd(-1, &sigset, SFD_CLOEXEC);
|
||||
|
||||
/* control vars setup */
|
||||
pthread_mutex_init(&control.sensors_mtx, nullptr);
|
||||
pthread_cond_init(&control.sensors_ready, nullptr);
|
||||
control.running = true;
|
||||
|
||||
/* thread setup */
|
||||
pthread_t sensors_pthread;
|
||||
pthread_t display_pthread;
|
||||
|
||||
/* actually start the threads */
|
||||
pthread_create(&sensors_pthread, nullptr, sensors_thread, sensors);
|
||||
pthread_create(&display_pthread, nullptr, display_thread, sensors);
|
||||
|
||||
/* halts here until signal to stop */
|
||||
const ssize_t ret = read(sfd, &info, sizeof(info));
|
||||
(void)ret;
|
||||
|
||||
/* cleanup on exit */
|
||||
applog(LOG_WRN, "got stop signal, shutting down...");
|
||||
close(sfd);
|
||||
control.running = false;
|
||||
pthread_join(sensors_pthread, nullptr);
|
||||
pthread_join(display_pthread, nullptr);
|
||||
free(sensors);
|
||||
return 0;
|
||||
}
|
||||
118
src/sys.c
Normal file
118
src/sys.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "sys.h"
|
||||
#include "utils.h"
|
||||
|
||||
static sensor_file_t sensors;
|
||||
|
||||
char *sys_get_time_string(char *buf, const size_t bufsz, const time_t t) {
|
||||
const struct tm *tm = localtime(&t);
|
||||
snprintf(buf, bufsz, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *sys_get_date_string(char *buf, const size_t bufsz, const time_t t) {
|
||||
const struct tm *tm = localtime(&t);
|
||||
constexpr char months[][4] = {"sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paz", "lis", "gru"};
|
||||
constexpr char wdays[][4] = {"Nie", "Pon", "Wto", "Sro", "Czw", "Pia", "Sob"};
|
||||
snprintf(buf, bufsz, "%s, %02d %s", wdays[tm->tm_wday], tm->tm_mday, months[tm->tm_mon]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void sys_get_load_avg(double *load_avg) {
|
||||
getloadavg(load_avg, 3);
|
||||
}
|
||||
|
||||
void sys_get_distro(char* name, char* ver_str) {
|
||||
char buf[128];
|
||||
FILE *f = fopen("/etc/os-release", "r");
|
||||
if (f == nullptr)
|
||||
return;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
sscanf(buf, "NAME=\"%s\"", name); // NOLINT we live dangerously
|
||||
sscanf(buf, "VERSION=\"%s\"", ver_str); // NOLINT (its not really that dangerous)
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void sys_get_ram(struct memory_t *ram) {
|
||||
char buf[64];
|
||||
memset(ram, 0, sizeof(struct memory_t)); // zero out all values so we dont break out of the loop early
|
||||
|
||||
FILE *f = fopen("/proc/meminfo", "r");
|
||||
if (f == nullptr)
|
||||
return;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
sscanf(buf, "MemTotal: %lu kB", &ram->total); // NOLINT we live dangerously
|
||||
sscanf(buf, "MemAvailable: %lu kB", &ram->free); // NOLINT (its not really that dangerous)
|
||||
if (ram->total && ram->free)
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
ram->used = ram->total - ram->free;
|
||||
}
|
||||
|
||||
void sys_get_disk(struct disk_t *disk) {
|
||||
struct statvfs diskData;
|
||||
statvfs(disk->mountpoint, &diskData);
|
||||
disk->usage.free = diskData.f_bfree * diskData.f_frsize;
|
||||
disk->usage.used = (diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize;
|
||||
disk->usage.total = diskData.f_blocks * diskData.f_frsize;
|
||||
}
|
||||
|
||||
void sys_get_network(struct network_t *network) {
|
||||
struct _net_t {
|
||||
struct timespec ts;
|
||||
uint64_t rx;
|
||||
uint64_t tx;
|
||||
};
|
||||
|
||||
static struct _net_t prev;
|
||||
struct _net_t current = {};
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t.ts);
|
||||
fast_read_sensor_into_mem(&network->f_rx, ¤t.rx);
|
||||
fast_read_sensor_into_mem(&network->f_tx, ¤t.tx);
|
||||
const int64_t diff_us = timespec_diff_us(¤t.ts, &prev.ts);
|
||||
const uint64_t rx_delta = current.rx >= prev.rx ? current.rx - prev.rx : 0;
|
||||
const uint64_t tx_delta = current.tx >= prev.tx ? current.tx - prev.tx : 0;
|
||||
const double diff_s = (double)diff_us / 1000000.0;
|
||||
network->download = (uint32_t)((double)rx_delta / diff_s);
|
||||
network->upload = (uint32_t)((double)tx_delta / diff_s);
|
||||
prev = current;
|
||||
// still fucky?
|
||||
}
|
||||
|
||||
void sys_netdev_detect(struct network_t *network) {
|
||||
applog(LOG_INF, "Opening netdev %s", network->device);
|
||||
static char path[128];
|
||||
snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/", network->device);
|
||||
open_sensor(&network->f_rx, path, "rx_bytes", nullptr, 1, SENSOR_U64);
|
||||
open_sensor(&network->f_tx, path, "tx_bytes", nullptr, 1, SENSOR_U64);
|
||||
}
|
||||
|
||||
void sys_detect(struct syssensors_t *s, const char *platform) {
|
||||
snprintf(s->hwmon, sizeof(s->hwmon), "/sys/devices/platform/%s/hwmon", platform);
|
||||
const int ret = get_hwmon_dir(s->hwmon, sizeof(s->hwmon));
|
||||
if (ret != 0) {
|
||||
s->hwmon[0] = '\0';
|
||||
applog(LOG_WRN, "Can't open system hwmon. Kernel params added? Module loaded? See README");
|
||||
return;
|
||||
}
|
||||
applog(LOG_INF, "Detected system sensors in %s", s->hwmon);
|
||||
open_sensor(&sensors, s->hwmon, "/temp5_input", &s->t_sensor, 1000, SENSOR_I16);
|
||||
}
|
||||
|
||||
void sys_update_sensors(const struct syssensors_t *s) {
|
||||
if (!s->hwmon[0])
|
||||
return;
|
||||
|
||||
fast_read_sensor(&sensors);
|
||||
}
|
||||
87
src/sys.cpp
87
src/sys.cpp
@@ -1,87 +0,0 @@
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
#include <log.hpp>
|
||||
#include <string>
|
||||
#include <sys.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
int getVal(const std::string_view target, std::string_view content) {
|
||||
int result = -1;
|
||||
if (const std::size_t start = content.find(target); start != std::string::npos) {
|
||||
content.remove_prefix(start + target.length());
|
||||
const std::size_t end = content.find(" kB");
|
||||
while (std::isspace(content.front()))
|
||||
content.remove_prefix(1);
|
||||
std::from_chars(content.data(), content.data() + end, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void sys::getTimeDate(TimeDate* td) {
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto local = std::chrono::current_zone()->to_local(now);
|
||||
const std::chrono::year_month_day ymd{floor<std::chrono::days>(local)};
|
||||
const std::chrono::weekday wd{floor<std::chrono::days>(local)};
|
||||
td->time = std::format("{:%H:%M:%S}", floor<std::chrono::seconds>(local));
|
||||
td->date = std::format("{}, {} {}", wdays[wd.c_encoding()], ymd.day(), months[static_cast<unsigned>(ymd.month()) - 1]);
|
||||
}
|
||||
|
||||
void sys::getRam(Memory* mem) {
|
||||
static std::array<char, 128> buf; // file is longer but we only need first 128 chars
|
||||
utils::readFile("/proc/meminfo", buf);
|
||||
mem->free = getVal("MemAvailable:", buf.data());
|
||||
mem->total = getVal("MemTotal:", buf.data()); // shouldn't really update this on each loop
|
||||
mem->used = mem->total - mem->free;
|
||||
}
|
||||
|
||||
void sys::getDisk(Disk* disk) {
|
||||
struct statvfs diskData{};
|
||||
statvfs(disk->mountpoint.c_str(), &diskData);
|
||||
disk->usage.free = diskData.f_bfree * diskData.f_frsize;
|
||||
disk->usage.used = (diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize;
|
||||
disk->usage.total = diskData.f_blocks * diskData.f_frsize;
|
||||
}
|
||||
|
||||
void sys::getNetwork(Network* net, const std::string& device) {
|
||||
struct Network {
|
||||
std::chrono::time_point<std::chrono::steady_clock> ts;
|
||||
uint64_t rx = 0;
|
||||
uint64_t tx = 0;
|
||||
};
|
||||
|
||||
static std::array<char, 32> buf;
|
||||
static Network prev;
|
||||
Network current;
|
||||
|
||||
current.ts = std::chrono::steady_clock::now();
|
||||
utils::fastReadNum("/sys/class/net/" + device + "/statistics/rx_bytes", buf, current.rx);
|
||||
utils::fastReadNum("/sys/class/net/" + device + "/statistics/tx_bytes", buf, current.tx);
|
||||
const double ts_diff = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(current.ts - prev.ts).count()) / 1000000.0f;
|
||||
net->download = static_cast<uint32_t>(static_cast<double>(current.rx - prev.rx) / ts_diff);
|
||||
net->upload = static_cast<uint32_t>(static_cast<double>(current.tx - prev.tx) / ts_diff);
|
||||
prev = current;
|
||||
}
|
||||
|
||||
int sys::detect(sysSensors* s, const std::string& platform) {
|
||||
// we dont really need getFirstDir since its a static folder, but its useful for try/catch
|
||||
try {
|
||||
s->hwmon = utils::getFirstDir("/sys/devices/platform/" + platform + "/hwmon");
|
||||
} catch (...) {
|
||||
applog(LOG::ERR, "Can't open \"/sys/devices/platform/{}/hwmon\". Kernel params added? Module loaded?", platform);
|
||||
return -1;
|
||||
}
|
||||
applog(LOG::INF, "Found system sensors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys::updateSensors(sysSensors* s) {
|
||||
if (s->hwmon.empty())
|
||||
return;
|
||||
static std::array<char, 8> buf;
|
||||
utils::fastReadNum(s->hwmon + "/fan2_input", buf, s->fan_speed[0]);
|
||||
utils::fastReadNum(s->hwmon + "/fan7_input", buf, s->fan_speed[1]);
|
||||
utils::fastReadNum<1000>(s->hwmon + "/temp5_input", buf, s->t_sensor);
|
||||
}
|
||||
151
src/utils.c
Normal file
151
src/utils.c
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glob.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
int get_instance_lock() {
|
||||
const char *xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
|
||||
char tmp_dir[256];
|
||||
snprintf(tmp_dir, sizeof(tmp_dir), "%s/linuxSmartie.lock", xdg_runtime_dir);
|
||||
|
||||
const int file = open(tmp_dir, O_CREAT | O_RDWR | O_CLOEXEC, 0600);
|
||||
if (file < 0) {
|
||||
applog(LOG_ERR, "Couldn't create a lock file at %s", tmp_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flock(file, LOCK_EX | LOCK_NB) < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
applog(LOG_ERR, "another instance already running, this one will exit.");
|
||||
else
|
||||
applog(LOG_ERR, "flock failed: %s", strerror(errno));
|
||||
close(file);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void timespec_add_ms(struct timespec *ts, const uint16_t ms) {
|
||||
ts->tv_nsec += ms * 1000000L;
|
||||
if (ts->tv_nsec >= 1000000000L) {
|
||||
ts->tv_sec++;
|
||||
ts->tv_nsec -= 1000000000L;
|
||||
}
|
||||
}
|
||||
|
||||
inline int64_t timespec_diff_us(const struct timespec *a, const struct timespec *b) {
|
||||
const int64_t sec = a->tv_sec - b->tv_sec;
|
||||
const int64_t nsec = a->tv_nsec - b->tv_nsec;
|
||||
return sec * 1000000LL + nsec / 1000LL;
|
||||
}
|
||||
|
||||
inline char *pretty_num(const double num, char *buf, const size_t bufsz) {
|
||||
const uint8_t decimals = (num <= 10.0) ? 2 : (num <= 100.0) ? 1 : 0;
|
||||
snprintf(buf, bufsz, "%.*f", decimals, num);
|
||||
return buf;
|
||||
}
|
||||
|
||||
inline char *pretty_bytes(const uint64_t bytes, int8_t start_suffix, char *buf, const size_t bufsz) {
|
||||
constexpr char suffix_list[] = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'};
|
||||
start_suffix *= -1;
|
||||
double bytes_d = (double)bytes;
|
||||
while (bytes_d >= 1024.0) {
|
||||
bytes_d /= 1024.0;
|
||||
start_suffix++;
|
||||
}
|
||||
snprintf(buf, bufsz, "%s%c", P_NUM(bytes_d), suffix_list[MAX(0, start_suffix)]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* path has to have at least 8 free chars at the end for glob */
|
||||
int get_hwmon_dir(char *path, const size_t bufsz) {
|
||||
glob_t g;
|
||||
strcat(path, "/hwmon*");
|
||||
|
||||
if (glob(path, 0, nullptr, &g) == 0) {
|
||||
strlcpy(path, g.gl_pathv[0], bufsz); // same size as hwmon length, careful
|
||||
globfree(&g);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void open_sensor(sensor_file_t* s, const char* dir, const char *file, void* value, const uint32_t divider, const sensor_type_t type) {
|
||||
char path[256];
|
||||
char *nt = stpcpy(path, dir); // nt is a pointer to the null terminator of the copied string
|
||||
strcpy(nt, file); // copy to the null terminator of prev copy, append basically
|
||||
s->divider = divider;
|
||||
s->value = value;
|
||||
s->type = type;
|
||||
s->fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (s->fd < 0)
|
||||
applog(LOG_ERR, "couldn't open %s", path);
|
||||
}
|
||||
|
||||
inline void fast_read_sensor_into_mem(const sensor_file_t *s, void* val) {
|
||||
if (s->fd < 0) {
|
||||
applog(LOG_ERR, "invalid sensor fd %d", s->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
lseek(s->fd, 0, SEEK_SET);
|
||||
const ssize_t len = read(s->fd, buf, sizeof(buf));
|
||||
|
||||
if (len <= 0) {
|
||||
applog(LOG_ERR, "error reading sensor");
|
||||
return;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
switch (s->type) {
|
||||
case SENSOR_I16:
|
||||
*(int16_t*)val = (int16_t)(strtol(buf, nullptr, 10) / s->divider);
|
||||
break;
|
||||
|
||||
case SENSOR_U8:
|
||||
*(uint8_t*)val = (uint8_t)(strtol(buf, nullptr, 10) / s->divider);
|
||||
break;
|
||||
|
||||
case SENSOR_U16:
|
||||
*(uint16_t*)val = (uint16_t)(strtol(buf, nullptr, 10) / s->divider);
|
||||
break;
|
||||
|
||||
case SENSOR_U64:
|
||||
*(uint64_t*)val = strtoull(buf, nullptr, 10) / s->divider;
|
||||
break;
|
||||
|
||||
case SENSOR_FLOAT:
|
||||
const uint64_t t = strtoull(buf, nullptr, 10);
|
||||
*(float*)val = (float)t / (float)s->divider;
|
||||
break;
|
||||
|
||||
default:
|
||||
applog(LOG_ERR, "unknown sensor type %d", s->type);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void fast_read_sensor(const sensor_file_t *s) {
|
||||
if (s->value != nullptr) {
|
||||
fast_read_sensor_into_mem(s, s->value);
|
||||
return;
|
||||
}
|
||||
applog(LOG_ERR, "attempted to read into nullptr");
|
||||
}
|
||||
|
||||
void close_sensor(const sensor_file_t* s) {
|
||||
close(s->fd);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/* pads given string to length */
|
||||
std::string pad(std::string s, const uint8_t len, const just j) {
|
||||
if (len > s.size())
|
||||
s.insert(j == left ? s.end() : s.begin(), len - s.size(), fill_char);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* returns the string centered within given length */
|
||||
std::string center(std::string str, const uint8_t len) {
|
||||
const uint8_t padding = len - str.size();
|
||||
str.insert(str.begin(), padding / 2, fill_char);
|
||||
str.insert(str.end(), padding / 2, fill_char);
|
||||
return str;
|
||||
}
|
||||
|
||||
/* finds first dir in path and returns it. don't refactor, you don't understand it, its fast enough, and you only use it on init */
|
||||
std::string getFirstDir(const std::string_view& path) {
|
||||
for (const auto& entry : std::filesystem::directory_iterator(path))
|
||||
return entry.path();
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
Reference in New Issue
Block a user