35#if !defined(OS_VXWORKS)
43#ifndef DOXYGEN_SHOULD_SKIP_THIS
51static bool xwrite(
const std::string& fn,
int fh,
const void *buf,
size_t count)
56 cm_msg(
MERROR,
"xwrite",
"Error writing %d bytes to file \"%s\" errno %d (%s)", (
int)
count, fn.c_str(), errno, strerror(errno));
60 if ((
size_t)wr !=
count) {
61 cm_msg(
MERROR,
"xwrite",
"Error writing %d bytes to file \"%s\", short write %d bytes", (
int)
count, fn.c_str(), (
int)wr);
73static int xread(
const std::string& fn,
int fh,
void *buf,
size_t count,
bool eof_ok =
false)
78 cm_msg(
MERROR,
"xread",
"Error reading from file \"%s\" errno %d (%s)", fn.c_str(), errno, strerror(errno));
85 cm_msg(
MERROR,
"xread",
"Error: Unexpected end-of-file when reading file \"%s\"", fn.c_str());
89 if ((
size_t)rd !=
count) {
90 cm_msg(
MERROR,
"xread",
"Error: Truncated read from file \"%s\", requested %d bytes, read %d bytes", fn.c_str(), (
int)
count, (
int)rd);
97static bool xseek(
const std::string& fn,
int fh,
DWORD pos)
99 off_t off = lseek(fh, pos, SEEK_SET);
102 cm_msg(
MERROR,
"xseek",
"Error in lseek(%llu, SEEK_SET) for file \"%s\", errno %d (%s)", (
unsigned long long)pos, fn.c_str(), errno, strerror(errno));
111 off_t off = lseek(fh, 0, SEEK_END);
114 cm_msg(
MERROR,
"xseek_end",
"Error in lseek(SEEK_END) to end-of-file for file \"%s\", errno %d (%s)", fn.c_str(), errno, strerror(errno));
123 off_t off = lseek(fh,
offset, SEEK_CUR);
126 cm_msg(
MERROR,
"xseek_cur",
"Error in lseek(%d, SEEK_CUR) for file \"%s\", errno %d (%s)",
offset, fn.c_str(), errno, strerror(errno));
135 off_t off = lseek(fh, 0, SEEK_CUR);
138 cm_msg(
MERROR,
"xcurpos",
"Error in lseek(0, SEEK_CUR) for file \"%s\", errno %d (%s)", fn.c_str(), errno, strerror(errno));
145 cm_msg(
MERROR,
"xcurpos",
"Error: lseek(0, SEEK_CUR) for file \"%s\" returned value %llu does not fir into a DWORD, maybe file is bigger than 2GiB or 4GiB", fn.c_str(), (
unsigned long long)off);
154 off_t off = lseek(fh, pos, SEEK_SET);
157 cm_msg(
MERROR,
"xtruncate",
"Error in lseek(%llu) for file \"%s\", errno %d (%s)", (
unsigned long long)pos, fn.c_str(), errno, strerror(errno));
161 int status = ftruncate(fh, pos);
164 cm_msg(
MERROR,
"xtruncate",
"Error setting file size of \"%s\" to %llu, errno %d (%s)", fn.c_str(), (
unsigned long long)pos, errno, strerror(errno));
181 assert(path[0] != 0);
193#ifndef DOXYGEN_SHOULD_SKIP_THIS
213 ttime = (time_t) ltime;
214 localtime_r(&ttime, &tms);
220 sprintf(tmp,
"%02d%02d%02d", tms.tm_year % 100, tms.tm_mon + 1, tms.tm_mday);
266 cm_msg(
MINFO,
"hs_gen_index",
"generating index files for time %d", (
int) ltime);
267 printf(
"Recovering index files...\n");
270 ltime = (
DWORD) time(NULL);
277 hs_open_file(ltime,
"idx", O_RDWR | O_CREAT | O_TRUNC, &fni, &fhi);
278 hs_open_file(ltime,
"idf", O_RDWR | O_CREAT | O_TRUNC, &fnd, &fhd);
280 if (fhd < 0 || fhi < 0) {
281 cm_msg(
MERROR,
"hs_gen_index",
"cannot create index file");
293 if (
xread(fn, fh, (
char *) &rec,
sizeof(rec),
true) <= 0) {
298 if (rec.record_type ==
RT_DEF) {
300 if (
xread(fn, fh, event_name,
sizeof(event_name)) < 0)
303 printf(
"Event definition %s, ID %d\n", event_name, rec.event_id);
307 memcpy(def_rec.
event_name, event_name,
sizeof(event_name));
310 def_rec.
def_offset = pos -
sizeof(event_name) -
sizeof(rec);
311 xwrite(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec));
317 }
else if (rec.record_type ==
RT_DATA && rec.data_size > 1 && rec.data_size < 1 * 1024 * 1024) {
320 irec.
time = rec.time;
323 irec.
offset = pos -
sizeof(rec);
324 xwrite(fni, fhi, (
char *) &irec,
sizeof(irec));
332 cm_msg(
MERROR,
"hs_gen_index",
"broken history file for time %d, trying to recover", (
int) ltime);
346 printf(
"...done.\n");
384 lt = (time_t) * ltime;
391 lt += direction * 3600 * 24;
394 }
while (fh < 0 && (
INT) * ltime - (
INT) lt < 3600 * 24 * 365 && lt <= (time_t)
ss_time());
399 if (lt != (time_t) *ltime) {
402 localtime_r(<, &tms);
403 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
419 if (fhd < 0 || fhi < 0)
465 std::string fn, fni, fnd;
521 if (fh_pos > 0 && fhd_pos == 0) {
534 ltime = (time_t) rec.
time;
536 localtime_r(<ime, &tmb);
537 tmb.tm_hour = tmb.tm_min = tmb.tm_sec = 0;
560 n = fhd_pos /
sizeof(def_rec);
562 for (
int i =
n - 1;
i >= 0;
i--) {
573 memset(buffer, 0, size);
576 xread(fn, fh, (
char *) &prev_rec,
sizeof(prev_rec));
578 xread(fn, fh, buffer, size);
581 if (prev_rec.data_size != size || strcmp(
str, event_name) != 0 || memcmp(buffer, tag, size) != 0) {
583 xwrite(fn, fh, (
char *) &rec,
sizeof(rec));
585 xwrite(fn, fh, (
char *) tag, size);
589 memcpy(def_rec.
event_name, event_name,
sizeof(event_name));
591 xwrite(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec));
599 xwrite(fn, fh, (
char *) &rec,
sizeof(rec));
601 xwrite(fn, fh, (
char *) tag, size);
605 memcpy(def_rec.
event_name, event_name,
sizeof(event_name));
607 xwrite(fn, fhd, (
char *) &def_rec,
sizeof(def_rec));
617 memset(buffer, 0, size);
620 xread(fn, fh, (
char *) &prev_rec,
sizeof(prev_rec));
622 xread(fn, fh, buffer, size);
627 if (prev_rec.data_size != size || strcmp(
str, event_name) != 0 || memcmp(buffer, tag, size) != 0) {
634 xwrite(fn, fh, (
char *) &rec,
sizeof(rec));
636 xwrite(fn, fh, (
char *) tag, size);
640 memcpy(def_rec.
event_name, event_name,
sizeof(event_name));
642 xwrite(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec));
684 DWORD last_pos_data, last_pos_index;
685 std::string fn, fni, fnd;
722 ltime = (time_t) rec.
time;
723 localtime_r(<ime, &tmr);
725 localtime_r(<ime, &tmb);
727 if (tmr.tm_yday != tmb.tm_yday) {
770 tmr.tm_hour = tmr.tm_min = tmr.tm_sec = 0;
779 xwrite(fn, fh, (
char *) &drec,
sizeof(drec));
787 xwrite(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec));
808 int size_of_irec =
sizeof(irec);
854 cm_msg(
MERROR,
"hs_enum_events",
"cannot find recent history file");
861 if (fh < 0 || fhd < 0) {
862 cm_msg(
MERROR,
"hs_enum_events",
"cannot open index files");
871 if (
xread(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec),
true) <= 0)
875 for (
i = 0;
i <
n;
i++)
877 strcpy(event_name +
i *
NAME_LENGTH, def_rec.event_name);
884 cm_msg(
MERROR,
"hs_enum_events",
"index buffer too small");
891 strcpy(event_name +
i *
NAME_LENGTH, def_rec.event_name);
900 *id_size =
n *
sizeof(
INT);
935 cm_msg(
MERROR,
"hs_count_events",
"cannot find recent history file");
942 if (fh < 0 || fhd < 0) {
943 cm_msg(
MERROR,
"hs_count_events",
"cannot open index files");
958 if (
xread(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec),
true) <= 0)
962 for (
i = 0;
i <
n;
i++)
963 if (
id[
i] == def_rec.event_id)
968 id[
i] = def_rec.event_id;
1006 std::string fn, fnd;
1013 ltime = (
DWORD) time(NULL);
1020 cm_msg(
MERROR,
"hs_count_events",
"cannot find recent history file");
1027 if (fh < 0 || fhd < 0) {
1028 cm_msg(
MERROR,
"hs_count_events",
"cannot open index files");
1036 if (
xread(fnd, fhd, (
char *) &def_rec,
sizeof(def_rec),
true) <= 0)
1039 if (strcmp(
name, def_rec.event_name) == 0) {
1040 *
id = def_rec.event_id;
1053 }
while (lt > ltime - 3600 * 24 * 365 * 10);
1080 std::string fn, fnd;
1088 cm_msg(
MERROR,
"hs_count_tags",
"cannot find recent history file");
1095 if (fh < 0 || fhd < 0) {
1096 cm_msg(
MERROR,
"hs_count_tags",
"cannot open index files");
1102 n =
xcurpos(fnd, fhd) /
sizeof(def_rec);
1104 for (
i =
n - 1;
i >= 0;
i--) {
1117 xread(fn, fh, (
char *) &rec,
sizeof(rec));
1154 std::string fn, fnd;
1163 cm_msg(
MERROR,
"hs_enum_vars",
"cannot find recent history file");
1170 if (fh < 0 || fhd < 0) {
1171 cm_msg(
MERROR,
"hs_enum_vars",
"cannot open index files");
1177 n =
xcurpos(fnd, fhd) /
sizeof(def_rec);
1179 for (
i =
n - 1;
i >= 0;
i--) {
1192 xread(fn, fh, (
char *) &rec,
sizeof(rec));
1208 cm_msg(
MERROR,
"hs_enum_vars",
"tag buffer too small");
1216 for (
i = 0;
i <
n;
i++) {
1221 *n_size =
n *
sizeof(
DWORD);
1258 std::string fn, fnd;
1267 cm_msg(
MERROR,
"hs_get_var",
"cannot find recent history file");
1274 if (fh < 0 || fhd < 0) {
1275 cm_msg(
MERROR,
"hs_get_var",
"cannot open index files");
1281 n =
xcurpos(fnd, fhd) /
sizeof(def_rec);
1283 for (
i =
n - 1;
i >= 0;
i--) {
1296 xread(fn, fh, (
char *) &rec,
sizeof(rec));
1305 for (
i = 0;
i <
n;
i++)
1316 *
type = *n_data = 0;
1353 std::string fn, fnd;
1362 assert(!
"RPC not implemented");
1367 cm_msg(
MERROR,
"hs_get_tags",
"cannot find recent history file, hs_search_file() status %d",
status);
1374 if (fh < 0 || fhd < 0) {
1375 cm_msg(
MERROR,
"hs_get_tags",
"cannot open index files for time %d", ltime);
1385 n =
xcurpos(fnd, fhd) /
sizeof(def_rec);
1387 for (
i =
n - 1;
i >= 0;
i--) {
1428 return *(((
BYTE *) ybuffer) +
j);
1430 return *(((
char *) ybuffer) +
j);
1432 return *(((
char *) ybuffer) +
j);
1434 return *(((
WORD *) ybuffer) +
j);
1436 return *(((
short *) ybuffer) +
j);
1438 return *(((
DWORD *) ybuffer) +
j);
1440 return *(((
INT *) ybuffer) +
j);
1442 return *(((
BOOL *) ybuffer) +
j);
1444 return *(((
float *) ybuffer) +
j);
1446 return *(((
double *) ybuffer) +
j);
1451static INT hs_read(
DWORD event_id,
DWORD start_time,
DWORD end_time,
DWORD interval,
const char *tag_name,
DWORD var_index,
DWORD * time_buffer,
DWORD * tbsize,
void *data_buffer,
DWORD * dbsize,
DWORD * data_type,
DWORD * data_n,
MidasHistoryBufferInterface* buffer)
1488 DWORD prev_time, last_irec_time;
1489 int fh, fhd, fhi, cp = 0;
1490 std::string fn, fnd, fni;
1504 unsigned var_size = 0;
1505 unsigned var_offset = 0;
1514 if (start_time == 0)
1515 start_time = (
DWORD) time(NULL) - 3600;
1517 end_time = (
DWORD) time(NULL);
1522 last_irec_time = start_time;
1541 if (fh < 0 || fhd < 0 || fhi < 0) {
1560 cache_size =
xcurpos(fni, fhi);
1562 if (cache_size == 0) {
1566 if (cache_size > 0) {
1567 cache = (
char *)
M_MALLOC(cache_size);
1570 if (
xread(fni, fhi, cache, cache_size) < 0) {
1583 if (cache == NULL) {
1585 delta = (
xcurpos(fni, fhi) /
sizeof(irec)) / 2;
1586 xseek(fni, fhi, delta *
sizeof(irec));
1588 delta = (int) (abs(delta) / 2.0 + 0.5);
1589 if (
xread(fni, fhi, (
char *) &irec,
sizeof(irec)) < 0)
1591 if (irec.time > start_time)
1594 xseek_cur(fni, fhi, (delta - 1) *
sizeof(irec));
1595 }
while (abs(delta) > 1 && irec.
time != start_time);
1596 if (
xread(fni, fhi, (
char *) &irec,
sizeof(irec)) < 0)
1598 if (irec.time > start_time)
1599 delta = -abs(delta);
1601 int i =
xcurpos(fni, fhi) + (delta - 1) *
sizeof(irec);
1605 xseek_cur(fni, fhi, (delta - 1) *
sizeof(irec));
1606 if (
xread(fni, fhi, (
char *) &irec,
sizeof(irec)) < 0)
1609 delta = (cache_size /
sizeof(irec)) / 2;
1610 cp = delta *
sizeof(irec);
1612 delta = (int) (abs(delta) / 2.0 + 0.5);
1617 if (pirec->
time > start_time)
1620 cp = cp + delta *
sizeof(irec);
1624 if (cp >= cache_size)
1625 cp = cache_size -
sizeof(irec);
1626 }
while (abs(delta) > 1 && pirec->
time != start_time);
1628 if (pirec->
time > start_time)
1629 delta = -abs(delta);
1631 if (cp <= delta * (
int)
sizeof(irec))
1634 cp = cp + delta *
sizeof(irec);
1636 if (cp >= cache_size)
1637 cp = cache_size -
sizeof(irec);
1641 memcpy(&irec, (
INDEX_RECORD *) (cache + cp),
sizeof(irec));
1647 irec.
time = start_time;
1651 old_def_offset = -1;
1652 last_irec_time = start_time - 24 * 60 * 60;
1656 if (irec.
time < last_irec_time) {
1657 cm_msg(
MERROR,
"hs_read",
"corrupted history data: time does not increase: %d -> %d", last_irec_time, irec.
time);
1668 last_irec_time = irec.
time;
1671 if (irec.
time >= prev_time + interval) {
1672 prev_time = irec.
time;
1674 if (
xread(fn, fh, (
char *) &rec,
sizeof(rec)) < 0) {
1675 cm_msg(
MERROR,
"hs_read",
"corrupted history data at time %d", (
int) irec.
time);
1688 if ((
INT) rec.def_offset != old_def_offset) {
1689 xseek(fn, fh, rec.def_offset);
1690 xread(fn, fh, (
char *) &drec,
sizeof(drec));
1711 xread(fn, fh, (
char *) tag, drec.data_size);
1714 for (
DWORD i = 0;
i < drec.data_size /
sizeof(
TAG);
i++)
1731 if (tag_index >= 0 && var_index >= tag[tag_index].n_data) {
1751 if (tag_index >= 0) {
1752 var_type = tag[tag_index].type;
1755 *data_type = var_type;
1759 for (
int i=0;
i<tag_index;
i++)
1764 var_size = tag[tag_index].n_data;
1768 var_offset += var_size * var_index;
1772 old_def_offset = rec.def_offset;
1780 assert(var_size <=
sizeof(buf));
1782 xread(fn, fh, buf, var_size);
1784 }
else if (tag_index >= 0 && data_n) {
1786 if ((*data_n) *
sizeof(
DWORD) >= *tbsize || (*data_n) * var_size >= *dbsize) {
1787 *dbsize = (*data_n) * var_size;
1788 *tbsize = (*data_n) *
sizeof(
DWORD);
1801 time_buffer[*data_n] = irec.
time;
1805 xread(fn, fh, (
char *) data_buffer + (*data_n) * var_size, var_size);
1815 if (cp >= cache_size) {
1823 ieof =
sizeof(irec);
1825 memcpy(&irec, cache + cp,
sizeof(irec));
1829 if (irec.
time < last_irec_time || irec.
time > last_irec_time + 24 * 60 * 60) {
1835 while (cp < cache_size) {
1849 ieof =
xread(fni, fhi, (
char *) &irec,
sizeof(irec),
true);
1865 ltime = (time_t) last_irec_time;
1867 localtime_r(<ime, &tms);
1868 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
1871 last_irec_time += 3600 * 24;
1873 if (last_irec_time > end_time)
1882 hs_open_file(last_irec_time,
"hst", O_RDONLY, &fn, &fh);
1883 hs_open_file(last_irec_time,
"idf", O_RDONLY, &fnd, &fhd);
1884 hs_open_file(last_irec_time,
"idx", O_RDONLY, &fni, &fhi);
1885 if (fh < 0 || fhd < 0 || fhi < 0) {
1892 cache_size =
xcurpos(fni, fhi);
1894 if (cache_size == 0) {
1899 cache = (
char *)
M_MALLOC(cache_size);
1901 if (
xread(fni, fhi, cache, cache_size) < 0) {
1906 memcpy(&irec, cache,
sizeof(irec));
1909 if (
xread(fni, fhi, (
char *) &irec,
sizeof(irec)) < 0) {
1915 old_def_offset = -1;
1919 }
while (irec.
time < end_time);
1930 if (dbsize && data_n)
1931 *dbsize = *data_n * var_size;
1932 if (tbsize && data_n)
1933 *tbsize = *data_n *
sizeof(
DWORD);
1956 DWORD prev_time, last_irec_time;
1959 std::string fn, fnd, fni;
1960 INT i,
j, delta,
status, n_tag = 0, old_n_tag = 0;
1964 TAG *tag = NULL, *old_tag = NULL;
1965 char data_buffer[10000];
1970 if (start_time == 0)
1971 start_time = (
DWORD) time(NULL) - 3600;
1973 end_time = (
DWORD) time(NULL);
1978 cm_msg(
MERROR,
"hs_dump",
"cannot find recent history file");
1986 if (fh < 0 || fhd < 0 || fhi < 0) {
1993 delta = (
xcurpos(fni, fhi) /
sizeof(irec)) / 2;
1994 xseek(fni, fhi, delta *
sizeof(irec));
1996 delta = (int) (abs(delta) / 2.0 + 0.5);
1997 xread(fni, fhi, (
char *) &irec,
sizeof(irec));
1998 if (irec.time > start_time)
2001 xseek_cur(fni, fhi, (delta - 1) *
sizeof(irec));
2002 }
while (abs(delta) > 1 && irec.
time != start_time);
2003 xread(fni, fhi, (
char *) &irec,
sizeof(irec));
2004 if (irec.
time > start_time)
2005 delta = -abs(delta);
2007 i =
xcurpos(fni, fhi) + (delta - 1) *
sizeof(irec);
2011 xseek_cur(fni, fhi, (delta - 1) *
sizeof(irec));
2012 xread(fni, fhi, (
char *) &irec,
sizeof(irec));
2015 old_def_offset = -1;
2019 if (irec.
time < last_irec_time) {
2020 cm_msg(
MERROR,
"hs_dump",
"corrupted history data: time does not increase: %d -> %d", last_irec_time, irec.
time);
2024 last_irec_time = irec.
time;
2026 if (irec.
time >= prev_time + interval) {
2027 prev_time = irec.
time;
2029 xread(fn, fh, (
char *) &rec,
sizeof(rec));
2032 if ((
INT) rec.def_offset != old_def_offset) {
2034 xseek(fn, fh, rec.def_offset);
2035 xread(fn, fh, (
char *) &drec,
sizeof(drec));
2041 tag = (
TAG *) realloc(tag, drec.data_size);
2044 xread(fn, fh, (
char *) tag, drec.data_size);
2045 n_tag = drec.data_size /
sizeof(
TAG);
2048 if (old_tag == NULL || old_n_tag != n_tag || memcmp(old_tag, tag, drec.data_size) != 0) {
2050 for (
i = 0;
i < n_tag;
i++) {
2052 printf(
"%s\t", tag[
i].
name);
2054 for (
j = 0;
j < (
INT) tag[
i].n_data;
j++)
2055 printf(
"%s%d\t", tag[
i].
name,
j);
2059 if (old_tag == NULL)
2062 old_tag = (
TAG *) realloc(old_tag, drec.data_size);
2063 memcpy(old_tag, tag, drec.data_size);
2067 old_def_offset = rec.def_offset;
2073 printf(
"%d ", irec.
time);
2075 ltime = (time_t) irec.
time;
2077 ctime_r(<ime, ctimebuf);
2079 mstrlcpy(
str, ctimebuf + 4,
sizeof(
str));
2085 xread(fn, fh, data_buffer, rec.data_size);
2089 for (
i = 0;
i < n_tag;
i++) {
2092 printf(
"%s\t", data_buffer +
offset);
2094 }
else if (tag[
i].n_data == 1) {
2097 printf(
"%s\t", data_str.c_str());
2101 for (
j = 0;
j < (
INT) tag[
i].n_data;
j++) {
2103 printf(
"%s\t", data_str.c_str());
2112 i =
xread(fni, fhi, (
char *) &irec,
sizeof(irec),
true);
2121 ltime = (time_t) last_irec_time;
2123 localtime_r(<ime, &tms);
2124 tms.tm_hour = tms.tm_min = tms.tm_sec = 0;
2127 last_irec_time += 3600 * 24;
2128 if (last_irec_time > end_time)
2137 hs_open_file(last_irec_time,
"hst", O_RDONLY, &fn, &fh);
2138 hs_open_file(last_irec_time,
"idf", O_RDONLY, &fnd, &fhd);
2139 hs_open_file(last_irec_time,
"idx", O_RDONLY, &fni, &fhi);
2140 if (fh < 0 || fhd < 0 || fhi < 0) {
2146 i =
xread(fni, fhi, (
char *) &irec,
sizeof(irec),
true);
2151 old_def_offset = -1;
2153 }
while (irec.
time < end_time);
2165#ifndef DOXYGEN_SHOULD_SKIP_THIS
2173char* sort_names(
char* names)
2179 struct poor_mans_list sorted;
2181 for (
i=0, p=0; names[p]!=0;
i++) {
2182 const char*pp = names+p;
2183 int pplen = strlen(pp);
2187 p += strlen(names+p) + 1;
2194 arr_names = (
char*)malloc(len*num);
2196 for (
i=0, p=0; names[p]!=0;
i++) {
2197 const char*pp = names+p;
2198 mstrlcpy(arr_names+
i*len, pp, len);
2199 p += strlen(names+p) + 1;
2204 qsort(arr_names, num, len, sort_tags);
2208 for (
i=0;
i<num;
i++)
2209 list_add(&sorted, arr_names+
i*len);
2211 return sorted.names;
2251 printf(
"hs_connect: path [%s]\n", path);
2276 printf(
"hs_clear_cache!\n");
2291 mstrlcpy(
name, event_name,
sizeof(
name));
2292 char *s = strchr(
name,
'/');
2300 for (
int i = 0;;
i++) {
2318 int size =
sizeof(tmp);
2338 mstrlcpy(
name, event_name,
sizeof(
name));
2339 char *s = strchr(
name,
'/');
2344 if (strcmp(
name,
"Run transitions")==0) {
2351 std::string tmp =
msprintf(
"/Equipment/%s/Common/Event ID",
name);
2354 int size =
sizeof(evid);
2358 std::string he =
msprintf(
"/History/Events/%d", evid);
2363 cm_msg(
MERROR,
"add_event",
"History events \"%s\" and \"%s\" use the same history event id %d. If both equipments write to the history, their data will be mixed up. To fix this, enable per-variable history, turn off the \"MIDAS\" history (use \"FILE\" history) or change event IDs or set \"common/log history\" to zero", event_name, xname.c_str(), evid);
2375 for (
int evid = 101; evid < 65000; evid++) {
2379 sprintf(tmp,
"/History/Events/%d", evid);
2393 cm_msg(
MERROR,
"AllocateEventId",
"Cannot allocate history event id - all in use - please examine /History/Events");
2408 size =
sizeof(disableTags);
2412 size =
sizeof(oldTags);
2418 cm_msg(
MERROR,
"add_event",
"Cannot delete /History/Tags, db_delete() status %d",
status);
2420 }
else if (oldTags) {
2424 sprintf(buf,
"/History/Tags/%d",
event_id);
2431 for (
int i=0;
i<ntags;
i++) {
2433 sprintf(buf,
"/History/Tags/Tags %d/%s",
event_id, tags[
i].
name);
2442 "Tag name \'%s\' in event %d (%s) may have been truncated to %d characters",
2452 sprintf(buf,
"/History/Tags/%d",
event_id);
2469 cm_msg(
MINFO,
"add_event",
"Converting old event %d (%s) tags to new style",
event_id, event_name);
2471 mstrlcpy(buf, event_name, kLength);
2476 sprintf(buf,
"/History/Tags/Tags %d",
event_id);
2481 for (
int i=0; ;
i++) {
2498 sprintf(buf,
"%d[%d] %s", 0, w,
key.
name);
2519 char* s = (
char*)malloc(size);
2535 if (isdigit(ss[0])) {
2538 t[
i].
type = strtoul(ss, &ss, 0);
2541 t[
i].
n_data = strtoul(ss, &ss, 0);
2552 for (
int i=0;
i<ntags;
i++) {
2557 if ((tags[
i].
type!=t[
j].
type) || (tags[
i].n_data!=t[
j].n_data)) {
2558 cm_msg(
MINFO,
"add_event",
"Event %d (%s) tag \"%s\" type and size changed from %d[%d] to %d[%d]",
2562 tags[
i].
type, tags[
i].n_data);
2578 sprintf(buf,
"%d[%d] %s", tags[
i].
type, tags[
i].n_data, tags[
i].
name);
2600 mstrlcpy(buf, event_name, kLength);
2605 for (
int i=0;
i<ntags;
i++) {
2606 sprintf(buf,
"%d[%d] %s", tags[
i].
type, tags[
i].n_data, tags[
i].
name);
2631 return ::hs_define_event(
event_id, (
char*)event_name, (
TAG*)tags, ntags*
sizeof(
TAG));
2640 return ::hs_write_event(
event_id, (
void*)
data, data_size);
2664 for (
int i = 0;;
i++) {
2674 size =
sizeof(evname);
2678 s = strchr(evname,
':');
2685 for (
unsigned i=0;
i<events->size();
i++) {
2695 events->push_back(evname);
2714 for (
int i = 0;;
i++) {
2743 size =
sizeof(evname);
2750 for (
unsigned i=0;
i<events->size();
i++) {
2760 events->push_back(evname);
2777 printf(
"hs_get_events: reading events list!\n");
2804 for (
int i = 0;;
i++) {
2833 mstrlcpy(event_name, buf,
sizeof(event_name));
2835 s = strchr(buf,
':');
2846 for (
int j=0;
j<ntags;
j++) {
2874 for (
int i = 0;;
i++) {
2903 s = strchr(buf,
'/');
2917 if (!isdigit(buf[0]))
2920 s = strchr(buf,
' ');
2938 int GetEventId(time_t t,
const char* event_name,
const char* tag_name,
int *pevid)
2942 if (
fDebug && event_name != NULL && tag_name != NULL)
2943 printf(
"xhs_event_id for event [%s], tag [%s]\n", event_name, tag_name);
2973 time_t now = time(NULL);
2980 printf(
"hs_get_tags: get tags for event [%s] %d\n", event_name, evid);
2989 for (
int i=0;
i<ntags;
i++)
2990 ptags->push_back(tags[
i]);
2996 printf(
"hs_get_tags: get tags for event [%s] %d, found %d tags\n", event_name, evid, ntags);
3012 for (
int i = 0;;
i++) {
3048 for (
int j=0; ;
j++) {
3063 size =
sizeof(array);
3076 ptags->push_back(t);
3089 if (strchr(event_name,
'/')==NULL) {
3090 char* s = strchr(buf,
'/');
3113 if (!isdigit(buf[0]))
3116 sscanf(buf,
"%d[%d]", &ev_type, &array);
3118 s = strchr(buf,
' ');
3132 ptags->push_back(t);
3141 int hs_get_tags(
const char* event_name, time_t t, std::vector<TAG> *ptags)
3143 std::vector<TAG>& ttt =
fTagsCache[event_name];
3145 if (ttt.size() == 0) {
3149 printf(
"hs_get_tags: reading tags for event [%s]\n", event_name);
3160 for (
unsigned i=0;
i<ttt.size();
i++)
3161 ptags->push_back(ttt[
i]);
3168 int hs_get_last_written(time_t start_time,
int num_var,
const char*
const event_name[],
const char*
const tag_name[],
const int var_index[], time_t last_written[])
3170 for (
int i=0;
i<num_var;
i++)
3171 last_written[
i] = 0;
3178 int hs_read(time_t start_time, time_t end_time, time_t interval,
3180 const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
3182 time_t* time_buffer[],
double* data_buffer[],
3185 DWORD* tbuffer = NULL;
3186 char* ybuffer = NULL;
3188 int hbuffer_size = 0;
3190 if (hbuffer_size == 0) {
3191 hbuffer_size = 1000 *
sizeof(
DWORD);
3192 tbuffer = (
DWORD*)malloc(hbuffer_size);
3193 ybuffer = (
char*)malloc(hbuffer_size);
3196 for (
int i=0;
i<num_var;
i++) {
3200 if (event_name[
i]==NULL) {
3216 bsize = tsize = hbuffer_size;
3217 memset(ybuffer, 0, bsize);
3219 tag_name[
i], var_index[
i],
3226 printf(
"hs_read %d \'%s\' [%d] returned %d, %d entries\n",
event_id, tag_name[
i], var_index[
i],
status, n_point);
3230 tbuffer = (
DWORD*)realloc(tbuffer, hbuffer_size);
3232 ybuffer = (
char*)realloc(ybuffer, hbuffer_size);
3240 time_t* x = (time_t*)malloc(n_point*
sizeof(time_t));
3242 double* y = (
double*)malloc(n_point*
sizeof(
double));
3250 for (
unsigned j = 0;
j < n_point;
j++) {
3251 x[n_vp] = tbuffer[
j];
3259 y[n_vp] = *(((
BYTE *) ybuffer) +
j);
3262 y[n_vp] = *(((
char *) ybuffer) +
j);
3265 y[n_vp] = *(((
char *) ybuffer) +
j);
3268 y[n_vp] = *(((
WORD *) ybuffer) +
j);
3271 y[n_vp] = *(((
short *) ybuffer) +
j);
3274 y[n_vp] = *(((
DWORD *) ybuffer) +
j);
3277 y[n_vp] = *(((
INT *) ybuffer) +
j);
3280 y[n_vp] = *(((
BOOL *) ybuffer) +
j);
3283 y[n_vp] = *(((
float *) ybuffer) +
j);
3286 y[n_vp] = *(((
double *) ybuffer) +
j);
3293 num_entries[
i] = n_vp;
3306 int hs_read2(time_t start_time, time_t end_time, time_t interval,
3308 const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
3310 time_t* time_buffer[],
3311 double* mean_buffer[],
3312 double* rms_buffer[],
3313 double* min_buffer[],
3314 double* max_buffer[],
3317 int status =
hs_read(start_time, end_time, interval, num_var, event_name, tag_name, var_index, num_entries, time_buffer, mean_buffer, read_status);
3319 for (
int i=0;
i<num_var;
i++) {
3320 int num = num_entries[
i];
3321 rms_buffer[
i] = (
double*)malloc(
sizeof(
double)*num);
3322 min_buffer[
i] = (
double*)malloc(
sizeof(
double)*num);
3323 max_buffer[
i] = (
double*)malloc(
sizeof(
double)*num);
3325 for (
int j=0;
j<num;
j++) {
3326 rms_buffer[
i][
j] = 0;
3327 min_buffer[
i][
j] = mean_buffer[
i][
j];
3328 max_buffer[
i][
j] = mean_buffer[
i][
j];
3337 int num_var,
const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
3341 for (
int i=0;
i<num_var;
i++) {
3344 if (event_name[
i]==NULL) {
3357 tag_name[
i], var_index[
i],
3364 printf(
"hs_read %d \'%s\' [%d] returned %d\n",
event_id, tag_name[
i], var_index[
i],
status);
3374 int num_var,
const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
3376 int* count_bins[],
double* mean_bins[],
double* rms_bins[],
double* min_bins[],
double* max_bins[],
3377 time_t* bins_first_time[],
double* bins_first_value[],
3378 time_t* bins_last_time[],
double* bins_last_value[],
3379 time_t
last_time[],
double last_value[],
3387 for (
int i=0;
i<num_var;
i++) {
3389 xbuffer[
i] = buffer[
i];
3394 buffer[
i]->
fMean = mean_bins[
i];
3396 buffer[
i]->
fRms = rms_bins[
i];
3398 buffer[
i]->
fMin = min_bins[
i];
3400 buffer[
i]->
fMax = max_bins[
i];
3401 if (bins_first_time)
3403 if (bins_first_value)
3407 if (bins_last_value)
3418 num_var, event_name, tag_name, var_index,
3422 for (
int i=0;
i<num_var;
i++) {
3454#define HISTORY_PANEL(_name) const char *_name[] = {\
3456"Variables = STRING : [64] :",\
3457"Timescale = STRING : [32] 10m",\
3458"Zero ylow = BOOL : n",\
3459"Show run markers = BOOL : y",\
3460"Buttons = STRING[7] :",\
3468"Log axis = BOOL : n",\
3469"Show values = BOOL : y",\
3470"Sort vars = BOOL : n",\
3471"Show old vars = BOOL : n",\
3472"Minimum = DOUBLE : -inf",\
3473"Maximum = DOUBLE : inf",\
3474"Label = STRING : [32] ",\
3475"Colour = STRING : [32] ",\
3476"Formula = STRING : [64] ",\
3477"Show fill = BOOL : y",\
3488 const char *
color[] = {
3489 "#00AAFF",
"#FF9000",
"#FF00A0",
"#00C030",
3490 "#A0C0D0",
"#D0A060",
"#C04010",
"#807060",
3491 "#F0C000",
"#2090A0",
"#D040D0",
"#90B000",
3492 "#B0B040",
"#B0B0FF",
"#FFA0A0",
"#A0FFA0",
3497 snprintf(
str,
sizeof(
str),
"/History/Display/%s/%s", group, panel);
3505 for(
auto const& v: var) {
3521 const std::vector<std::string> label,
const std::vector<std::string> formula,
3522 const std::vector<std::string>
color)
3528 const char *default_color[] = {
3529 "#00AAFF",
"#FF9000",
"#FF00A0",
"#00C030",
3530 "#A0C0D0",
"#D0A060",
"#C04010",
"#807060",
3531 "#F0C000",
"#2090A0",
"#D040D0",
"#90B000",
3532 "#B0B040",
"#B0B0FF",
"#FFA0A0",
"#A0FFA0",
3537 snprintf(
str,
sizeof(
str),
"/History/Display/%s/%s", group, panel);
3545 for(
auto const& v: var) {
3549 if (
i < (
int)formula.size())
3550 mstrlcpy(
str, formula[
i].c_str(),
sizeof(
str)-1);
3555 if (
i < (
int)label.size())
3556 mstrlcpy(
str, label[
i].c_str(),
sizeof(
str)-1);
3561 if (
i < (
int)
color.size())
3564 mstrlcpy(
str, default_color[
i < 16 ?
i : 16],
sizeof(
str)-1);
virtual void Add(time_t time, double value)=0
char type[NAME_LENGTH]
history channel name
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
INT cm_get_experiment_semaphore(INT *semaphore_alarm, INT *semaphore_elog, INT *semaphore_history, INT *semaphore_msg)
#define DB_NO_MORE_SUBKEYS
#define HS_UNDEFINED_EVENT
static INT hs_open_file(time_t ltime, const char *suffix, INT mode, std::string *pfile_name, int *fh)
static std::vector< HISTORY * > _history
static int xread(const std::string &fn, int fh, void *buf, size_t count, bool eof_ok=false)
int GetEventsFromOdbTags(std::vector< std::string > *events)
static INT hs_enum_vars(DWORD ltime, DWORD event_id, char *var_name, DWORD *size, DWORD *var_n, DWORD *n_size)
MidasHistoryInterface * MakeMidasHistory()
static INT hs_search_file(DWORD *ltime, INT direction)
int hs_define_event(const char *event_name, time_t timestamp, int ntags, const TAG tags[])
see hs_define_event(), returns HS_SUCCESS or HS_FILE_ERROR
static bool xwrite(const std::string &fn, int fh, const void *buf, size_t count)
int hs_flush_buffers()
flush buffered data to storage where it is visible to mhttpd
int hs_get_last_written(time_t start_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], time_t last_written[])
static INT hs_define_event(DWORD event_id, const char *name, const TAG *tag, DWORD size)
static bool xtruncate(const std::string &fn, int fh, DWORD pos)
int hs_disconnect()
disconnect from history, returns HS_SUCCESS
int GetEventId(time_t t, const char *event_name, const char *tag_name, int *pevid)
int hs_read_buffer(time_t start_time, time_t end_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], MidasHistoryBufferInterface *buffer[], int read_status[])
returns HS_SUCCESS
static INT hs_count_vars(DWORD ltime, DWORD event_id, DWORD *count)
int hs_write_event(const char *event_name, time_t timestamp, int data_size, const char *data)
see hs_write_event(), returns HS_SUCCESS or HS_FILE_ERROR
int GetTagsFromOdb(const char *event_name, std::vector< TAG > *ptags)
static DWORD xcurpos(const std::string &fn, int fh)
int hs_set_debug(int debug)
set debug level, returns previous debug level
int hs_read_binned(time_t start_time, time_t end_time, int num_bins, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], int *count_bins[], double *mean_bins[], double *rms_bins[], double *min_bins[], double *max_bins[], time_t *bins_first_time[], double *bins_first_value[], time_t *bins_last_time[], double *bins_last_value[], time_t last_time[], double last_value[], int read_status[])
returns HS_SUCCESS
INT hs_define_panel2(const char *group, const char *panel, const std::vector< std::string > var, const std::vector< std::string > label, const std::vector< std::string > formula, const std::vector< std::string > color)
INT hs_define_panel(const char *group, const char *panel, const std::vector< std::string > var)
int FindEventId(const char *event_name)
int GetEventsFromOdbEvents(std::vector< std::string > *events)
static INT hs_count_events(DWORD ltime, DWORD *count)
static INT hs_get_tags(DWORD ltime, DWORD event_id, char event_name[NAME_LENGTH], int *n_tags, TAG **tags)
int GetTagsFromHS(const char *event_name, std::vector< TAG > *ptags)
int hs_get_tags(const char *event_name, time_t t, std::vector< TAG > *ptags)
get list of history variables for given event (use event names returned by hs_get_events()) that exis...
int hs_get_events(time_t t, std::vector< std::string > *pevents)
get list of events that exist(ed) at given time and later (value 0 means "return all events from begi...
static bool xseek_end(const std::string &fn, int fh)
std::vector< std::string > fEventsCache
#define HISTORY_PANEL(_name)
static INT hs_read(DWORD event_id, DWORD start_time, DWORD end_time, DWORD interval, const char *tag_name, DWORD var_index, DWORD *time_buffer, DWORD *tbsize, void *data_buffer, DWORD *dbsize, DWORD *data_type, DWORD *data_n, MidasHistoryBufferInterface *buffer)
static INT hs_get_event_id(DWORD ltime, const char *name, DWORD *id)
static INT hs_enum_events(DWORD ltime, char *event_name, DWORD *name_size, INT event_id[], DWORD *id_size)
int hs_clear_cache()
clear internal cache, returns HS_SUCCESS
static bool xseek_cur(const std::string &fn, int fh, int offset)
double hs_to_double(int tid, const void *ybuffer)
static INT hs_get_var(DWORD ltime, DWORD event_id, const char *var_name, DWORD *type, INT *n_data)
static INT hs_gen_index(DWORD ltime)
int AllocateEventId(const char *event_name)
int CreateOdbTags(int event_id, const char *event_name, int ntags, const TAG tags[])
int GetEventIdFromHS(time_t ltime, const char *evname, const char *tagname)
std::map< std::string, std::vector< TAG > > fTagsCache
static INT hs_set_path(const char *path)
static INT hs_dump(DWORD event_id, DWORD start_time, DWORD end_time, DWORD interval, BOOL binary_time)
int hs_read(time_t start_time, time_t end_time, time_t interval, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], time_t *time_buffer[], double *data_buffer[], int read_status[])
see hs_read(), returns HS_SUCCESS
static bool xseek(const std::string &fn, int fh, DWORD pos)
int GetEventIdFromOdbTags(const char *evname, const char *tagname)
int hs_connect(const char *path)
returns HS_SUCCESS
static std::string _hs_path_name
static INT hs_write_event(DWORD event_id, const void *data, DWORD size)
std::map< std::string, int > fEvidCache
time_t ss_mktime(struct tm *tms)
INT ss_semaphore_release(HNDLE semaphore_handle)
INT ss_semaphore_wait_for(HNDLE semaphore_handle, DWORD timeout_millisec)
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
BOOL equal_ustring(const char *str1, const char *str2)
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
std::string strcomb1(const char **list)
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
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)
INT db_set_data_index(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type)
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
INT db_delete(HNDLE hDB, HNDLE hKeyRoot, const char *odb_path)
INT db_sprintf(char *string, const void *data, INT data_size, INT idx, DWORD type)
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
INT db_set_value_index(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT idx, DWORD type, BOOL trunc)
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
BOOL debug
debug printouts
std::string msprintf(const char *format,...)
#define DIR_SEPARATOR_STR
#define write(n, a, f, d)
char event_name[NAME_LENGTH]