MIDAS
Loading...
Searching...
No Matches
Midas Alarm Functions (al_xxx)

Functions

static BOOL al_evaluate_single_condition (const char *alarm_name, const char *condition, std::string *pvalue)
 
BOOL al_evaluate_condition (const char *alarm_name, const char *condition, std::string *pvalue)
 
static midas::odb al_make_alarm_odb (bool periodic=false)
 
INT al_trigger_alarm (const char *alarm_name, const char *alarm_message, const char *default_class, const char *cond_str, INT type)
 
INT al_trigger_class (const char *alarm_class, const char *alarm_message, BOOL first)
 
INT al_reset_alarm (const char *alarm_name)
 
INT al_check ()
 
INT al_get_alarms (std::string *presult)
 
INT EXPRT al_define_odb_alarm (const char *name, const char *condition, const char *aclass, const char *message)
 

Detailed Description

dox


Function Documentation

◆ al_check()

INT al_check ( void  )

Scan ODB for alarms.

Returns
AL_SUCCESS

Definition at line 692 of file alarm.cxx.

692 {
693 if (rpc_is_remote()) {
694 return rpc_call(RPC_AL_CHECK);
695 }
696
697#ifdef LOCAL_ROUTINES
698 {
699 INT status, size, semaphore;
700 HNDLE hDB, hkeyroot, hkey;
701 KEY key;
702 //char str[256];
703 BOOL flag;
704
706
707 if (hDB == 0)
708 return AL_SUCCESS; /* called from server not yet connected */
709
710 /* check online mode */
711 flag = TRUE;
712 size = sizeof(flag);
713 db_get_value(hDB, 0, "/Runinfo/Online Mode", &flag, &size, TID_INT, TRUE);
714 if (!flag)
715 return AL_SUCCESS;
716
717 /* check global alarm flag */
718 flag = TRUE;
719 size = sizeof(flag);
720 db_get_value(hDB, 0, "/Alarms/Alarm system active", &flag, &size, TID_BOOL, TRUE);
721 if (!flag)
722 return AL_SUCCESS;
723
724 /* request semaphore */
725 cm_get_experiment_semaphore(&semaphore, NULL, NULL, NULL);
726 status = ss_semaphore_wait_for(semaphore, 100);
727 if (status == SS_TIMEOUT)
728 return AL_SUCCESS; /* someone else is doing alarm business */
729 if (status != SS_SUCCESS) {
730 fprintf(stderr, "al_check: Something is wrong with our semaphore, ss_semaphore_wait_for() returned %d, aborting.\n", status);
731 // abort(); // DOES NOT RETURN
732 // NOT REACHED
733 fprintf(stderr, "al_check: Cannot abort - this will lock you out of odb. From this point, MIDAS will not work correctly. Please read the discussion at https://midas.triumf.ca/elog/Midas/945\n");
734 return AL_SUCCESS;
735 }
736
737 /* check ODB alarms */
738 db_find_key(hDB, 0, "/Alarms/Alarms", &hkeyroot);
739 if (!hkeyroot) {
740 /* create default ODB alarm */
741 midas::odb demo_odb = al_make_alarm_odb();
742 demo_odb.connect("/Alarms/Alarms/Demo ODB");
743
744 db_find_key(hDB, 0, "/Alarms/Alarms", &hkeyroot);
745 if (!hkeyroot) {
746 ss_semaphore_release(semaphore);
747 return AL_SUCCESS;
748 }
749
750 midas::odb demo_periodic = al_make_alarm_odb(true);
751 demo_periodic.connect("/Alarms/Alarms/Demo periodic");
752
753 db_find_key(hDB, 0, "/Alarms/Alarms", &hkeyroot);
754 if (!hkeyroot) {
755 ss_semaphore_release(semaphore);
756 return AL_SUCCESS;
757 }
758
759 /* create default alarm classes */
760 midas::odb alarm = {
761 {"Write system message", true},
762 {"Write Elog message", false},
763 {"System message interval", 60},
764 {"System message last", (uint32_t)0},
765 {"Execute command", ""},
766 {"Execute interval", 0},
767 {"Execute last", (uint32_t)0},
768 {"Stop run", false},
769 {"Display BGColor", "red"},
770 {"Display FGColor", "black"},
771 {"Alarm sound", true}
772 };
773 auto warning = alarm;
774 alarm.connect("/Alarms/Classes/Alarm");
775 warning["Display BGColor"] = "yellow";
776 warning.connect("/Alarms/Classes/Warning");
777 }
778
779 for (int i = 0;; i++) {
780 status = db_enum_key(hDB, hkeyroot, i, &hkey);
782 break;
783
784 db_get_key(hDB, hkey, &key);
785
786 std::string alarm_path = "/Alarms/Alarms/" + std::string(key.name);
788 alarm.connect_and_fix_structure(alarm_path);
789
790 int alarm_type = alarm["Type"];
791 if (alarm_type < 1 || alarm_type > AT_LAST) {
792 cm_msg(MERROR, "al_check", "Alarm \"%s\" has invalid type %d", key.name, alarm_type);
793 continue;
794 }
795
796 bool active = alarm["Active"];
797 int check_interval = alarm["Check interval"];
798 DWORD checked_last = alarm["Checked last"];
799
800 /* check periodic alarm only when active */
801 if (active && alarm_type == AT_PERIODIC && check_interval > 0 && (INT) ss_time() - (INT) checked_last > check_interval) {
802 /* if checked_last has not been set, set it to current time */
803 if (checked_last == 0) {
804 checked_last = ss_time();
805 alarm["Checked last"] = checked_last;
806 } else {
807 std::string alarm_message = alarm["Alarm Message"];
808 std::string alarm_class = alarm["Alarm Class"];
809 al_trigger_alarm(key.name, alarm_message.c_str(), alarm_class.c_str(), "", AT_PERIODIC);
810 }
811 }
812
813 /* check alarm only when active and not internal */
814 if (active && alarm_type == AT_EVALUATED && check_interval > 0 && (INT) ss_time() - (INT) checked_last > check_interval) {
815 /* if condition is true, trigger alarm */
816 std::string condition = alarm["Condition"];
817 std::string value;
818 if (al_evaluate_condition(key.name, condition.c_str(), &value)) {
819 alarm["Checked last"] = (uint32_t)ss_time();
820 DWORD trigger_count = alarm["Trigger count"];
821 DWORD trigger_count_required = alarm["Trigger count required"];
822 alarm["Trigger count"] = ++trigger_count;
823 if (trigger_count >= trigger_count_required) {
824 alarm["Trigger count"] = (uint32_t)0;
825
826 std::string str = alarm["Alarm Message"];
827 size_t value_pos = str.find("%s");
828 if (value_pos != std::string::npos)
829 str.replace(value_pos, 2, value);
830 if (trigger_count_required > 0)
831 str += " (for more than " + std::to_string(trigger_count_required) + "*" +
832 std::to_string(check_interval) + " seconds)";
833 std::string alarm_class = alarm["Alarm Class"];
834 al_trigger_alarm(key.name, str.c_str(), alarm_class.c_str(), "", AT_EVALUATED);
835 }
836 } else {
837 alarm["Checked last"] = (uint32_t)ss_time();
838 alarm["Trigger count"] = (uint32_t)0;
839 }
840 }
841 }
842
843 /* check /programs alarms */
844 db_find_key(hDB, 0, "/Programs", &hkeyroot);
845 if (hkeyroot) {
846 for (int i = 0;; i++) {
847 status = db_enum_key(hDB, hkeyroot, i, &hkey);
849 break;
850
851 db_get_key(hDB, hkey, &key);
852
853 /* don't check "execute on xxx" */
854 if (key.type != TID_KEY)
855 continue;
856
857 midas::odb program_info("/Programs/" + std::string(key.name));
858
859 time_t now = ss_time();
860
861 // get name of this client
862 std::string name = rpc_get_name();
863 std::string str = name;
864
865 // truncate name of this client to the length of program name in /Programs/xxx
866 // to get rid if "odbedit1", "odbedit2", etc.
867 str.resize(strlen(key.name));
868
869 //printf("str [%s], key.name [%s]\n", str.c_str(), key.name);
870
871 // cm_exist() must be called with bUnique set to FALSE because we want
872 // the "program is not running" alarm check all
873 // alternative names "client", "client1", "client2", etc. K.O. Aug 2026
874
875 if (!equal_ustring(str.c_str(), key.name) && cm_exist(key.name, FALSE) == CM_NO_CLIENT) {
876 DWORD first_failed = program_info["First failed"];
877 if (first_failed == 0) {
878 first_failed = (DWORD) now;
879 program_info["First failed"] = first_failed;
880 }
881
882 // printf("check %d-%d = %d >= %d\n", now, program_info.first_failed, now - program_info.first_failed,
883 // program_info.check_interval / 1000);
884
885 /* fire alarm when not running for more than what specified in check interval */
886 DWORD check_interval = program_info["Check interval"];
887 if (now - first_failed >= check_interval / 1000) {
888 /* if not running and alarm class defined, trigger alarm */
889 std::string alarm_class = program_info["Alarm class"];
890 if (!alarm_class.empty()) {
891 std::string str = msprintf("Program %s is not running", key.name);
892 al_trigger_alarm(key.name, str.c_str(), alarm_class.c_str(), "Program not running", AT_PROGRAM);
893 }
894
895 /* auto restart program */
896 bool auto_restart = program_info["Auto restart"];
897 std::string start_command = program_info["Start command"];
898 if (auto_restart && !start_command.empty()) {
899 ss_system(start_command.c_str());
900 program_info["First failed"] = (uint32_t)0;
901 cm_msg(MTALK, "al_check", "Program %s restarted", key.name);
902 }
903 }
904 } else {
905 DWORD first_failed = program_info["First failed"];
906 if (first_failed != 0)
907 program_info["First failed"] = (uint32_t)0;
908 }
909 }
910 }
911
912 ss_semaphore_release(semaphore);
913 }
914#endif /* LOCAL_COUTINES */
915
916 return SUCCESS;
917}
#define FALSE
Definition cfortran.h:309
void connect_and_fix_structure(std::string path)
Definition odbxx.cxx:1472
void connect(const std::string &path, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults=false)
Definition odbxx.cxx:1390
static midas::odb al_make_alarm_odb(bool periodic=false)
Definition alarm.cxx:342
BOOL al_evaluate_condition(const char *alarm_name, const char *condition, std::string *pvalue)
Definition alarm.cxx:259
INT al_trigger_alarm(const char *alarm_name, const char *alarm_message, const char *default_class, const char *cond_str, INT type)
Definition alarm.cxx:396
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3049
INT cm_get_experiment_semaphore(INT *semaphore_alarm, INT *semaphore_elog, INT *semaphore_history, INT *semaphore_msg)
Definition midas.cxx:3071
INT cm_exist(const char *name, BOOL bClientName)
Definition midas.cxx:7562
#define CM_NO_CLIENT
Definition midas.h:584
#define DB_NO_MORE_SUBKEYS
Definition midas.h:647
#define SS_SUCCESS
Definition midas.h:664
#define SS_TIMEOUT
Definition midas.h:675
#define AL_SUCCESS
Definition midas.h:755
unsigned int DWORD
Definition mcstd.h:51
#define SUCCESS
Definition mcstd.h:54
#define TID_KEY
Definition midas.h:349
#define TID_BOOL
Definition midas.h:340
#define MERROR
Definition midas.h:559
#define MTALK
Definition midas.h:564
#define TID_INT
Definition midas.h:338
INT ss_semaphore_release(HNDLE semaphore_handle)
Definition system.cxx:2860
DWORD ss_time()
Definition system.cxx:3541
INT ss_semaphore_wait_for(HNDLE semaphore_handle, DWORD timeout_millisec)
Definition system.cxx:2718
INT ss_system(const char *command)
Definition system.cxx:2188
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:931
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3780
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5680
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6538
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4751
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5852
std::string rpc_get_name()
Definition midas.cxx:13285
bool rpc_is_remote(void)
Definition midas.cxx:12962
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:14185
#define RPC_AL_CHECK
Definition mrpc.h:114
HNDLE hDB
main ODB handle
Definition mana.cxx:207
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
DWORD auto_restart
Definition mfe.cxx:51
#define DWORD
Definition mhdump.cxx:31
std::string msprintf(const char *format,...)
Definition midas.cxx:419
INT HNDLE
Definition midas.h:132
DWORD BOOL
Definition midas.h:105
#define AT_PROGRAM
Definition midas.h:1442
int INT
Definition midas.h:129
#define AT_PERIODIC
Definition midas.h:1444
#define AT_LAST
Definition midas.h:1445
#define TRUE
Definition midas.h:182
#define AT_EVALUATED
Definition midas.h:1443
#define name(x)
Definition midas_macro.h:24
double value[100]
Definition odbhist.cxx:42
char str[256]
Definition odbhist.cxx:33
DWORD status
Definition odbhist.cxx:39
Definition midas.h:1027
DWORD type
Definition midas.h:1028
char name[NAME_LENGTH]
Definition midas.h:1030
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_define_odb_alarm()

