149 lines
5.3 KiB
C++
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 |