LdmrsSopasLayer.cpp
Go to the documentation of this file.
1 //
2 // LdmrsSopasLayer.cpp
3 //
4 //
5 #include "LdmrsSopasLayer.hpp"
6 #include "../datatypes/EvalCaseResult.hpp"
7 #include "../tools/errorhandler.hpp"
8 
9 namespace devices
10 {
11 
12 using namespace datatypes;
13 
14 //
15 // ****************************** LdmrsSopasLayer ************************************* //
16 //
17 
18 
19 
21  const UINT8 deviceId,
22  std::string ipAddress,
23  UINT16 portNumber,
24  bool weWantFieldData,
25  bool weWantScanData,
26  bool readOnlyMode)
27 {
28  m_beVerbose = false;
29 
30  m_manager = manager;
31  m_deviceId = deviceId;
32  m_ipAddress = ipAddress;
33  m_portNumber = portNumber;
34  m_weWantFieldData = weWantFieldData;
35  m_weWantScanData = weWantScanData;
36  m_readOnlyMode = readOnlyMode;
37 }
38 
39 
40 
42 {
43 }
44 
45 
46 
47 bool LdmrsSopasLayer::init(Tcp::DisconnectFunction disconnectFunction, void* obj)
48 {
49  bool success = SopasBase::init(CoLa_B,
50  m_ipAddress,
51  m_portNumber,
52  m_weWantScanData,
53  m_weWantFieldData,
54  m_readOnlyMode,
55  disconnectFunction, obj);
56 
57  if (success == true)
58  {
59  // Success
60  printInfoMessage("LdmrsSopasLayer::init: SopasBase was initialized successfully.", m_beVerbose);
61  }
62  else
63  {
64  printError("LdmrsSopasLayer::init: Failed, aborting!");
65  return false;
66  }
67 
68  //
69  // Connect to the sensor
70  //
71  success = connect();
72  if (success == true)
73  {
74  // Success
75  printInfoMessage("LdmrsSopasLayer::init: Connected to scanner successfully.", m_beVerbose);
76  }
77  else
78  {
79  printError("LdmrsSopasLayer::init: Failed to connect to scanner, aborting!");
80  return false;
81  }
82 
83  // Read the field and eval case configuration, but only if we want field data
84  if (m_weWantFieldData == true)
85  {
86  // Field configuration
87  printInfoMessage("LdmrsSopasLayer::init: Reading current field configuration.", m_beVerbose);
88  success = action_readFields();
89  if (success == true)
90  {
91  printInfoMessage("LdmrsSopasLayer::init: Successfully read the field configuration (" +
92  ::toString(m_fields.getFields().size()) + " fields).", m_beVerbose);
93 
94  // Post the fields to the manager
95  Fields* f = new Fields;
96  *f = m_fields;
97  f->setSourceId(m_deviceId);
98  m_manager->setDeviceData(f);
99  }
100  else
101  {
102  // Fail
103  printError("LdmrsSopasLayer::init: Failed to read the field configuration, aborting!");
104  return false;
105  }
106 
107  // Eval cases
108  printInfoMessage("LdmrsSopasLayer::init: Reading current eval case configuration.", m_beVerbose);
109  success = action_readEvalCases();
110  if (success == true)
111  {
112  printInfoMessage("LdmrsSopasLayer::init: Successfully read the eval cases (" +
113  ::toString(m_evalCases.getEvalCases().size()) + " cases).", m_beVerbose);
114 
115  // Post the eval cases to the manager
116  EvalCases* e = new EvalCases;
117  *e = m_evalCases;
118  e->setSourceId(m_deviceId);
119  m_manager->setDeviceData(e);
120  }
121  else
122  {
123  // Fail
124  printError("LdmrsSopasLayer::init: Failed to read the eval cases, aborting!");
125  return false;
126  }
127  }
128  else
129  {
130  printInfoMessage("LdmrsSopasLayer::init: Skipping field configuration as we want no field data.", m_beVerbose);
131  }
132 
133  return success;
134 }
135 
136 //
137 // Register for the wanted events.
138 //
140 {
141  bool beVerboseHere = m_beVerbose;
142 // beVerboseHere = true;
143 
144  printInfoMessage("LdmrsSopasLayer::run: Called.", beVerboseHere);
145 
146  bool result = false;
147 
148  // Field data?
149  if (m_weWantFieldData == true)
150  {
151  printInfoMessage("LdmrsSopasLayer::run: Now subscribing to EvalCaseResults.", beVerboseHere);
152  result = action_subscribeEvalCaseResults();
153  if (result == false)
154  {
155  // Fail
156  printError("LdmrsSopasLayer::run: Failed to subscribe to EvalCaseResults, aborting.");
157  return false;
158  }
159  printInfoMessage("LdmrsSopasLayer::run: Subscription to EvalCaseResults was successful.", beVerboseHere);
160  }
161 
162  // Here, we could also subscribe to scan data. However, scans are handeled more efficientely over the LUX
163  // interface, so we ignore this part here.
164  if (m_weWantScanData == true)
165  {
166 // printWarning("LdmrsSopasLayer::run: Scan data reading via SOPAS / CoLa is not implemented, ignoring this setting.");
167  printInfoMessage("LdmrsSopasLayer::run: Now subscribing to scan data.", beVerboseHere);
168  result = action_subscribeScanData();
169  if (result == false)
170  {
171  // Fail
172  printError("LdmrsSopasLayer::run: Failed to subscribe to scan data, aborting.");
173  return false;
174  }
175  printInfoMessage("LdmrsSopasLayer::run: Subscription to scan data was successful.", beVerboseHere);
176 
177  }
178 
179  return true;
180 }
181 
182 //
183 // Save all field-related (=SOPAS) parameters permanently.
184 // This function can be called from runlevel USER, so no login is required.
185 //
187 {
188  bool beVerboseHere = m_beVerbose;
189 // beVerboseHere = true;
190 
191  printInfoMessage("LdmrsSopasLayer::action_flashFieldParameters: Called.", beVerboseHere);
192 
193  if (isConnected() == false)
194  {
195  printWarning("LdmrsSopasLayer::action_flashFieldParameters: LD-MRS not connected - aborting.");
196  return false;
197  }
198 
199  bool result = false;
200  SopasAnswer* answer = NULL;
201  UINT8 parameterBuffer[128];
202  UINT16 parameterBufferLen = 0;
203 
204  result = invokeMethod(index_meth_FlashFieldParameters, parameterBuffer, parameterBufferLen, answer);
205 
206  if ((result == true) && (answer != NULL) && (answer->isValid() == true) && (answer->size() > 0))
207  {
208  // Evaluate answer. Successful? 0 = false, 1 = true
209  BYTE* buffer = answer->getBuffer();
210  UINT8 success = buffer[0]; // ::memread_UINT8 (buffer);
211  if (success == 0)
212  {
213  // 0 = Not successful
214  m_isLoggedIn = false;
215  result = false;
216  printError("LdmrsSopasLayer::action_flashFieldParameters: FlashFieldPara command was not successful!");
217  }
218  else
219  {
220  // Success
221  m_isLoggedIn = true;
222  result = true;
223  printInfoMessage("LdmrsSopasLayer::action_flashFieldParameters: Field parameters flashed successfully.", beVerboseHere);
224  }
225  }
226 
227  // free memory for answer
228  if (answer != NULL)
229  {
230  delete answer;
231  answer = NULL;
232  }
233 
234  printInfoMessage("LdmrsSopasLayer::action_flashFieldParameters: All done, leaving.", beVerboseHere);
235  return result;
236 }
237 
238 //
239 // Save all scan-related (=LUX/MRS) parameters permanently.
240 // This function can be called from runlevel USER, so no login is required.
241 //
243 {
244  bool beVerboseHere = m_beVerbose;
245 // beVerboseHere = true;
246 
247  printInfoMessage("LdmrsSopasLayer::action_flashMrsParameters: Called.", beVerboseHere);
248 
249  if (isConnected() == false)
250  {
251  printWarning("LdmrsSopasLayer::action_flashMrsParameters: LD-MRS not connected - aborting.");
252  return false;
253  }
254 
255  bool result = false;
256  SopasAnswer* answer = NULL;
257  UINT8 parameterBuffer[128];
258  UINT16 parameterBufferLen = 0;
259 
260  result = invokeMethod(index_meth_MthdFlashLUXParameters, parameterBuffer, parameterBufferLen, answer);
261 
262  if ((result == true) && (answer != NULL) && (answer->isValid() == true) && (answer->size() > 0))
263  {
264  // Evaluate answer. Successful? 0 = false, 1 = true
265  BYTE* buffer = answer->getBuffer();
266  UINT8 success = buffer[0]; // ::memread_UINT8 (buffer);
267  if (success == 0)
268  {
269  // 0 = Not successful
270  m_isLoggedIn = false;
271  result = false;
272  printError("LdmrsSopasLayer::action_flashMrsParameters: FlashLUXPara command was not successful!");
273  }
274  else
275  {
276  // Success
277  m_isLoggedIn = true;
278  result = true;
279  printInfoMessage("LdmrsSopasLayer::action_flashMrsParameters: MRS parameters flashed successfully.", beVerboseHere);
280  }
281  }
282 
283  // free memory for answer
284  if (answer != NULL)
285  {
286  delete answer;
287  }
288 
289  printInfoMessage("LdmrsSopasLayer::action_flashMrsParameters: All done, leaving.", beVerboseHere);
290 
291  return result;
292 }
293 
294 
295 //
296 // Log in as "Authorized client".
297 //
298 // This is required to set parameters.
299 //
301 {
302  bool beVerboseHere = m_beVerbose;
303 // beVerboseHere = true;
304 
305  // cola-B ByIndex
306  printInfoMessage("LdmrsSopasLayer::action_login: Trying to log in as authorized client.", beVerboseHere);
307 
308  bool result = false;
309 
310  if (isConnected() == true)
311  {
312  const static UINT32 passwordHash_LDMRS = 0xF4724744; // Hash for "client"
313  SopasAnswer* answer = NULL;
314 
315  INT8 level = 3; // 3 = AUTHORIZEDCLIENT
316  UINT8 parameterBuffer[128];
317  UINT16 parameterBufferLen = 0;
318 
319  colab::addIntegerToBuffer<INT8>(parameterBuffer, parameterBufferLen, level); // user level
320  colab::addIntegerToBuffer<UINT32>(parameterBuffer, parameterBufferLen, passwordHash_LDMRS); // password hash
321 
322  result = invokeMethod(index_meth_SetAccessMode, parameterBuffer, parameterBufferLen, answer);
323 
324  if ((result == true) && (answer != NULL) && (answer->isValid() == true) && (answer->size() > 0))
325  {
326  // Evaluate answer. Login successful? 0 = false, 1 = true
327  BYTE* buffer = answer->getBuffer();
328  UINT8 success = buffer[0]; // ::memread_UINT8 (buffer);
329  if (success == 0)
330  {
331  // 0 = Not successful
332  m_isLoggedIn = false;
333  result = false;
334  printError("LdmrsSopasLayer::action_login: Login was not successful!");
335  }
336  else
337  {
338  // Success
339  m_isLoggedIn = true;
340  result = true;
341  printInfoMessage("LdmrsSopasLayer::action_login: Login was successful.", beVerboseHere);
342  }
343  }
344 
345  // free memory for answer
346  if (answer != NULL)
347  {
348  delete answer;
349  }
350  }
351  else
352  {
353  printWarning("LdmrsSopasLayer::action_login: LD-MRS not connected - cannot login.");
354  }
355 
356  return result;
357 }
358 
359 
360 //
361 // Logout.
362 //
364 {
365  // cola-B ByIndex
366  bool beVerboseHere = m_beVerbose;
367 // beVerboseHere = true;
368 
369  // cola-B ByIndex
370  printInfoMessage("LdmrsSopasLayer::action_logout: Logging out now.", beVerboseHere);
371 
372  bool result = false;
373 
374  if (isConnected() == true)
375  {
376  const static UINT32 passwordHash_LDMRS = 0x00000000; // Not needed for LOGOUT
377  SopasAnswer* answer = NULL;
378 
379  INT8 level = 1; // 1 = Logout, 3 = AUTHORIZEDCLIENT
380  UINT8 parameterBuffer[128];
381  UINT16 parameterBufferLen = 0;
382 
383  colab::addIntegerToBuffer<INT8>(parameterBuffer, parameterBufferLen, level); // user level
384  colab::addIntegerToBuffer<UINT32>(parameterBuffer, parameterBufferLen, passwordHash_LDMRS); // password hash
385 
386  result = invokeMethod(index_meth_SetAccessMode, parameterBuffer, parameterBufferLen, answer);
387 
388  if ((result == true) && (answer != NULL) && (answer->isValid() == true) && (answer->size() > 0))
389  {
390  // Evaluate answer. Logout successful? 0 = false, 1 = true
391  BYTE* buffer = answer->getBuffer();
392  UINT8 success = buffer[0]; // ::memread_UINT8 (buffer);
393  if (success == 0)
394  {
395  // 0 = Not successful
396  result = false;
397  printError("LdmrsSopasLayer::action_logout: Logout was not successful!");
398  }
399  else
400  {
401  // Success
402  m_isLoggedIn = false;
403  result = true;
404  printInfoMessage("LdmrsSopasLayer::action_logout: Logout was successful.", beVerboseHere);
405  }
406  }
407 
408  // free memory for answer
409  if (answer != NULL)
410  {
411  delete answer;
412  }
413  }
414  else
415  {
416  printWarning("LdmrsSopasLayer::action_logout: LD-MRS not connected - cannot log out, aborting.");
417  }
418 
419  return result;
420 }
421 
422 
423 //
424 // Subscribe to EvalCase results. After the subscription, the scanner will send EvalCaseResults whenever
425 // there is a change in the EvalCase status.
426 //
428 {
429  // cola-B ByIndex
430  bool result = false;
431 
432  if (isConnected() == false)
433  {
434  printError("LdmrsSopasLayer::action_subscribeEvalCaseResults: LD-MRS not connected, aborting!");
435  return false;
436  }
437 
438  result = registerEvent((UINT16)(index_event_aEvalCaseResult));
439 
440  if (result == true)
441  {
442  m_fieldEventIsRegistered = true;
443  }
444  else
445  {
446  printError("LdmrsSopasLayer::action_subscribeEvalCaseResults: Failed to subscribe, aborting!");
447  }
448 
449  return result;
450 }
451 
452 //
453 // Un-subscribe from the EvalCase results.
454 //
456 {
457  // cola-B ByIndex
458  bool result = unregisterEvent((UINT16)(index_event_aEvalCaseResult));
459 
460  if (result == true)
461  {
462  m_fieldEventIsRegistered = false;
463  }
464  else
465  {
466  printError("LdmrsSopasLayer::action_unSubscribeEvalCases: Failed to un-subscribe, aborting!");
467  }
468 
469  return result;
470 }
471 
472 
473 
474 //
475 // Subscribe to scan data. After the subscription, the scanner will send new scan data whenever
476 // a scan is ready.
477 //
479 {
480  bool beVerboseHere = m_beVerbose;
481 // beVerboseHere = true;
482  printInfoMessage("LdmrsSopasLayer::action_subscribeScanData: Called.", beVerboseHere);
483 
484  // cola-B ByIndex
485  bool result = false;
486 
487  if (isConnected() == false)
488  {
489  printError("LdmrsSopasLayer::action_subscribeScanData: LD-MRS not connected, aborting!");
490  return false;
491  }
492 
493  result = registerEvent((UINT16)(index_event_ScanDataMonitor));
494 
495  if (result == true)
496  {
497  m_scanEventIsRegistered = true;
498  }
499  else
500  {
501  printError("LdmrsSopasLayer::action_subscribeScanData: Failed to subscribe, aborting!");
502  }
503 
504  printInfoMessage("LdmrsSopasLayer::action_subscribeScanData: Done, leaving.", beVerboseHere);
505  return result;
506 }
507 
508 
509 //
510 // Un-subscribe from the scan data.
511 //
513 {
514  // cola-B ByIndex
515  bool result = unregisterEvent((UINT16)(index_event_ScanDataMonitor));
516 
517  if (result == true)
518  {
519  m_scanEventIsRegistered = false;
520  }
521  else
522  {
523  printError("LdmrsSopasLayer::action_unSubscribeScanData: Failed to un-subscribe, aborting!");
524  }
525 
526  return result;
527 }
528 
529 
530 
531 
533 {
534  SopasAnswer* answer = NULL;
535  bool success = readVariable(index_var_ScanConfig, answer);
536 
537  if (success && answer != NULL && answer->size() > 0)
538  {
539  // decode scanconfig
540  BYTE* bufferPos = answer->getBuffer();
541  ScanFreqEnum scanFreqEnum = ScanFreqEnum(memread_UINT8(bufferPos));
542 
543  switch (scanFreqEnum)
544  {
545  case ScanFreq1250:
546  m_scanFreq = 12.5;
547  break;
548  case ScanFreq2500:
549  m_scanFreq = 25.;
550  break;
551  case ScanFreq5000:
552  m_scanFreq = 50.;
553  break;
554  }
555 
556  UINT16 length = memread_UINT16(bufferPos);
557 
558  if (length > 0)
559  {
560  m_angleResolution = angleToRad(memread_INT16(bufferPos));
561  m_scanStartAngle = angleToRad(memread_INT16(bufferPos));
562  m_scanEndAngle = angleToRad(memread_INT16(bufferPos));
563  }
564  }
565 
566  if (answer != NULL)
567  {
568  delete answer;
569  }
570 
571  return success;
572 }
573 
574 //
575 // Read the current eval cases.
576 // Note that this is 'just' the configuration of the eval cases, not their current evaluation status,
577 // which is the EvalCaseResult.
578 //
580 {
581  SopasAnswer* answer = NULL;
582  bool success = readVariable(index_var_evalCaseParam, answer);
583 
584  if (success)
585  {
586  m_evalCases = colaB_evalCaseDecoder(answer);
587  }
588 
589  if (answer != NULL)
590  {
591  delete answer;
592  }
593 
594  return success;
595 }
596 
597 //
598 // Decode the configured eval cases.
599 //
601 {
602  bool beVerboseHere = m_beVerbose;
603 // beVerboseHere = true;
604 
605  printInfoMessage("LdmrsSopasLayer::colaB_evalCaseDecoder: Called.", beVerboseHere);
606 
607  EvalCases evalCases;
608 
609  if (answer != NULL && answer->size() > 0)
610  {
611  // decode answer
612  BYTE* bufferPos = answer->getBuffer();
613 
614  UINT16 arrayLength = memread_UINT16(bufferPos);
615 
616  for (UINT16 i = 0; i < arrayLength; ++i)
617  {
618  EvalCase_ptr evalCasePtr(new EvalCase);
619  EvalCase& evalCase = *evalCasePtr; // just for easier access
620 
621  evalCase.setVersionNumber(memread_UINT16(bufferPos));
622  evalCase.setCaseNumber(memread_UINT8(bufferPos));
624  evalCase.setResultNegation(memread_UINT8(bufferPos) != 0);
625  evalCase.setResponseTime(memread_UINT32(bufferPos));
626  evalCase.setResponseTimeExtended(memread_UINT32(bufferPos));
627  evalCase.setOutputNumber(memread_UINT8(bufferPos));
628  // EnumX
629  // no hardware inputs available
630 // evalCase.setHardwareInputs(EvalCaseParameter::inputState_from_UINT8(memread_UINT8(bufferPos), 2));
631 // memread_UINT8(bufferPos); // reserved
632  UINT8 inputs = memread_UINT8(bufferPos);
633  evalCase.setLogicalInputState_from_UINT8(inputs);
634  memread_UINT8(bufferPos); // reserved
635  evalCase.setDistDependent(memread_UINT8(bufferPos) != 0);
636  evalCase.setMaxRadialCorridor(double(memread_UINT16(bufferPos)) / 1000. ); // conversion from [mm] to [m]
638  evalCase.setBlankingSize(double(memread_UINT16(bufferPos)) / 1000.); // conversion from [mm] to [m]
639  evalCase.setMinFieldExp(double(memread_UINT16(bufferPos)) / 1000.); // conversion from [mm] to [m]
640  evalCase.setFieldNumber(memread_UINT8(bufferPos));
641  evalCase.setFilterType(EvalCase::FilterType(memread_UINT8(bufferPos)));
642 
643  UINT16 nameLength = memread_UINT16(bufferPos);
644 
645  std::string name = std::string((char *)bufferPos, nameLength);
646  bufferPos += nameLength;
647  evalCase.setCaseName(name);
648  printInfoMessage("LdmrsSopasLayer::colaB_evalCaseDecoder: Decoding EvalCase with the name " +
649  name + ". Inputs: " + ::toHexString(inputs) + ".", beVerboseHere);
650 
651  UINT16 commentLength = memread_UINT16(bufferPos);
652  std::string comment = std::string((char*)bufferPos, commentLength);
653  bufferPos += commentLength,
654  evalCase.setComment(comment);
655 
656  evalCases.add(evalCasePtr);
657  }
658  }
659 
660  printInfoMessage("LdmrsSopasLayer::colaB_evalCaseDecoder: Done. Decoded " +
661  ::toString(evalCases.getEvalCases().size()) + " cases.", beVerboseHere);
662 
663  return evalCases;
664 }
665 
666 //
667 // Encode the given eval cases.
668 // Returns the number of bytes that have been written into the buffer.
669 //
671 {
672  bool beVerboseHere = m_beVerbose;
673 // beVerboseHere = true;
674 
675  printInfoMessage("LdmrsSopasLayer::colaB_evalCaseEncoder: Called.", m_beVerbose);
676 
677  //
678  // Encode the cases
679  //
680  BYTE* bufferPos = buffer;
681 
682  // Number of eval cases
683  UINT16 arrayLength = evalCases.getEvalCases().size();
684  memwrite_UINT16(bufferPos, arrayLength);
685 
686  // The cases
687  for (UINT16 i = 0; i < arrayLength; i++)
688  {
689  EvalCase* evalCase = evalCases.getEvalCases().at(i);
690 
691  printInfoMessage("LdmrsSopasLayer::colaB_evalCaseEncoder: Encoding EvalCase with the name " +
692  evalCase->getCaseName() + ".", beVerboseHere);
693 
694  // Version number
695  UINT16 versionNumber = evalCase->getVersionNumber();
696  memwrite_UINT16(bufferPos, versionNumber);
697 
698  // Case number
699  UINT8 caseNumber = evalCase->getCaseNumber();
700  memwrite_UINT8(bufferPos, caseNumber);
701 
702  // Eval strategy
703  UINT8 evalStrategy = (UINT8)(evalCase->getStrategy());
704  memwrite_UINT8(bufferPos, evalStrategy);
705 
706  // Result negation
707  bool resultNegation = evalCase->getResultNegation();
708  if (resultNegation == true)
709  {
710  memwrite_UINT8(bufferPos, 1);
711  }
712  else
713  {
714  memwrite_UINT8(bufferPos, 0);
715  }
716 
717  // Response time
718  UINT32 responseTime = evalCase->getResponseTime();
719  memwrite_UINT32(bufferPos, responseTime);
720 
721  // Response time extended
722  UINT32 responseTimeExtended = evalCase->getResponseTimeExtended();
723  memwrite_UINT32(bufferPos, responseTimeExtended);
724 
725  // Output number
726  UINT8 outputNumber = evalCase->getOutputNumber();
727  memwrite_UINT8(bufferPos, outputNumber);
728 
729  // Assigned inputs
730  UINT8 logicalInputs = evalCase->getLogicalInputState_as_UINT8();
731  memwrite_UINT8(bufferPos, logicalInputs);
732 
733  memread_UINT8(bufferPos); // reserved
734 
735  // DistDependent
736  bool distDependent = evalCase->getDistDependent();
737  if (distDependent == true)
738  {
739  memwrite_UINT8(bufferPos, 1);
740  }
741  else
742  {
743  memwrite_UINT8(bufferPos, 0);
744  }
745 
746  // RadialCorridor
747  UINT16 maxRadialCorridor = (UINT16)((evalCase->getMaxRadialCorridor() * 1000.0) + 0.5);
748  memwrite_UINT16(bufferPos, maxRadialCorridor);
749 
750  // Sensitivity
751  UINT8 manipulationPrevention = (UINT8)(evalCase->getManipulationPrevention()); // Effectively boolean
752  memwrite_UINT8(bufferPos, manipulationPrevention);
753 
754  // Blanking size
755  UINT16 blankingSize = (UINT16)((evalCase->getBlankingSize() * 1000.0) + 0.5);
756  memwrite_UINT16(bufferPos, blankingSize);
757 
758  // MinFieldExp
759  UINT16 minFieldExp = (UINT16)((evalCase->getMinFieldExp() * 1000.0) + 0.5);
760  memwrite_UINT16(bufferPos, minFieldExp);
761 
762  // Field number (of assigned field)
763  UINT8 fieldNumber = evalCase->getFieldNumber();
764  memwrite_UINT8(bufferPos, fieldNumber);
765 
766  // Filter type
767  UINT8 filterType = (UINT8)(evalCase->getFilterType());
768  memwrite_UINT8(bufferPos, filterType);
769 
770  // Name length + name
771  std::string name = evalCase->getCaseName();
772  memwrite_UINT16(bufferPos, name.length());
773  memwrite_string(bufferPos, name);
774 
775  // Comment length + comment
776  std::string comment = evalCase->getComment();
777  memwrite_UINT16(bufferPos, comment.length());
778  memwrite_string(bufferPos, comment);
779  }
780 
781  // How many bytes have been used?
782  UINT32 len = (UINT32)((UINT64)bufferPos - (UINT64)buffer);
783 
784  printInfoMessage("LdmrsSopasLayer::colaB_evalCaseEncoder: Done. Encoded " +
785  ::toString(evalCases.getEvalCases().size()) + " cases. Used " +
786  ::toString(len) + " bytes.", beVerboseHere);
787 
788  return len;
789 }
790 
791 
792 //
793 // Write a single field.
794 // fieldNum = Number of the field to be written (0..15).
795 //
796 // Must be logged in as AuthorizedClient in order to do this.
797 //
799 {
800  bool beVerboseHere = m_beVerbose;
801 // beVerboseHere = true;
802 
803  printInfoMessage("LdmrsSopasLayer::action_writeField: Called for field " + toString(fieldNum) + ".", beVerboseHere);
804  bool result = false;
805 
806  if (fieldNum > 15)
807  {
808  printError("LdmrsSopasLayer::action_writeField: FieldNum must be 0..15, but is " + toString(fieldNum) + ", aborting!");
809  return false;
810  }
811 
812  // Build the internal data structure
813  UINT32 bufferSize = 1024;
814  UINT16 usedBufferLen = 0;
815  BYTE* buffer = new BYTE[bufferSize];
816  usedBufferLen = colaB_fieldEncoder(buffer, para);
817 
818  // Write the variable
819  result = writeVariable(index_var_field000 + fieldNum, buffer, usedBufferLen);
820 
821  if (result == false)
822  {
823  // Failure
824  printError("LdmrsSopasLayer::action_writeField: Failed to write field " + toString(fieldNum) + ", aborting!");
825  return false;
826  }
827 
828  // All done
829  printInfoMessage("LdmrsSopasLayer::action_writeField: All done, leaving.", beVerboseHere);
830  return result;
831 }
832 
833 
834 //
835 // Write all eval cases.
836 //
837 // Must be logged in as AuthorizedClient in order to do this.
838 //
840 {
841  bool beVerboseHere = m_beVerbose;
842 // beVerboseHere = true;
843 
844  printInfoMessage("LdmrsSopasLayer::action_writeEvalCases: Called, with " + toString(evalCases.getEvalCases().size()) + " eval cases.", beVerboseHere);
845  bool result = false;
846 
847  if (evalCases.getEvalCases().size() > 16)
848  {
849  printError("LdmrsSopasLayer::action_writeEvalCases: The MRS can only handle up to 16 eval cases, aborting!");
850  return false;
851  }
852 
853  // Build the internal data structure
854  UINT32 bufferSize = 1024;
855  UINT16 usedBufferLen = 0;
856  BYTE* buffer = new BYTE[bufferSize];
857  usedBufferLen = colaB_evalCaseEncoder(buffer, evalCases);
858 
859  // Write the variable
860  result = writeVariable(index_var_evalCaseParam, buffer, usedBufferLen);
861 
862  if (result == false)
863  {
864  // Failure
865  printError("LdmrsSopasLayer::action_writeEvalCases: Failed to write eval cases, aborting!");
866  return false;
867  }
868 
869  // All done
870  printInfoMessage("LdmrsSopasLayer::action_writeEvalCases: All done, leaving.", beVerboseHere);
871  return result;
872 }
873 
874 
875 //
876 // Read the current parameters of all fields.
877 // The MRS always has 16 fields.
878 //
880 {
881  SopasAnswer* answer = NULL;
882  bool success;
883 
884  // Find out how many fields we've got
885  // Unfortunately, this does not work with the MRS. The reply is
886  // always "16".
887 /* success = readVariable(index_var_numOfParamFields, answer);
888  UINT16 numOfParamFields = 0;
889 
890  if ((success == true) &&
891  (answer != NULL) &&
892  (answer->size() > 0))
893  {
894  // always 0 !!! ???
895  BYTE* bufferPos = answer->getBuffer();
896  numOfParamFields = memread_UINT16(bufferPos);
897 
898  printInfoMessage("LdmrsSopasLayer::action_readFields: NumOfParamFields=" + toString(numOfParamFields) + ".", m_beVerbose);
899  }
900 
901  // Get rid of the answer
902  if (answer != NULL)
903  {
904  delete answer;
905  }
906 */
907  // Now read all possible fields
908  // As the parameter "index_var_numOfParamFields" seems unreliable, read all (!) possible fields.
909  for (UINT16 i = 0; i < MAX_NUM_OF_FIELDS; ++i)
910  {
911  printInfoMessage("LdmrsSopasLayer::action_readFields: Reading field " + toString(i) + ".", true);
912  success = readVariable(index_var_field000 + i, answer);
913 
914  if ((success == true) &&
915  (answer != NULL) &&
916  (answer->size() > 0))
917  {
918  FieldParameter* fieldPtr = colaB_fieldDecoder(answer);
919 
920  // handle dummy field answer: no field will be set
921  if (fieldPtr != NULL)
922  {
923  m_fields.add(fieldPtr);
924  }
925  }
926 
927  if (answer != NULL)
928  {
929  delete answer;
930  answer = NULL;
931  }
932  }
933 
934  return success;
935 }
936 
939 {
940  return ((double)angle / 32.0) * deg2rad;
941 }
942 
943 //
944 // Decode an incoming Field strucure. This is the parameter set for one of the 16 possible
945 // fields.
946 //
947 // Note: A field with field number = 0 is invalid.
948 //
950 {
951  bool beVerboseHere = m_beVerbose;
952 // beVerboseHere = true;
953 
954 
955  FieldParameter* fieldPtr(new FieldParameter);
956 
957  if ((answer != NULL) && (answer->size() > 0))
958  {
959  FieldParameter& field = *fieldPtr; // just for easier access
960  BYTE* bufferPos = answer->getBuffer();
961 
962  field.setDistScaleFactor(memread_float(bufferPos)); // [mm per step]
963  field.setDistScaleOffset(memread_float(bufferPos)); // [mm]
964  field.setAngleScaleFactor(memread_UINT32(bufferPos)); // 1/32°
965  field.setAngleScaleOffset(memread_INT32(bufferPos)); // 1/32°
966  field.setFieldTypeIntern(memread_UINT8(bufferPos)); // Field type (Rectangular or Segmented)
967  field.setFieldNumber(memread_UINT8(bufferPos));
968 
969  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: setDistScaleFactor: " + toString(field.getDistScaleFactor(), 2) + ".", beVerboseHere);
970  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: setDistScaleOffset: " + toString(field.getDistScaleOffset(), 2) + ".", beVerboseHere);
971  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: setAngleScaleFactor: " + toString(field.getAngleScaleFactor()) + ".", beVerboseHere);
972  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: setAngleScaleOffset: " + toString(field.getAngleScaleOffset()) + ".", beVerboseHere);
973  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: setFieldTypeIntern: " + toString((INT32)(field.getFieldTypeIntern())) + ".", beVerboseHere);
974  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Field number: " + toString(field.getFieldNumber()) + ".", beVerboseHere);
975 
976  // Segmented field
977  UINT16 fieldSeg = memread_UINT16(bufferPos);
978  if (fieldSeg == 1)
979  {
980  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Found segmented field.", beVerboseHere);
981 
982  UINT8 arrayLength = memread_UINT16(bufferPos);
983  FieldSegmented* seg(new FieldSegmented);
984 
985  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: ArrayLength=" + toString(arrayLength) + ".", beVerboseHere);
986 
987  // iterate through points to fill the polygon in the correct order
988  for (UINT8 i = 0; i < arrayLength; ++i)
989  {
990  UINT16 angleIdx = memread_UINT16(bufferPos);
991  UINT16 startDist = memread_UINT16(bufferPos);
992  UINT16 endDist = memread_UINT16(bufferPos);
993 
994  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Point " + toString(i) + ": AngIdx=" +
995  toString(angleIdx) + ", StartDist=" + toString(startDist) + ", EndDist=" +
996  toString(endDist) + ".", beVerboseHere);
997 
998  // start dist not valid if 65535
999  double s = (startDist == 65535) ? ::NaN_double : ((double)startDist / 1000.) * field.getDistScaleFactor() + (field.getDistScaleOffset() / 1000.); // from [mm] to [m]
1000  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: StartDist is " + toString(s, 2) + ".", beVerboseHere);
1001 
1002  // transform to 1/32° tics
1003  double angle = field.getAngleScaleOffset() + (double)angleIdx * field.getAngleScaleFactor();
1004  // Quick hack: The LD-MRS treats the angle direction differently as expected and defined in DIN70000. Therefore, the
1005  // sign has to be reversed here.
1006  angle = -angle;
1007  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Angle is " + toString(angle, 2) + ".", beVerboseHere);
1008 
1009  // end dist not valid if 65535
1010  double e = (endDist == 65535) ? ::NaN_double : ((double)endDist / 1000.) * field.getDistScaleFactor() + (field.getDistScaleOffset() / 1000.); // from [mm] to [m]
1011  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: EndDist is " + toString(e, 2) + ".", beVerboseHere);
1012 
1013  seg->addPoint(FieldSegmentedPoint(angleToRad(angle), s, e));
1014  }
1015  seg->computePolygon();
1016 
1017  field.setField((FieldDescription*)(seg));
1018  }
1019 
1020  // Rectangular field
1021  UINT16 fieldRect = memread_UINT16(bufferPos);
1022  if (fieldRect == 1)
1023  {
1024  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Found rectangular field.", beVerboseHere);
1025 
1026  FieldRectangle* rect(new FieldRectangle);
1027  INT32 refPointAngle = memread_INT32(bufferPos);
1028  // Quick hack: The LD-MRS treats the angle direction differently as expected. Therefore, the
1029  // sign has to be reversed here.
1030  refPointAngle = -refPointAngle;
1031  UINT32 refPointDist = (memread_UINT16(bufferPos) * field.getDistScaleFactor()) + field.getDistScaleOffset();
1032  INT32 rotAngle = memread_INT32(bufferPos);
1033  // Quick hack: The LD-MRS treats the angle direction differently as expected. Therefore, the
1034  // sign has to be reversed here.
1035  rotAngle = -rotAngle;
1036  UINT32 length = memread_UINT32(bufferPos); // width and length changed due to other coordiante system in LD-MRS!!!
1037  UINT32 width = memread_UINT32(bufferPos);
1038 
1039  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: refPointDist is " + toString(refPointDist) + ".", beVerboseHere);
1040  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: refPointAngle is " + toString(-refPointAngle) + ".", beVerboseHere);
1041  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: rotAngle is " + toString(rotAngle, 2) + ".", beVerboseHere);
1042  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: length is " + toString(length, 2) + ".", beVerboseHere);
1043  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: width is " + toString(width, 2) + ".", beVerboseHere);
1044 
1045  // convert to [m] and [rad]
1046  rect->setRefPointAngle(angleToRad(refPointAngle)); // 1/32°
1047  rect->setRefPointDist((double)refPointDist / 1000.);
1048  rect->setRotAngle(angleToRad(rotAngle));
1049  rect->setWidth((double) width / 1000.);
1050  rect->setLength((double) length / 1000.);
1051 
1052  rect->computePolygon();
1053 
1054  field.setField((FieldDescription*)(rect));
1055  }
1056 
1057  // Radial field
1058  UINT16 fieldRad = memread_UINT16(bufferPos);
1059  if (fieldRad == 1)
1060  {
1061  printError("LdmrsSopasLayer::colaB_fieldDecoder: Found radial field, but the LD-MRS does not support radial fields!");
1062  return NULL;
1063  }
1064 
1065  // Dynamic field
1066  UINT16 fieldDyn = memread_UINT16(bufferPos);
1067  if (fieldDyn == 1)
1068  {
1069  printError("LdmrsSopasLayer::colaB_fieldDecoder: Found dynamic field, but the LD-MRS does not support dynamic fields!");
1070  return NULL;
1071  }
1072 
1073  // The rest of the data
1074  UINT16 versionNumber = memread_UINT16(bufferPos);
1075  field.setVersionNumber(versionNumber);
1076  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Field version number= " + toString(versionNumber) + ".", beVerboseHere);
1077  UINT16 fieldNameLength = memread_UINT16(bufferPos);
1078 
1079  if (fieldNameLength > 0)
1080  {
1081  std::string fieldName = colab::getStringFromBuffer(bufferPos, fieldNameLength);
1082  field.setFieldName(fieldName);
1083 
1084  printInfoMessage("LdmrsSopasLayer::colaB_fieldDecoder: Field name= " + fieldName + ".", beVerboseHere);
1085  }
1086 
1087  UINT16 commentLength = memread_UINT16(bufferPos);
1088 
1089  if (commentLength > 0)
1090  {
1091  std::string comment = colab::getStringFromBuffer(bufferPos, commentLength);
1092  field.setComment(comment);
1093  }
1094 
1095  // Rest of information not needed and therefore not decoded
1096  // - bool enable layer filter
1097  // - layer bit field
1098  }
1099 
1100  return fieldPtr;
1101 }
1102 
1103 
1104 //
1105 // Decodes incoming scans.
1106 //
1107 // Note that the created scans are not sorted by (increasing) hporizontal scanpoint angle. Instead, the scanpoints
1108 // are decoded into the scan structure in the order in which they are transmitted in the message. If a sorted
1109 // scan is required, this has to be done.
1110 //
1112 {
1113  bool beVerboseHere = m_beVerbose;
1114  beVerboseHere = true; // false;
1115 
1116  // cola-B by index
1117  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Called. Decoding SOPAS frame with length=" +
1118  ::toString(frame.size()) + " bytes.", beVerboseHere);
1119 
1120  // Decode this data only if we want the results
1121  if (m_weWantScanData == false)
1122  {
1123  // No scan data wanted, so ignore this message.
1124  return;
1125  }
1126 
1127  std::string receivedName;
1128  UINT32 receiveIndex;
1129  BYTE* bufferPos;
1130 
1131  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Reading variable index.", beVerboseHere);
1132  receiveIndex = frame.getVariableIndex(); // byte number 12 13
1133 
1134  if (receiveIndex != index_event_ScanDataMonitor)
1135  {
1136  printError("LdmrsSopasLayer::scanDataDecoder: This is not a scan data message, aborting!");
1137  return;
1138  }
1139  else
1140  {
1141  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: This is a scan data message.", beVerboseHere);
1142  }
1143 
1144  // Obviously scan data events are registered. This is just for global information.
1145  m_scanEventIsRegistered = true;
1146 
1147  bufferPos = &(frame.getPayLoad()[5]); // pay load without "sSI + index (2 byte)"
1148  UINT16 versionNumber = memread_UINT16(bufferPos);
1149  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Version number=" + ::toString(versionNumber) + ".", beVerboseHere);
1150 
1151  // Device block
1152  UINT16 logicalNumber = memread_UINT16(bufferPos);
1153  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Logical number of the device=" + ::toString(logicalNumber) + ".", beVerboseHere);
1154  UINT32 serialNumber = memread_UINT32(bufferPos);
1155  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Serial number of the device=" + ::toString(serialNumber) + ".", beVerboseHere);
1156  UINT16 statusBits = memread_UINT16(bufferPos);
1157  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Status bits=" + ::toString(statusBits) + ".", beVerboseHere);
1158 
1159  // Status block
1160  UINT16 telegramCount = memread_UINT16(bufferPos);
1161  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Telegram count=" + ::toString(telegramCount) + ".", beVerboseHere);
1162  UINT16 scanCount = memread_UINT16(bufferPos);
1163  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Scan count=" + ::toString(scanCount) + ".", beVerboseHere);
1164  UINT32 systemTimeScan = memread_UINT32(bufferPos);
1165  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: System time scan=" + ::toString(systemTimeScan) + ".", beVerboseHere);
1166  UINT32 systemTimeTransmit = memread_UINT32(bufferPos);
1167  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: System time transmit=" + ::toString(systemTimeTransmit) + ".", beVerboseHere);
1168  UINT16 inputState = memread_UINT16(bufferPos);
1169  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Input state=" + ::toString(inputState) + ".", beVerboseHere);
1170  UINT16 outputState = memread_UINT16(bufferPos);
1171  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Output state=" + ::toString(outputState) + ".", beVerboseHere);
1172  UINT16 reserved_1 = memread_UINT16(bufferPos);
1173  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Reserved_1=" + ::toString(reserved_1) + ".", beVerboseHere);
1174  UINT32 scanFrequency = memread_UINT32(bufferPos); // [1/256 Hz]
1175  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Scan frequency=" + ::doubleToString(double(scanFrequency) / 256.0, 2) + " Hz.", beVerboseHere);
1176  UINT32 measurementFrequency = memread_UINT32(bufferPos); // [100 Hz]
1177  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Measurement frequency=" + ::doubleToString(double(measurementFrequency) / 10.0, 1) + " kHz.", beVerboseHere);
1178 
1179  // Encoder block (Always 0 as the MRS has no encoder inputs)
1180  UINT16 numOfEncoders = memread_UINT16(bufferPos);
1181  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of encoder blocks=" + ::toString(numOfEncoders) + ".", beVerboseHere);
1182  for (UINT16 i = 0; i<numOfEncoders; i++)
1183  {
1184  UINT32 encoderPos = memread_UINT32(bufferPos); // [inc]
1185  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Encoder position=" + ::toString(encoderPos) + " increments.", beVerboseHere);
1186  INT16 encoderSpeed = memread_INT16(bufferPos); // [inc/mm]
1187  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Encoder speed=" + ::toString(encoderSpeed) + " inc/mm.", beVerboseHere);
1188  }
1189 
1190  // 16-bit data channels
1191  UINT16 numOf16BitDataChannels = memread_UINT16(bufferPos);
1192  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of 16-bit data channels=" + ::toString(numOf16BitDataChannels) + ".", beVerboseHere);
1193 
1194  // Setup of the vertical layer angles. Only valid for standard "4-layer" devices,
1195  // so-called "8-layer" devices have different angles!
1196  double vAngles[4];
1197  vAngles[0] = -1.6 * 0.75 * deg2rad;
1198  vAngles[1] = -1.6 * 0.25 * deg2rad;
1199  vAngles[2] = 1.6 * 0.25 * deg2rad;
1200  vAngles[3] = 1.6 * 0.75 * deg2rad;
1201 
1202  // Create the new scan
1203  Scan* scan = new Scan;
1204  // Decode the range data
1205  for (UINT16 i = 0; i<numOf16BitDataChannels; i++)
1206  {
1207  // Data channel header
1208  std::string contentType = memread_string(bufferPos, 6);
1209  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Content type=" + contentType + ".", beVerboseHere);
1210  float scaleFactor = memread_float(bufferPos);
1211  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Scale factor=" + ::doubleToString(double(scaleFactor), 10) + ".", beVerboseHere);
1212  float scaleOffset = memread_float(bufferPos);
1213  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Scale offset=" + ::doubleToString(double(scaleOffset), 10) + ".", beVerboseHere);
1214  INT32 startAngle = memread_INT32(bufferPos); // [1/10000 deg]
1215  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Start angle=" + ::doubleToString(double(startAngle)/10000.0, 2) + ".", beVerboseHere);
1216  UINT32 angularResolution = memread_UINT16(bufferPos); // [1/10000 deg]. Decoded value is UINT16, but needed as UINT32 later.
1217  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Angular resolution=" + ::doubleToString(double(angularResolution)/10000.0, 2) + ".", beVerboseHere);
1218 
1219  // Decode the channel header
1220  UINT16 layer = contentType.c_str()[4] - 'A'; // A, B, C or D --> 0..3
1221  UINT16 echo = contentType.c_str()[5] - '1'; // 1, 2 or 3 --> 0..2
1222  if (layer > 3)
1223  {
1224  printError("LdmrsSopasLayer::scanDataDecoder: We have decoded an invalid layer value of " + toString(layer) + ", allowed is 0..3.");
1225  return;
1226  }
1227  if (echo > 2)
1228  {
1229  printError("LdmrsSopasLayer::scanDataDecoder: We have decoded an invalid echo value of " + toString(echo) + ", allowed is 0..2.");
1230  return;
1231  }
1232 
1233  // The data
1234  UINT16 numOf16BitData = memread_UINT16(bufferPos);
1235  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of 16-bit data=" + ::toString(numOf16BitData) + ".", beVerboseHere);
1236  for (UINT16 d = 0; d<numOf16BitData; d++)
1237  {
1238  // Read the point
1239  UINT16 data = memread_UINT16(bufferPos);
1240 // printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Data=" + ::toString(data) + ".", beVerboseHere);
1241 
1242  // Add the point only if it is valid.
1243  if ((data > 0) && (data != 0xFFFF))
1244  {
1245  // Create the new point structure in the scan, and fill it with the values
1246  ScanPoint& newPoint = scan->addNewPoint();
1247 
1248  // Horizontal angle
1249  double hAngle = ((startAngle + d * angularResolution) / 10000.0) * deg2rad; // hAngle is in [rad]
1250 
1251  // Radial distance
1252  double dist = (double(data) * scaleFactor) / 1000.0; // dist is in [m]
1253 
1254  // Set the dist and angle values
1255  newPoint.setPolar (dist, hAngle, vAngles[layer]);
1256 
1257  // Copy data to new scan point
1258  newPoint.setEchoWidth (0.0);
1259  newPoint.setFlags (0);
1260  newPoint.setSourceId (m_deviceId);
1261  newPoint.setLayer (layer);
1262  newPoint.setEchoNum (echo); // 0 or 1 or ...
1263  }
1264  }
1265  }
1266 
1267  // 8-bit data
1268  UINT16 numOf8BitDataChannels = memread_UINT16(bufferPos);
1269  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of 8-bit data channels=" + ::toString(numOf8BitDataChannels) + ".", beVerboseHere);
1270 
1271  // Position block (scanner coordinates)
1272  UINT16 numOfPositionBlocks = memread_UINT16(bufferPos);
1273  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of position blocks=" + ::toString(numOfPositionBlocks) + ".", beVerboseHere);
1274  if (numOfPositionBlocks == 1)
1275  {
1276  float posX = memread_float(bufferPos);
1277  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Position X=" + ::doubleToString(double(posX), 2) + ".", beVerboseHere);
1278  float posY = memread_float(bufferPos);
1279  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Position Y=" + ::doubleToString(double(posY), 2) + ".", beVerboseHere);
1280  float posZ = memread_float(bufferPos);
1281  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Position Z=" + ::doubleToString(double(posZ), 2) + ".", beVerboseHere);
1282  float rotX = memread_float(bufferPos); // roll angle
1283  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Rot angle X=" + ::doubleToString(double(rotX), 2) + ".", beVerboseHere);
1284  float rotY = memread_float(bufferPos);
1285  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Rot angle Y=" + ::doubleToString(double(rotY), 2) + ".", beVerboseHere);
1286  float rotZ = memread_float(bufferPos);
1287  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Rot angle Z=" + ::doubleToString(double(rotZ), 2) + ".", beVerboseHere);
1288  UINT8 rotMode = memread_UINT8(bufferPos);
1289  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Rot mode=" + ::toString(rotMode) + ".", beVerboseHere);
1290  }
1291 
1292  // Device name
1293  UINT16 numOfDeviceNames = memread_UINT16(bufferPos);
1294  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of device names=" + ::toString(numOfDeviceNames) + ".", beVerboseHere);
1295  if (numOfDeviceNames == 1)
1296  {
1297  UINT16 deviceNameStringLen = memread_UINT16(bufferPos);
1298  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Device name string length=" + ::toString(deviceNameStringLen) + ".", beVerboseHere);
1299  if (deviceNameStringLen > 16)
1300  {
1301  printError("LdmrsSopasLayer::scanDataDecoder: We have decoded an invalid device name string length of " +
1302  toString(deviceNameStringLen) + ", allowed is 0..16.");
1303  return;
1304  }
1305  std::string deviceName = memread_string(bufferPos, deviceNameStringLen);
1306  }
1307 
1308  // Comment block
1309  UINT16 numOfCommentBlocks = memread_UINT16(bufferPos);
1310  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Number of comment blocks=" + ::toString(numOfCommentBlocks) + ".", beVerboseHere);
1311  if (numOfCommentBlocks == 1)
1312  {
1313  UINT16 commentStringLen = memread_UINT16(bufferPos);
1314  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Comment string length=" + ::toString(commentStringLen) + ".", beVerboseHere);
1315  if (commentStringLen > 128)
1316  {
1317  printError("LdmrsSopasLayer::scanDataDecoder: We have decoded an invalid comment string length of " +
1318  toString(commentStringLen) + ", allowed is 0..128.");
1319  return;
1320  }
1321  std::string commentString = memread_string(bufferPos, commentStringLen);
1322  }
1323 
1324  //
1325  // Ignore the rest of the data as the MRS does not fill it with any information.
1326  //
1327 
1328 
1329  //
1330  // Set some information about the scanner. As we have very little information,
1331  // fill most values with "0.0".
1332  // For more information, use the LuxBase-Scandata instead.
1333  //
1334  // Create Scanner Info
1335  ScannerInfo si;
1336  si.setStartAngle(m_scanStartAngle);
1337  si.setEndAngle(m_scanEndAngle);
1338 // printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Scan start angle=" + ::doubleToString(scanStartAngle * rad2deg, 1) + ".", beVerboseHere);
1339 // printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Scan end angle=" + ::doubleToString(scanEndAngle * rad2deg, 1) + ".", beVerboseHere);
1340 
1341  si.setScanFrequency(double(scanFrequency) / 256.0);
1342  si.setBeamTilt(0.0); // For 8-layer devices, the beam tilt is different (either 1.2 or 1.6 deg)!
1343  si.setScanFlags(0);
1344  si.setScanNumber(scanCount);
1345  si.setDeviceID(m_deviceId);
1346  si.setScannerType(Sourcetype_LDMRS); // for compatibility, if no value is set in the scanner's config.
1347  Time start, end;
1348  start.set(double(systemTimeScan) / 1000000.0); // No real information available
1349  end.set((double(systemTimeScan) / 1000000.0) + (1.0 / (double(scanFrequency) / 256.0))); // No real information available
1350  si.setTimestamps(start, end);
1351 
1352  // Mounting position
1353  double yawAngle, pitchAngle, rollAngle, offsetX, offsetY, offsetZ;
1354  yawAngle = 0.0; // No information available
1355  pitchAngle = 0.0; // No information available
1356  rollAngle = 0.0; // No information available
1357  offsetX = 0.0; // No information available
1358  offsetY = 0.0; // No information available
1359  offsetZ = 0.0; // No information available
1360  Position3D mp(yawAngle, pitchAngle, rollAngle, offsetX, offsetY, offsetZ);
1361  si.setMountingPosition(mp);
1363 
1364  // Post this scan to the world above...
1365  scan->setSourceId(m_deviceId);
1366  m_manager->setDeviceData(scan);
1367 
1368  // All done
1369  printInfoMessage("LdmrsSopasLayer::scanDataDecoder: Done, leaving.", beVerboseHere);
1370 }
1371 
1372 
1373 //
1374 // Decodes incoming EvalCaseResult-Messages.
1375 //
1377 {
1378  // cola-B by index
1379  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: Called. Decoding SOPAS frame with length=" +
1380  ::toString(frame.size()) + " bytes.", m_beVerbose);
1381 
1382  if (m_weWantFieldData == true)
1383  {
1384  std::string receivedName;
1385  UINT32 receiveIndex;
1386  BYTE* bufferPos;
1387 
1388  EvalCaseResults* evalCases;
1389  evalCases = new EvalCaseResults();
1390  evalCases->setSourceId(m_deviceId);
1391 
1392  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: Reading variable index.", m_beVerbose);
1393  receiveIndex = frame.getVariableIndex(); // byte number 12 13
1394 
1395  if (receiveIndex != index_event_aEvalCaseResult)
1396  {
1397  printError("LdmrsSopasLayer::evalCaseResultDecoder: This is not an eval case message, aborting!");
1398  return;
1399  }
1400  else
1401  {
1402  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: This is an eval case message.", m_beVerbose);
1403  }
1404 
1405  // Obviously field events are registered. This is just for global information.
1406  m_fieldEventIsRegistered = true;
1407 
1408  // Read the number of eval cases
1409  bufferPos = &(frame.getPayLoad()[5]); // pay load without "sSI + index (2 byte)"
1410  UINT16 cases = memread_UINT16 (bufferPos); // 14 15, array length in sopas is always decoded in uint16 !!!
1411  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: This frame contains " + ::toString(cases) + " cases to decode.", m_beVerbose);
1412 
1413  UINT16 length;
1414  for (UINT16 i = 0; i < cases; i++)
1415  {
1416  EvalCaseResult result;
1417 
1418  result.uiVersionNo = memread_UINT16 (bufferPos); // 16 17
1419  result.CaseHdr.usiNumber = memread_UINT8 (bufferPos); // 18
1420  result.CaseHdr.udiSysCount = memread_UINT32 (bufferPos); // 19 20 21 22
1421  result.CaseHdr.dDistScaleFactor = memread_float (bufferPos); // 23 24 25 26
1422  result.CaseHdr.dDistScaleOffset = memread_float (bufferPos); // 27 28 29 30
1423  result.CaseHdr.uiAngleScaleFactor = memread_UINT32 (bufferPos); // 31 32 33 34
1424  result.CaseHdr.iAngleScaleOffset = memread_INT32 (bufferPos); // 35 36 37 38
1425  UINT8 caseResultMRS = memread_UINT8 (bufferPos);
1426  EvalCaseResult::CaseResult caseResult;
1427  std::string resTxt;
1428  switch (caseResultMRS)
1429  {
1430  case 1:
1431  caseResult = EvalCaseResult::ECR_DONT_CARE;
1432  resTxt = "dont_care";
1433  break;
1434  case 2:
1435  // NOTE: LD-MRS signals always ECR_FALLING instead of LOW
1436  caseResult = EvalCaseResult::ECR_FALLING;
1437  caseResult = EvalCaseResult::ECR_LOW;
1438  resTxt = "low";
1439  break;
1440  case 3:
1441  caseResult = EvalCaseResult::ECR_LOW;
1442  resTxt = "low";
1443  break;
1444  case 4:
1445  caseResult = EvalCaseResult::ECR_DETECTING;
1446  resTxt = "detecting";
1447  break;
1448  case 5:
1449  caseResult = EvalCaseResult::ECR_INVALID;
1450  resTxt = "invalid";
1451  break;
1452  case 6:
1453  // NOTE: LD-MRS signals always ECR_RAISING instead of HIGH
1454  caseResult = EvalCaseResult::ECR_RAISING;
1455  caseResult = EvalCaseResult::ECR_HIGH;
1456  resTxt = "high";
1457  break;
1458  case 7:
1459  caseResult = EvalCaseResult::ECR_HIGH;
1460  resTxt = "high";
1461  break;
1462  default:
1463  caseResult = EvalCaseResult::ECR_INVALID;
1464  resTxt = "invalid";
1465  break;
1466  }
1467  result.m_eCaseResult = caseResult; // 39
1468  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: CaseResult is <" + resTxt + ">.", m_beVerbose);
1469 
1470  // Dummy read for aFieldInfringement (always 0). Currently not in use, use the
1471  // result from above instead.
1472  length = memread_UINT16 (bufferPos); // 40 41
1473 // if (length == 0)
1474 // {
1475 // printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: FieldInfringement found.", m_beVerbose);
1476 // std::string fieldInfringement = colab::getStringFromBuffer(bufferPos, length);
1477 // printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: FieldInfringement: " + fieldInfringement + ".", m_beVerbose);
1478 // }
1479 
1480  length = memread_UINT16 (bufferPos); // 42 43
1481  if (length == 0)
1482  {
1483  result.m_sCaseName = "";
1484  }
1485  else
1486  {
1487  result.m_sCaseName = colab::getStringFromBuffer(bufferPos, length);
1488  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: Case name: " + result.m_sCaseName + ".", m_beVerbose);
1489  }
1490 
1491  length = memread_UINT16 (bufferPos); // 44 45
1492  if (length == 0)
1493  {
1494  result.m_sComment = "";
1495  }
1496  else
1497  {
1498  result.m_sComment = colab::getStringFromBuffer(bufferPos, length);
1499  printInfoMessage("LdmrsSopasLayer::evalCaseResultDecoder: Comment: "+ result.m_sComment + ".", m_beVerbose);
1500  }
1501 
1502  length = memread_UINT16 (bufferPos); // 46 47
1503  if (length == 1)
1504  {
1505  result.aTimeBlock.uiYear = memread_UINT16 (bufferPos);
1506  result.aTimeBlock.usiMonth = memread_UINT8 (bufferPos);
1507  result.aTimeBlock.usiDay = memread_UINT8 (bufferPos);
1508  result.aTimeBlock.usiHour = memread_UINT8 (bufferPos);
1509  result.aTimeBlock.usiMinute = memread_UINT8 (bufferPos);
1510  result.aTimeBlock.usiSec = memread_UINT8 (bufferPos);
1511  result.aTimeBlock.udiUSec = memread_UINT32 (bufferPos);
1512  }
1513 
1514  //traceDebug(LDMRS_VERSION) << result << std::endl;
1515  evalCases->add(result);
1516  }
1517 
1518  // notify only in case of data change
1519  if ((evalCases->size() > 0) &&
1520  ((*evalCases) != m_lastEvalCaseResults))
1521  {
1522  m_lastEvalCaseResults = *evalCases;
1523  m_manager->setDeviceData((BasicData*)evalCases);
1524  }
1525  }
1526  else
1527  {
1528  printWarning("LdmrsSopasLayer::evalCaseResultDecoder: Received eval case, but we do not want to listen to eval cases!");
1529 
1530  unregisterEvent(index_event_aEvalCaseResult);
1531  }
1532 }
1533 
1534 //
1535 //
1536 //
1538 {
1539  SensorStateInfo sensorStateInfo;
1540  sensorStateInfo.setSourceId(m_deviceId);
1541  sensorStateInfo.setEvalCases(m_evalCases);
1542  sensorStateInfo.setFields(m_fields);
1543 
1544  MeasurementList measureList;
1545  measureList.setSourceId(m_deviceId);
1546  Measurement meas;
1547 // measureList.setGroupName("SensorState");
1548 // measureList.setListName("SensorStates");
1549 
1551  meas.m_textValue = m_scannerName;
1552  measureList.m_list.push_back(meas);
1553 
1555  meas.m_textValue = m_scannerVersion;
1556  measureList.m_list.push_back(meas);
1557 
1559  meas.m_doubleValue = m_scanFreq;
1560  measureList.m_list.push_back(meas);
1561 
1563  meas.m_doubleValue = m_scanStartAngle;
1564  measureList.m_list.push_back(meas);
1565 
1567  meas.m_doubleValue = m_scanEndAngle;
1568  measureList.m_list.push_back(meas);
1569 
1571  meas.m_doubleValue = m_angleResolution;
1572  measureList.m_list.push_back(meas);
1573 
1574 // measureList.add(Measurement::Temperature, m_temperature);
1575 
1576  // no sensor state available
1577 // std::bitset<16> stateBits(state);
1578 // std::bitset<16> inputBits(inputs);
1579 // std::bitset<16> outputBits(outputs);
1580 
1581  // build sensorStateInfo
1582  // traceDebug("") << "state: " << stateBits << " - inputs: " << inputBits << " - outputs: " << outputBits << std::endl;
1583 // SensorStateInfo::StateMap stateMap;
1584 
1585 
1586 // stateMap[STATENAME_DEVICE_ERROR] = stateBits[0];
1587 // stateMap[STATENAME_CONTAMINATION_WARNING] = stateBits[1];
1588 // stateMap[STATENAME_CONTAMINATION_ERROR] = stateBits[2];
1589 // stateMap["N_TO_1_FILTER_ENABLED"] = m_bNto1FilterEnable;
1590 // stateMap["PARTICLE_FILTER_ENABLED"] = m_particleFilter.bEnable;
1591 // stateMap["MEAN_FILTER_ENABLED"] = m_meanFilter.bEnable;
1592 // sensorStateInfo.setStateMap(stateMap);
1593 
1594 // SensorStateInfo::StateVector inputStates(16, SensorStateInfo::OFF);
1595 // SensorStateInfo::StateVector outputStates(16, SensorStateInfo::OFF);
1596 // for (UINT32 j = 0; j < 16; ++j)
1597 // {
1598 // inputStates[j] = inputBits[j] ? SensorStateInfo::ON : SensorStateInfo::OFF;
1599 // outputStates[j] = outputBits[j] ? SensorStateInfo::ON : SensorStateInfo::OFF;
1600 // }
1601 // sensorStateInfo.setInputStates(inputStates);
1602 // sensorStateInfo.setOutputStates(outputStates);
1603 
1604 // measureList.add(Measurement::SerialNumber, serialNo);
1605  sensorStateInfo.setMeasurementList(measureList);
1606  sensorStateInfo.setLastKnownEvalCaseResults(m_lastEvalCaseResults);
1607 
1608  return sensorStateInfo;
1609 }
1610 
1611 
1612 //
1613 // Encode a FieldParameter structure into CoLa-B-data. This structure can then be sent to the MRS to
1614 // parametrize one of the 16 possible fields.
1615 // Returns the number of bytes that have been written into the buffer.
1616 //
1618 {
1619  bool beVerboseHere = m_beVerbose;
1620 // beVerboseHere = true;
1621 
1622  // Make a copy of the original buffer pos
1623  BYTE* bufferOrg = buffer;
1624 
1625  // Print some information about the field
1626  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: DistScaleFactor: " + toString(field.getDistScaleFactor(), 2) + ".", beVerboseHere);
1627  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: DistScaleOffset: " + toString(field.getDistScaleOffset(), 2) + ".", beVerboseHere);
1628  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: AngleScaleFactor: " + toString(field.getAngleScaleFactor()) + ".", beVerboseHere);
1629  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: AngleScaleOffset: " + toString(field.getAngleScaleOffset()) + ".", beVerboseHere);
1630  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: FieldTypeIntern: " + toString((INT32)(field.getFieldTypeIntern())) + ".", beVerboseHere);
1631  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: Field number: " + toString(field.getFieldNumber()) + ".", beVerboseHere);
1632 
1633  // Encode the first part
1634  memwrite_float(buffer, field.getDistScaleFactor());
1635  memwrite_float(buffer, field.getDistScaleOffset());
1636  memwrite_UINT32(buffer, field.getAngleScaleFactor());
1637  memwrite_INT32(buffer, field.getAngleScaleOffset());
1638  memwrite_UINT8(buffer, field.getFieldTypeIntern());
1639  memwrite_UINT8(buffer, field.getFieldNumber());
1640 
1641  // Segmented?
1643  {
1644  // Yes
1645  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: Writing a segmented field.", beVerboseHere);
1646  // There is 1 segmented field structure
1647  memwrite_UINT16(buffer, 1);
1648 
1649  // Number of points
1650  FieldSegmented* seg = (FieldSegmented*)field.getField();
1651  memwrite_UINT16(buffer, seg->getNumberOfPoints());
1652 
1653  // The points
1654  for (UINT16 p=0; p<seg->getNumberOfPoints(); p++)
1655  {
1656  // Angle index (transform to 1/32° tics)
1657 // double angle = angleToRad(field.getAngleScaleOffset() + (double)angleIdx * field.getAngleScaleFactor());
1658  double angle = seg->getPoints().at(p).getAngle() * rad2deg;
1659  angle = -angle;
1660  angle *= 32;
1661  INT32 angleInt = (INT32)angle;
1662  INT32 angleDiff = angleInt - field.getAngleScaleOffset();
1663  angleDiff /= field.getAngleScaleFactor();
1664  UINT16 angleIdx = (UINT16)angleDiff;
1665  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: AngleIdx = " + toString(angleIdx) + ".", beVerboseHere);
1666 
1667  memwrite_UINT16(buffer, angleIdx);
1668 
1669  // Start dist
1670  double startDist = seg->getPoints().at(p).getStartDist();
1671  if (startDist == NaN_double)
1672  {
1673  // Invalid
1674  memwrite_UINT16(buffer, 0xFFFF);
1675  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: StartDist = invalid.", beVerboseHere);
1676  }
1677  else
1678  {
1679  startDist *= 1000;
1680  startDist /= field.getDistScaleFactor();
1681  startDist -= field.getDistScaleOffset();
1682  UINT16 startDistInt = (UINT16)startDist;
1683  memwrite_UINT16(buffer, startDistInt);
1684  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: StartDist = " + toString(startDistInt) + ".", beVerboseHere);
1685  }
1686 
1687  // End dist
1688  double endDist = seg->getPoints().at(p).getEndDist();
1689  if (endDist == NaN_double)
1690  {
1691  // Invalid
1692  memwrite_UINT16(buffer, 0xFFFF);
1693  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: EndDist = invalid.", beVerboseHere);
1694  }
1695  else
1696  {
1697  endDist *= 1000;
1698  endDist /= field.getDistScaleFactor();
1699  endDist -= field.getDistScaleOffset();
1700  UINT16 endDistInt = (UINT16)endDist;
1701  memwrite_UINT16(buffer, endDistInt);
1702  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: EndDist = " + toString(endDistInt) + ".", beVerboseHere);
1703  }
1704  }
1705  }
1706  else
1707  {
1708  // It is not a segmented field
1709  memwrite_UINT16(buffer, 0);
1710  }
1711 
1712  // Rectangular?
1714  {
1715  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: Writing rectangular field.", beVerboseHere);
1716  memwrite_UINT16(buffer, 1);
1717 
1718  FieldRectangle* rect = (FieldRectangle*)field.getField();
1719 
1720  // RefPointAngle
1721  INT32 refPointAngle = rect->getRefPointAngle() * rad2deg * 32.0; // ) .getField(). = memread_INT32(bufferPos);
1722  refPointAngle = -refPointAngle;
1723  memwrite_INT32(buffer, refPointAngle);
1724 
1725  // RefPointDist
1726  UINT16 refPointDist = (UINT16)(((rect->getRefPointDist() * 1000.0) / field.getDistScaleFactor()) + field.getDistScaleOffset());
1727  memwrite_UINT16(buffer, refPointDist);
1728 
1729  // RotAngle
1730  INT32 rotAngle = rect->getRotAngle() * rad2deg * 32.0;
1731  rotAngle = -rotAngle;
1732  memwrite_INT32(buffer, rotAngle);
1733 
1734  // Length
1735  UINT32 length = rect->getLength() * 1000;
1736  memwrite_UINT32(buffer, length);
1737 
1738  // Width
1739  UINT32 width = rect->getWidth() * 1000;
1740  memwrite_UINT32(buffer, width);
1741  }
1742  else
1743  {
1744  // It is not a rectangular field
1745  memwrite_UINT16(buffer, 0);
1746  }
1747 
1748  // It is not a radial field - the MRS does not support radial fields
1749  memwrite_UINT16(buffer, 0);
1750 
1751  // It is not a dynamic field - the MRS does not support dynamic fields.
1752  memwrite_UINT16(buffer, 0);
1753 
1754  // Version number
1755  memwrite_UINT16(buffer, (UINT16)field.getVersionNumber());
1756 
1757  // Field name length
1758  memwrite_UINT16(buffer, (UINT16)field.getFieldName().length());
1759 
1760  // Field name
1761  if (field.getFieldName().length() > 0)
1762  {
1763  memwrite_string(buffer, field.getFieldName());
1764  }
1765 
1766  // Comment length
1767  memwrite_UINT16(buffer, (UINT16)field.getComment().length());
1768 
1769  // Comment
1770  if (field.getComment().length() > 0)
1771  {
1772  memwrite_string(buffer, field.getComment());
1773  }
1774 
1775  // enable layer filter
1776  memwrite_UINT8(buffer, 0x00); // 0 = disabled, 1 = enabled
1777 
1778  // layer bit field
1779  memwrite_UINT16(buffer, 0x000F); // 0x000F = all layers enabled
1780 
1781  // How many bytes have been used?
1782  UINT32 len = (UINT32)((UINT64)buffer - (UINT64)bufferOrg);
1783 
1784  printInfoMessage("LdmrsSopasLayer::colaB_fieldEncoder: Encoded " + toString(len) + " bytes. All done, leaving.", beVerboseHere);
1785 
1786  //
1787  // Debug
1788  //
1789 // traceBuffer("Field buffer contents:", bufferOrg, len);
1790 
1791  // Debug: Decode this set of data
1792 // SopasAnswer a(bufferOrg, len);
1793 // colaB_fieldDecoder(&a);
1794 
1795  return len;
1796 }
1797 
1798 
1799 } // namespace devices
double getDistScaleFactor() const
void setScannerType(UINT8 newScannerType)
void printError(std::string message)
void setSourceId(UINT8 id)
Definition: ScanPoint.hpp:166
std::string toString(const PositionWGS84::PositionWGS84SourceType &type)
const double NaN_double
Not-a-Number in double precision.
Definition: MathToolbox.cpp:13
void add(const EvalCaseResult &newCase)
BYTE * getPayLoad()
contains &#39;s&#39; + command string(2 byte) + content(payload length - 3)
Definition: SopasBase.cpp:2214
void setMountingPosition(const Position3D &v)
void setMinFieldExp(double minFieldExp)
Definition: EvalCase.cpp:195
void setResponseTime(UINT32 responseTime)
Definition: EvalCase.cpp:205
FieldSegmentedPoints getPoints()
Definition: Fields.cpp:71
void setDistDependent(bool distDependent)
Definition: EvalCase.cpp:160
unsigned char BYTE
void setStrategy(EvaluationStrategy strategy)
Definition: EvalCase.cpp:225
std::string toHexString(UINT32 val)
Definition: toolbox.cpp:71
Class that encapsulates a buffer that was sent as return to a sync call. (variable / method) ...
Definition: SopasBase.hpp:484
double getMaxRadialCorridor() const
Definition: EvalCase.cpp:77
#define rad2deg
const FieldDescription::FieldType getFieldType() const
uint16_t UINT16
A Position with orientation.
Definition: Position3D.hpp:149
double getRefPointDist() const
Definition: Fields.cpp:108
void add(EvalCase_ptr evalCase)
Definition: EvalCases.cpp:27
void setFields(const Fields &fields)
Class that represents a message that was sent by a sensor. (Event message)
Definition: SopasBase.hpp:416
void memwrite_UINT32(BYTE *&buffer, UINT32 value)
Definition: toolbox.cpp:554
std::string doubleToString(double val, std::string::size_type digits_before_decimal_point, std::string::size_type digits_after_decimal_point)
Definition: toolbox.cpp:307
void addPoint(const FieldSegmentedPoint &point)
Definition: Fields.hpp:107
void setFieldNumber(UINT16 fieldNumber)
Definition: EvalCase.cpp:170
Definition: Time.hpp:44
void setEndAngle(double v)
const std::string & getComment() const
Definition: EvalCase.cpp:51
void setEchoNum(UINT8 sub)
Definition: ScanPoint.hpp:169
INT32 getVariableIndex()
Returns the index of a variable (answer to read variable by index). In case of error a negative value...
Definition: SopasBase.cpp:2233
void setDistScaleFactor(double distScaleFactor)
double getMinFieldExp() const
Definition: EvalCase.cpp:82
std::string getStringFromBuffer(UINT8 *buffer, UINT16 &pos, UINT16 length)
Definition: colab.cpp:34
void setMeasurementList(const MeasurementList &m_measurementList)
void(* DisconnectFunction)(void *obj)
Definition: tcp.hpp:53
#define printInfoMessage(a, b)
bool getResultNegation()
Definition: EvalCase.cpp:220
ManipulationPrevention
Manipulation prevention. If active, shadowing of field parts may trigger an event.
Definition: EvalCase.hpp:58
void setDeviceID(UINT8 v)
Definition: ScannerInfo.hpp:43
void setScanFrequency(double freq)
Set the scanner&#39;s scan frequency in [Hz]. Must be non-negative.
void setAngleScaleFactor(UINT32 angleScaleFactor)
double getLength() const
Definition: Fields.cpp:98
uint32_t UINT32
const UINT16 getFieldNumber() const
double getRotAngle() const
Definition: Fields.cpp:113
void setScannerInfos(const ScannerInfoVector &v)
Definition: Scan.cpp:212
void setAngleScaleOffset(INT32 angleScaleOffset)
const std::string & getCaseName() const
Definition: EvalCase.cpp:41
const std::string & getFieldName() const
void setField(FieldDescription *field)
void setStartAngle(double v)
Definition: ScannerInfo.cpp:94
FilterType
kind of filter which is connected to evaluation case
Definition: EvalCase.hpp:65
void setScanNumber(UINT16 v)
Definition: ScannerInfo.hpp:53
UINT8 getOutputNumber() const
Definition: EvalCase.cpp:87
void evalCaseResultDecoder(SopasEventMessage &frame)
void setPolar(double dist, double hAngle, double vAngle)
Definition: ScanPoint.cpp:106
double getRefPointAngle() const
Definition: Fields.cpp:103
UINT32 colaB_fieldEncoder(BYTE *buffer, const FieldParameter &fieldPara)
void setEchoWidth(double echoWidth)
Set the echo pulse width, typically in [m].
Definition: ScanPoint.cpp:237
void setCaseName(const std::string &caseName)
Definition: EvalCase.cpp:133
#define deg2rad
FilterType getFilterType() const
Definition: EvalCase.cpp:61
void setOutputNumber(UINT8 outputNumber)
Definition: EvalCase.cpp:200
double getBlankingSize() const
Definition: EvalCase.cpp:36
LdmrsSopasLayer(Manager *manager, const UINT8 deviceID, std::string ipAddress, UINT16 portNumber, bool weWantFieldData, bool weWantScanData, bool readOnlyMode)
void setRefPointDist(double refPointDist)
Definition: Fields.cpp:143
void setFlags(UINT16 flags)
Sets the scan point flags directly.
Definition: ScanPoint.hpp:172
void memwrite_float(BYTE *&buffer, float value)
Definition: toolbox.cpp:534
UINT16 getFieldNumber() const
Definition: EvalCase.cpp:56
void set(double time)
Definition: Time.cpp:69
UINT32 getResponseTimeExtended() const
Definition: EvalCase.cpp:97
UINT32 getResponseTime() const
Definition: EvalCase.cpp:92
std::vector< Measurement > m_list
Definition: Measurement.hpp:89
void scanDataDecoder(SopasEventMessage &frame)
float memread_float(BYTE *&buffer)
Definition: toolbox.cpp:523
EvaluationStrategy getStrategy() const
Definition: EvalCase.cpp:102
ScanPoint & addNewPoint()
Definition: Scan.cpp:173
UINT8 memread_UINT8(BYTE *&buffer)
Definition: toolbox.cpp:464
bool action_writeField(UINT16 fieldNum, const FieldParameter &para)
MeasurementType m_measType
Definition: Measurement.hpp:57
FieldTypeIntern getFieldTypeIntern() const
void setRotAngle(double rotAngle)
Definition: Fields.cpp:152
bool action_writeEvalCases(const EvalCases &evalCases)
void setDistScaleOffset(double distScaleOffset)
void setWidth(double width)
Definition: Fields.cpp:163
INT32 getAngleScaleOffset() const
INT32 memread_INT32(BYTE *&buffer)
Definition: toolbox.cpp:485
const EvalCaseVector & getEvalCases() const
Definition: EvalCases.cpp:41
void memwrite_string(BYTE *&buffer, std::string text)
Definition: toolbox.cpp:604
void setVersionNumber(UINT16 versionNumber)
Definition: EvalCase.cpp:233
ManipulationPrevention getManipulationPrevention() const
Definition: EvalCase.cpp:246
void setBlankingSize(double blankingSize)
Definition: EvalCase.cpp:122
UINT8 getCaseNumber() const
Definition: EvalCase.cpp:46
int32_t INT32
SensorStateInfo getSensorStateInfo()
EvalCases colaB_evalCaseDecoder(SopasAnswer *answer)
UINT32 colaB_evalCaseEncoder(BYTE *buffer, const EvalCases &evalCases)
void setFieldTypeIntern(UINT8 fieldTypeIntern)
void setLogicalInputState_from_UINT8(UINT8 value)
Definition: EvalCase.cpp:260
double getWidth() const
Definition: Fields.cpp:118
struct datatypes::EvalCaseResult::@0 CaseHdr
void setCaseNumber(UINT8 caseNumber)
Definition: EvalCase.cpp:142
const std::string & getComment() const
double angleToRad(INT32 angle)
computes an angle in [rad] from INT32 as 1/10000 deg in scanner coordinate system ...
void setResultNegation(bool resultNegation)
Definition: EvalCase.cpp:215
void setLastKnownEvalCaseResults(const EvalCaseResults &evalCaseResults)
UINT32 getNumberOfPoints()
Definition: Fields.cpp:63
void setResponseTimeExtended(UINT32 responseTimeExtended)
Definition: EvalCase.cpp:210
void setLayer(UINT8 ch)
Definition: ScanPoint.hpp:168
void setMaxRadialCorridor(double maxRadialCorridor)
Definition: EvalCase.cpp:190
void memwrite_UINT16(BYTE *&buffer, UINT16 value)
Definition: toolbox.cpp:576
std::vector< ScannerInfo > ScannerInfoVector
Definition: Scan.hpp:31
void setScanFlags(UINT32 flags)
void setFilterType(FilterType filterType)
Definition: EvalCase.cpp:175
struct datatypes::EvalCaseResult::@1 aTimeBlock
void setManipulationPrevention(ManipulationPrevention manPrev)
Definition: EvalCase.cpp:251
void memwrite_UINT8(BYTE *&buffer, UINT8 value)
Definition: toolbox.cpp:586
int8_t INT8
void setComment(const std::string &comment)
UINT32 memread_UINT32(BYTE *&buffer)
Definition: toolbox.cpp:439
void setEvalCases(const EvalCases &evalCases)
double getDistScaleOffset() const
UINT32 getAngleScaleFactor() const
void setComment(const std::string &comment)
Definition: EvalCase.cpp:151
void setBeamTilt(double tilt)
FieldDescription * getField() const
int16_t INT16
void setTimestamps(const Time &start, const Time &end)
Set the start and end timestamp of the scan received by this scanner (in terms of the host computer c...
UINT16 getVersionNumber()
Definition: EvalCase.cpp:241
void setRefPointAngle(double refPointAngle)
Definition: Fields.cpp:138
UINT16 memread_UINT16(BYTE *&buffer)
Definition: toolbox.cpp:453
virtual void setSourceId(UINT16 id)
void setVersionNumber(UINT8 m_versionNumber)
const UINT8 getLogicalInputState_as_UINT8() const
Definition: EvalCase.cpp:71
void computePolygon()
fills the polygon clockwise
Definition: Fields.cpp:82
void setFieldNumber(UINT16 m_fieldNumber)
uint64_t UINT64
void printWarning(std::string message)
bool init(Tcp::DisconnectFunction function, void *obj)
void setLength(double length)
Definition: Fields.cpp:126
void memwrite_INT32(BYTE *&buffer, INT32 value)
Definition: toolbox.cpp:545
void setFieldName(const std::string &fieldName)
std::string memread_string(BYTE *&buffer, UINT16 length)
Definition: toolbox.cpp:498
uint8_t UINT8
INT16 memread_INT16(BYTE *&buffer)
Definition: toolbox.cpp:474
virtual bool init(SopasProtocol protocol, std::string ipAddress, UINT16 portNumber, bool weWantScanData, bool weWantFieldData, bool readOnlyMode, Tcp::DisconnectFunction disconnectFunction, void *obj)
Initialization.
Definition: SopasBase.cpp:96
void computePolygon()
fills the polygon clockwise
Definition: Fields.cpp:20
FieldParameter * colaB_fieldDecoder(SopasAnswer *answer)


libsick_ldmrs
Author(s): SICK AG , Martin Günther , Jochen Sprickerhof
autogenerated on Mon Oct 26 2020 03:27:30