INT EXPRT al_define_odb_alarm ( const char *  name,
const char *  condition,
const char *  aclass,
const char *  message 
)

Create an alarm that will trigger when an ODB condition is met.

Parameters
nameAlarm name, defined in /alarms/alarms
classAlarm class to be triggered
conditionAlarm condition to be evaluated
messageAlarm message
Returns
AL_SUCCESS

Definition at line 1001 of file alarm.cxx.

1001 {
1002 std::string str = msprintf("/Alarms/Alarms/%s", name);
1003
1004 midas::odb alarm = al_make_alarm_odb();
1005 alarm.connect(str);
1006 alarm["Condition"] = condition;
1007 alarm["Alarm Class"] = aclass;
1008 alarm["Alarm Message"] = message;
1009
1010 return AL_SUCCESS;
1011}
#define message(type, str)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_evaluate_condition()

BOOL al_evaluate_condition ( const char *  alarm_name,
const char *  condition,
std::string *  pvalue 
)

Definition at line 259 of file alarm.cxx.

260{
261 auto trim = [](const std::string& s) {
262 size_t first = s.find_first_not_of(" \t\r\n");
263 if (first == std::string::npos)
264 return std::string();
265 size_t last = s.find_last_not_of(" \t\r\n");
266 return s.substr(first, last - first + 1);
267 };
268
269 auto invalid_condition = [alarm_name, pvalue](const char* condition) {
270 cm_msg(MERROR, "al_evaluate_condition", "Alarm \"%s\": Invalid alarm condition \"%s\"",
271 alarm_name, condition ? condition : "");
272 if (pvalue)
273 *pvalue = "(invalid condition)";
274 return FALSE;
275 };
276
277 if (condition == nullptr || trim(condition).empty())
278 return invalid_condition(condition);
279
280 std::string expression(condition);
281 std::vector<std::vector<std::string>> groups;
282 size_t or_begin = 0;
283
284 // Split into OR groups and AND terms before evaluating anything, so
285 // malformed expressions are reported even if short-circuiting would
286 // otherwise skip the malformed part.
287 while (or_begin <= expression.size()) {
288 size_t or_end = expression.find("||", or_begin);
289 std::string group = expression.substr(or_begin, or_end - or_begin);
290 if (trim(group).empty())
291 return invalid_condition(condition);
292
293 std::vector<std::string> terms;
294 size_t and_begin = 0;
295 while (and_begin <= group.size()) {
296 size_t and_end = group.find("&&", and_begin);
297 std::string term = trim(group.substr(and_begin, and_end - and_begin));
298 if (term.empty())
299 return invalid_condition(condition);
300 terms.push_back(term);
301 if (and_end == std::string::npos)
302 break;
303 and_begin = and_end + 2;
304 }
305 groups.push_back(terms);
306
307 if (or_end == std::string::npos)
308 break;
309 or_begin = or_end + 2;
310 }
311
312 std::string all_values;
313 bool expression_result = false;
314
315 // Evaluate all terms so callers can display one current value per
316 // condition. Values are returned as one newline-separated string.
317 for (const auto& group : groups) {
318 bool group_result = true;
319 for (const auto& term : group) {
320 std::string term_value;
321 BOOL term_result = al_evaluate_single_condition(alarm_name, term.c_str(), &term_value);
322 if (!term_result)
323 group_result = false;
324 if (!all_values.empty())
325 all_values += "\n";
326 all_values += term_value;
327 }
328 if (group_result)
329 expression_result = true;
330 }
331
332 if (pvalue)
333 *pvalue = all_values;
334
335 return expression_result;
336}
static BOOL al_evaluate_single_condition(const char *alarm_name, const char *condition, std::string *pvalue)
Definition alarm.cxx:41
static te_expr * term(state *s)
Definition tinyexpr.c:539
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_evaluate_single_condition()

