first ePowerSwitch verion

This commit is contained in:
2026-04-28 08:20:38 +02:00
commit 4d809d11e0
8 changed files with 539 additions and 0 deletions
+246
View File
@@ -0,0 +1,246 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: ".*"
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: "(Test)?$"
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
---
+6
View File
@@ -0,0 +1,6 @@
.vscode/
CMakeCache.txt
CMakeFiles
Makefile
cmake_install.cmake
midas.log
+3
View File
@@ -0,0 +1,3 @@
[submodule "submodule/mepicsca"]
path = submodule/mepicsca
url = git@gitea.psi.ch:lin-midas-drivers/mepicsca.git
+98
View File
@@ -0,0 +1,98 @@
cmake_minimum_required(VERSION 3.03)
project(ePowerSwitchFront VERSION 1.0)
add_subdirectory(submodule/mepicsca)
add_compile_options(
-Wall
-Wformat=2
-g
-Wno-format-nonliteral
-Wno-strict-aliasing
-Wuninitialized
-Wno-unused-function
)
# Check if the required environment variables MIDASSYS and EPICSSYS are available
if (NOT DEFINED ENV{MIDASSYS})
message(SEND_ERROR "MIDASSYS environment variable not defined.")
endif()
if (NOT DEFINED ENV{EPICSSYS})
message(SEND_ERROR "EPICSSYS environment variable not defined.")
endif()
set(CMAKE_CXX_STANDARD 17)
set(MIDASSYS $ENV{MIDASSYS})
set(EPICSSYS $ENV{EPICSSYS})
# Select the correct EPICS library depending on the OS (currently Linus or Darwin are available)
if (${CMAKE_SYSTEM_NAME} MATCHES Linux)
link_directories(${EPICSSYS}/lib/linux-x86_64)
set(LIBS ${LIBS} -lpthread -lutil -lrt -lbsd -ldl)
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES Darwin)
link_directories(${EPICSSYS}/lib/darwin-aarch64)
set(LIBS ${LIBS} -lutil -lca)
endif()
set(LIBS
${LIBS}
${EPICSSYS}/lib/$ENV{EPICS_HOST_ARCH}/libca.so
${EPICSSYS}/lib/$ENV{EPICS_HOST_ARCH}/libCom.so # For alarm.h
$ENV{MIDASSYS}/lib/libmfe.a
$ENV{MIDASSYS}/lib/libmidas.a
$ENV{MIDASSYS}/lib/libmscb.a
)
find_package(Midas REQUIRED)
add_executable(ePowerSwitchFront
src/ePowerSwitchFront.cpp
)
set_property(
TARGET
ePowerSwitchFront
PROPERTY
CXX_STANDARD 17
)
target_include_directories(
ePowerSwitchFront
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE
$ENV{MIDASSYS}/drivers
$ENV{MIDASSYS}/include
#$ENV{MIDASSYS}/drivers
#$ENV{MIDASSYS}/include
# This is redundant if MIDASSYS =/ Midas repo, but needed if MIDAS has been
# installed in the repo directory, since the CMake file of MIDAS doesn't
# copy the headers into $ENV{MIDASSYS}/include in the latter case.
$ENV{MIDASSYS}/include/mscb
${EPICSSYS}/include
${EPICSSYS}/include/os/Linux
${EPICSSYS}/include/os/Darwin
${EPICSSYS}/include/compiler/gcc
${EPICSSYS}/include/compiler/clang
)
target_link_libraries(ePowerSwitchFront
PRIVATE
midas::mfe
m_epics_ca
${LIBS}
)
install(
TARGETS
ePowerSwitchFront
RUNTIME DESTINATION bin
)
# Run the executable during the install process to register it in MIDAS
# include(register_exe)
# register_executable_once("${CMAKE_INSTALL_PREFIX}/bin/ePowerSwitchFront")
+7
View File
@@ -0,0 +1,7 @@
#ifndef EPOWERSWITCH_CONFIG_H
#define EPOWERSWITCH_CONFIG_H
#define EPOWERSWITCH_SOCKET_COMMAND_PREFIX "ePowerSwitch_command_outlet_"
#define EPOWERSWITCH_SOCKETNUMBER_INFO_PREFIX "ePowerSwitch_config_maxOutlet"
#endif
+60
View File
@@ -0,0 +1,60 @@
#ifndef EPOWERSWITCH_FRONTEND_H
#define EPOWERSWITCH_FRONTEND_H
#include "m_epics_ca.h"
#include "tmfe.h"
#include <vector>
class ePowerSwitchEquipment : public TMFeEquipment {
public:
/**
* @brief contructor
*
* @param equipmentName name show on midas for the equipment
* @param equipmentFileName file name for automatic tagged message
*/
ePowerSwitchEquipment(std::string equipmentName,
const char *equipmentFileName);
/**
* @brief call periodicly by midas
*/
void HandlePeriodic();
private:
std::vector<mEpicsCa<int> *> outletCommandRecords;
std::vector<int> outletLastState;
mEpicsCa<int> outletNumberRecord;
int numberOfOutlet;
/**
* @brief refresh information about the given socket id
*
* @param socketId which socket to refresh
*/
void refreshSocket(int socketId);
/**
* @brief refresh information about all the available socket
*/
void refreshAllSockets();
/**
* @brief detect and modify the current socket pool in case of change
*/
void updateSocketNumber();
};
class ePowerSwitchFrontend : public TMFrontend {
public:
/**
* @brief contructor
*
* @param frontendName name show on midas for the frontend
* @param equipmentName name show on midas for the equipment
*/
ePowerSwitchFrontend(std::string frontendName, std::string equipmentName);
};
#endif
+118
View File
@@ -0,0 +1,118 @@
#include "ePowerSwitchFront.h"
#include "ePowerSwitchConfig.h"
#include "m_epics_ca.h"
#include "tmfe.h"
#include <format>
#include <sstream>
/**
* @brief local function, append an integer at the end of a string
* @param str string prfix
* @param value integer to append
* @return "str" + integer
*/
std::string format(std::string str, int value) {
std::stringstream ss;
ss << str;
ss << value;
return ss.str();
}
int main(int argc, char *argv[]) {
std::string frontendName = "ePowerSwitch";
std::string equipmentName = "powerswitch";
if (argc == 1) {
frontendName = std::string(argv[1]);
argv++;
argc--;
} else if (argc == 2) {
frontendName = std::string(argv[1]);
equipmentName = std::string(argv[2]);
argv += 2;
argc -= 2;
}
auto front = new ePowerSwitchFrontend(frontendName.c_str());
front->FeMain(argc, argv);
}
ePowerSwitchEquipment::ePowerSwitchEquipment(std::string equipmentName,
const char *equipmentFileName)
: TMFeEquipment(equipmentName, equipmentFileName),
outletNumberRecord(
mEpicsCa<int>(EPOWERSWITCH_SOCKETNUMBER_INFO_PREFIX, true)) {
fEqConfReadConfigFromOdb = false;
fEqConfPeriodMilliSec = 1000;
fEqConfLogHistory = 1;
fEqConfReadOnlyWhenRunning = false;
fEqConfWriteEventsToOdb = true;
this->numberOfOutlet = 0;
}
void ePowerSwitchEquipment::HandlePeriodic() {
updateSocketNumber();
refreshAllSockets();
}
void ePowerSwitchEquipment::refreshSocket(int socketId) {
std::string varname = format("Socket ", socketId);
int midasSocketState = 0; // default => turn off
fOdbEqVariables->RI(varname.c_str(), &midasSocketState, true);
if (midasSocketState != this->outletLastState.at(socketId)) {
this->outletCommandRecords.at(socketId)->put(&midasSocketState);
printf("send command : %d\n", midasSocketState);
}
this->outletLastState.at(socketId) = midasSocketState;
}
void ePowerSwitchEquipment::refreshAllSockets() {
for (int i = 0; i < this->numberOfOutlet; i++) {
refreshSocket(i);
}
}
void ePowerSwitchEquipment::updateSocketNumber() {
int epicsOutletNumber = 0;
if (!outletNumberRecord.connected())
return;
int returnCode = outletNumberRecord.get(&epicsOutletNumber);
if (returnCode < 0) {
printf("error\n");
return;
}
for (int i = this->numberOfOutlet; i < epicsOutletNumber; i++) {
std::string epicsRecordName =
format(EPOWERSWITCH_SOCKET_COMMAND_PREFIX, i);
this->outletCommandRecords.push_back(
new mEpicsCa<int>(epicsRecordName.c_str(), true));
this->outletLastState.push_back(0);
printf("new socket created\n");
}
for (int i = epicsOutletNumber; i < this->numberOfOutlet; i++) {
mEpicsCa<int> *ptr = this->outletCommandRecords.back();
delete ptr;
this->outletCommandRecords.pop_back();
this->outletLastState.pop_back();
printf("old socket destroyed\n");
}
this->numberOfOutlet = epicsOutletNumber;
}
ePowerSwitchFrontend::ePowerSwitchFrontend(std::string frontendName,
std::string equipmentName) {
FeSetName(frontname.c_str());
FeAddEquipment(new ePowerSwitchEquipment(equipmentName.c_str(), __FILE__));
}
Submodule submodule/mepicsca added at d9e17892ba