Files
sinqMotor/src/msgPrintControl.h
2025-05-09 11:59:51 +02:00

149 lines
5.3 KiB
C++

// SPDX-License-Identifier: GPL-3.0-only
#ifndef msgPrintControl_H
#define msgPrintControl_H
#define DefaultMaxRepetitions 4
#include <asynDriver.h>
#include <string.h>
#include <string>
#include <unordered_map>
/**
* @brief Class to identify a message print location. See the docstring of
* `msgPrintControl` on how to use this key.
*
*/
class msgPrintControlKey {
public:
std::string controller_;
// -1 indicates a non-axis specific message
int axisNo_;
const char *functionName_;
int line_;
/**
* @brief Maximum number of times a message is printed before it is
* suppressed. This number is not used as part of the hash.
*
*/
size_t maxRepetitions_;
msgPrintControlKey(char *controller_, int axisNo, const char *fileName,
int line, size_t maxRepetitions = DefaultMaxRepetitions);
bool operator==(const msgPrintControlKey &other) const {
return axisNo_ == other.axisNo_ && line_ == other.line_ &&
strcmp(functionName_, other.functionName_) == 0 &&
controller_ == other.controller_;
}
void format(char *buffer, size_t bufferSize);
};
/**
* @brief Implementation of the hash functionality for `msgPrintControlKey`
*
*/
namespace std {
template <> struct hash<msgPrintControlKey> {
size_t operator()(const msgPrintControlKey &obj) const {
// Combine the hashes of the members (x and y)
size_t h1 = std::hash<std::string>{}(obj.controller_);
size_t h2 = hash<int>{}(obj.axisNo_);
size_t h3 = std::hash<const char *>{}(obj.functionName_);
size_t h4 = hash<int>{}(obj.line_);
// Combine the hashes (simple XOR and shifting technique)
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
}
};
} // namespace std
/**
* @brief Class to control the number of repetitions of error messages
*
* This class is used to prevent excessive repetitions of identical error
* messages. For example, if the communication between a controller and an
* axis fails, a corresponding error message is created in each poll. This
* could "flood" the IOC shell with noise. To prevent this, this class keeps
* track of the number of subsequent error message repetition. Each message is
* uniquely identified by `msgPrintControlKey`. The function `shouldBePrinted`
* can be used in order to see if a message should be printed or not:
*
* ```
* const char* controller = "MCU" // Name of the controller
* int axisNo = 0; // Number of the axis
* bool wantToPrint = evaluateConditions(...); *
* if (msgPrintControl.shouldBePrinted(controller, axisNo, __PRETTY_FUNCTION__,
* __LINE__, wantToPrint)) { asynPrint(...)
* }
* ```
*/
class msgPrintControl {
public:
/**
* @brief Checks if the error message associated with "key" has been printed
* more than `this->maxRepetitions_` times in a row. If yes, returns false,
* otherwise true. Counter is reset if `wantToPrint` is false.
*
* If the conditions for printing a message are met, `wantToPrint` must be
* set to true. The function then checks if `maxRepetitions_` has been
* exceeded. If yes, the function returns no, indicating that the message
* should not be printed. If no, the number of repetitions stored in the map
* is incremented and the function returns true, indicating that the message
* should be printed.
*
* If the conditions for printing a message are not met, `wantToPrint` must
* be set to false. This resets the map entry.
*
* @param key Key associated with the message, used to
* identify individual messages
* @param wantToPrint If the message associated with key should be
* printed, this value should be true, otherwise false.
* @param pasynUser If the problem has been resolved (wantToPrint =
* false), a corresponding status message is printed using the given
* asynUser. If this pointer is a nullptr, no message is printed.
* @return bool If true, the message should be printed, if
* false, it should not.
*/
bool shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
asynUser *pasynUser);
/**
* @brief Like `shouldBePrinted(msgPrintControlKey key, bool wantToPrint)`,
* but constructs the key from the first four arguments.
*
* @param controller_
* @param axisNo
* @param fileName
* @param line
* @param wantToPrint
* @param pasynUser
*/
bool shouldBePrinted(char *controller, int axisNo, const char *functionName,
int line, bool wantToPrint, asynUser *pasynUser,
size_t maxRepetitions = DefaultMaxRepetitions);
/**
* @brief Reset the error message count incremented in `shouldBePrinted` for
* the given key
*
* @param key Key associated with the message, used to
* identify individual messages
* @param pasynUser If the problem has been resolved (`wantToPrint =
* false`), a corresponding status message is printed using the given
* asynUser. If this pointer is a nullptr, no message is printed.
*/
void resetCount(msgPrintControlKey &key, asynUser *pasynUser);
char *getSuffix();
private:
std::unordered_map<msgPrintControlKey, size_t> map_;
char suffix_[300] = {0};
};
#endif