static BOOL al_evaluate_single_condition ( const char *  alarm_name,
const char *  condition,
std::string *  pvalue 
)
static

dox

Definition at line 41 of file alarm.cxx.

42{
43 int i, j, size, status;
44
45 //char str[256];
46 //strcpy(str, condition);
47
48 std::vector<char> buf;
49 buf.insert(buf.end(), condition, condition+strlen(condition)+1);
50 char* str = buf.data();
51
52 /* find value and operator */
53 char op[3];
54 op[0] = op[1] = op[2] = 0;
55 for (i = strlen(str) - 1; i > 0; i--)
56 if (strchr("<>=!&", str[i]) != NULL)
57 break;
58 op[0] = str[i];
59 for (j = 1; str[i + j] == ' '; j++)
60 ;
61
62 std::string value2_str = str + i + j;
63 double value2 = atof(value2_str.c_str());
64
65 str[i] = 0;
66
67 if (i > 0 && strchr("<>=!&", str[i - 1])) {
68 op[1] = op[0];
69 op[0] = str[--i];
70 str[i] = 0;
71 }
72
73 i--;
74 while (i > 0 && str[i] == ' ')
75 i--;
76 str[i + 1] = 0;
77
78 /* check if function */
79 std::string function;
80 if (str[i] == ')') {
81 str[i--] = 0;
82 if (strchr(str, '(')) {
83 *strchr(str, '(') = 0;
84 function = str;
85 for (i = strlen(str) + 1, j = 0; str[i]; i++, j++)
86 str[j] = str[i];
87 str[j] = 0;
88 i = j - 1;
89 }
90 }
91
92 std::vector<int> indices;
93 bool index_present = false;
94
95 // process indices
96 if (strchr(str, '[') && str[strlen(str)-1] == ']') {
97 index_present = true;
98
99 // Remove the square brackets from the string
100 std::string cleanInput = strchr(str, '[') + 1;
101 cleanInput.pop_back();
102
103 // Remove index from str
104 *strchr(str, '[') = 0;
105
106 // retrieve key
107 if (!midas::odb::exists(str)) {
108 cm_msg(MERROR, "al_evaluate_condition", "Alarm \"%s\": Cannot find ODB key \"%s\" to evaluate alarm condition", alarm_name, str);
109 if (pvalue)
110 *pvalue = "(cannot find in odb)";
111 return FALSE;
112 }
113 midas::odb k((const char *)str);
114
115 // Split the string by commas
116 std::stringstream ss(cleanInput);
117 std::string token;
118 while (std::getline(ss, token, ',')) {
119 // Remove whitespace
120 token.erase(std::remove_if(token.begin(), token.end(), ::isspace), token.end());
121
122 // Check if token is "*", if so set all indices
123 if (token == "*") {
124 for (int i = 0; i < k.get_num_values(); ++i)
125 indices.push_back(i);
126 } else {
127 // Check if the token represents a range (e.g., "4-7")
128 auto dashPos = token.find('-');
129 if (dashPos != std::string::npos) {
130 // Extract the start and end of the range
131 int start = std::stoi(token.substr(0, dashPos));
132 int end = std::stoi(token.substr(dashPos + 1));
133
134 // Add all numbers in the range [start, end]
135 for (int i = start; i <= end; ++i) {
136 indices.push_back(i);
137 }
138 } else {
139 // It's a single number, add it to the list
140 indices.push_back(std::stoi(token));
141 }
142 }
143 }
144 }
145
146 HNDLE hDB, hkey;
148 db_find_key(hDB, 0, str, &hkey);
149 if (!hkey) {
150 cm_msg(MERROR, "al_evaluate_condition", "Alarm \"%s\": Cannot find ODB key \"%s\" to evaluate alarm condition", alarm_name, str);
151 if (pvalue)
152 *pvalue = "(cannot find in odb)";
153 return FALSE;
154 }
155
156 KEY key;
157 db_get_key(hDB, hkey, &key);
158
159 //printf("Alarm \"%s\": [%s], idx1 %d, idx2 %d, op [%s], value2 [%s] %g, function [%s]\n", alarm_name, condition, idx1, idx2, op, value2_str.c_str(), value2, function.c_str());
160
161 // put at least one value into the indices
162 if (indices.empty())
163 indices.push_back(0);
164
165 // go through all indices
166 for (int idx : indices) {
167 std::string value1_str;
168 double value1 = 0;
169
170 if (equal_ustring(function.c_str(), "access")) {
171 /* check key access time */
172 DWORD dtime;
173 db_get_key_time(hDB, hkey, &dtime);
174 value1_str = msprintf("%d", dtime);
175 value1 = atof(value1_str.c_str());
176 } else if (equal_ustring(function.c_str(), "access_running")) {
177 /* check key access time if running */
178 DWORD dtime;
179 db_get_key_time(hDB, hkey, &dtime);
180 int state = 0;
181 size = sizeof(state);
182 db_get_value(hDB, 0, "/Runinfo/State", &state, &size, TID_INT, FALSE);
183 if (state == STATE_RUNNING) {
184 value1_str = msprintf("%d", dtime);
185 value1 = atof(value1_str.c_str());
186 } else {
187 value1_str = "0";
188 value1 = 0;
189 }
190 } else {
191 /* get key data and convert to double */
192 status = db_get_key(hDB, hkey, &key);
193 if (status != DB_SUCCESS) {
194 cm_msg(MERROR, "al_evaluate_condition", "Alarm \"%s\": Cannot get ODB key \"%s\" to evaluate alarm condition", alarm_name, str);
195 if (pvalue)
196 *pvalue = "(odb error)";
197 return FALSE;
198 } else {
199 char data[256];
200 size = sizeof(data);
201 status = db_get_data_index(hDB, hkey, data, &size, idx, key.type);
202 if (status != DB_SUCCESS) {
203 cm_msg(MERROR, "al_evaluate_condition", "Alarm \"%s\": Cannot get ODB value \"%s\" index %d to evaluate alarm condition", alarm_name, str, idx);
204 if (pvalue)
205 *pvalue = "(odb error)";
206 return FALSE;
207 }
208
209 value1_str = db_sprintf(data, size, 0, key.type);
210 value1 = atof(value1_str.c_str());
211 }
212 }
213
214 /* convert boolean values to integers */
215 if (key.type == TID_BOOL) {
216 value1 = (value1_str[0] == 'Y' || value1_str[0] == 'y' || value1_str[0] == '1');
217 value2 = (value2_str[0] == 'Y' || value2_str[0] == 'y' || value2_str[0] == '1');
218 }
219
220 /* return value */
221 if (pvalue) {
222 if (index_present)
223 *pvalue = msprintf("[%d] %s", idx, value1_str.c_str());
224 else
225 *pvalue = value1_str;
226 }
227
228 /* now do logical operation */
229 if (strcmp(op, "=") == 0)
230 if (value1 == value2)
231 return TRUE;
232 if (strcmp(op, "==") == 0)
233 if (value1 == value2)
234 return TRUE;
235 if (strcmp(op, "!=") == 0)
236 if (value1 != value2)
237 return TRUE;
238 if (strcmp(op, "<") == 0)
239 if (value1 < value2)
240 return TRUE;
241 if (strcmp(op, ">") == 0)
242 if (value1 > value2)
243 return TRUE;
244 if (strcmp(op, "<=") == 0)
245 if (value1 <= value2)
246 return TRUE;
247 if (strcmp(op, ">=") == 0)
248 if (value1 >= value2)
249 return TRUE;
250 if (strcmp(op, "&") == 0)
251 if (((unsigned int) value1 & (unsigned int) value2) > 0)
252 return TRUE;
253 }
254
255 return FALSE;
256}
static bool exists(const std::string &name)
Definition odbxx.cxx:76
#define DB_SUCCESS
Definition midas.h:632
#define STATE_RUNNING
Definition midas.h:307
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:7412
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
Definition odb.cxx:11426
INT db_get_key_time(HNDLE hDB, HNDLE hKey, DWORD *delta)
Definition odb.cxx:6651
void * data
Definition mana.cxx:268
#define end
INT j
Definition odbhist.cxx:40
INT k
Definition odbhist.cxx:40
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_get_alarms()

