ICP  1
selogger.cpp
Go to the documentation of this file.
1 // selogger.cpp : Defines the entry point for the DLL application.
2 //
3 
4 #include "stdafx.h"
5 #include "selogger.h"
6 #include "isisdb.h"
7 #include "epicsdb.h"
8 #include "icputils.h"
9 
10 static bool database_debug = (getenv("ICP_DATABASE_DEBUG") != NULL);
11 static const char* database_debug_file = "c:\\data\\log\\database_debug.txt";
12 
13 
14 // START: taken from ICPUTILS - should make common
15 struct MyOverlapped : public OVERLAPPED
16 {
17 private:
19 public:
21  void* arg;
22  MyOverlapped(overlap_complete_func_t func_, void* arg_) : func(func_), arg(arg_)
23  {
24  memset(this, 0, sizeof(OVERLAPPED));
25  }
26 };
27 
28 struct my_overlap_t
29 {
30 private:
32 public:
33  HANDLE h;
34  char* data;
35  my_overlap_t(HANDLE h_, const char* data_) : h(h_), data(0)
36  {
37  data = strdup(data_);
38  }
40  {
41  free(data);
42  if (h != INVALID_HANDLE_VALUE)
43  {
44  CloseHandle(h);
45  }
46  }
47 };
48 
49 static void my_overlap(void* arg)
50 {
51  my_overlap_t* ov = (my_overlap_t*)arg;
52  delete ov;
53 }
54 
55 static HANDLE file_complete = NULL;
56 
57 static void my_io_complete(void* arg)
58 {
59  DWORD ntrans = 0;
60  ULONG_PTR key = 0;
61  MyOverlapped* overlapped = 0;
62  while(true)
63  {
64  GetQueuedCompletionStatus(file_complete, &ntrans, &key, (OVERLAPPED**)&overlapped, INFINITE);
65  (*(overlapped->func))(overlapped->arg);
66  delete overlapped;
67  }
68 }
69 
70 
71 static HANDLE createAppendFile(const char* filename)
72 {
73  static SECURITY_ATTRIBUTES sec_attr = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
74  if (file_complete == NULL)
75  {
76  file_complete = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1);
77  _beginthread(my_io_complete, 0, NULL);
78  }
79  // need to specify FILE_SHARE_WRITE so other threads in this process can access it etc.
80  HANDLE h = CreateFile(filename, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE,
81  &sec_attr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
82  if (h != INVALID_HANDLE_VALUE)
83  {
84  CreateIoCompletionPort(h, file_complete, 0 ,1);
85  }
86  return h;
87 }
88 
89 static void appendToFileAsync(HANDLE h, const char* message, bool close_after_write)
90 {
91  if (message == NULL)
92  {
93  return;
94  }
95  if (h != INVALID_HANDLE_VALUE)
96  {
97  my_overlap_t* arg;
98  if (close_after_write)
99  {
100  arg = new my_overlap_t(h, message);
101  }
102  else
103  {
104  arg = new my_overlap_t(INVALID_HANDLE_VALUE, message);
105  }
106  MyOverlapped* overlapped = new MyOverlapped(my_overlap, arg);
107  WriteFile(h, arg->data, strlen(message), NULL, overlapped);
108  }
109 }
110 
111 static void appendToFileAsync(const char* filename, const char* message)
112 {
113  if (message == NULL)
114  {
115  return;
116  }
117  HANDLE h = createAppendFile(filename);
118  if (h != INVALID_HANDLE_VALUE)
119  {
120  appendToFileAsync(h, message, true);
121  }
122 }
123 
124 // END: taken from ICPUTILS - should make common
125 
126 
127 #ifdef _MANAGED
128 #pragma managed(push, off)
129 #endif
130 
131 BOOL APIENTRY DllMain( HMODULE hModule,
132  DWORD ul_reason_for_call,
133  LPVOID lpReserved
134  )
135 {
136  switch (ul_reason_for_call)
137  {
138  case DLL_PROCESS_ATTACH:
139  case DLL_THREAD_ATTACH:
140  case DLL_THREAD_DETACH:
141  case DLL_PROCESS_DETACH:
142  break;
143  }
144  return TRUE;
145 }
146 
147 #ifdef _MANAGED
148 #pragma managed(pop)
149 #endif
150 
151 // ISO time of form "2004-11-10T17:04:54"
152 // return -1 on error
153 static time_t unixTime(const char* isotime)
154 {
155  int n;
156  struct tm tm_struct;
157  if (strlen(isotime) < 19)
158  {
159  return (time_t)-1;
160  }
161  n = sscanf(isotime, "%d-%d-%dT%d:%d:%d",
162  &tm_struct.tm_year, &tm_struct.tm_mon, &tm_struct.tm_mday,
163  &tm_struct.tm_hour, &tm_struct.tm_min, &tm_struct.tm_sec);
164 
165  if (n != 6) // enginx had " " rather than "T" separating the bits
166  {
167  n = sscanf(isotime, "%d-%d-%d %d:%d:%d",
168  &tm_struct.tm_year, &tm_struct.tm_mon, &tm_struct.tm_mday,
169  &tm_struct.tm_hour, &tm_struct.tm_min, &tm_struct.tm_sec);
170  }
171  if (n != 6)
172  {
173  return (time_t)-1;
174  }
175  tm_struct.tm_year -= 1900; // year field is 1900 based
176  tm_struct.tm_mon -= 1; // January is 0 not 1 in this structure
177  tm_struct.tm_isdst = -1; // status of DST is unknown - CRT will decide
178  return mktime(&tm_struct);
179 }
180 
181 static int ISOtime(time_t time, char* buffer, int len)
182 {
183  struct tm *tm_struct;
184  buffer[0] = '\0';
185  tm_struct = localtime(&time);
186  if (tm_struct != 0)
187  {
188  strftime(buffer, len, "%Y-%m-%dT%H:%M:%S", tm_struct);
189  }
190  else
191  {
192  strncpy(buffer, "1970-01-01T00:00:00", len);
193  }
194  buffer[len-1] = '\0';
195  return 0;
196 }
197 
198 static char last_error[1024];
199 
200 static volatile LONG num_async_requests = 0;
201 static volatile uint64_t num_work_iterations = 0;
202 static volatile HANDLE async_complete_event = NULL;
203 static CRITICAL_SECTION work_critical;
204 static volatile HANDLE work_queued = NULL;
205 
207 {
208 private:
209  workpacket(const workpacket& w);
210  workpacket& operator=(const workpacket& w);
211 
212 public:
213  HANDLE done_event;
214  workpacket(HANDLE ev = NULL) : done_event(ev) {}
215  virtual int execute() = 0;
216  int do_work()
217  {
218  int retcode = execute();
219  InterlockedDecrement(&num_async_requests);
220  if (done_event != NULL)
221  {
222  SetEvent(done_event);
223  }
224  SetEvent(async_complete_event);
225  return retcode;
226  }
227  virtual ~workpacket() {}
228 };
229 
230 static std::list<workpacket*> worklist;
231 
233 {
235  std::string source;
236  std::vector<std::string> iso_times;
237  std::vector<std::string> block_names;
238  std::vector<std::string> block_values;
239  se_log_values_t(long run_number_, const char* source_, const std::vector<std::string>& iso_times_, const std::vector<std::string>& block_names_, const std::vector<std::string>& block_values_) :
240  run_number(run_number_), source(source_), iso_times(iso_times_), block_names(block_names_), block_values(block_values_) {}
241  se_log_values_t(long run_number_, const char* source_, const char* iso_time_, const char* block_name_, const char* block_value_) : run_number(run_number_), source(source_)
242  {
243  iso_times.push_back(iso_time_), block_names.push_back(block_name_), block_values.push_back(block_value_);
244  }
245 };
246 
247 static std::list<se_log_values_t*> *se_worklist = NULL;
248 
249 static int __stdcall se_log_values_list(const std::list<se_log_values_t*> *tlist);
250 
251 static void process_requests(void* arg)
252 {
253  while(true)
254  {
255  if (WaitForSingleObject(work_queued, 30000 /*INFINITE*/) == WAIT_OBJECT_0)
256  {
257  EnterCriticalSection(&work_critical);
258  while (worklist.size() > 0)
259  {
260  workpacket* w = worklist.front();
261  worklist.pop_front();
262  LeaveCriticalSection(&work_critical);
263  int ret = w->do_work();
264  delete w;
265  EnterCriticalSection(&work_critical);
266  }
267  if (se_worklist != NULL)
268  {
269  std::list<se_log_values_t*> *tlist = se_worklist;
270  se_worklist = NULL;
271  LeaveCriticalSection(&work_critical);
272  se_log_values_list(tlist);
273  BOOST_FOREACH(se_log_values_t* item, *tlist)
274  {
275  delete item;
276  InterlockedDecrement(&num_async_requests);
277  }
278  tlist->clear();
279  delete tlist;
280  SetEvent(async_complete_event);
281  EnterCriticalSection(&work_critical);
282  }
284  LeaveCriticalSection(&work_critical);
285  Poco::Thread::sleep(200); // give somebody else a chance with the database
286  }
287  }
288 }
289 
290 static int general_init()
291 {
292  static volatile bool general_init_done = false;
293  static SECURITY_ATTRIBUTES sec_attr = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
294  if (!general_init_done)
295  {
296  general_init_done = true;
297  async_complete_event = CreateEvent(&sec_attr, FALSE, FALSE, NULL);
298  InitializeCriticalSection(&work_critical);
299  work_queued = CreateEvent(&sec_attr, FALSE, FALSE, NULL);
300  _beginthread(process_requests, 0, NULL);
301  }
302  return 0;
303 }
304 
305 static int __stdcall se_async(workpacket *work)
306 {
307  general_init();
308  InterlockedIncrement(&num_async_requests);
309  EnterCriticalSection(&work_critical);
310  worklist.push_back(work);
311  SetEvent(work_queued);
312  LeaveCriticalSection(&work_critical);
313  return 0;
314 }
315 
316 
317 static int count_rows_callback(void *arg, int argc, char **argv, char **azColName)
318 {
319  int* count = (int*)arg;
320  ++(*count);
321  return 0;
322 }
323 
324 
325 #define SQLITE_CHECK_RC(__rc) \
326  if (__rc != SQLITE_OK) \
327  { \
328  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: SQLITE error %s at %s:%d", errmsg, __FILE__, __LINE__); \
329  sqlite3_free(errmsg); \
330  return -1; \
331  }
332 
333 #define SQLITE_HANDLE_EXCEPTION(__func_name) \
334  catch(std::exception& ex) \
335  { \
336  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: %s: exception %s at %s:%d", #__func_name, ex.what(), __FILE__, __LINE__); \
337  return -1; \
338  }
339 
340 #define OPEN_DATABASE \
341  general_init(); \
342  ISISDB the_database(false);
343 
344 
345 const char* __stdcall se_version()
346 {
347  try {
349  return the_database.version();
350  }
351  catch(std::exception& ex)
352  {
353  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: %s: exception %s at %s:%d", "se_version", ex.what(), __FILE__, __LINE__);
354  return "unknown";
355  }
356 }
357 
358 static int my_sqlite3_exec(sqlite3* db, const char* sql, int (*callback)(void*,int,char**,char**), void* arg, char** errmsg)
359 {
360 // DBLock mylock;
361  *errmsg = NULL;
362  return sqlite3_exec(db, sql, callback, arg, errmsg);
363 }
364 
365 static int se_set_config_param(const char* name, const char* value)
366 {
367  char *sql_line;
368  char* errmsg = NULL;
369  try
370  {
372  // we cannot use "INSERT OR REPLACE" as this will not fire an UPDATE trigger
373  sql_line = sqlite3_mprintf(
374  "INSERT OR IGNORE INTO config VALUES ('%q', '%q'); "
375  "UPDATE config SET value='%q' WHERE name='%q'; ", name, value, value, name);
376  int rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
377  sqlite3_free(sql_line);
378  SQLITE_CHECK_RC(rc);
379  }
381  return 0;
382 }
383 
384 
385 static int se_get_config_param(const char* name, std::string& value)
386 {
387  char *sql_line;
388  char* errmsg = NULL;
389  int pnRow, pnColumn;
390  char** pazResult = NULL;
391  value = "";
392  int rc;
393  try
394  {
396  sql_line = sqlite3_mprintf(
397  "SELECT value FROM config WHERE name = '%q';", name);
398 // DBLock mylock;
399  rc = sqlite3_get_table(the_database, sql_line, &pazResult, &pnRow, &pnColumn, &errmsg);
400  sqlite3_free(sql_line);
401  SQLITE_CHECK_RC(rc);
402  if (pnRow == 1 && pnColumn == 1)
403  {
404  value = pazResult[1*pnColumn+0]; // 1st column, 2nd result row (first result row is column headers)
405  }
406  sqlite3_free_table(pazResult);
407  }
409  return 0;
410 }
411 
412 static int se_set_config_param(const char* name, long value)
413 {
414  char buffer[256];
415  _snprintf_s(buffer, sizeof(buffer), _TRUNCATE, "%ld", value);
416  return se_set_config_param(name, buffer);
417 }
418 
419 static long get_run_number()
420 {
421  std::string s;
422  if ( (se_get_config_param("run_number", s) == 0) && (s.length() > 0) )
423  {
424  return atol(s.c_str());
425  }
426  else
427  {
428  return -1;
429  }
430 }
431 
432 static long get_period()
433 {
434  std::string s;
435  if ( (se_get_config_param("period", s) == 0) && (s.length() > 0) )
436  {
437  return atol(s.c_str());
438  }
439  else
440  {
441  return -1;
442  }
443 }
444 
445 static int isReal(const char* value)
446 {
447  char* endptr = NULL;
448  double d = strtod(value, &endptr);
449  if (endptr != NULL && endptr != value)
450  {
451  return 1;
452  }
453  // on Windows strtod() does not handle NAN, INF, -INFINITY etc
454  int n = strlen(value);
455  char* tmpstr = strdup(value);
456  int is_real = 0;
457  for(int i=0; i<n; i++)
458  {
459  tmpstr[i] = toupper(tmpstr[i]);
460  }
461  if ( (strstr(tmpstr, "INF") != NULL) || (strstr(tmpstr, "NAN") != NULL) )
462  {
463  is_real = 1;
464  }
465  free(tmpstr);
466  return is_real;
467 }
468 
470 {
471  _beginthreadex(NULL, 0, run_epics_db, arg, 0, NULL);
472  return 0;
473 }
474 
475 SELOGGER_API int __stdcall se_set_block_value(const char* block_name, const char* block_value)
476 {
477  std::vector<std::string> block_names;
478  std::vector<std::string> block_values;
479  block_names.push_back(block_name);
480  block_values.push_back(block_value);
481  return se_set_block_values(block_names, block_values);
482 }
483 
484 SELOGGER_API int __stdcall se_set_block_values(const std::vector<std::string>& block_names, const std::vector<std::string>& block_values)
485 {
486  char* sql_line;
487  std::string s;
488  int nvalues = block_names.size();
489  s.reserve(nvalues*100);
490  char* errmsg = NULL;
491  time_t unix_time;
492  time(&unix_time);
493  char iso_time[64];
494  ISOtime(unix_time, iso_time, sizeof(iso_time));
495  if (database_debug)
496  {
497  std::stringstream sstr;
498  for(int i=0; i<nvalues; i++)
499  {
500  sstr << "se_set_block_values: " << block_names[i].c_str() << " = " << block_values[i].c_str() << (isReal(block_values[i].c_str()) ? " (real)" : " (string)") << "\r\n";
501  }
502  appendToFileAsync(database_debug_file, sstr.str().c_str());
503  }
504  try
505  {
507  int run_number = get_run_number();
508  s.append("BEGIN TRANSACTION; ");
509  for(int i=0; i<nvalues; i++)
510  {
511  sql_line = sqlite3_mprintf(
512  "UPDATE seblocks SET block_value='%q',is_real=%d,source='%q',value_time='%q' WHERE block_name='%q' AND run_number=%d; ",
513  block_values[i].c_str(), isReal(block_values[i].c_str()), "UNKNOWN", iso_time, block_names[i].c_str(), run_number);
514  s.append(sql_line);
515  sqlite3_free(sql_line);
516  }
517  s.append("END TRANSACTION; ");
518  int rc = my_sqlite3_exec(the_database, s.c_str(), NULL, NULL, &errmsg);
519  SQLITE_CHECK_RC(rc);
520  }
522  return 0;
523 }
524 
525 SELOGGER_API int __stdcall se_log_value(long run_number, const char* source, const char* iso_time, const char* block_name,
526  const char* block_value)
527 {
528  std::vector<std::string> block_names;
529  std::vector<std::string> block_values;
530  std::vector<std::string> block_times;
531  block_names.push_back(block_name);
532  block_values.push_back(block_value);
533  block_times.push_back(iso_time);
534  return se_log_values(run_number, source, block_times, block_names, block_values);
535 }
536 
538 {
539  general_init();
540  EnterCriticalSection(&work_critical);
541  uint64_t end_iter = num_work_iterations + 2;
542  while( (num_async_requests > 0) && (num_work_iterations <= end_iter) )
543  {
544  LeaveCriticalSection(&work_critical);
545  WaitForSingleObject(async_complete_event, 30000 /*INFINITE*/);
546  EnterCriticalSection(&work_critical);
547  }
548  LeaveCriticalSection(&work_critical);
549  return 0;
550 }
551 
552 static int __stdcall se_async(se_log_values_t *work)
553 {
554  general_init();
555  InterlockedIncrement(&num_async_requests);
556  EnterCriticalSection(&work_critical);
557  if (se_worklist == NULL)
558  {
559  se_worklist = new std::list<se_log_values_t*>;
560  }
561  se_worklist->push_back(work);
562  SetEvent(work_queued);
563  LeaveCriticalSection(&work_critical);
564  return 0;
565 }
566 
567 SELOGGER_API int __stdcall se_log_value_async(long run_number, const char* source, const char* iso_time, const char* block_name, const char* block_value)
568 {
569  return se_async(new se_log_values_t(run_number, source, iso_time, block_name, block_value));
570 }
571 
572 SELOGGER_API int __stdcall se_log_values_async(long run_number, const char* source, const std::vector<std::string>& iso_times, const std::vector<std::string>& block_names, const std::vector<std::string>& block_values)
573 {
574  return se_async(new se_log_values_t(run_number, source, iso_times, block_names, block_values));
575 }
576 
577 
578 SELOGGER_API int __stdcall se_log_fvalues(long run_number, const char* source, const std::vector<std::string>& iso_times, const std::vector<std::string>& block_names, const std::vector<float>& block_values)
579 {
580  std::vector<std::string> svals(block_values.size());
581  for(int i=0; i<block_values.size(); ++i)
582  {
583  svals[i] = Poco::NumberFormatter::format(block_values[i]);
584 // Poco::format(svals[i], "%hf", block_values[i]);
585  }
586  return se_log_values(run_number, source, iso_times, block_names, svals);
587 }
588 
589 SELOGGER_API int __stdcall se_log_values(long run_number, const char* source, const std::vector<std::string>& iso_times, const std::vector<std::string>& block_names, const std::vector<std::string>& block_values)
590 {
591  char* sql_line;
592  char* errmsg = NULL;
593  std::string s;
594  int nvalues = block_names.size();
595  if (database_debug)
596  {
597  std::stringstream sstr;
598  for(int i=0; i<nvalues; i++)
599  {
600  sstr << "se_log_values: " << iso_times[i].c_str() << " " << block_names[i].c_str() << " = " << block_values[i].c_str() << (isReal(block_values[i].c_str()) ? " (real)" : " (string)") << "\r\n";
601  }
602  appendToFileAsync(database_debug_file, sstr.str().c_str());
603  }
604  try
605  {
607  if (run_number <= 0)
608  {
609  if ( (se_get_config_param("run_number", s) == 0) && (s.length() > 0) )
610  {
611  run_number = atol(s.c_str());
612  }
613  else
614  {
615  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: unable to detremine run number");
616  return -1;
617  }
618  }
619  s.clear();
620  s.reserve(nvalues*100);
621  time_t unix_time;
622  s.append("BEGIN TRANSACTION; ");
623  for(int i=0; i<nvalues; i++)
624  {
625  unix_time = unixTime(iso_times[i].c_str());
626  sql_line = sqlite3_mprintf(
627  "INSERT INTO selog VALUES (%ld,'%q','%q',%llu,'%q','%q',%d); ",
628  run_number, source, iso_times[i].c_str(), (unsigned long long)unix_time,
629  block_names[i].c_str(), block_values[i].c_str(), isReal(block_values[i].c_str()));
630  s.append(sql_line);
631  sqlite3_free(sql_line);
632  }
633  s.append("END TRANSACTION; ");
634  int rc = my_sqlite3_exec(the_database, s.c_str(), NULL, NULL, &errmsg);
635  SQLITE_CHECK_RC(rc);
636  }
638  return 0;
639 }
640 
641 static int __stdcall se_log_values_list(const std::list<se_log_values_t*> *tlist)
642 {
643  char* sql_line;
644  char* errmsg = NULL;
645  std::string s;
646  int nvalues = 0;
647  int current_run_number, run_number;
648  BOOST_FOREACH(const se_log_values_t* item, *tlist)
649  {
650  nvalues += item->block_names.size();
651  }
652  try
653  {
655  if ( (se_get_config_param("run_number", s) == 0) && (s.length() > 0) )
656  {
657  current_run_number = atol(s.c_str());
658  }
659  else
660  {
661  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: unable to detremine run number");
662  return -1;
663  }
664  s.clear();
665  s.reserve(nvalues*100);
666  s.append("BEGIN TRANSACTION; ");
667  BOOST_FOREACH(const se_log_values_t* item, *tlist)
668  {
669  run_number = (item->run_number <= 0 ? current_run_number : item->run_number);
670  time_t unix_time;
671  for(int i=0; i<item->block_names.size(); ++i)
672  {
673  unix_time = unixTime(item->iso_times[i].c_str());
674  sql_line = sqlite3_mprintf(
675  "INSERT INTO selog VALUES (%ld,'%q','%q',%llu,'%q','%q',%d); ",
676  run_number, item->source.c_str(), item->iso_times[i].c_str(), (unsigned long long)unix_time,
677  item->block_names[i].c_str(), item->block_values[i].c_str(), isReal(item->block_values[i].c_str()));
678  s.append(sql_line);
679  sqlite3_free(sql_line);
680  }
681  }
682  s.append("END TRANSACTION; ");
683  int rc = my_sqlite3_exec(the_database, s.c_str(), NULL, NULL, &errmsg);
684  SQLITE_CHECK_RC(rc);
685  }
687  return 0;
688 }
689 
690 
691 SELOGGER_API int __stdcall se_close()
692 {
693  return 0;
694 }
695 
696 SELOGGER_API const char* __stdcall se_get_errmsg()
697 {
698  return last_error;
699 }
700 
701 SELOGGER_API int __stdcall se_log_run(int run_number, const char* source, const char* iso_time, int period,
702  int run_status, int is_running, int is_waiting,
703  int good_frames, int raw_frames,
704  float good_uamph, float raw_uamph,
705  int64_t monitor_sum0, float dae_beam_current, int64_t total_counts,
706  float count_rate, float npratio_current)
707 {
708  char *sql_line;
709  char* errmsg = NULL;
710  try
711  {
713  sql_line = sqlite3_mprintf(
714  "INSERT INTO run_status VALUES (%d,'%q','%q',%llu,%d,%d,%d,%d,%d,%d,%g,%g,%lld,%g,%lld,%g,%g);",
715  run_number, source, iso_time, static_cast<unsigned long long>(unixTime(iso_time)), period,
716  run_status, is_running, is_waiting,
717  good_frames, raw_frames,
718  good_uamph, raw_uamph,
719  static_cast<long long>(monitor_sum0), dae_beam_current, static_cast<long long>(total_counts),
720  count_rate, npratio_current);
721  int rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
722  sqlite3_free(sql_line);
723  SQLITE_CHECK_RC(rc);
724  }
726  return 0;
727 }
728 
729 SELOGGER_API int __stdcall se_set_run_number(int run_number)
730 {
731  return se_set_config_param("run_number", run_number);
732 }
733 
734 SELOGGER_API int __stdcall se_set_period(int period)
735 {
736  return se_set_config_param("period", period);
737 }
738 
739 SELOGGER_API int __stdcall se_get_seci_config(std::string& seci_config)
740 {
741  return se_get_config_param("seci_config", seci_config);
742 }
743 
744 SELOGGER_API int __stdcall se_set_run_state(int run_number, const char* state, int is_start)
745 {
746  char sql_line[512];
747  char iso_time[64];
748  ISOtime(time(NULL), iso_time, sizeof(iso_time));
749  char* errmsg = NULL;
750  try
751  {
753  int rc;
754  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
755  "INSERT INTO run_state VALUES (%d, %d, '%s', '%s', %llu); ",
756  run_number, is_start, state, iso_time, (unsigned long long)unixTime(iso_time));
757  rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
758  SQLITE_CHECK_RC(rc);
759  }
761  return 0;
762 }
763 
764 SELOGGER_API int __stdcall se_new_seci_config(const char* config_name)
765 {
766  char* errmsg = NULL;
767  try
768  {
769  if (se_set_config_param("seci_config", config_name) == -1)
770  {
771  return -1;
772  }
774  int run_number = get_run_number();
775  char* sql_line = sqlite3_mprintf("DELETE FROM seblocks WHERE run_number=%d; ", run_number);
776  int rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
777  sqlite3_free(sql_line);
778  SQLITE_CHECK_RC(rc);
779  }
781  return 0;
782 }
783 
784 SELOGGER_API int __stdcall se_set_block_details(const char* block_name, const char* setpoint_value,
785  const char* vi_name, const char* read_control_label, const char* set_control_label, const char* button_control_label,
786  unsigned options, const char* nexus_name, float low_limit, float high_limit,
787  const char* units, const char* current_value)
788 {
789  char* sql_line;
790  char* errmsg = NULL;
791  time_t unix_time;
792  time(&unix_time);
793  char iso_time[64];
794  ISOtime(unix_time, iso_time, sizeof(iso_time));
795  try
796  {
798  int rc;
799  int run_number = get_run_number();
800  sql_line = sqlite3_mprintf(
801  "INSERT OR REPLACE INTO seblocks VALUES (%d, '%q', '%q', '%q', '%q', '%q', '%q', %u, '%q', %g, %g, '%q', '%q', %d, '%q', '%q', '%q'); ",
802  run_number, block_name, setpoint_value, vi_name, read_control_label,
803  set_control_label, button_control_label,
804  options, nexus_name, low_limit, high_limit, units, current_value,
805  isReal(current_value), "UNKNOWN", iso_time, iso_time);
806  rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
807  sqlite3_free(sql_line);
808  SQLITE_CHECK_RC(rc);
809  }
811  return 0;
812 }
813 
814 
815 static int seblock_rows_callback(void *arg, int argc, char **argv, char **/*azColName*/)
816 {
817  seblock_map_t* blocks = (seblock_map_t*)arg;
818  if (argc == 0)
819  {
820  return 0;
821  }
822  // always create a block - this is so we can be used both on both selog and seblocks tables
823  SEBLOCK& block = (*blocks)[argv[1]];
824  if (argc >= 14) // we get called from two places, in one case we just want to create a blank entry
825  {
826  block.vi_name = argv[3];
827  block.read_control = argv[4];
828  block.set_control = argv[5];
829  block.button_control = argv[6];
830  block.options = atol(argv[7]);
831  block.nexus_name = argv[8];
832  block.low_limit = atof(argv[9]);
833  block.high_limit = atof(argv[10]);
834  block.units = argv[11];
835  block.is_real = (atol(argv[13]) != 0 ? true : false);
837  if (block.is_real)
838  {
839  if (block.fsetpoint_value.size() == 0)
840  {
841  block.fsetpoint_value.push_back(atof(argv[2]));
842  block.fcurrent_value.push_back(atof(argv[12]));
843  block.fsetpoint_spread.push_back(0.0);
844  block.fcurrent_spread.push_back(0.0);
845  }
846  else
847  {
848  block.fsetpoint_value[0] = atof(argv[2]);
849  block.fcurrent_value[0] = atof(argv[12]);
850  block.fsetpoint_spread[0] = 0.0;
851  block.fcurrent_spread[0] = 0.0;
852  }
853  }
854  else
855  {
856  if (block.setpoint_value.size() == 0)
857  {
858  block.setpoint_value.push_back(argv[2]);
859  block.current_value.push_back(argv[12]);
860  }
861  else
862  {
863  block.setpoint_value[0] = argv[2];
864  block.current_value[0] = argv[12];
865  }
866  }
867  }
868  return 0;
869 }
870 
871 
872 SELOGGER_API int __stdcall se_new_measurement(const char* label, std::string& res)
873 {
874  char sql_line[512];
875  char* errmsg = NULL;
876  unsigned char* uuid_str = NULL;
877  UUID the_uuid;
878  char iso_time[64];
879  ISOtime(time(NULL), iso_time, sizeof(iso_time));
880  res = "";
881  int run_number = 0;
882  std::string s;
883  try
884  {
886  if ( (se_get_config_param("run_number", s) == 0) && (s.length() > 0) )
887  {
888  run_number = atol(s.c_str());
889  }
890  UuidCreate(&the_uuid);
891  UuidToString(&the_uuid, &uuid_str);
892  int rc;
893  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
894  "INSERT INTO measurement VALUES ('%s', %d, '%s', '%s'); ",
895  uuid_str, run_number, iso_time, label);
896  rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
897  SQLITE_CHECK_RC(rc);
898  res = (const char*)uuid_str;
899  RpcStringFree(&uuid_str);
900  }
902  return 0;
903 }
904 
905 SELOGGER_API int __stdcall se_get_measurement_label(const char* measurement_id, std::string& res)
906 {
907  char sql_line[512];
908  char* errmsg = NULL;
909  int pnRow, pnColumn;
910  char** pazResult = NULL;
911  res = "";
912  try
913  {
915  int rc;
916  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
917  "SELECT label FROM measurement WHERE uuid='%s'; ", measurement_id);
918 // DBLock mylock;
919  rc = sqlite3_get_table(the_database, sql_line, &pazResult, &pnRow, &pnColumn, &errmsg);
920  SQLITE_CHECK_RC(rc);
921  if (pnRow == 1 && pnColumn == 1)
922  {
923  res = pazResult[1*pnColumn+0]; // 1st column, 2nd result row (first result row is column headers)
924  }
925  sqlite3_free_table(pazResult);
926  }
928  return 0;
929 }
930 
931 SELOGGER_API int __stdcall se_set_measurement_label(const char* measurement_id, const char* label)
932 {
933  char sql_line[512];
934  char* errmsg = NULL;
935  try
936  {
938  int rc;
939  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
940  "UPDATE measurement SET label='%s' WHERE uuid='%s'; ", label, measurement_id);
941  rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
942  }
944  return 0;
945 }
946 
947 SELOGGER_API int __stdcall se_get_measurement_id(const char* label, std::string& measurement_id)
948 {
949  char sql_line[512];
950  char* errmsg = NULL;
951  int pnRow, pnColumn;
952  char** pazResult = NULL;
953  measurement_id = "";
954  try
955  {
957  int rc;
958  // may be more than one measurement id with this label, so order by creation date to get latest
959  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
960  "SELECT uuid FROM measurement WHERE label='%s' ORDER BY iso_time DESC; ", label);
961 // DBLock mylock;
962  rc = sqlite3_get_table(the_database, sql_line, &pazResult, &pnRow, &pnColumn, &errmsg);
963  SQLITE_CHECK_RC(rc);
964  if (pnRow >= 1 && pnColumn == 1)
965  {
966  measurement_id = pazResult[1*pnColumn+0]; // 1st column, 2nd result row (first result row is column headers)
967  }
968  sqlite3_free_table(pazResult);
969  }
971  return 0;
972 }
973 
974 SELOGGER_API int __stdcall se_get_measurement_first_run(const char* measurement_id, long& run_number)
975 {
976  char sql_line[512];
977  char* errmsg = NULL;
978  int pnRow, pnColumn;
979  char** pazResult = NULL;
980  run_number = 0;
981  try
982  {
984  int rc;
985  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
986  "SELECT run_number FROM measurement WHERE uuid='%s'; ", measurement_id);
987 // DBLock mylock;
988  rc = sqlite3_get_table(the_database, sql_line, &pazResult, &pnRow, &pnColumn, &errmsg);
989  SQLITE_CHECK_RC(rc);
990  if (pnRow == 1 && pnColumn == 1)
991  {
992  run_number = atol(pazResult[1*pnColumn+0]); // 1st column, 2nd result row (first result row is column headers)
993  }
994  sqlite3_free_table(pazResult);
995  }
997  return 0;
998 }
999 
1000 static int se_clear_values2(int run_start, int run_finish)
1001 {
1002  char sql_line[512];
1003  char* errmsg = NULL;
1004  try
1005  {
1006  OPEN_DATABASE;
1007  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1008  "BEGIN TRANSACTION; "
1009  "DELETE FROM run_state WHERE (run_number BETWEEN %d AND %d) OR (run_number=-1); "
1010  "DELETE FROM seperiods WHERE (run_number BETWEEN %d AND %d) OR (run_number=-1); "
1011  "DELETE FROM selog WHERE (run_number BETWEEN %d AND %d) OR (run_number=-1); "
1012  "DELETE FROM run_status WHERE (run_number BETWEEN %d AND %d) OR (run_number=-1); "
1013  "DELETE FROM seblocks WHERE (run_number BETWEEN %d AND %d) OR (run_number=-1); "
1014  "END TRANSACTION; ",
1015  run_start, run_finish, run_start, run_finish, run_start, run_finish, run_start, run_finish, run_start, run_finish);
1016  int rc = my_sqlite3_exec(the_database, sql_line, NULL, NULL, &errmsg);
1017  SQLITE_CHECK_RC(rc);
1018  }
1020  return 0;
1021 }
1022 
1024 {
1027  se_clear_values2_t(long run_start_, long run_finish_) :
1028  workpacket(), run_start(run_start_), run_finish(run_finish_) {}
1029  int execute()
1030  {
1032  }
1033 };
1034 
1035 SELOGGER_API int __stdcall se_clear_values2_async(int run_start, int run_finish)
1036 {
1037  return se_async(new se_clear_values2_t(run_start, run_finish));
1038 }
1039 
1040 SELOGGER_API int __stdcall se_clear_values(int run_start, int run_finish)
1041 {
1042 // char* errmsg = NULL;
1043  std::string s;
1044  int current_run_number;
1045  if ( (se_get_config_param("run_number", s) == 0) && (s.length() > 0) )
1046  {
1047  current_run_number = atol(s.c_str());
1048  }
1049  else
1050  {
1051  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: unable to detremine run number");
1052  return -1;
1053  }
1054  run_start = (run_start <= 0 ? current_run_number : run_start);
1055  run_finish = (run_finish <= 0 ? current_run_number : run_finish);
1056  se_clear_values2_async(run_start, run_finish);
1057  return 0;
1058 }
1059 
1060 SELOGGER_API int __stdcall se_get_blocks(int run_number, time_t ref_time, seblock_map_t& blocks)
1061 {
1062  int n = 0;
1063  const char* pzTail;
1064  char sql_line[512];
1065  char* errmsg = NULL;
1066 
1068 
1069 // DBLock mylock;
1070 
1071  blocks.clear();
1072 
1073  sqlite3_stmt *stmt, *stmt2, *stmt3, *stmt4, *stmt_real0;
1074  OPEN_DATABASE;
1075  // this fills up the table with blocks we know about
1076  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1077  "SELECT * FROM seblocks WHERE run_number=%d;", run_number);
1078  int rc = my_sqlite3_exec(the_database, sql_line, seblock_rows_callback, &blocks, &errmsg);
1079  SQLITE_CHECK_RC(rc);
1080  // this fills up the rest of the table with blocks we have log files for but not "seblock" entries
1081  // it relies on seblock_rows_callback creating a blank block if the number of columns in the
1082  // row passed is not correct
1083  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1084  "SELECT DISTINCT run_number, block_name FROM selog WHERE run_number=%d;", run_number);
1085  rc = my_sqlite3_exec(the_database, sql_line, seblock_rows_callback, &blocks, &errmsg);
1086  SQLITE_CHECK_RC(rc);
1087  seblock_map_t::iterator it;
1088  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1089  "SELECT unix_time, block_value FROM selog WHERE run_number=? AND block_name=?;");
1090  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt, &pzTail);
1091  SQLITE_CHECK_RC(rc);
1092  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1093  "SELECT COUNT(unix_time) FROM selog WHERE run_number=? AND block_name=?;");
1094  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt3, &pzTail);
1095  SQLITE_CHECK_RC(rc);
1096 // use last rather than average value - stops e.g. averaging over values before run started
1097  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1098  "SELECT period, block_setpoint, block_value FROM seperiods "
1099  "WHERE run_number=? AND block_name=? "
1100  "ORDER BY period DESC, unix_time ASC;");
1101  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt2, &pzTail);
1102  SQLITE_CHECK_RC(rc);
1103  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1104  "SELECT period, "
1105  "avg(block_setpoint), avg(block_value), min(block_setpoint), min(block_value), max(block_setpoint), max(block_value) "
1106  "FROM seperiods WHERE run_number=? AND block_name=? AND unix_time>=%lu "
1107  "GROUP BY period ORDER BY period DESC;", ref_time);
1108  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt4, &pzTail);
1109  SQLITE_CHECK_RC(rc);
1110  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1111  "SELECT COUNT(unix_time) FROM selog WHERE run_number=? AND block_name=? AND is_real=0;");
1112  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt_real0, &pzTail);
1113  SQLITE_CHECK_RC(rc);
1114  for(it=blocks.begin(); it != blocks.end(); ++it)
1115  {
1116  SEBLOCK& block = it->second;
1117  block.ref_time = ref_time;
1118  rc = sqlite3_reset(stmt);
1119  SQLITE_CHECK_RC(rc);
1120  rc = sqlite3_bind_int(stmt, 1, run_number);
1121  SQLITE_CHECK_RC(rc);
1122  rc = sqlite3_bind_text(stmt, 2, it->first.c_str(), -1, SQLITE_STATIC);
1123  SQLITE_CHECK_RC(rc);
1124  rc = sqlite3_reset(stmt3);
1125  SQLITE_CHECK_RC(rc);
1126  rc = sqlite3_bind_int(stmt3, 1, run_number);
1127  SQLITE_CHECK_RC(rc);
1128  rc = sqlite3_bind_text(stmt3, 2, it->first.c_str(), -1, SQLITE_STATIC);
1129  SQLITE_CHECK_RC(rc);
1130  if ( (rc = sqlite3_step(stmt3)) == SQLITE_ROW )
1131  {
1132  // we add a few values on in case something gets logged before the real query is run
1133  // and this vaues is not big enough. Everything would still work, but the vector would
1134  // get reallocated and that is inefficient.
1135  // also we want to avoid (n == 0)
1136  n = sqlite3_column_int(stmt3, 0) + 10;
1137  }
1138  else
1139  {
1140  n = 200;
1141  SQLITE_CHECK_RC(rc);
1142  }
1143 
1144  rc = sqlite3_reset(stmt_real0);
1145  SQLITE_CHECK_RC(rc);
1146  rc = sqlite3_bind_int(stmt_real0, 1, run_number);
1147  SQLITE_CHECK_RC(rc);
1148  rc = sqlite3_bind_text(stmt_real0, 2, it->first.c_str(), -1, SQLITE_STATIC);
1149  SQLITE_CHECK_RC(rc);
1150  if ( (rc = sqlite3_step(stmt_real0)) == SQLITE_ROW )
1151  {
1152  block.is_real = (sqlite3_column_int(stmt_real0, 0) == 0);
1153  }
1154  else
1155  {
1156  block.is_real = false;
1157  SQLITE_CHECK_RC(rc);
1158  }
1159 
1160  block.time.reserve(n);
1161  block.svalues.reserve(n);
1162  block.fvalues.reserve(n);
1163  while( (rc = sqlite3_step(stmt)) == SQLITE_ROW )
1164  {
1165  block.time.push_back(sqlite3_column_int64(stmt, 0) - ref_time);
1166  if (block.is_real)
1167  {
1168  block.fvalues.push_back(sqlite3_column_double(stmt, 1));
1169  }
1170  else
1171  {
1172  block.svalues.push_back((const char*)sqlite3_column_text(stmt, 1));
1173  }
1174  }
1175  if (rc != SQLITE_DONE)
1176  {
1177  SQLITE_CHECK_RC(rc);
1178  }
1179  rc = sqlite3_reset(stmt2);
1180  SQLITE_CHECK_RC(rc);
1181  rc = sqlite3_bind_int(stmt2, 1, run_number);
1182  SQLITE_CHECK_RC(rc);
1183  rc = sqlite3_bind_text(stmt2, 2, it->first.c_str(), -1, SQLITE_STATIC);
1184  SQLITE_CHECK_RC(rc);
1185  while( (rc = sqlite3_step(stmt2)) == SQLITE_ROW )
1186  {
1187  int period = sqlite3_column_int(stmt2, 0);
1188  if (block.is_real)
1189  {
1190  if (block.fsetpoint_value.size() <= period)
1191  {
1192  block.fsetpoint_value.resize(period+1);
1193  block.fcurrent_value.resize(period+1);
1194  block.fsetpoint_spread.resize(period+1);
1195  block.fcurrent_spread.resize(period+1);
1196  }
1197  block.fsetpoint_value[period] = sqlite3_column_double(stmt2, 1);
1198  block.fcurrent_value[period] = sqlite3_column_double(stmt2, 2);
1199  }
1200  else
1201  {
1202  if (block.setpoint_value.size() <= period)
1203  {
1204  block.setpoint_value.resize(period+1);
1205  block.current_value.resize(period+1);
1206  }
1207  block.setpoint_value[period] = (const char*)sqlite3_column_text(stmt2, 1);
1208  block.current_value[period] = (const char*)sqlite3_column_text(stmt2, 2);
1209  }
1210  }
1211  if (rc != SQLITE_DONE)
1212  {
1213  SQLITE_CHECK_RC(rc);
1214  }
1215  rc = sqlite3_reset(stmt4);
1216  SQLITE_CHECK_RC(rc);
1217  rc = sqlite3_bind_int(stmt4, 1, run_number);
1218  SQLITE_CHECK_RC(rc);
1219  rc = sqlite3_bind_text(stmt4, 2, it->first.c_str(), -1, SQLITE_STATIC);
1220  SQLITE_CHECK_RC(rc);
1221  while( (rc = sqlite3_step(stmt4)) == SQLITE_ROW )
1222  {
1223  int period = sqlite3_column_int(stmt4, 0);
1224  if (block.is_real)
1225  {
1226  block.fsetpoint_spread[period] = sqlite3_column_double(stmt4, 5) - sqlite3_column_double(stmt4, 3);
1227  block.fcurrent_spread[period] = sqlite3_column_double(stmt4, 6) - sqlite3_column_double(stmt4, 4);
1228  }
1229  }
1230  if (rc != SQLITE_DONE)
1231  {
1232  SQLITE_CHECK_RC(rc);
1233  }
1234  }
1235  rc = sqlite3_finalize(stmt);
1236  SQLITE_CHECK_RC(rc);
1237  rc = sqlite3_finalize(stmt2);
1238  SQLITE_CHECK_RC(rc);
1239  rc = sqlite3_finalize(stmt3);
1240  SQLITE_CHECK_RC(rc);
1241  rc = sqlite3_finalize(stmt4);
1242  SQLITE_CHECK_RC(rc);
1243  rc = sqlite3_finalize(stmt_real0);
1244  SQLITE_CHECK_RC(rc);
1245  return 0;
1246 }
1247 
1248 SELOGGER_API int __stdcall se_get_run_status(int run_number, time_t ref_time, RUNBLOCK& blocks)
1249 {
1250  char sql_line[512];
1251  sqlite3_stmt *stmt, *stmt2;
1252  char* errmsg = NULL;
1253  const char* pzTail;
1254  int rc, n;
1255 
1256 // DBLock mylock;
1257  OPEN_DATABASE;
1258  blocks.ref_time = ref_time;
1259  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1260  "SELECT * FROM run_status WHERE run_number=%d;", run_number);
1261  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt, &pzTail);
1262  SQLITE_CHECK_RC(rc);
1263  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1264  "SELECT COUNT(unix_time) FROM run_status WHERE run_number=%d;", run_number);
1265  rc = sqlite3_prepare_v2(the_database, sql_line, -1, &stmt2, &pzTail);
1266  SQLITE_CHECK_RC(rc);
1267  if ( (rc = sqlite3_step(stmt2)) == SQLITE_ROW )
1268  {
1269  // we add a few values on in case something gets logged before the real query is run
1270  // and this vaues is not big enough. Everything would still work, but the vector would
1271  // get reallocated and that is inefficient.
1272  // also we want to avoid (n == 0)
1273  n = sqlite3_column_int(stmt2, 0) + 10;
1274  }
1275  else
1276  {
1277  n = 200;
1278  SQLITE_CHECK_RC(rc);
1279  }
1280  blocks.time.reserve(n);
1281  blocks.period.reserve(n);
1282  blocks.run_status.reserve(n);
1283  blocks.is_running.reserve(n);
1284  blocks.is_waiting.reserve(n);
1285  blocks.good_frames.reserve(n);
1286  blocks.raw_frames.reserve(n);
1287  blocks.good_uamps.reserve(n);
1288  blocks.raw_uamps.reserve(n);
1289  blocks.monitor1_sum.reserve(n);
1290  blocks.dae_beam_current.reserve(n);
1291  blocks.total_counts.reserve(n);
1292  blocks.count_rate.reserve(n);
1293  blocks.np_ratio.reserve(n);
1294  while( (rc = sqlite3_step(stmt)) == SQLITE_ROW )
1295  {
1296  blocks.time.push_back(sqlite3_column_int64(stmt, 3) - blocks.ref_time);
1297  blocks.period.push_back(sqlite3_column_int(stmt, 4));
1298  blocks.run_status.push_back(sqlite3_column_int(stmt, 5));
1299  blocks.is_running.push_back(sqlite3_column_int(stmt, 6));
1300  blocks.is_waiting.push_back(sqlite3_column_int(stmt, 7));
1301  blocks.good_frames.push_back(sqlite3_column_int(stmt, 8));
1302  blocks.raw_frames.push_back(sqlite3_column_int(stmt, 9));
1303  blocks.good_uamps.push_back(sqlite3_column_double(stmt, 10));
1304  blocks.raw_uamps.push_back(sqlite3_column_double(stmt, 11));
1305  blocks.monitor1_sum.push_back(sqlite3_column_int64(stmt, 12));
1306  blocks.dae_beam_current.push_back(sqlite3_column_double(stmt, 13));
1307  blocks.total_counts.push_back(sqlite3_column_int64(stmt, 14));
1308  blocks.count_rate.push_back(sqlite3_column_double(stmt, 15));
1309  blocks.np_ratio.push_back(sqlite3_column_double(stmt, 16));
1310  }
1311  if (rc != SQLITE_DONE)
1312  {
1313  SQLITE_CHECK_RC(rc);
1314  }
1315  rc = sqlite3_finalize(stmt);
1316  SQLITE_CHECK_RC(rc);
1317  rc = sqlite3_finalize(stmt2);
1318  SQLITE_CHECK_RC(rc);
1319  return 0;
1320 }
1321 
1322 static void db_profile_func(void* arg, const char* sql, sqlite3_uint64 tim)
1323 {
1324  FILE* f = (FILE*)arg;
1325  fprintf(f, "SQL \"%s\" took %8.3f s\n", sql, (double)tim / 1e9);
1326 }
1327 
1328 SELOGGER_API int __stdcall se_profile(const char* filename)
1329 {
1330 // char* errmsg = NULL;
1331  OPEN_DATABASE;
1332  FILE* f = fopen(filename, "wtN");
1333  if (f != NULL)
1334  {
1335  sqlite3_profile(the_database, db_profile_func, f);
1336  return 0;
1337  }
1338  else
1339  {
1340  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: cannot profile to %s", filename);
1341  return -1;
1342  }
1343 }
1344 
1345 
1347 {
1348  int period;
1349  se_set_period_t(int period_, HANDLE ev = NULL) : workpacket(ev), period(period_) {}
1350  int execute()
1351  {
1352  return se_set_period(period);
1353  }
1354 };
1355 
1356 SELOGGER_API int __stdcall se_set_period_async(int period)
1357 {
1358  static volatile HANDLE h = NULL; // just testing for now
1359  static SECURITY_ATTRIBUTES sec_attr = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
1360  if (h == NULL)
1361  {
1362  h = CreateEvent(&sec_attr, FALSE, FALSE, NULL);
1363  }
1364  int ret = se_async(new se_set_period_t(period, h));
1365 // WaitForSingleObject(h, INFINITE);
1366  return ret;
1367 }
1368 
1370 {
1372  std::string state;
1374  se_set_run_state_t(int run_number_, const char* state_, int is_start_) :
1375  workpacket(), run_number(run_number_), state(state_), is_start(is_start_) {}
1376  int execute()
1377  {
1378  return se_set_run_state(run_number, state.c_str(), is_start);
1379  }
1380 };
1381 
1382 SELOGGER_API int __stdcall se_set_run_state_async(int run_number, const char* state, int is_start)
1383 {
1384  return se_async(new se_set_run_state_t(run_number, state, is_start));
1385 }
1386 
1387 
1389 {
1390  char* errmsg = NULL;
1391  int rc;
1392  blocks.clear();
1393  OPEN_DATABASE;
1394  // this fills up the table with blocks we know about
1395  // this returns only one period with the setpoint and value for the current period as the first period
1396  int run_number = get_run_number();
1397  char* sql_line = sqlite3_mprintf("SELECT * FROM seblocks WHERE run_number=%d;", run_number);
1398  rc = sqlite3_exec(the_database, sql_line, seblock_rows_callback, &blocks, &errmsg);
1399  sqlite3_free(sql_line);
1400  SQLITE_CHECK_RC(rc);
1401  return 0;
1402 }
1403 
1404 SELOGGER_API int __stdcall se_set_block_setpoint(const char* block_name, const char* block_setpoint)
1405 {
1406  std::vector<std::string> block_names;
1407  std::vector<std::string> block_setpoints;
1408  block_names.push_back(block_name);
1409  block_setpoints.push_back(block_setpoint);
1410  return se_set_block_setpoints(block_names, block_setpoints);
1411 }
1412 
1413 SELOGGER_API int __stdcall se_set_block_setpoints(const std::vector<std::string>& block_names, const std::vector<std::string>& block_setpoints)
1414 {
1415  char *sql_line;
1416  std::string s;
1417  int nvalues = block_names.size();
1418  s.reserve(nvalues*200);
1419  char* errmsg = NULL;
1420  time_t unix_time;
1421  time(&unix_time);
1422  char iso_time[64];
1423  ISOtime(unix_time, iso_time, sizeof(iso_time));
1424  try
1425  {
1426  OPEN_DATABASE;
1427  int run_number = get_run_number();
1428  s.append("BEGIN TRANSACTION; ");
1429  for(int i=0; i<nvalues; i++)
1430  { // iso_time='%s', unix_time=%I64u (unsigned __int64)unix_time
1431  sql_line = sqlite3_mprintf(
1432  "UPDATE seblocks SET setpoint_value='%q',setpoint_time='%q' WHERE block_name='%q' AND run_number=%d; ",
1433  block_setpoints[i].c_str(), iso_time, block_names[i].c_str(), run_number);
1434  s.append(sql_line);
1435  sqlite3_free(sql_line);
1436  }
1437  s.append("END TRANSACTION; ");
1438  int rc = my_sqlite3_exec(the_database, s.c_str(), NULL, NULL, &errmsg);
1439  SQLITE_CHECK_RC(rc);
1440  }
1442  return 0;
1443 }
1444 
1445 
1446 SELOGGER_API int __stdcall se_get_values(long run_number, const char* source, const char* block_name, std::vector<std::string>& iso_times, std::vector<std::string>& block_values)
1447 {
1448  using namespace Poco::Data;
1449  std::string s;
1450  if (run_number <= 0)
1451  {
1452  if ( (se_get_config_param("run_number", s) == 0) && (s.length() > 0) )
1453  {
1454  run_number = atol(s.c_str());
1455  }
1456  else
1457  {
1458  _snprintf_s(last_error, sizeof(last_error), _TRUNCATE, "SELOGGER: unable to detremine run number");
1459  return -1;
1460  }
1461  }
1462  try
1463  {
1464  OPEN_DATABASE;
1465  Session ses(sqlite_session_pool.get()->get());
1466 
1467  Statement stmt(ses);
1468  iso_times.clear();
1469  block_values.clear();
1470  stmt << "SELECT iso_time, block_value FROM selog WHERE run_number=:run_number AND source=:source AND block_name=:block_name",
1471  into(iso_times), into(block_values), use(run_number), use(source), use(block_name);
1472  while(!stmt.done())
1473  {
1474  stmt.execute();
1475  }
1476  return 0;
1477  }
1479 }
1480 
1481 SELOGGER_API int __stdcall se_get_block_details(const char* block_name, SEBLOCK_DETAILS& block)
1482 {
1483  using namespace Poco::Data;
1484  try
1485  {
1486  OPEN_DATABASE;
1487  int run_number = get_run_number();
1488  Session ses(sqlite_session_pool.get()->get());
1489  Statement stmt(ses);
1490  stmt << "SELECT block_name, setpoint_value, vi_name, read_control, set_control, button_control, "
1491  "options, nexus_name, low_limit, high_limit, units, block_value, is_real, source, "
1492  "setpoint_time, value_time FROM seblocks WHERE block_name=:block_name AND run_number=" << run_number,
1493  into(block.tuple()), use(block_name);
1494  while(!stmt.done())
1495  {
1496  stmt.execute();
1497  }
1498  return 0;
1499  }
1501 }
1502 
1503 SELOGGER_API int __stdcall se_exec_sql(const char* sql, std::string& result)
1504 {
1505  using namespace Poco::Data;
1506  static const int limit_rows_returned = 200;
1507  try
1508  {
1509  OPEN_DATABASE;
1510  Session ses(sqlite_session_pool.get()->get());
1511  Statement stmt(ses);
1512  stmt << sql, limit(limit_rows_returned);
1513  unsigned nrows = stmt.execute();
1514  RecordSet rs(stmt);
1515  std::stringstream sstr;
1516  for(int i=0; i < rs.columnCount(); ++i)
1517  {
1518  sstr << (i > 0 ? " | " : "") << rs.columnName(i);
1519  }
1520  sstr << "\n";
1521  for(int row=0; row < rs.rowCount(); ++row)
1522  {
1523  for(int col=0; col < rs.columnCount(); ++col)
1524  {
1525  sstr << (col > 0 ? " | " : "") << rs.value(col, row).convert<std::string>();
1526  }
1527  sstr << "\n";
1528  }
1529  if ( !stmt.done() ) // check if row limit truncated results
1530  {
1531  sstr << "*** RESULT TRUNCATED AT " << limit_rows_returned << " ROWS ***\n";
1532  }
1533  if ( nrows != rs.rowCount() )
1534  {
1535  sstr << "*** ROW COUNT MISMATCH ***\n";
1536  }
1537  if ( nrows <= 0 || rs.columnCount() <= 0 )
1538  {
1539  sstr << "*** NULL result: nrows=" << nrows << " ncols=" << rs.columnCount() <<" ***\n";
1540  }
1541  result = sstr.str();
1542  return 0;
1543  }
1545 }
1546 
1547 
1548 
1549 // old stuff
1550 #if 0
1551 static int selog_rows_callback(void *arg, int argc, char **argv, char **azColName)
1552 {
1553  SEBLOCK* block = (SEBLOCK*)arg;
1554  if (argc >= 3)
1555  {
1556  block->time.push_back(atoi(argv[0]) - block->ref_time);
1557  int is_real = atol(argv[2]);
1558  if (is_real)
1559  {
1560  block->fvalues.push_back(atof(argv[1]));
1561  }
1562  else
1563  {
1564  block->svalues.push_back(argv[1]);
1565  }
1566  }
1567  return 0;
1568 }
1569 
1570 static int seperiods_rows_callback(void *arg, int argc, char **argv, char **azColName)
1571 {
1572  SEBLOCK& block = *(SEBLOCK*)arg;
1573  if (argc >= 3)
1574  {
1575  int period = atol(argv[0]);
1576  if (block.is_real)
1577  {
1578  if (block.fsetpoint_value.size() <= period)
1579  {
1580  block.fsetpoint_value.resize(period+1);
1581  block.fcurrent_value.resize(period+1);
1582  }
1583  block.fsetpoint_value[period] = atof(argv[1]);
1584  block.fcurrent_value[period] = atof(argv[2]);
1585  }
1586  else
1587  {
1588  if (block.setpoint_value.size() <= period)
1589  {
1590  block.setpoint_value.resize(period+1);
1591  block.current_value.resize(period+1);
1592  }
1593  block.setpoint_value[period] = argv[1];
1594  block.current_value[period] = argv[2];
1595  }
1596  }
1597  return 0;
1598 }
1599 
1600 SELOGGER_API int __stdcall se_get_blocks(int run_number, time_t ref_time, seblock_map_t& blocks)
1601 {
1602  char sql_line[512];
1603  char* errmsg = NULL;
1604  OPEN_DATABASE;
1605  // this fills up the table with blocks we know about
1606  int rc = my_sqlite3_exec(the_database, "SELECT * FROM seblocks;", seblock_rows_callback, &blocks, &errmsg);
1607  SQLITE_CHECK_RC(rc);
1608  // this fills up the rest of the table with blocks we have log files for but not "seblock" entries
1609  // it relies on seblock_rows_callback creating a blank block if the number of columns in the
1610  // row passed is not correct
1611  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1612  "SELECT DISTINCT block_name FROM selog WHERE run_number=%d;", run_number);
1613  rc = my_sqlite3_exec(the_database, sql_line, seblock_rows_callback, &blocks, &errmsg);
1614  SQLITE_CHECK_RC(rc);
1615  seblock_map_t::iterator it;
1616  for(it=blocks.begin(); it != blocks.end(); ++it)
1617  {
1618  it->second.ref_time = ref_time;
1619  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1620  "SELECT unix_time, block_value, is_real FROM selog WHERE run_number=%d AND block_name='%s';",
1621  run_number, it->first.c_str());
1622  rc = my_sqlite3_exec(the_database, sql_line, selog_rows_callback, &(it->second), &errmsg);
1623  SQLITE_CHECK_RC(rc);
1624  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1625  "SELECT period, avg(block_setpoint), avg(block_value) FROM seperiods WHERE run_number=%d AND block_name='%s' "
1626  "GROUP BY period ORDER BY period DESC;", run_number, it->first.c_str());
1627  rc = my_sqlite3_exec(the_database, sql_line, seperiods_rows_callback, &(it->second), &errmsg);
1628  SQLITE_CHECK_RC(rc);
1629  }
1630  return 0;
1631 }
1632 
1633 static int run_rows_callback(void *arg, int argc, char **argv, char **azColName)
1634 {
1635  RUNBLOCK* blocks = (RUNBLOCK*)arg;
1636  if (argc >= 17)
1637  {
1638  blocks->time.push_back(atoi(argv[3]) - blocks->ref_time);
1639  blocks->period.push_back(atoi(argv[4]));
1640  blocks->run_status.push_back(atoi(argv[5]));
1641  blocks->is_running.push_back(atoi(argv[6]));
1642  blocks->is_waiting.push_back(atoi(argv[7]));
1643  blocks->good_frames.push_back(atoi(argv[8]));
1644  blocks->raw_frames.push_back(atoi(argv[9]));
1645  blocks->good_uamps.push_back(atof(argv[10]));
1646  blocks->raw_uamps.push_back(atof(argv[11]));
1647  blocks->monitor1_sum.push_back(atoi(argv[12]));
1648  blocks->dae_beam_current.push_back(atof(argv[13]));
1649  blocks->total_counts.push_back(atoi(argv[14]));
1650  blocks->count_rate.push_back(atof(argv[15]));;
1651  blocks->np_ratio.push_back(atof(argv[16]));
1652  }
1653  return 0;
1654 }
1655 
1656 SELOGGER_API int __stdcall se_get_run_status(int run_number, time_t ref_time, RUNBLOCK& blocks)
1657 {
1658  char sql_line[512];
1659  char* errmsg = NULL;
1660  OPEN_DATABASE;
1661  blocks.ref_time = ref_time;
1662  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1663  "SELECT * FROM run_status WHERE run_number=%d;", run_number);
1664  int rc = my_sqlite3_exec(the_database, sql_line, run_rows_callback, &blocks, &errmsg);
1665  SQLITE_CHECK_RC(rc);
1666  return 0;
1667 }
1668 
1669 SELOGGER_API int __stdcall se_get_num_blocks(int run_number)
1670 {
1671  char sql_line[512];
1672  char* errmsg = NULL;
1673  OPEN_DATABASE;
1674  // we may have changed config during a run etc. so there could be log files for blocks
1675  // that are no longer defined in the seblocks table
1676  int count = 0;
1677  _snprintf_s(sql_line, sizeof(sql_line), _TRUNCATE,
1678  "SELECT block_name FROM seblocks UNION SELECT block_name FROM selog WHERE run_number=%d;", run_number);
1679  int rc = my_sqlite3_exec(the_database, sql_line, count_rows_callback, &count, &errmsg);
1680  SQLITE_CHECK_RC(rc);
1681  return count;
1682 }
1683 
1684 #endif /* if 0 */
1685 
static int my_sqlite3_exec(sqlite3 *db, const char *sql, int(*callback)(void *, int, char **, char **), void *arg, char **errmsg)
Definition: selogger.cpp:358
SELOGGER_API int __stdcall se_clear_values2_async(int run_start, int run_finish)
Definition: selogger.cpp:1035
static void process_requests(void *arg)
Definition: selogger.cpp:251
static int count_rows_callback(void *arg, int argc, char **argv, char **azColName)
Definition: selogger.cpp:317
SELOGGER_API int __stdcall se_log_run(int run_number, const char *source, const char *iso_time, int period, int run_status, int is_running, int is_waiting, int good_frames, int raw_frames, float good_uamph, float raw_uamph, int64_t monitor_sum0, float dae_beam_current, int64_t total_counts, float count_rate, float npratio_current)
Definition: selogger.cpp:701
SELOGGER_API int __stdcall se_new_seci_config(const char *config_name)
Definition: selogger.cpp:764
workpacket(const workpacket &w)
std::vector< int > raw_frames
Definition: selogger.h:109
float high_limit
Definition: selogger.h:87
std::vector< int64_t > total_counts
Definition: selogger.h:114
std::vector< float > count_rate
Definition: selogger.h:115
static int general_init()
Definition: selogger.cpp:290
SELOGGER_API int __stdcall se_new_measurement(const char *label, std::string &res)
Definition: selogger.cpp:872
workpacket & operator=(const workpacket &w)
static volatile HANDLE work_queued
Definition: selogger.cpp:204
SELOGGER_API int __stdcall se_get_run_status(int run_number, time_t ref_time, RUNBLOCK &blocks)
Definition: selogger.cpp:1248
SELOGGER_API int __stdcall se_get_block_values(seblock_map_t &blocks)
Definition: selogger.cpp:1388
SELOGGER_API int __stdcall se_get_measurement_id(const char *label, std::string &measurement_id)
Definition: selogger.cpp:947
static int __stdcall se_async(workpacket *work)
Definition: selogger.cpp:305
std::string units
Definition: selogger.h:88
bool is_real
Definition: selogger.h:92
SELOGGER_API int __stdcall se_set_run_state_async(int run_number, const char *state, int is_start)
Definition: selogger.cpp:1382
static time_t unixTime(const char *isotime)
Definition: selogger.cpp:153
SELOGGER_API int __stdcall se_start_epics_thread(epics_thread_data_t *arg)
Definition: selogger.cpp:469
std::vector< float > fcurrent_spread
per period
Definition: selogger.h:91
static volatile HANDLE async_complete_event
Definition: selogger.cpp:202
Poco::SingletonHolder< SQLITESessionPool > sqlite_session_pool
Definition: ISISDB.cpp:357
void(* overlap_complete_func_t)(void *arg)
Definition: icputils.h:311
SELOGGER_API int __stdcall se_get_num_blocks()
std::string set_control
Definition: selogger.h:82
static long get_period()
Definition: selogger.cpp:432
std::vector< std::string > iso_times
Definition: selogger.cpp:236
std::vector< float > fsetpoint_value
per period
Definition: selogger.h:78
std::map< std::string, SEBLOCK > seblock_map_t
Definition: selogger.h:128
void my_io_complete(void *arg)
Definition: icputils.cpp:410
std::vector< std::string > setpoint_value
per period
Definition: selogger.h:77
std::vector< float > raw_uamps
Definition: selogger.h:111
std::vector< float > good_uamps
Definition: selogger.h:110
se_set_run_state_t(int run_number_, const char *state_, int is_start_)
Definition: selogger.cpp:1374
static int ISOtime(time_t time, char *buffer, int len)
Definition: selogger.cpp:181
SELOGGER_API int __stdcall se_log_values(long run_number, const char *source, const std::vector< std::string > &iso_times, const std::vector< std::string > &block_names, const std::vector< std::string > &block_values)
Definition: selogger.cpp:589
SELOGGER_API const char *__stdcall se_get_errmsg()
Definition: selogger.cpp:696
static int isReal(const char *value)
Definition: selogger.cpp:445
SELOGGER_API int __stdcall se_set_period(int period)
Definition: selogger.cpp:734
static bool database_debug
Definition: selogger.cpp:10
std::vector< std::string > current_value
per period
Definition: selogger.h:89
std::vector< std::string > block_names
Definition: selogger.cpp:237
#define OPEN_DATABASE
Definition: selogger.cpp:340
SELOGGER_API int __stdcall se_log_value(long run_number, const char *source, const char *iso_time, const char *block_name, const char *block_value)
Definition: selogger.cpp:525
void * arg
Definition: icputils.cpp:374
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
Definition: selogger.cpp:131
void appendToFileAsync(HANDLE h, const char *message, bool close_after_write)
Definition: icputils.cpp:441
std::vector< float > np_ratio
Definition: selogger.h:116
static volatile uint64_t num_work_iterations
Definition: selogger.cpp:201
SELOGGER_API int __stdcall se_profile(const char *filename)
Definition: selogger.cpp:1328
std::string state
Definition: selogger.cpp:1372
std::vector< float > time
Definition: selogger.h:103
std::string button_control
Definition: selogger.h:83
virtual ~workpacket()
Definition: selogger.cpp:227
static void my_overlap(void *arg)
Definition: selogger.cpp:49
std::string read_control
Definition: selogger.h:81
std::vector< int > period
Definition: selogger.h:104
se_log_values_t(long run_number_, const char *source_, const std::vector< std::string > &iso_times_, const std::vector< std::string > &block_names_, const std::vector< std::string > &block_values_)
Definition: selogger.cpp:239
static int __stdcall se_log_values_list(const std::list< se_log_values_t * > *tlist)
Definition: selogger.cpp:641
const char *__stdcall se_version()
Definition: selogger.cpp:345
SELOGGER_API int __stdcall se_get_block_details(const char *block_name, SEBLOCK_DETAILS &block)
Definition: selogger.cpp:1481
SELOGGER_API int __stdcall se_get_measurement_label(const char *measurement_id, std::string &res)
Definition: selogger.cpp:905
float low_limit
Definition: selogger.h:86
SELOGGER_API int __stdcall se_log_fvalues(long run_number, const char *source, const std::vector< std::string > &iso_times, const std::vector< std::string > &block_names, const std::vector< float > &block_values)
Definition: selogger.cpp:578
SELOGGER_API int __stdcall se_set_block_setpoints(const std::vector< std::string > &block_names, const std::vector< std::string > &block_setpoints)
Definition: selogger.cpp:1413
#define SQLITE_CHECK_RC(__rc)
Definition: selogger.cpp:325
HANDLE createAppendFile(const char *filename)
Definition: icputils.cpp:424
SEBLOCK_DETAILS_tuple & tuple()
Definition: selogger.h:31
static void db_profile_func(void *arg, const char *sql, sqlite3_uint64 tim)
Definition: selogger.cpp:1322
static HANDLE file_complete
Definition: selogger.cpp:55
static long get_run_number()
Definition: selogger.cpp:419
SELOGGER_API int __stdcall se_set_run_number(int run_number)
Definition: selogger.cpp:729
std::vector< std::string > block_values
Definition: selogger.cpp:238
SELOGGER_API int __stdcall se_set_period_async(int period)
Definition: selogger.cpp:1356
se_clear_values2_t(long run_start_, long run_finish_)
Definition: selogger.cpp:1027
SELOGGER_API int __stdcall se_close()
Definition: selogger.cpp:691
SELOGGER_API int __stdcall se_get_values(long run_number, const char *source, const char *block_name, std::vector< std::string > &iso_times, std::vector< std::string > &block_values)
Definition: selogger.cpp:1446
std::vector< float > fvalues
Definition: selogger.h:95
std::vector< float > fcurrent_value
per period
Definition: selogger.h:90
SELOGGER_API int __stdcall se_get_seci_config(std::string &seci_config)
Definition: selogger.cpp:739
std::vector< float > dae_beam_current
Definition: selogger.h:113
static char last_error[1024]
Definition: selogger.cpp:198
static int se_clear_values2(int run_start, int run_finish)
Definition: selogger.cpp:1000
std::vector< int > is_waiting
Definition: selogger.h:107
std::vector< float > fsetpoint_spread
per period
Definition: selogger.h:79
virtual int execute()=0
SELOGGER_API int __stdcall se_get_measurement_first_run(const char *measurement_id, long &run_number)
Definition: selogger.cpp:974
std::vector< int > is_running
Definition: selogger.h:106
static volatile LONG num_async_requests
Definition: selogger.cpp:200
static int se_set_config_param(const char *name, const char *value)
Definition: selogger.cpp:365
SELOGGER_API int __stdcall se_exec_sql(const char *sql, std::string &result)
Definition: selogger.cpp:1503
std::vector< std::string > svalues
Definition: selogger.h:96
SELOGGER_API int __stdcall se_get_blocks(int run_number, time_t ref_time, seblock_map_t &blocks)
Definition: selogger.cpp:1060
SELOGGER_API int __stdcall se_set_run_state(int run_number, const char *state, int is_start)
Definition: selogger.cpp:744
std::vector< float > time
Definition: selogger.h:94
se_log_values_t(long run_number_, const char *source_, const char *iso_time_, const char *block_name_, const char *block_value_)
Definition: selogger.cpp:241
SELOGGER_API int __stdcall se_set_block_setpoint(const char *block_name, const char *block_setpoint)
Definition: selogger.cpp:1404
SELOGGER_API int __stdcall se_clear_values(int run_start, int run_finish)
Definition: selogger.cpp:1040
SELOGGER_API int __stdcall se_set_block_value(const char *block_name, const char *block_value)
Definition: selogger.cpp:475
std::string nexus_name
Definition: selogger.h:85
SELOGGER_API int __stdcall se_set_measurement_label(const char *measurement_id, const char *label)
Definition: selogger.cpp:931
SELOGGER_API int __stdcall se_set_block_values(const std::vector< std::string > &block_names, const std::vector< std::string > &block_values)
Definition: selogger.cpp:484
char * data
Definition: icputils.cpp:387
time_t ref_time
Definition: selogger.h:76
SELOGGER_API int __stdcall se_log_value_async(long run_number, const char *source, const char *iso_time, const char *block_name, const char *block_value)
Definition: selogger.cpp:567
static int se_get_config_param(const char *name, std::string &value)
Definition: selogger.cpp:385
static std::list< workpacket * > worklist
Definition: selogger.cpp:230
static int seblock_rows_callback(void *arg, int argc, char **argv, char **)
Definition: selogger.cpp:815
#define SELOGGER_API
Definition: selogger.h:12
SELOGGER_API int __stdcall se_set_block_details(const char *block_name, const char *setpoint_value, const char *vi_name, const char *read_control_label, const char *set_control_label, const char *button_control_label, unsigned options, const char *nexus_name, float low_limit, float high_limit, const char *units, const char *current_value)
Definition: selogger.cpp:784
int do_work()
Definition: selogger.cpp:216
SELOGGER_API int __stdcall se_wait_for_async()
Definition: selogger.cpp:537
unsigned __stdcall run_epics_db(void *arg)
Definition: epicsdb.cpp:42
std::string source
Definition: selogger.cpp:235
static CRITICAL_SECTION work_critical
Definition: selogger.cpp:203
#define SQLITE_HANDLE_EXCEPTION(__func_name)
Definition: selogger.cpp:333
overlap_complete_func_t func
Definition: icputils.cpp:373
workpacket(HANDLE ev=NULL)
Definition: selogger.cpp:214
unsigned options
Definition: selogger.h:84
se_set_period_t(int period_, HANDLE ev=NULL)
Definition: selogger.cpp:1349
MyOverlapped(overlap_complete_func_t func_, void *arg_)
Definition: selogger.cpp:22
std::vector< int > run_status
Definition: selogger.h:105
time_t ref_time
Definition: selogger.h:102
std::string vi_name
Definition: selogger.h:80
static const char * database_debug_file
Definition: selogger.cpp:11
std::vector< int > good_frames
Definition: selogger.h:108
my_overlap_t(HANDLE h_, const char *data_)
Definition: selogger.cpp:35
HANDLE done_event
Definition: selogger.cpp:213
SELOGGER_API int __stdcall se_log_values_async(long run_number, const char *source, const std::vector< std::string > &iso_times, const std::vector< std::string > &block_names, const std::vector< std::string > &block_values)
Definition: selogger.cpp:572
std::vector< int64_t > monitor1_sum
Definition: selogger.h:112
static std::list< se_log_values_t * > * se_worklist
Definition: selogger.cpp:247