Changeset 159 for Evidence


Ignore:
Timestamp:
02/04/10 15:26:55 (15 years ago)
Author:
ogrimm
Message:
Change in history handling
Location:
Evidence
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • Evidence/Alarm.cc

    r154 r159  
    109109       
    110110        // Update State: unavailable or current severity of status 
    111         if (getInfo()->getSize()==strlen(NO_LINK)+1 &&
    112                 strcmp(getInfo()->getString(), NO_LINK)==0) State[i] = 4;
     111        if (!ServiceOK(getInfo())) State[i] = 4;
    113112        else {
    114113          State[i] = *(getInfo()->getString()+getInfo()->getSize()-1);
    115114
    116   printf("*** String length: %d  Message length: %d    Last number: %d\n",strlen(getInfo()->getString()),getInfo()->getSize(),State[i]);
    117115          // Print message
    118116          time_t RawTime = getInfo()->getTimestamp();
  • Evidence/DColl.cc

    r152 r159  
    3838#include <regex.h>
    3939
     40using namespace std;
     41
    4042//
    4143// Class declaration
     
    4749          DimStampedInfo *DataItem;
    4850      DimService *HistService;
    49           struct EvidenceHistoryItem *HistBuffer;
    50           int HistPointer;
     51          char *Buffer;
     52          int Next;
    5153          double LastValue;
    5254          double MinAbsChange;
     
    101103  // Request configuration data
    102104  char *Change = GetConfig(SERVER_NAME " minchange");
    103 
    104105  DataDir = GetConfig(SERVER_NAME " datadir");
    105 
    106106  char *Logname = GetConfig(SERVER_NAME " logfile");
    107 
    108107  SizeUpdateDelay = atoi(GetConfig(SERVER_NAME " sizeupdate"));
    109 
    110108  HistSize = atoi(GetConfig(SERVER_NAME " histsize"));
    111   if (HistSize < 1) HistSize = 1; // Minimum one items
    112 
     109  if (HistSize < 3*sizeof(int)) HistSize = 3*sizeof(int);
    113110  HistDir = GetConfig(SERVER_NAME " histdir");
    114111   
     
    163160  // Subscribe to list of servers at DIS_DNS
    164161  AddService("DIS_DNS/SERVER_LIST");
    165 
    166   DimClient::sendCommand("DColl/Log", SERVER_NAME" *** Logging started ***");
    167162}
    168163
     
    171166//
    172167DataHandler::~DataHandler() {
    173 
    174   DimClient::sendCommand("DColl/Log", SERVER_NAME" *** Logging stopped ***");
    175168
    176169  // Delete DIM subscriptions and command first so handlers and not called anymore
     
    179172  }
    180173  delete LogCommand;
    181  
     174
    182175  // Save history buffers to files (replace '/' by '_')
     176  State(INFO, "Writing history buffers to files");
     177
    183178  for (int i=0; i<List.size(); i++) {
    184179    string Name = List[i].HistService->getName();
     
    186181    FILE *File = fopen((HistDir + "/" + Name).c_str(), "wb");
    187182        if (File != NULL) {
    188       fwrite(&List[i].HistPointer, sizeof(List[i].HistPointer), 1, File);
    189       fwrite(List[i].HistBuffer, sizeof(EvidenceHistoryItem), HistSize, File);
     183      fwrite(&List[i].Next, sizeof(List[i].Next), 1, File);
     184      fwrite(List[i].Buffer, sizeof(char), HistSize, File);
    190185      fclose(File);
    191186        }
    192187        delete List[i].HistService;
    193     delete[] List[i].HistBuffer;
     188    delete[] List[i].Buffer;
    194189  }
    195190
     
    223218void DataHandler::infoHandler() {
    224219
     220  static const int WrapMark[] = {0, -1};
     221  static const int EndMark[] = {0, 0};
     222
    225223  DimInfo *Info = getInfo();
    226224
    227225  // Check if service available
    228   if (Info->getSize()==strlen(NO_LINK)+1 && strcmp(Info->getString(), NO_LINK)==0) return;
    229 
     226  if (!ServiceOK(Info)) return;
     227
     228  //
     229  // ====== Part A: Handle service subscriptions ===
     230  //
     231 
    230232  // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
    231233  if (strcmp(Info->getName(), "DIS_DNS/SERVER_LIST") == 0) {   
     
    259261  }
    260262
     263  //
     264  // ====== Part B: Handle opening data files ===
     265  //
     266
    261267  // If it is time to open new data file, close the current one
    262268  if (time(NULL) >= TimeForNextFile) {
     
    296302        TimeForNextFile = mktime(T);
    297303  }
    298    
     304
     305  //
     306  // ====== Part C: Handle writing to data file ===
     307  //
     308
    299309  // Identify index of service
    300   int Service; 
     310  int Service;
    301311  for (Service=0; Service<List.size(); Service++) if (Info == List[Service].DataItem) break;
    302312  if (Service == List.size()) return;  // Service not found
    303313
    304   // If negative value for absolute change, ignore this entry
    305   if (List[Service].MinAbsChange < 0) return;
     314  // If negative value for absolute change, do not write to file
     315  if (List[Service].MinAbsChange >= 0) {
    306316
    307317  // Write data header
     
    313323  // Translate data into ASCII
    314324  char *Text = EvidenceServer::ToString(Info);
     325
    315326  if (Text != NULL) {
    316327        // Replace all control characters by white space
     
    320331    fprintf(DataFile, "%s\n", Text);
    321332       
    322         // Add to history buffer if change large enough
    323         if ((fabs(atof(Text)-List[Service].LastValue) > List[Service].MinAbsChange)) {
    324           List[Service].HistBuffer[List[Service].HistPointer].Seconds = Info->getTimestamp();
    325       List[Service].HistBuffer[List[Service].HistPointer].Value = atof(Text);
    326       List[Service].HistService->updateService();
    327           List[Service].HistPointer++;
    328           if (List[Service].HistPointer >= HistSize) List[Service].HistPointer = 0;
    329           List[Service].LastValue = atof(Text);
    330         }
    331333        free(Text);
    332334  }
    333335  else fprintf(DataFile, "Cannot interpret format identifier\n");
    334336 
    335   fflush(DataFile);
    336 
    337337  // Terminate if error because otherwise infinite loop might result as
    338338  // next call to this infoHandler() will try to (re-)open file
     
    343343  }
    344344
    345   // Update datafile size service
     345  // Update datafile size service (not every time to avoid infinite loop)
    346346  if (time(NULL) - DataSizeLastUpdate > SizeUpdateDelay) {
     347    fflush(DataFile); // not continuously to reduce load
     348
    347349        DataSizekB = FileSize(DataFile);
    348350        DataSizeService->updateService();
    349351        DataSizeLastUpdate = time(NULL);
    350352  }
     353 
     354  } // Check for MinAbsChange
     355
     356  //
     357  // ====== Part D: Handle history service ===
     358  //
     359 
     360  if (Info->getSize() == 0) return;
     361 
     362  // Check if data should be added to history buffer
     363  char *Text = EvidenceServer::ToString(Info);
     364  if (Text != NULL && strcmp(Info->getFormat(),"C") != 0
     365          && fabs(atof(Text)-List[Service].LastValue) < fabs(List[Service].MinAbsChange)) {
     366        free(Text);
     367        return;
     368  }
     369  free(Text);
     370
     371  // Check if data fits into buffer
     372  if (HistSize < Info->getSize() + 5*sizeof(int)) return;
     373
     374  int Size = Info->getSize() + 4*sizeof(int), Next = List[Service].Next;
     375  void *WrapPos = NULL;
     376  char *Buffer = List[Service].Buffer;
     377  int Oldest = *(int *) Buffer;
     378
     379  // Check if buffer wrap-around (write wrap mark after Oldest is adjusted)
     380  if (Next + Size >= HistSize) {
     381    WrapPos = Buffer + Next;
     382    Next = 4;
     383  }
     384
     385  // Adapt pointer to oldest entry
     386  while ((Oldest < Next + Size) &&
     387                 (Oldest + *((int *) (Buffer + Oldest) + 1) + 2*sizeof(int) > Next)) {
     388        // Check for wrap-around
     389        if (memcmp(Buffer + Oldest, WrapMark, sizeof(WrapMark)) == 0) {
     390          Oldest = 4;
     391          continue;
     392        }
     393        // Check if end marker reached, then only one event fits buffer
     394        if (memcmp(Buffer + Oldest, EndMark, sizeof(EndMark)) == 0) {
     395          Oldest = Next;
     396          break;
     397        }
     398        // Move to next entry
     399    Oldest += *((int *) (Buffer + Oldest) + 1) + 2*sizeof(int);
     400  }
     401  // Update pointer in buffer
     402  *(int *) Buffer = Oldest;
     403
     404  // Write wrap mark if necessary
     405  if (WrapPos != NULL) memcpy(WrapPos, WrapMark, sizeof(WrapMark));
     406
     407  // Copy data into ring buffer
     408  *((int *) (Buffer + Next)) = Info->getTimestamp();
     409  *((int *) (Buffer + Next + sizeof(int))) = Info->getSize();
     410  memcpy(Buffer + Next + 2*sizeof(int), Info->getData(), Info->getSize());
     411
     412  // Adjust pointer for next entry and write end marker to buffer
     413  Next += Info->getSize() + 2*sizeof(int);
     414  memcpy(Buffer + Next, EndMark, sizeof(EndMark));
     415 
     416  List[Service].Next = Next;
    351417}
    352418
     
    403469  }
    404470 
    405   // Create new entry in item list
    406471  struct Item New;
    407472
     
    413478        }
    414479  }
    415                
     480
    416481  // Create history service
    417   New.HistBuffer = new struct EvidenceHistoryItem [HistSize];
    418   memset(New.HistBuffer, 0, HistSize*sizeof(EvidenceHistoryItem));
    419   New.HistPointer = 0;
     482  New.Buffer = new char [HistSize];
     483  memset(New.Buffer, 0, HistSize);
     484  *(int *) New.Buffer = 4;
     485  New.Next = 4;
    420486  New.LastValue = DBL_MAX;
    421487  New.HistService = new DimService ((Name+".hist").c_str(), (char *) "C",
    422                                           New.HistBuffer, HistSize*sizeof(EvidenceHistoryItem));
    423        
     488                                          New.Buffer, HistSize);
     489
    424490  // Load history buffer from file if existing
    425491  string Filename = New.HistService->getName();
     
    427493  FILE *File = fopen((HistDir + "/" + Filename).c_str(), "rb");
    428494  if (File != NULL) {
    429     fread(&New.HistPointer, sizeof(New.HistPointer), 1, File);
    430     fread(New.HistBuffer, sizeof(EvidenceHistoryItem), HistSize, File);
    431     fclose(File);
     495    // Only load if current buffer size if equal or larger
     496    if (FileSize(File) <= HistSize*sizeof(char)+sizeof(New.Next) && FileSize(File) != -1) {
     497      fread(&New.Next, sizeof(New.Next), 1, File);
     498      fread(New.Buffer, sizeof(char), HistSize, File);
     499      fclose(File);
     500        }
    432501  }
    433502 
  • Evidence/Edd/Edd.cc

    r154 r159  
    99a DIM status service
    1010
    11 December 2009, Oliver Grimm
     11February 2010, Oliver Grimm
    1212
    1313============================================================ */
     
    3535 
    3636  // Connect to DIM handler
    37   if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QString, QByteArray, QString)), SLOT(Update(DimInfo*, int, QString, QByteArray, QString))) == false) {
     37  if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
    3838    printf("Failed connection for %s\n", DIMService.toAscii().data());
    3939  }
     
    4343  Menu->addAction("Open history", this, SLOT(MenuOpenHistory()));
    4444  Menu->addAction("Copy service", this, SLOT(MenuCopyService()));
     45  Menu->addAction("Copy data", this, SLOT(MenuCopyData()));
    4546
    4647  // DIM client
    47   Data = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, (char *) NO_LINK, Handler);
     48  Data = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, NO_LINK, Handler);
    4849}
    4950
     
    5455
    5556// Update widget
    56 void Edd_Indicator::Update(DimInfo *Info, int Time, QString Format, QByteArray Data, QString Text) {
    57 
    58   if (Info != this->Data) return;
     57void Edd_Indicator::Update(DimInfo *Info, int Time, QByteArray Array, QString Text) {
     58
     59  if (Info != Data) return;
    5960   
    6061  QPalette Pal = palette(); 
     
    6768  }
    6869  else {
    69     // If this is a status indicator, adapt background colour
    70     if (Data.size() == Text.size()+2) {
    71       switch (Data[Text.size() + 1]) {
    72         case 0:  Pal.setColor(QPalette::Base, Qt::white); break;
    73         case 1:  Pal.setColor(QPalette::Base, Qt::yellow); break;
    74         case 2:  Pal.setColor(QPalette::Base, Qt::red); break;
    75         case 3:  Pal.setColor(QPalette::Base, Qt::red); break;
    76         default: break;
    77       }
     70    // Backgound colour determined by last byte
     71    switch (Array[Array.size()]) {
     72      case 0:  Pal.setColor(QPalette::Base, Qt::white); break;
     73      case 1:  Pal.setColor(QPalette::Base, Qt::yellow); break;
     74      case 2:  Pal.setColor(QPalette::Base, Qt::red); break;
     75      case 3:  Pal.setColor(QPalette::Base, Qt::red); break;
     76      default: break;
    7877    }
    79     else Pal.setColor(QPalette::Base, Qt::white);
    8078       
    8179        if (!ShowAsTime) setText(Text);
     
    8381       
    8482    // Update status tip
    85     setStatusTip(QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Format));
     83    setStatusTip(QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Info->getFormat()));
    8684  }
    8785 
     
    134132}
    135133
    136 // Open history plot
     134// Menu: Open history plot
    137135void Edd_Indicator::MenuOpenHistory() {
    138136 
     
    141139}
    142140
    143 // Copy service name
     141// Menu: Copy service name
    144142void Edd_Indicator::MenuCopyService() {
    145143 
    146144  QApplication::clipboard()->setText(QString(Data->getName()));
     145}
     146
     147// Menu: Copy data
     148void Edd_Indicator::MenuCopyData() {
     149 
     150  QApplication::clipboard()->setText(text());
    147151}
    148152
     
    154158// Constructor
    155159//
    156 Edd_Plot::Edd_Plot(QString DIMService, QWidget *P): QwtPlot(P) {
     160Edd_Plot::Edd_Plot(QString DIMService, QWidget *P): QwtPlot(P), EvidenceHistory() {
    157161
    158162  setAcceptDrops(true);
     
    180184 
    181185  // Connect to DIM handler
    182   if (connect(Handler, SIGNAL(YEP(DimInfo *, int, QString, QByteArray, QString)), SLOT(Update(DimInfo *, int, QString, QByteArray, QString))) == false) {
     186  if (connect(Handler, SIGNAL(YEP(DimInfo *, int, QByteArray, QString)), SLOT(Update(DimInfo *, int, QByteArray, QString))) == false) {
    183187    printf("Failed connection for %s\n", DIMService.toAscii().data());
    184188  }
     
    211215
    212216  for (int i=0; i<Items.size(); i++) {
    213     delete Items[i].Data;
    214217    delete Items[i].LiveData;
    215218    delete Items[i].Signal;
    216     delete[] Items[i].x;
    217     delete[] Items[i].y;
    218219  } 
    219220  delete Grid;
     
    225226void Edd_Plot::AddService(QString Name) {
    226227
    227   QString HistName = Name+".hist";
    228 
    229228  // Lock before accessing Items list
    230229  QMutexLocker Locker(&Mutex);
    231230
    232   // Check if already subsribed to service
     231  // Check if already subscribed to service
    233232  for (int i=0; i<Items.size(); i++) {
    234     if (HistName == Items[i].Data->getName()) {
    235       QMessageBox::warning(this, "Edd Message",HistName+" already present",QMessageBox::Ok);
     233    if (Name == Items[i].LiveData->getName()) {
     234      QMessageBox::warning(this, "Edd Message",Name+".hist already present",QMessageBox::Ok);
    236235      return;
    237236    }
     
    242241  New.Signal = new QwtPlotCurve;
    243242  New.Signal->attach(this);
    244   New.Signal->setTitle(HistName);
     243  New.Signal->setTitle(Name+".hist");
    245244  New.Signal->setPen(QColor(LineColors[Items.size() % (sizeof(LineColors)/sizeof(Qt::GlobalColor))]));
    246   New.x = NULL;
    247   New.y = NULL;
    248   New.Count = 0;
    249   New.Data = new DimStampedInfo(HistName.toAscii().data(), (char *) NO_LINK, Handler);
    250   New.LiveData = new DimStampedInfo(Name.toAscii().data(), (char *) NO_LINK, Handler);
     245  New.SizeLimit = 5000;
     246  New.LiveData = new DimStampedInfo(Name.toAscii().data(), NO_LINK, Handler);
    251247
    252248  Items.append(New);
     
    254250
    255251// Update widget (must happen in GUI thread)
    256 void Edd_Plot::Update(DimInfo *Info, int Time, QString Format, QByteArray Data, QString Text) {
     252void Edd_Plot::Update(DimInfo *Info, int Time, QByteArray, QString Text) {
    257253
    258254  // Check if service available
     
    266262  // Determine which plot item this call belongs to
    267263  int ItemNo;
    268   for (ItemNo=0; ItemNo<Items.size(); ItemNo++) if (Info == Items[ItemNo].Data) {
    269     // This is a history service 
    270     EvidenceHistoryItem *Curr = (EvidenceHistoryItem *) Data.data();
    271     int Count=0, DataPoints = Data.size()/sizeof(struct EvidenceHistoryItem);
    272 
    273     delete[] Items[ItemNo].x;
    274     delete[] Items[ItemNo].y;
    275     Items[ItemNo].x = new int [DataPoints];
    276     Items[ItemNo].y = new double [DataPoints];
    277 
    278     // Find oldest item
    279     int Oldest;
    280     for (Oldest=1; Oldest<DataPoints; Oldest++) {
    281       if (Curr[Oldest].Seconds < Curr[Oldest-1].Seconds) break;
     264  for (ItemNo=0; ItemNo<Items.size(); ItemNo++) if (Info == Items[ItemNo].LiveData) {
     265 
     266        // If size limit reached, clear buffer
     267    if (Items[ItemNo].x.size() > Items[ItemNo].SizeLimit) {
     268          Items[ItemNo].x.clear();
     269          Items[ItemNo].y.clear();
    282270    }
    283271
    284     // Plot data starting with oldest value
    285     for (int i=0; i<DataPoints; i++) {
    286       Items[ItemNo].x[Count] = Curr[(i+Oldest)%DataPoints].Seconds;
    287       Items[ItemNo].y[Count] = Curr[(i+Oldest)%DataPoints].Value;
    288       if (Items[ItemNo].x[Count] != 0) Count++;
    289     }
    290 
    291     // Find smallest and largest item
    292     double Smallest = DBL_MAX, Largest = DBL_MIN;
    293     for (int i=0; i<Count; i++) {
    294       if (Largest < Items[ItemNo].y[i]) Largest = Items[ItemNo].y[i];
    295       if (Smallest > Items[ItemNo].y[i]) Smallest = Items[ItemNo].y[i];
    296     }
    297     Items[ItemNo].Smallest = Smallest;
    298     Items[ItemNo].Largest = Largest;
    299     Items[ItemNo].Count = Count;
    300 
    301     // Clear local history
    302     Items[ItemNo].Live.clear();
     272        // If buffer empty, request new history buffer
     273    if (Items[ItemNo].x.isEmpty()) {
     274          int Time, Size;
     275          void *Data;
     276
     277          if (GetHistory(Items[ItemNo].LiveData->getName())) {
     278        double Smallest = DBL_MAX, Largest = DBL_MIN;
     279                double Number=0;
     280                while (Next(Time, Size, Data)) {
     281                  switch (*(Info->getFormat())) {
     282                case 'I':  Number = *(int *) Data;   break;
     283                case 'S':  Number = *(short *) Data;   break;
     284                case 'F':  Number = *(float *) Data;   break;
     285                case 'D':  Number = *(double *) Data;   break;
     286                case 'X':  Number = *(long long *) Data;   break;
     287                default: break;
     288                  }
     289
     290                  Items[ItemNo].x.append(Time);
     291                  Items[ItemNo].y.append(Number);
     292                 
     293          if (Largest < Items[ItemNo].y.last()) Largest = Items[ItemNo].y.last();
     294          if (Smallest > Items[ItemNo].y.last()) Smallest = Items[ItemNo].y.last();
     295                }
     296
     297        Items[ItemNo].Smallest = Smallest;
     298        Items[ItemNo].Largest = Largest;
     299
     300                // Local buffer always at least twice as large as history
     301                if (Items[ItemNo].SizeLimit < 2*Items[ItemNo].x.size()) {
     302                  Items[ItemNo].SizeLimit = 2*Items[ItemNo].x.size();
     303                }               
     304          }
     305        }
     306
     307    // Append data
     308    Items[ItemNo].x.append(Time);
     309    Items[ItemNo].y.append(atof(Text.toAscii().data()));
     310
     311    // Update largest and smallest value   
     312    if (Items[ItemNo].y.last() > Items[ItemNo].Largest) Items[ItemNo].Largest = Items[ItemNo].y.last();
     313    if (Items[ItemNo].y.last() < Items[ItemNo].Smallest) Items[ItemNo].Smallest = Items[ItemNo].y.last();   
    303314
    304315    // Update status tip
    305316    QDateTime Timex = QDateTime::fromTime_t(Time);
    306     StatusTip = QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), Timex.toString()).arg(Format);
    307 
    308   } else if (Info == Items[ItemNo].LiveData) {
    309     // This is a live service
    310 
    311     // Limit size of list
    312     if (Items[ItemNo].Live.size() > 1000) Items[ItemNo].Live.removeFirst();
    313 
    314     // Append data
    315     struct EvidenceHistoryItem Data;
    316     Data.Seconds = Time;
    317     Data.Value = atof(Text.toAscii().data());           
    318     Items[ItemNo].Live.append(Data);
    319 
    320     // Update largest and smallest value   
    321     if (Data.Value > Items[ItemNo].Largest) Items[ItemNo].Largest = Data.Value;
    322     if (Data.Value < Items[ItemNo].Smallest) Items[ItemNo].Smallest = Data.Value;   
     317    StatusTip = QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), Timex.toString()).arg(Info->getFormat());
    323318  }
    324319
     
    352347    else Items[ItemNo].Signal->setSymbol(Sym1);
    353348
    354     int DataPoints = Items[ItemNo].Count + Items[ItemNo].Live.size();
     349    int DataPoints = Items[ItemNo].x.size();
    355350       
    356351        if (DataPoints == 0) continue;
     
    361356    // Adapt time scale and normalize y scale if requested
    362357    for (int i=0; i<DataPoints; i++) {
    363       if (i < Items[ItemNo].Count) {
    364         x[i] = Items[ItemNo].x[i] / 86400.0 + 40587.5 - 55200;
    365         y[i] = Items[ItemNo].y[i];
    366       }
    367       else {
    368         x[i]= Items[ItemNo].Live[i-Items[ItemNo].Count].Seconds / 86400.0 + 40587.5 - 55200;
    369         y[i] = Items[ItemNo].Live[i-Items[ItemNo].Count].Value;
    370       }
     358      x[i] = Items[ItemNo].x[i] / 86400.0 + 40587.5 - 55200;
     359      y[i] = Items[ItemNo].y[i];
    371360
    372361      if (NormAction->isChecked()) {
    373         if (Items[ItemNo].Smallest != Items[ItemNo].Largest) y[i] = (y[i] - Items[ItemNo].Smallest)/(Items[ItemNo].Largest-Items[ItemNo].Smallest);
    374         else y[i] = 1;
     362            if (Items[ItemNo].Smallest != Items[ItemNo].Largest) {
     363                  y[i] = (y[i] - Items[ItemNo].Smallest)/(Items[ItemNo].Largest-Items[ItemNo].Smallest);
     364                }
     365            else y[i] = 1;
    375366      } 
    376367    }
    377368
    378     // Plot datas
     369    // Plot data
    379370    Items[ItemNo].Signal->setData(x, y, DataPoints);
    380371    Items[ItemNo].Signal->show();
     
    443434
    444435  while (Items.size() > 1) { 
    445     delete Items.last().Data;
    446436    delete Items.last().LiveData;
    447437    delete Items.last().Signal;
    448     delete[] Items.last().x;
    449     delete[] Items.last().y;
    450438    Items.takeLast();
    451439  }
     
    473461   // Write x and y data for all signals to file
    474462  for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
    475     Stream << QString("# ")+Items[ItemNo].Data->getName() << endl;
     463    Stream << QString("# ")+Items[ItemNo].LiveData->getName()+".hist" << endl;
    476464    for (int i=0; i<Items[ItemNo].Signal->dataSize(); i++) {
    477       Stream << (int) Items[ItemNo].x[i] << " " << Items[ItemNo].Signal->y(i) << endl;
     465      Stream << (int) Items[ItemNo].x.at(i) << " " << Items[ItemNo].Signal->y(i) << endl;
    478466    }
    479467  }
     
    514502
    515503
     504///////////////////////////////////////
     505// History text box for DIM service //
     506//////////////////////////////////////
     507
     508//
     509// Constructor
     510//
     511Edd_TextHist::Edd_TextHist(QString DIMService, QWidget *P): QTextEdit(P), EvidenceHistory() {
     512 
     513  // Widget properties
     514  setReadOnly(true);
     515  setAttribute(Qt::WA_DeleteOnClose);
     516  setAutoFillBackground(true);
     517  document()->setMaximumBlockCount(1000);
     518 
     519  // Connect to DIM handler
     520  if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
     521    printf("Failed connection for %s\n", DIMService.toAscii().data());
     522  }
     523
     524  // Get history for this service
     525  int Time, Size;
     526  void *Data;
     527
     528  if (GetHistory(DIMService.toAscii().data())) {
     529        while (Next(Time, Size, Data)) {
     530          moveCursor (QTextCursor::Start);
     531          insertPlainText(QString("(")+QDateTime::fromTime_t(Time).toString()+") ");     
     532          insertPlainText(QString((char *) Data) + "\n");         
     533        }
     534  }
     535
     536  // DIM client
     537  Service = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, NO_LINK, Handler);
     538}
     539
     540// Destructor
     541Edd_TextHist::~Edd_TextHist() {
     542
     543  delete Service;
     544}
     545
     546
     547// Update widget (must happen in GUI thread)
     548void Edd_TextHist::Update(DimInfo *Info, int Time, QByteArray, QString Text) {
     549
     550  if (Info != this->Service) return;
     551
     552  // Check if service available
     553  if (Time == -1) {
     554        setStatusTip(QString("%1:  unavailable").arg(Info->getName()));
     555        return;
     556  }
     557
     558  QDateTime Timex = QDateTime::fromTime_t(Time);
     559
     560  moveCursor(QTextCursor::Start);
     561  insertPlainText(QString("(")+Timex.toString()+QString(") "));   
     562  insertPlainText(Text + "\n");   
     563       
     564  // Update status tip
     565  StatusTip = QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), Timex.toString()).arg(Info->getFormat());
     566}
     567
     568
    516569//////////////////
    517570// Text display //
     
    528581 
    529582  // Connect to DIM handler
    530   if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QString, QByteArray, QString)), SLOT(Update(DimInfo*, int, QString, QByteArray, QString))) == false) {
     583  if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
    531584    printf("Failed connection for %s\n", DIMService.toAscii().data());
    532585  }
    533586
    534587  // DIM client
    535   Data = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, (char *) NO_LINK, Handler);
     588  Data = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, NO_LINK, Handler);
    536589}
    537590
     
    543596
    544597// Handling of DIM service update
    545 void Edd_Textout::Update(DimInfo *Info, int Time, QString Format, QByteArray, QString Text) {
     598void Edd_Textout::Update(DimInfo *Info, int Time, QByteArray, QString Text) {
    546599
    547600  if (Info != this->Data) return;
     
    561614       
    562615    // Add if service contains only a string
    563     if (Format == "C") insertPlainText(Text);
     616    if (strcmp(Info->getFormat(), "C") == 0) insertPlainText(Text);
    564617
    565618    // Update status tip
    566     setStatusTip(QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Format));
     619    setStatusTip(QString("%1:  Last update %2  Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Info->getFormat()));
    567620  }
    568621  setPalette(Pal);
     
    652705  MainLayout->addWidget(Value, 7, 0, 1, 1);
    653706
     707  QPushButton *Button = new QPushButton();
     708  Button->setText("Start DIM browser");
     709  connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
     710  MainLayout->addWidget(Button, 7, 1, 1, 1);
     711
     712  Edd_TextHist *Bla;
     713  Bla = new Edd_TextHist("DColl/CurrentFile");
     714  MainLayout->addWidget(Bla, 8, 0, 1, 1);
    654715
    655716  // Layout of all widgets
     
    669730    Text = Text.sprintf("Bias/VOLT/ID00/00-%.3d",i);
    670731    Value = new Edd_Indicator(Text);
     732
    671733    BiasLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
    672734    Graph->AddService(Text);
     
    686748  Textout->setFixedWidth(400);
    687749  BiasLayout->addWidget(Textout, 10, 0, 4, 4);     
    688  
     750
    689751  // Environment page
    690752  EnvironmentWidget = new QWidget();
     
    772834
    773835  // Check if service available
    774   if (getInfo()->getSize() == strlen(NO_LINK)+1 && strcmp(getInfo()->getString(), NO_LINK) == 0) {
    775     YEP(getInfo(), -1);
    776   }
     836  if (!EvidenceServer::ServiceOK(getInfo())) YEP(getInfo(), -1);
    777837  else {
    778838    char *Txt = EvidenceServer::ToString(getInfo());
    779839
    780     YEP(getInfo(), getInfo()->getTimestamp(), getInfo()->getFormat(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), QString(Txt));
    781                 free(Txt);
    782   }
    783 }
     840    YEP(getInfo(), getInfo()->getTimestamp(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), QString(Txt));
     841        free(Txt);
     842  }
     843}
     844
     845// Start DIM Browser
     846void GUI::StartDIMBrowser() {
     847
     848  QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
     849}
     850
    784851
    785852//---------------------------------------------------------------------
  • Evidence/Edd/Edd.h

    r152 r159  
    4646       
    4747  private slots:
    48         void Update(DimInfo *, int, QString, QByteArray, QString);
     48        void Update(DimInfo *, int, QByteArray, QString);
    4949    void contextMenuEvent(QContextMenuEvent *);   
    5050    void MenuOpenHistory();
    5151    void MenuCopyService();
     52    void MenuCopyData();
    5253};
    5354
    5455// Graph class for history display
    55 class Edd_Plot: public QwtPlot, public DimClient {
     56class Edd_Plot: public QwtPlot, public EvidenceHistory {
    5657    Q_OBJECT
    5758
    5859    struct PlotItem {
    59       DimInfo *Data;
    6060      DimInfo *LiveData;
    6161      QwtPlotCurve *Signal;
    62       int *x;
    63       double *y;
    64       int Count;
    6562      double Smallest;
    6663      double Largest;
    67       QList<struct EvidenceHistoryItem> Live;
     64          int SizeLimit;
     65          QVector<double> x;
     66          QVector<double> y;     
    6867    };
    6968
     
    9392  private slots:
    9493    void UpdatePlot();
    95         void Update(DimInfo* Info, int, QString, QByteArray, QString);
     94        void Update(DimInfo* Info, int, QByteArray, QString);
    9695
    9796    void HandleZoom(const QwtDoubleRect &);
     
    106105};
    107106
     107// Text history class
     108class Edd_TextHist: public QTextEdit, public EvidenceHistory {
     109    Q_OBJECT
     110
     111        QString StatusTip;
     112        DimStampedInfo *Service;
     113       
     114  public:
     115    Edd_TextHist(QString, QWidget * = NULL);
     116    ~Edd_TextHist();
     117
     118  private slots:
     119        void Update(DimInfo* Info, int, QByteArray, QString);
     120};
     121
    108122// Textout indicator for DIM service
    109 class Edd_Textout: public QTextEdit, public DimClient {
     123class Edd_Textout: public QTextEdit, public EvidenceHistory {
    110124    Q_OBJECT
    111125
     
    119133       
    120134  private slots:
    121         void Update(DimInfo* Info, int, QString, QByteArray, QString);
     135        void Update(DimInfo* Info, int, QByteArray, QString);
    122136};
    123137
     
    143157    void MenuAbout();
    144158    void MenuNewHistory();
     159        void StartDIMBrowser();
    145160       
    146161  signals:
    147     void YEP(DimInfo *, int, QString = QString(), QByteArray = QByteArray(), QString = QString());
     162    void YEP(DimInfo *, int, QByteArray = QByteArray(), QString = QString());
    148163};
    149164
  • Evidence/Evidence.cc

    r154 r159  
    2525#include "Evidence.h"
    2626
     27using namespace std;
     28
     29//////////////////////////
     30// EvidenceServer Class //
     31//////////////////////////
     32
    2733EvidenceServer *ThisServer;
    2834
     
    5056  start(Name);
    5157  addExitHandler(this);
    52 
    5358}
    5459
     
    5661EvidenceServer::~EvidenceServer() {
    5762
     63  State(INFO, "Server stopped");
     64 
    5865  for (unsigned int i=0; i<ConfigList.size(); i++) {
    5966        delete[] ConfigList[i].Name;
     
    6471// DIM exit handler
    6572void EvidenceServer::exitHandler(int Code) {
    66   State(INFO, "Server stopped (DIM exit code %d)", Code);
     73  State(INFO, "Exit handler called (DIM exit code %d)", Code);
    6774  exit(EXIT_SUCCESS);
    6875}
     
    104111  // Send message to console and log file
    105112  printf("%s\n", TBuf);
    106   if (Severity != INFO) DimClient::sendCommand("DColl/Log", TBuf);
     113  DimClient::sendCommandNB("DColl/Log", TBuf);
    107114
    108115  // Update DIM status service (including severity encoding)
     
    188195
    189196// Translates DIMInfo to string (memory has to be freed by caller)
    190 // No DIM structures are supported (only a single number or string is converted)
     197// DIM structures are converted to hexadecimal representation
    191198// For string conversion, a terminating \0 is enforced.
    192199char *EvidenceServer::ToString(DimInfo *Item) {
    193200
    194201  char *Text;
    195   int R;
    196  
    197   if (strlen(Item->getFormat()) != 1) return NULL;
    198  
    199   switch (*(Item->getFormat())) {
    200     case 'I':  R = asprintf(&Text, "%d", Item->getInt());   break;
    201     case 'S':  R = asprintf(&Text, "%hd", Item->getShort());   break;
    202     case 'F':  R = asprintf(&Text, "%.5f", Item->getFloat());   break;
    203     case 'D':  R = asprintf(&Text, "%.5f", Item->getDouble());   break;
    204     case 'X':  R = asprintf(&Text, "%lld", Item->getLonglong());   break;
    205     case 'C':  *(Item->getString() + Item->getSize()) = '\0';
    206                            R = asprintf(&Text, "%s", Item->getString());
    207                            break;
    208     default: return NULL;
    209   }
    210 
     202  int R=0;
     203 
     204  if (strlen(Item->getFormat()) != 1) {
     205    if ((Text = (char *) malloc(3*Item->getSize()+1)) != NULL) {
     206          for (int i=0; i<Item->getSize(); i++) sprintf(Text+3*i, "%02x", *((char *) Item->getData() + i));
     207        }
     208  }
     209  else {
     210        switch (*(Item->getFormat())) {
     211      case 'I':  R = asprintf(&Text, "%d", Item->getInt());   break;
     212      case 'S':  R = asprintf(&Text, "%hd", Item->getShort());   break;
     213      case 'F':  R = asprintf(&Text, "%.5f", Item->getFloat());   break;
     214      case 'D':  R = asprintf(&Text, "%.5f", Item->getDouble());   break;
     215      case 'X':  R = asprintf(&Text, "%lld", Item->getLonglong());   break;
     216      case 'C':  *(Item->getString() + Item->getSize() - 1) = '\0';
     217                                 R = asprintf(&Text, "%s", Item->getString());
     218                                 break;
     219      default: return NULL;
     220        }
     221  }
     222 
    211223  return (R == -1) ? NULL : Text;
    212224}
     225
     226// Checks if service contents indicates not available
     227bool EvidenceServer::ServiceOK(DimInfo *Item) {
     228
     229  return !((Item->getSize() == strlen(NO_LINK)+1) && 
     230          (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0));
     231
     232}
     233
     234
     235///////////////////////////
     236// EvidenceHistory Class //
     237///////////////////////////
     238
     239// Organisaztion of history buffer
     240// F | T S D | T S D | 0 0 ......  | T S D | T S D | 0 -1
     241//
     242// F: Offset of oldest entry  T: Time  S: Size  D: Data
     243// F, T, S: int
     244
     245// Marker for history buffer
     246const int EvidenceHistory::WrapMark[] = {0, -1};
     247const int EvidenceHistory::EndMark[] = {0, 0};
     248
     249// Constructor
     250EvidenceHistory::EvidenceHistory() {
     251
     252  Buffer = NULL;
     253}
     254
     255// Destructor
     256EvidenceHistory::~EvidenceHistory() {
     257
     258  delete[] Buffer;
     259}
     260
     261// Requests service history
     262bool EvidenceHistory::GetHistory(char *Name) {
     263
     264  DimCurrentInfo Info((string(Name)+".hist").c_str(), NO_LINK);
     265
     266  // Check if service available
     267  if (((Info.getSize() == strlen(NO_LINK)+1) && 
     268          (memcmp(Info.getData(), NO_LINK, Info.getSize()) == 0))) return false;
     269
     270  delete[] Buffer;
     271  BufferSize = Info.getSize();
     272  Buffer = new char [BufferSize];
     273
     274  memcpy(Buffer, Info.getData(), BufferSize);
     275  Offset = *(int *) Buffer;
     276 
     277  return true;
     278}
     279
     280// Returns next item in history buffer
     281bool EvidenceHistory::Next(int &Time, int &Size, void *&Data) {
     282
     283  if (Buffer == NULL) return false;
     284
     285  // Check for wrap around
     286  if (memcmp(Buffer+Offset, WrapMark, sizeof(WrapMark)) == 0) Offset = 4;
     287 
     288  // Check if at end of ring buffer
     289  if (memcmp(Buffer+Offset, EndMark, sizeof(EndMark)) == 0) return false;
     290
     291  Time = *(int *) (Buffer + Offset);
     292  Size = *(int *) (Buffer + Offset + sizeof(int));
     293  Data = Buffer + Offset + 2*sizeof(int);
     294
     295  Offset += *((int *) (Buffer + Offset) + 1) + 2*sizeof(int);
     296
     297  return true;
     298}
  • Evidence/Evidence.h

    r154 r159  
    1515#define STATUS_SIZE 1000                                        // Bytes for status service string
    1616
    17 using namespace std;
    18 
    19 // Declaration of item for history buffer (see DColl.cc)
    20 struct EvidenceHistoryItem {
    21   int Seconds;
    22   double Value;
    23 } __attribute__((__packed__));
    24 
    2517// Class declation of Evidence server
    2618class EvidenceServer: public DimServer {
     
    3224          int Time;
    3325        };
    34         vector<struct ConfigItem> ConfigList;
     26        std::vector<struct ConfigItem> ConfigList;
    3527
    3628    DimService *Status;
     
    5042        char* GetConfig(const char *, const char * = NULL);
    5143        static char* ToString(DimInfo *);
     44        static bool ServiceOK(DimInfo *);
    5245
    5346    bool ExitRequest;
    5447};
    5548
     49class EvidenceHistory: public DimClient {
     50
     51  static const int WrapMark[];
     52  static const int EndMark[];
     53
     54  std::string HistoryName;
     55  char *Buffer;
     56  int BufferSize;
     57  int Offset;
     58   
     59  public:
     60        EvidenceHistory();
     61        ~EvidenceHistory();
     62       
     63        bool GetHistory(char *);
     64        bool Next(int &, int &, void *&);
     65};
    5666#endif
Note: See TracChangeset for help on using the changeset viewer.