INT al_get_alarms ( std::string *  presult)

Scan ODB for alarms.

Returns
AL_SUCCESS

Definition at line 924 of file alarm.cxx.

925{
926 if (!presult)
927 return 0;
928
929 HNDLE hDB, hkey;
930
932 presult->clear();
933 int n = 0;
934 db_find_key(hDB, 0, "/Alarms/Alarms", &hkey);
935 if (hkey) {
936 /* check global alarm flag */
937 int flag = TRUE;
938 int size = sizeof(flag);
939 db_get_value(hDB, 0, "/Alarms/Alarm System active", &flag, &size, TID_BOOL, FALSE);
940 if (flag) {
941 for (int i = 0;; i++) {
942 HNDLE hsubkey;
943
944 db_enum_link(hDB, hkey, i, &hsubkey);
945
946 if (!hsubkey)
947 break;
948
949 KEY key;
950 db_get_key(hDB, hsubkey, &key);
951
952 flag = 0;
953 size = sizeof(flag);
954 db_get_value(hDB, hsubkey, "Triggered", &flag, &size, TID_INT, FALSE);
955 if (flag) {
956 n++;
957
958 std::string alarm_class, msg;
959 int alarm_type;
960
961 db_get_value_string(hDB, hsubkey, "Alarm Class", 0, &alarm_class);
962 db_get_value_string(hDB, hsubkey, "Alarm Message", 0, &msg);
963
964 size = sizeof(alarm_type);
965 db_get_value(hDB, hsubkey, "Type", &alarm_type, &size, TID_INT, FALSE);
966
967 std::string str;
968
969 if (alarm_type == AT_EVALUATED) {
970 db_get_value_string(hDB, hsubkey, "Condition", 0, &str);
971
972 /* retrieve value */
973 std::string value;
975 str = msprintf(msg.c_str(), value.c_str());
976 } else
977 str = msg;
978
979 *presult += alarm_class;
980 *presult += ": ";
981 *presult += str;
982 *presult += "\n";
983 }
984 }
985 }
986 }
987
988 return n;
989}
INT EXPRT db_get_value_string(HNDLE hdb, HNDLE hKeyRoot, const char *key_name, int index, std::string *s, BOOL create, int create_string_length)
Definition odb.cxx:14528
INT db_enum_link(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5990
DWORD n[4]
Definition mana.cxx:247
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_make_alarm_odb()

static midas::odb al_make_alarm_odb ( bool  periodic = false)
static

dox

Definition at line 342 of file alarm.cxx.

343{
344 std::string time_triggered(31, '\0');
345 std::string condition(255, '\0');
346 std::string alarm_class = periodic ? "Warning" : "Alarm";
347 std::string alarm_message = periodic ? "Please do your shift checks" : "Run number became too large";
348 alarm_class.resize(31, '\0');
349 alarm_message.resize(79, '\0');
350
351 midas::odb alarm = {
352 {"Active", false},
353 {"Triggered", 0},
354 {"Type", periodic ? AT_PERIODIC : AT_EVALUATED},
355 {"Check interval", periodic ? 28800 : 60},
356 {"Checked last", (uint32_t)0},
357 {"Trigger count", (uint32_t)0},
358 {"Trigger count required", (uint32_t)0},
359 {"Time triggered first", time_triggered},
360 {"Time triggered last", time_triggered},
361 {"Condition", condition},
362 {"Alarm Class", alarm_class},
363 {"Alarm Message", alarm_message}
364 };
365
366 if (!periodic) {
367 condition.replace(0, strlen("/Runinfo/Run number > 100"), "/Runinfo/Run number > 100");
368 alarm["Condition"].set(condition);
369 }
370
371 return alarm;
372}
void set(std::string str)
Definition odbxx.cxx:1597
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_reset_alarm()

INT al_reset_alarm ( const char *  alarm_name)

dox Reset (acknoledge) alarm.

Parameters
alarm_nameAlarm name, defined in /alarms/alarms
Returns
AL_SUCCESS, AL_RESETE, AL_INVALID_NAME

Definition at line 605 of file alarm.cxx.

605 {
606 int i;
607 HNDLE hDB, hkeyalarm, hsubkey;
608 KEY key;
609
611
612 if (alarm_name == NULL) {
613 /* reset all alarms */
614 db_find_key(hDB, 0, "/Alarms/Alarms", &hkeyalarm);
615 if (hkeyalarm) {
616 for (i = 0;; i++) {
617 db_enum_link(hDB, hkeyalarm, i, &hsubkey);
618
619 if (!hsubkey)
620 break;
621
622 db_get_key(hDB, hsubkey, &key);
624 }
625 }
626 return AL_SUCCESS;
627 }
628
629 /* find alarm and alarm class */
630 std::string str = msprintf("/Alarms/Alarms/%s", alarm_name);
631 db_find_key(hDB, 0, str.c_str(), &hkeyalarm);
632 if (!hkeyalarm) {
633 /*cm_msg(MERROR, "al_reset_alarm", "Alarm %s not found in ODB", alarm_name);*/
634 return AL_INVALID_NAME;
635 }
636
639
640 std::string alarm_class = alarm["Alarm Class"];
641 str = msprintf("/Alarms/Classes/%s", alarm_class.c_str());
642 if (!midas::odb::exists(str)) {
643 cm_msg(MERROR, "al_reset_alarm", "Alarm class %s not found in ODB", alarm_class.c_str());
644 return AL_INVALID_NAME;
645 }
646
647 midas::odb ac(str);
648
649 int triggered = alarm["Triggered"];
650 if (triggered) {
651 int alarm_type = alarm["Type"];
652 if (alarm_type == AT_PERIODIC) {
653
654 // set checked_last to occurrence of alarm, to get exactly one period until next alarm
655
656 struct tm tm_time;
657 memset(&tm_time, 0, sizeof(tm_time));
658
659 std::string time_triggered_first = alarm["Time triggered first"];
660 strptime(time_triggered_first.c_str(), "%a %b %d %H:%M:%S %Y", &tm_time);
661 time_t t = mktime(&tm_time);
662
663 int check_interval = alarm["Check interval"];
664 while ((int)ss_time() > t + check_interval)
665 t += check_interval;
666
667 alarm["Checked last"] = (uint32_t)t;
668 } else {
669 alarm["Checked last"] = (uint32_t)0;
670 }
671
672 alarm["Triggered"] = 0;
673 alarm["Time triggered first"] = "";
674 alarm["Time triggered last"] = "";
675 alarm["Trigger count"] = (uint32_t)0;
676
677 ac["System message last"] = (uint32_t)0;
678 ac["Execute last"] = (uint32_t)0;
679
680 cm_msg(MINFO, "al_reset_alarm", "Alarm \"%s\" reset", alarm_name);
681 return AL_RESET;
682 }
683
684 return AL_SUCCESS;
685}
INT al_reset_alarm(const char *alarm_name)
Definition alarm.cxx:605
#define AL_INVALID_NAME
Definition midas.h:756
#define AL_RESET
Definition midas.h:758
#define MINFO
Definition midas.h:560
MUTEX_T * tm
Definition odbedit.cxx:39
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_trigger_alarm()

INT al_trigger_alarm ( const char *  alarm_name,
const char *  alarm_message,
const char *  default_class,
const char *  cond_str,
INT  type 
)

Trigger a certain alarm.

...
lazy.alarm[0] = 0;
size = sizeof(lazy.alarm);
db_get_value(hDB, pLch->hKey, "Settings/Alarm Class", lazy.alarm, &size, TID_STRING, TRUE);
// trigger alarm if defined
if (lazy.alarm[0])
al_trigger_alarm("Tape", "Tape full...load new one!", lazy.alarm, "Tape full", AT_INTERNAL);
...
#define TID_STRING
Definition midas.h:346
LAZY_SETTING lazy
#define AT_INTERNAL
Definition midas.h:1441
char alarm[32]
Parameters
alarm_nameAlarm name, defined in /alarms/alarms
alarm_messageOptional message which goes with alarm
default_classIf alarm is not yet defined under /alarms/alarms/<alarm_name>, a new one is created and this default class is used.
cond_strString displayed in alarm condition
typeAlarm type, one of AT_xxx
Returns
AL_SUCCESS, AL_INVALID_NAME

Definition at line 396 of file alarm.cxx.

397 {
398 if (rpc_is_remote())
399 return rpc_call(RPC_AL_TRIGGER_ALARM, alarm_name, alarm_message, default_class, cond_str, type);
400
401#ifdef LOCAL_ROUTINES
402 {
403 int size;
404 HNDLE hDB, hkey;
405 BOOL flag;
406
408
409 /* check online mode */
410 flag = TRUE;
411 size = sizeof(flag);
412 db_get_value(hDB, 0, "/Runinfo/Online Mode", &flag, &size, TID_INT, TRUE);
413 if (!flag)
414 return AL_SUCCESS;
415
416 /* find alarm */
417 std::string alarm_path = msprintf("/Alarms/Alarms/%s", alarm_name);
418
419 bool new_alarm = !midas::odb::exists(alarm_path);
421 alarm.connect_and_fix_structure(alarm_path);
422 if (new_alarm) {
423 /* alarm must be an internal analyzer alarm, so create a default alarm */
424 if (default_class && default_class[0])
425 alarm["Alarm Class"] = default_class;
426 alarm["Active"] = true;
427 }
428
429 /* set parameters for internal alarms */
430 if (type != AT_EVALUATED && type != AT_PERIODIC) {
431 alarm["Type"] = type;
432 alarm["Condition"] = cond_str;
433 }
434
435 int alarm_type = alarm["Type"];
436
437 /* if internal alarm, check if active and check interval */
438 if (alarm_type != AT_EVALUATED && alarm_type != AT_PERIODIC) {
439 /* check global alarm flag */
440 flag = TRUE;
441 size = sizeof(flag);
442 db_get_value(hDB, 0, "/Alarms/Alarm system active", &flag, &size, TID_BOOL, TRUE);
443 if (!flag)
444 return AL_SUCCESS;
445
446 if (!(bool)alarm["Active"])
447 return AL_SUCCESS;
448
449 DWORD checked_last = alarm["Checked last"];
450 int check_interval = alarm["Check interval"];
451 if ((INT) ss_time() - (INT) checked_last < check_interval)
452 return AL_SUCCESS;
453 }
454
455 std::string alarm_class = alarm["Alarm Class"];
456 if (alarm_type == AT_PROGRAM) {
457 /* alarm class of "program not running" alarms is set in two places,
458 * complain if they do not match */
459 if (!equal_ustring(alarm_class.c_str(), default_class)) {
460 cm_msg(MERROR, "al_trigger_alarm",
461 "Program alarm class mismatch: \"%s/Alarm class\" set to \"%s\" does not match \"/Programs/%s/Alarm "
462 "Class\" set to \"%s\"",
463 alarm_path.c_str(), alarm_class.c_str(), alarm_name, default_class);
464 }
465 }
466
467 /* write back alarm message for internal alarms */
468 if (alarm_type != AT_EVALUATED && alarm_type != AT_PERIODIC)
469 alarm["Alarm Message"] = alarm_message;
470
471 /* now trigger alarm class defined in this alarm */
472 int triggered = alarm["Triggered"];
473 if (!alarm_class.empty())
474 al_trigger_class(alarm_class.c_str(), alarm_message, triggered > 0);
475
476 /* check for and trigger "All" class */
477 if (db_find_key(hDB, 0, "/Alarms/Classes/All", &hkey) == DB_SUCCESS)
478 al_trigger_class("All", alarm_message, triggered > 0);
479
480 /* signal alarm being triggered */
481 std::string now = cm_asctime();
482
483 if (!triggered)
484 alarm["Time triggered first"] = now;
485
486 alarm["Triggered"] = ++triggered;
487 alarm["Time triggered last"] = now;
488 alarm["Checked last"] = (uint32_t)ss_time();
489 }
490#endif /* LOCAL_ROUTINES */
491
492 return AL_SUCCESS;
493}
INT al_trigger_class(const char *alarm_class, const char *alarm_message, BOOL first)
Definition alarm.cxx:499
std::string cm_asctime()
Definition midas.cxx:1428
#define RPC_AL_TRIGGER_ALARM
Definition mrpc.h:115
INT type
Definition mana.cxx:269
Here is the call graph for this function:
Here is the caller graph for this function:

◆ al_trigger_class()

INT al_trigger_class ( const char *  alarm_class,
const char *  alarm_message,
BOOL  first 
)

dox

Definition at line 499 of file alarm.cxx.

520{
521 int size, state;
522 HNDLE hDB;
523 DWORD now = ss_time();
524
526
527 /* get alarm class */
528 std::string alarm_path = msprintf("/Alarms/Classes/%s", alarm_class);
529 if (!midas::odb::exists(alarm_path)) {
530 cm_msg(MERROR, "al_trigger_class", "Alarm class \"%s\" for alarm \"%s\" not found in ODB", alarm_class, alarm_message);
531 return AL_INVALID_NAME;
532 }
533
534 midas::odb ac(alarm_path);
535
536 std::string msg;
537
538 /* write system message */
539 bool write_system_message = ac["Write system message"];
540 int system_message_interval = ac["System message interval"];
541 DWORD system_message_last = ac["System message last"];
542 if (write_system_message && (now - system_message_last >= (DWORD) system_message_interval)) {
543 if (equal_ustring(alarm_class, "All"))
544 msg = msprintf("General alarm: %s", alarm_message);
545 else
546 msg = msprintf("%s: %s", alarm_class, alarm_message);
547 cm_msg(MTALK, "al_trigger_class", "%s", msg.c_str());
548 system_message_last = now;
549 ac["System message last"] = (uint32_t)system_message_last;
550 }
551
552 /* write elog message on first trigger if using internal ELOG */
553 if ((bool)ac["Write Elog message"] && first) {
554 BOOL external_elog = FALSE;
555 size = sizeof(external_elog);
556 db_get_value(hDB, 0, "/Elog/External Elog", &external_elog, &size, TID_BOOL, FALSE);
557 if (!external_elog) {
558 char tag[32];
559 tag[0] = 0;
560 el_submit(0, "Alarm system", "Alarm", "General", alarm_class, msg.c_str(), "", "plain", "", "", 0, "", "", 0, "", "", 0, tag, sizeof(tag));
561 }
562 }
563
564 /* execute command */
565 std::string execute_command = ac["Execute command"];
566 int execute_interval = ac["Execute interval"];
567 DWORD execute_last = ac["Execute last"];
568 if (!execute_command.empty() && execute_interval > 0 && (INT) ss_time() - (INT) execute_last > execute_interval) {
569 if (equal_ustring(alarm_class, "All"))
570 msg = msprintf("General alarm: %s", alarm_message);
571 else
572 msg = msprintf("%s: %s", alarm_class, alarm_message);
573 std::string command = msprintf(execute_command.c_str(), msg.c_str());
574 cm_msg(MINFO, "al_trigger_class", "Execute: %s", command.c_str());
575 ss_system(command.c_str());
576 execute_last = ss_time();
577 ac["Execute last"] = (uint32_t)execute_last;
578 }
579
580 /* stop run */
581 if ((bool)ac["Stop run"]) {
583 size = sizeof(state);
584 db_get_value(hDB, 0, "/Runinfo/State", &state, &size, TID_INT, TRUE);
585 if (state != STATE_STOPPED) {
586 cm_msg(MINFO, "al_trigger_class", "Stopping the run from alarm class \'%s\', message \'%s\'", alarm_class,
587 alarm_message);
588 cm_transition(TR_STOP, 0, NULL, 0, TR_DETACH, FALSE);
589 }
590 }
591
592 return AL_SUCCESS;
593}
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5326
INT el_submit(int run, const char *author, const char *type, const char *syst, const char *subject, const char *text, const char *reply_to, const char *encoding, const char *afilename1, const char *buffer1, INT buffer_size1, const char *afilename2, const char *buffer2, INT buffer_size2, const char *afilename3, const char *buffer3, INT buffer_size3, char *tag, INT tag_size)
Definition elog.cxx:126
#define STATE_STOPPED
Definition midas.h:305
#define TR_DETACH
Definition midas.h:360
#define TR_STOP
Definition midas.h:406
Here is the call graph for this function:
Here is the caller graph for this function: