43 #include "PlusConfigure.h" 44 #include "vtkIGSIORecursiveCriticalSection.h" 50 #include <ndicapi_math.h> 51 #include <ndicapi_serial.h> 54 #include <vtkCharArray.h> 56 #include <vtkMatrix4x4.h> 57 #include <vtkObjectFactory.h> 58 #include <vtkSocketCommunicator.h> 59 #include <vtkTimerLog.h> 60 #include <vtkTransform.h> 63 #include <igsioCommon.h> 71 #if defined(HAVE_FUTURE) 77 const int VIRTUAL_SROM_SIZE = 1024;
92 , LeaveDeviceOpenAfterProbe(false)
94 , MeasurementVolumeNumber(0)
97 , TrackingFrequencyNumber(0)
98 , FirmwareMajorRevision(1)
99 , FirmwareMinorRevision(1)
100 , HardwareDataAveragingDepth(1)
101 , CommandMutex(vtkIGSIORecursiveCriticalSection::New())
121 delete [] toolDescriptorIt->second.VirtualSROM;
122 toolDescriptorIt->second.VirtualSROM = NULL;
133 char ndiLog[USHRT_MAX];
134 ndiLogState(this->
Device, ndiLog);
136 os << indent <<
"SerialDevice: " << this->
SerialDevice << std::endl;
137 os << indent <<
"SerialPort: " << this->
SerialPort << std::endl;
138 os << indent <<
"BaudRate: " << this->
BaudRate << std::endl;
139 os << indent <<
"IsDeviceTracking: " << this->
IsDeviceTracking << std::endl;
142 os << indent <<
"CommandReply: " << this->
CommandReply << std::endl;
143 os << indent <<
"LastFrameNumber: " << this->
LastFrameNumber << std::endl;
145 os << indent <<
"CheckDSR: " << this->
CheckDSR << std::endl;
151 os << indent <<
iter->first <<
": " << std::endl;
152 os << indent <<
" " <<
"PortEnabled: " <<
iter->second.PortEnabled << std::endl;
153 os << indent <<
" " <<
"PortHandle: " <<
iter->second.PortHandle << std::endl;
154 os << indent <<
" " <<
"VirtualSROM: " <<
iter->second.VirtualSROM << std::endl;
155 os << indent <<
" " <<
"WiredPortNumber: " <<
iter->second.WiredPortNumber << std::endl;
162 std::ostringstream version;
163 version <<
"NDICAPI-" << NDICAPI_MAJOR_VERSION <<
"." << NDICAPI_MINOR_VERSION;
164 return version.str();
177 const char* devicename = NULL;
178 int errnum = NDI_OPEN_ERROR;
179 devicename = ndiSerialDeviceName(this->
SerialPort - 1);
182 errnum = ndiSerialProbe(devicename, this->
CheckDSR);
183 LOG_DEBUG(
"Serial port " << devicename <<
" probe error (" << errnum <<
"): " << ndiErrorString(errnum));
186 if (errnum != NDI_OKAY)
191 this->
Device = ndiOpenSerial(devicename);
200 #if defined(HAVE_FUTURE) 201 return ProbeSerialInternal();
204 const char* devicename = NULL;
205 int errnum = NDI_OPEN_ERROR;
207 const int MAX_SERIAL_PORT_NUMBER = 20;
208 for (
int i = 0;
i < MAX_SERIAL_PORT_NUMBER;
i++)
210 devicename = ndiSerialDeviceName(
i);
211 LOG_DEBUG(
"Testing serial port: " << devicename);
214 errnum = ndiSerialProbe(devicename, this->
CheckDSR);
215 LOG_DEBUG(
"Serial port " << devicename <<
" probe error (" << errnum <<
"): " << ndiErrorString(errnum));
216 if (errnum == NDI_OKAY)
219 this->
Device = ndiOpenSerial(devicename);
220 LOG_DEBUG(
"device: " << (this->
Device ==
nullptr));
249 va_start(ap, format);
254 if (format !=
nullptr)
256 vsprintf(command, format, ap);
257 LOG_DEBUG(
"NDI Command:" << command);
261 LOG_DEBUG(
"NDI Command:send serial break");
266 va_start(ap, format);
270 igsioLockGuard<vtkIGSIORecursiveCriticalSection> lock(this->
CommandMutex);
275 std::string cmd(command);
276 if (cmd.find(
':') != std::string::npos)
278 cmd = cmd.substr(0, cmd.find(
':'));
280 else if (cmd.find(
' ') != std::string::npos)
282 cmd = cmd.substr(0, cmd.find(
' '));
284 bool isBinary = (cmd ==
"BX" || cmd ==
"BX2" || cmd ==
"GETLOG" || cmd ==
"VGET");
286 if (vtkIGSIOLogger::Instance()->GetLogLevel() >= vtkIGSIOLogger::LOG_LEVEL_DEBUG)
294 std::stringstream ss;
297 for (
unsigned int i = 0;
i < ndiGetBX2ReplyLength(this->
Device); ++
i)
299 ss << std::setfill(
'0') << std::setw(2) << (
unsigned int)(
unsigned char)this->
CommandReply[
i];
326 LOG_ERROR(
"Unable to connect to NDI device.");
339 LOG_ERROR(
"Failed to enable tool ports");
350 std::string revision =
"";
351 revision = this->
Command(
"GET:%s",
"Features.Firmware.API Revision");
352 int errnum = ndiGetError(this->
Device);
355 revision = this->
Command(
"APIREV ");
356 int errnum = ndiGetError(this->
Device);
359 LOG_ERROR(ndiErrorString(errnum));
366 std::vector<std::string> result = igsioCommon::SplitStringIntoTokens(revision,
'.',
false);
368 igsioCommon::StringToNumber<uint32_t>(result[1].c_str(), ver);
370 igsioCommon::StringToNumber<uint32_t>(result[2].c_str(), ver);
378 std::vector<std::string> answers = igsioCommon::SplitStringIntoTokens(revision,
'=',
false);
379 std::vector<std::string> result = igsioCommon::SplitStringIntoTokens(answers[1],
'.',
false);
381 igsioCommon::StringToNumber<uint32_t>(result[1].c_str(), ver);
383 igsioCommon::StringToNumber<uint32_t>(result[2].c_str(), ver);
396 LOG_ERROR(
"Failed to detect device" << (this->
SerialPort < 0 ?
". Port scanning failed. " :
" on serial port " + std::string(ndiSerialDeviceName(this->
SerialPort)) +
" (index " + igsioCommon::ToString<int>(this->
SerialPort) +
"). ") << ndiErrorString(NDI_OPEN_ERROR));
404 this->
Command(
"COMM:%X%03d%d", baudVal, NDI_8N1, NDI_NOHANDSHAKE);
405 int errnum = ndiGetError(this->
Device);
406 if (errnum == NDI_OKAY)
412 LOG_WARNING(
"Unable to set requested baud rate. Reverting to auto-select.");
420 const unsigned int numberOfBaudRates = 9;
421 int baudRates[numberOfBaudRates] = { NDI_1228739, NDI_921600, NDI_230400, NDI_115200, NDI_57600, NDI_38400, NDI_19200, NDI_14400, NDI_9600 };
422 #elif defined(__APPLE__) 423 const unsigned int numberOfBaudRates = 6;
424 int baudRates[numberOfBaudRates] = { NDI_115200, NDI_57600, NDI_38400, NDI_19200, NDI_14400, NDI_9600 };
425 #elif defined(__linux__) 426 const unsigned int numberOfBaudRates = 6;
427 int baudRates[numberOfBaudRates] = { NDI_115200, NDI_57600, NDI_38400, NDI_19200, NDI_14400, NDI_9600 };
429 const unsigned int numberOfBaudRates = 6;
430 int baudRates[numberOfBaudRates] = { NDI_115200, NDI_57600, NDI_38400, NDI_19200, NDI_14400, NDI_9600 };
432 for (
unsigned int baudIndex = 0; baudIndex < numberOfBaudRates; baudIndex++)
434 int baud = baudRates[baudIndex];
436 this->
Command(
"COMM:%X%03d%d", baud, NDI_8N1, NDI_NOHANDSHAKE);
437 int errnum = ndiGetError(this->
Device);
438 if (errnum != NDI_OKAY && errnum != NDI_COMM_FAIL)
441 LOG_ERROR(ndiErrorString(errnum));
442 ndiCloseSerial(this->
Device);
446 if (errnum == NDI_OKAY)
461 if (this->
Device ==
nullptr)
468 ndiTimeoutSocket(this->
Device, 5000);
470 auto reply = this->
Command(
"INIT");
473 ndiTimeoutSocket(this->
Device, 100);
490 int errnum = ndiGetError(this->
Device);
493 LOG_ERROR(ndiErrorString(errnum));
510 int errnum = ndiGetError(this->
Device);
513 LOG_ERROR(
"Failed TSTART: " << ndiErrorString(errnum));
532 int errnum = ndiGetError(this->
Device);
535 LOG_ERROR(ndiErrorString(errnum));
547 LOG_ERROR(
"called Update() when NDI was not tracking");
566 FILE* file = fopen(filename,
"rb");
569 LOG_ERROR(
"Couldn't find srom file " << filename);
573 if (toolDescriptor.VirtualSROM == 0)
575 toolDescriptor.VirtualSROM =
new unsigned char[VIRTUAL_SROM_SIZE];
578 memset(toolDescriptor.VirtualSROM, 0, VIRTUAL_SROM_SIZE);
579 fread(toolDescriptor.VirtualSROM, 1, VIRTUAL_SROM_SIZE, file);
593 int errnum = ndiGetError(this->
Device);
596 LOG_ERROR(ndiErrorString(errnum));
603 int errnum = ndiGetError(this->
Device);
604 if (errnum != NDI_OKAY)
606 LOG_ERROR(
"Unable to get the number of handles. Error: " << ndiErrorString(errnum));
610 int ntools = ndiGetPHSRNumberOfHandles(this->
Device);
611 for (
int ndiToolIndex = 0; ndiToolIndex < ntools; ndiToolIndex++)
613 int portHandle = ndiGetPHSRHandle(this->
Device, ndiToolIndex);
614 this->
Command(
"PHF:%02X", portHandle);
615 int errnum = ndiGetError(this->
Device);
618 LOG_ERROR(ndiErrorString(errnum));
628 if (toolDescriptorIt->second.VirtualSROM != NULL)
632 LOG_ERROR(
"Failed to determine NDI port handle for tool " << toolDescriptorIt->first);
637 LOG_ERROR(
"Failed send SROM to NDI tool " << toolDescriptorIt->first);
649 ntools = ndiGetPHSRNumberOfHandles(this->
Device);
650 for (
int ndiToolIndex = 0; ndiToolIndex < ntools; ndiToolIndex++)
652 int portHandle = ndiGetPHSRHandle(this->
Device, ndiToolIndex);
653 this->
Command(
"PINIT:%02X", portHandle);
654 errnum = ndiGetError(this->
Device);
657 std::stringstream ss;
658 ss << ndiErrorString(errnum) <<
". errnum: " << errnum;
664 while (ntools > 0 && errnum == 0);
668 ntools = ndiGetPHSRNumberOfHandles(this->
Device);
669 for (
int ndiToolIndex = 0; ndiToolIndex < ntools; ndiToolIndex++)
671 int portHandle = ndiGetPHSRHandle(this->
Device, ndiToolIndex);
672 this->
Command(
"PHINF:%02X0001", portHandle);
674 ndiGetPHINFToolInfo(this->
Device, identity);
676 if (identity[1] == 0x03)
680 else if (identity[1] == 0x01)
686 int errnum = ndiGetError(this->
Device);
689 LOG_ERROR(ndiErrorString(errnum));
699 if (toolDescriptorIt->second.WiredPortNumber >= 0 && toolDescriptorIt->second.VirtualSROM == NULL)
703 LOG_ERROR(
"Failed to determine NDI port handle for tool " << toolDescriptorIt->first);
708 LOG_ERROR(
"Failed send SROM to NDI tool " << toolDescriptorIt->first);
722 LOG_ERROR(
"Failed to get NDI tool: " << toolDescriptorIt->first);
727 this->
Command(
"PHINF:%02X0025", toolDescriptorIt->second.PortHandle);
728 int errnum = ndiGetError(this->
Device);
731 LOG_ERROR(ndiErrorString(errnum));
738 ndiGetPHINFToolInfo(this->
Device, identity);
740 std::string serialNumber(&identity[23]);
741 igsioCommon::Trim(serialNumber);
744 std::string toolRevision(&identity[20]);
745 igsioCommon::Trim(toolRevision);
748 std::string toolManufacturer(&identity[8]);
749 igsioCommon::Trim(toolManufacturer);
752 std::string ndiIdentity(&identity[0]);
753 igsioCommon::Trim(ndiIdentity);
756 ndiGetPHINFPartNumber(this->
Device, partNumber);
757 partNumber[20] =
'\0';
758 std::string toolPartNumber(&partNumber[0]);
759 igsioCommon::Trim(toolPartNumber);
761 int status = ndiGetPHINFPortStatus(this->
Device);
763 toolDescriptorIt->second.PortEnabled = ((status & NDI_ENABLED) != 0);
764 if (!toolDescriptorIt->second.PortEnabled)
766 LOG_ERROR(
"Failed to enable NDI tool " << toolDescriptorIt->first);
775 int errnum = ndiGetError(this->
Device);
778 LOG_ERROR(
"Failed TSTART: " << ndiErrorString(errnum));
794 int errnum = ndiGetError(this->
Device);
797 LOG_ERROR(ndiErrorString(errnum));
803 int ntools = ndiGetPHSRNumberOfHandles(this->
Device);
804 for (
int ndiToolIndex = 0; ndiToolIndex < ntools; ndiToolIndex++)
806 int portHandle = ndiGetPHSRHandle(this->
Device, ndiToolIndex);
807 this->
Command(
"PDIS:%02X", portHandle);
808 int errnum = ndiGetError(this->
Device);
811 LOG_ERROR(ndiErrorString(errnum));
818 toolDescriptorIt->second.PortEnabled =
false;
825 int errnum = ndiGetError(this->
Device);
828 LOG_ERROR(ndiErrorString(errnum));
838 LOG_ERROR(
"vtkPlusNDITracker::Beep failed: not connected to the device");
850 int errnum = ndiGetError(this->
Device);
860 LOG_ERROR(
"vtkPlusNDITracker::InternalSetToolLED failed: not recording");
863 NdiToolDescriptorsType::iterator ndiToolDescriptorIt = this->
NdiToolDescriptors.find(sourceId);
866 LOG_ERROR(
"InternalSetToolLED failed: Tool descriptor is not found for tool " << sourceId);
869 int portHandle = ndiToolDescriptorIt->second.PortHandle;
872 LOG_ERROR(
"vtkPlusNDITracker::InternalSetToolLED failed: invalid port handle");
876 int plstate = NDI_BLANK;
889 LOG_ERROR(
"vtkPlusNDITracker::InternalSetToolLED failed: unsupported LED state: " <<
state);
893 this->
Command(
"LED:%02X%d%c", portHandle, led + 1, plstate);
894 int errnum = ndiGetError(this->
Device);
902 if (toolDescriptor.WiredPortNumber >= 0)
905 int ntools = ndiGetPHSRNumberOfHandles(this->
Device);
906 int ndiToolIndex = 0;
907 for (; ndiToolIndex < ntools; ndiToolIndex++)
909 if (ndiGetPHSRInformation(this->
Device, ndiToolIndex) & NDI_TOOL_IN_PORT)
911 int portHandle = ndiGetPHSRHandle(this->
Device, ndiToolIndex);
912 this->
Command(
"PHINF:%02X0021", portHandle);
914 ndiGetPHINFPortLocation(this->
Device, location);
915 int foundWiredPortNumber = (location[10] -
'0') * 10 + (location[11] -
'0') - 1;
916 int foundWiredPortChannel = (location[12] -
'0') * 10 + (location[13] -
'0');
917 int combinedPortAndChannelNumber = foundWiredPortChannel * 100 + foundWiredPortNumber;
918 if (toolDescriptor.WiredPortNumber == combinedPortAndChannelNumber)
921 toolDescriptor.PortHandle = portHandle;
926 if (ndiToolIndex == ntools)
928 LOG_ERROR(
"Active NDI tool not found in port " << toolDescriptor.WiredPortNumber <<
". Make sure the tool is plugged in.");
934 this->
Command(
"PHRQ:*********1****");
935 int portHandle = ndiGetPHRQHandle(this->
Device);
936 toolDescriptor.PortHandle = portHandle;
939 int errnum = ndiGetError(this->
Device);
942 LOG_ERROR(ndiErrorString(errnum));
953 if (toolDescriptor.VirtualSROM == NULL)
959 igsioLockGuard<vtkIGSIORecursiveCriticalSection> lock(this->
CommandMutex);
960 const int TRANSFER_BLOCK_SIZE = 64;
961 char hexbuffer[TRANSFER_BLOCK_SIZE * 2];
962 for (
int i = 0;
i < VIRTUAL_SROM_SIZE;
i += TRANSFER_BLOCK_SIZE)
965 strcmp(this->
Command(
"PVWR:%02X%04X%.128s", toolDescriptor.PortHandle,
i,
966 ndiHexEncode(hexbuffer, &(toolDescriptor.VirtualSROM[
i]), TRANSFER_BLOCK_SIZE)).c_str(),
"OKAY") == 0,
969 int errnum = ndiGetError(this->
Device);
972 std::stringstream ss;
973 ss <<
"Failed to send SROM to NDI tracker: " << ndiErrorString(errnum);
985 if (toolDescriptor.VirtualSROM == NULL)
991 this->
Command(
"PHF:%02X", toolDescriptor.PortHandle);
992 toolDescriptor.PortEnabled =
false;
993 toolDescriptor.PortHandle = 0;
1004 delete [] toolDescriptorIt->second.VirtualSROM;
1005 toolDescriptorIt->second.VirtualSROM = NULL;
1011 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
unsigned long,
SerialPort, deviceConfig);
1012 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
unsigned long,
BaudRate, deviceConfig);
1015 LOG_WARNING(
"Invalid baud rate specified, reverting to auto-select.");
1023 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
NetworkPort, deviceConfig);
1024 XML_READ_BOOL_ATTRIBUTE_OPTIONAL(
CheckDSR, deviceConfig);
1026 XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig,
"DataSources");
1028 for (
int nestedElementIndex = 0; nestedElementIndex < dataSourcesElement->GetNumberOfNestedElements(); nestedElementIndex++)
1030 vtkXMLDataElement* toolDataElement = dataSourcesElement->GetNestedElement(nestedElementIndex);
1031 if (STRCASECMP(toolDataElement->GetName(),
"DataSource") != 0)
1036 bool isEqual(
false);
1042 const char* toolId = toolDataElement->GetAttribute(
"Id");
1045 LOG_ERROR(
"Failed to initialize NDI tool: DataSource Id is missing");
1049 std::string toolSourceId = toolTransformName.GetTransformName();
1053 LOG_ERROR(
"Failed to get NDI tool: " << toolSourceId);
1057 int wiredPortNumber = -1;
1058 if (toolDataElement->GetAttribute(
"PortName") != NULL)
1060 if (!toolDataElement->GetScalarAttribute(
"PortName", wiredPortNumber))
1062 LOG_WARNING(
"NDI wired tool's PortName attribute has to be an integer >=0");
1067 NdiToolDescriptor toolDescriptor;
1068 toolDescriptor.PortEnabled =
false;
1069 toolDescriptor.PortHandle = 0;
1070 toolDescriptor.VirtualSROM = NULL;
1071 toolDescriptor.WiredPortNumber = wiredPortNumber;
1073 const char* romFileName = toolDataElement->GetAttribute(
"RomFile");
1077 if (wiredPortNumber >= 0)
1079 LOG_WARNING(
"NDI PortName and RomFile are both specified for tool " << toolSourceId <<
". Assuming broken wired rom, using virtual rom instead");
1097 trackerConfig->SetIntAttribute(
"SerialPort", this->
SerialPort);
1100 XML_WRITE_STRING_ATTRIBUTE_IF_NOT_EMPTY(
NetworkHostname, trackerConfig);
1103 trackerConfig->SetIntAttribute(
"NetworkPort", this->
NetworkPort);
1113 trackerConfig->SetIntAttribute(
"BaudRate", this->
BaudRate);
1123 trackerConfig->SetAttribute(
"CheckDSR", this->
CheckDSR ?
"true" :
"false");
1131 auto reply = this->
Command(
"GETINFO:Param.Tracking.Available Volumes");
1133 unsigned int numVolumes(0);
1134 int errnum = ndiGetError(this->
Device);
1137 const unsigned char MODE_GET_VOLUMES_LIST = 0x03;
1138 auto volumeListCommandReply = this->
Command(
"SFLIST:%02X", MODE_GET_VOLUMES_LIST);
1139 numVolumes = ndiHexToUnsignedInt(volumeListCommandReply.c_str(), 1);
1143 auto tokens = igsioCommon::SplitStringIntoTokens(reply,
'=',
false);
1144 auto dataFields = igsioCommon::SplitStringIntoTokens(tokens[1],
';',
true);
1145 numVolumes = dataFields.size() / 7;
1148 if (selectedVolume == 0)
1150 LOG_DYNAMIC(
"Number of available measurement volumes: " << numVolumes, logLevel);
1153 reply = this->
Command(
"GETINFO:Features.Volumes.*");
1154 if (reply.find(
"ERROR") != std::string::npos)
1161 auto lines = igsioCommon::SplitStringIntoTokens(reply,
'\n',
false);
1163 for (
auto iter = begin(lines);
iter != end(lines); ++
iter)
1165 auto tokens = igsioCommon::SplitStringIntoTokens(*
iter,
'=',
true);
1166 auto dataFields = igsioCommon::SplitStringIntoTokens(tokens[1],
';',
true);
1167 if (selectedVolume > 0 &&
1168 tokens[0].find(
"Features.Volumes.Index") != std::string::npos &&
1169 dataFields[0][0] -
'0' == selectedVolume - 1)
1171 LOG_DYNAMIC(
"Measurement volume " << selectedVolume, logLevel);
1178 for (
int i = 0;
i < 13; ++
i)
1180 auto tokens = igsioCommon::SplitStringIntoTokens(*(
iter +
i),
'=',
true);
1181 auto names = igsioCommon::SplitStringIntoTokens(tokens[0],
'.',
false);
1182 auto dataFields = igsioCommon::SplitStringIntoTokens(tokens[1],
';',
true);
1183 LOG_DYNAMIC(
" " << names[2] <<
": " << dataFields[0], logLevel);
1189 auto names = igsioCommon::SplitStringIntoTokens(tokens[0],
'.',
false);
1190 LOG_DYNAMIC(names[2] <<
": " << dataFields[0], logLevel);
1197 std::string volumeListCommandReply = this->
Command(
"SFLIST:03");
1198 for (
unsigned int volIndex = 0; volIndex < numVolumes; ++volIndex)
1200 const char* volDescriptor = volumeListCommandReply.c_str() + 1 + volIndex * 74;
1202 LOG_DYNAMIC(
"Measurement volume " << volIndex + 1, logLevel);
1204 std::string shapeType;
1205 bool isOptical(
false);
1206 switch (volDescriptor[0])
1215 shapeType =
"Polaris (Pyramid or extended pyramid)";
1219 shapeType =
"Vicra (Pyramid)";
1223 shapeType =
"unknown";
1225 LOG_DYNAMIC(
" Shape type: " << shapeType <<
" (" << volDescriptor[0] <<
")", logLevel);
1227 LOG_DYNAMIC(
" D1 = " << ndiSignedToLong(volDescriptor + 1, 7) / 100, logLevel);
1228 LOG_DYNAMIC(
" D2 = " << ndiSignedToLong(volDescriptor + 8, 7) / 100, logLevel);
1229 LOG_DYNAMIC(
" D3 = " << ndiSignedToLong(volDescriptor + 15, 7) / 100, logLevel);
1230 LOG_DYNAMIC(
" D4 = " << ndiSignedToLong(volDescriptor + 22, 7) / 100, logLevel);
1231 LOG_DYNAMIC(
" D5 = " << ndiSignedToLong(volDescriptor + 29, 7) / 100, logLevel);
1232 LOG_DYNAMIC(
" D6 = " << ndiSignedToLong(volDescriptor + 36, 7) / 100, logLevel);
1233 LOG_DYNAMIC(
" D7 = " << ndiSignedToLong(volDescriptor + 43, 7) / 100, logLevel);
1234 LOG_DYNAMIC(
" D8 = " << ndiSignedToLong(volDescriptor + 50, 7) / 100, logLevel);
1235 LOG_DYNAMIC(
" D9 = " << ndiSignedToLong(volDescriptor + 57, 7) / 100, logLevel);
1236 LOG_DYNAMIC(
" D10 = " << ndiSignedToLong(volDescriptor + 64, 7) / 100, logLevel);
1240 LOG_DYNAMIC(
" Reserved: " << volDescriptor[71], logLevel);
1242 std::string metalResistant;
1243 switch (volDescriptor[72])
1246 metalResistant =
"no information";
1249 metalResistant =
"metal resistant";
1252 metalResistant =
"not metal resistant";
1255 metalResistant =
"unknown";
1257 LOG_DYNAMIC(
" Metal resistant: " << metalResistant <<
" (" << volDescriptor[72] <<
")", logLevel);
1261 unsigned int numWavelengths = volDescriptor[71] -
'0';
1262 LOG_DYNAMIC(
" Number of wavelengths supported: " << numWavelengths, logLevel);
1263 for (
unsigned int i = 0;
i < numWavelengths; ++
i)
1265 switch (volDescriptor[72 +
i])
1268 LOG_DYNAMIC(
" Wavelength " <<
i <<
": 930nm", logLevel);
1271 LOG_DYNAMIC(
" Wavelength " <<
i <<
": 880nm", logLevel);
1274 LOG_DYNAMIC(
" Wavelength " <<
i <<
": 870nm", logLevel);
1277 LOG_DYNAMIC(
" Wavelength " <<
i <<
": unknown (" << volDescriptor[72 +
i] <<
")", logLevel);
1290 ndiCloseSerial(device);
1294 ndiCloseNetwork(device);
1306 std::string reply = this->
Command(
"GETINFO:Param.Tracking.Available Volumes");
1307 int errnum = ndiGetError(this->
Device);
1314 auto tokens = igsioCommon::SplitStringIntoTokens(reply,
'=',
false);
1315 auto dataFields = igsioCommon::SplitStringIntoTokens(tokens[1],
';',
true);
1320 LOG_ERROR(
"Selected measurement volume does not exist. Using default.");
1328 int errnum = ndiGetError(this->
Device);
1331 LOG_ERROR(
"Failed to set measurement volume " << this->
MeasurementVolumeNumber <<
": " << ndiErrorString(errnum));
1347 int errnum = ndiGetError(this->
Device);
1350 LOG_ERROR(
"Failed to set measurement volume " << this->
MeasurementVolumeNumber <<
": " << ndiErrorString(errnum));
1401 std::string reply = this->
Command(
"GET:Param.Tracking.Track Frequency");
1403 int errnum = ndiGetError(this->
Device);
1412 int errnum = ndiGetError(this->
Device);
1415 LOG_ERROR(
"Failed to set tracking frequency " << this->
TrackingFrequencyNumber <<
": " << ndiErrorString(errnum));
1428 int errnum = ndiGetError(this->
Device);
1431 LOG_ERROR(
"Failed to set tracking frequency " << this->
TrackingFrequencyNumber <<
": " << ndiErrorString(errnum));
1443 std::string model = this->
Command(
"GET:%s",
"Features.Hardware.Model");
1446 int errnum = ndiGetError(this->
Device);
1449 LOG_ERROR(
"Unable to set data averaging depth: " << ndiErrorString(errnum));
1456 std::string result = this->
Command(
"GET:%s",
"Param.Tracking.Frame Frequency");
1457 std::vector<std::string> tokens = igsioCommon::SplitStringIntoTokens(result,
'=');
1458 unsigned int frameFreq;
1459 igsioCommon::StringToNumber<unsigned int>(tokens[1], frameFreq);
1461 result = this->
Command(
"GET:%s",
"Param.Tracking.Track Frequency");
1462 tokens = igsioCommon::SplitStringIntoTokens(result,
'=');
1463 unsigned int trackFreqEnum;
1464 igsioCommon::StringToNumber<unsigned int>(tokens[1], trackFreqEnum);
1477 double trackFreq(0);
1478 if (model.find(
"Vega") != std::string::npos)
1480 switch (trackFreqEnum)
1483 trackFreq = frameFreq / 3;
1486 trackFreq = frameFreq / 2;
1489 trackFreq = frameFreq;
1495 else if (model.find(
"Lyra") != std::string::npos)
1497 switch (trackFreqEnum)
1500 trackFreq = frameFreq / 3;
1503 trackFreq = frameFreq / 2;
1513 ndiTimeoutSocket(this->
Device, static_cast<unsigned int>(
timeoutMs) + 25);
1555 errnum = ndiGetError(this->
Device);
1558 if (errnum == NDI_BAD_CRC || errnum == NDI_TIMEOUT)
1560 LOG_WARNING(ndiErrorString(errnum));
1564 LOG_ERROR(ndiErrorString(errnum));
1572 const double toolTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
1573 vtkSmartPointer<vtkMatrix4x4> toolToTrackerTransform = vtkSmartPointer<vtkMatrix4x4>::New();
1576 ToolStatus toolFlags = TOOL_OK;
1577 toolToTrackerTransform->Identity();
1578 unsigned long toolFrameNumber = defaultToolFrameNumber;
1580 std::string toolSourceId = trackerTool->GetId();
1581 NdiToolDescriptorsType::iterator ndiToolDescriptorIt = this->
NdiToolDescriptors.find(toolSourceId);
1584 LOG_ERROR(
"Tool descriptor is not found for tool " << toolSourceId);
1585 this->
ToolTimeStampedUpdate(trackerTool->GetId(), toolToTrackerTransform, toolFlags, toolFrameNumber, toolTimestamp);
1588 int portHandle = ndiToolDescriptorIt->second.PortHandle;
1589 if (portHandle <= 0)
1591 LOG_ERROR(
"Port handle is invalid for tool " << toolSourceId);
1592 this->
ToolTimeStampedUpdate(toolSourceId.c_str(), toolToTrackerTransform, toolFlags, toolFrameNumber, toolTimestamp);
1596 float ndiTransform[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
1597 int ndiToolAbsent = ndiGetBXTransform(this->
Device, portHandle, ndiTransform);
1598 int ndiPortStatus = ndiGetBXPortStatus(this->
Device, portHandle);
1599 unsigned long ndiFrameIndex = ndiGetBXFrame(this->
Device, portHandle);
1602 const unsigned long ndiPortStatusValidFlags = NDI_TOOL_IN_PORT | NDI_INITIALIZED | NDI_ENABLED;
1603 if ((ndiPortStatus & ndiPortStatusValidFlags) != ndiPortStatusValidFlags)
1605 toolFlags = TOOL_MISSING;
1611 toolFlags = TOOL_OUT_OF_VIEW;
1613 if (ndiPortStatus & NDI_OUT_OF_VOLUME)
1615 toolFlags = TOOL_OUT_OF_VOLUME;
1623 ndiTransformToMatrixfd(ndiTransform, *toolToTrackerTransform->Element);
1624 toolToTrackerTransform->Transpose();
1628 if (!ndiToolAbsent && ndiFrameIndex)
1631 toolFrameNumber = ndiFrameIndex;
1639 this->
ToolTimeStampedUpdate(toolSourceId.c_str(), toolToTrackerTransform, toolFlags, toolFrameNumber, toolTimestamp);
1643 if (ndiGetBXSystemStatus(this->
Device) & NDI_PORT_OCCUPIED)
1645 LOG_WARNING(
"A wired tool has been plugged into tracker " << (this->
GetDeviceId().empty() ? this->
GetDeviceId() :
"(unknown NDI tracker"));
1658 this->
Command(
"BX2:--6d=tools --1d=none");
1659 errnum = ndiGetError(this->
Device);
1662 if (errnum == NDI_BAD_CRC || errnum == NDI_TIMEOUT)
1664 LOG_WARNING(ndiErrorString(errnum));
1668 LOG_ERROR(ndiErrorString(errnum));
1676 const double toolTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
1677 vtkSmartPointer<vtkMatrix4x4> toolToTrackerTransform = vtkSmartPointer<vtkMatrix4x4>::New();
1678 unsigned long ndiFrameIndex = ndiGetBX2Frame(this->
Device);
1681 ToolStatus toolFlags = TOOL_OK;
1682 toolToTrackerTransform->Identity();
1683 unsigned long toolFrameNumber = defaultToolFrameNumber;
1685 std::string toolSourceId = trackerTool->GetId();
1686 NdiToolDescriptorsType::iterator ndiToolDescriptorIt = this->
NdiToolDescriptors.find(toolSourceId);
1689 LOG_ERROR(
"Tool descriptor is not found for tool " << toolSourceId);
1690 this->
ToolTimeStampedUpdate(trackerTool->GetId(), toolToTrackerTransform, toolFlags, toolFrameNumber, toolTimestamp);
1693 int portHandle = ndiToolDescriptorIt->second.PortHandle;
1694 if (portHandle <= 0)
1696 LOG_ERROR(
"Port handle is invalid for tool " << toolSourceId);
1697 this->
ToolTimeStampedUpdate(toolSourceId.c_str(), toolToTrackerTransform, toolFlags, toolFrameNumber, toolTimestamp);
1701 float ndiTransform[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
1702 int ndiToolAbsent = ndiGetBX2Transform(this->
Device, portHandle, ndiTransform);
1703 int ndiPortStatus = ndiGetBX2PortStatus(this->
Device, portHandle);
1706 if (ndiPortStatus & NDI_BX2_MISSING_BIT)
1708 toolFlags = TOOL_MISSING;
1712 if (ndiPortStatus == NDI_BX2_PARTIAL_VIEW)
1714 toolFlags = TOOL_OUT_OF_VIEW;
1716 if (ndiPortStatus == NDI_BX2_OUT_OF_VOLUME)
1718 toolFlags = TOOL_OUT_OF_VOLUME;
1726 ndiTransformToMatrixfd(ndiTransform, *toolToTrackerTransform->Element);
1727 toolToTrackerTransform->Transpose();
1731 if (ndiToolAbsent == NDI_BX2_ENABLED && ndiFrameIndex)
1734 toolFrameNumber = ndiFrameIndex;
1742 this->
ToolTimeStampedUpdate(toolSourceId.c_str(), toolToTrackerTransform, toolFlags, toolFrameNumber, toolTimestamp);
1745 int alerts = ndiGetBX2SystemAlertsCount(this->
Device);
1746 for (
int i = 0;
i < alerts; ++
i)
1748 unsigned short* alert = ndiGetBX2SystemAlert(this->
Device,
i);
1749 if (alert[1] == NDI_SYS_EVENT_TOOL_CONNECTED)
1751 LOG_WARNING(
"A wired tool has been plugged into tracker " << (this->
GetDeviceId().empty() ? this->
GetDeviceId() :
"(unknown NDI tracker"));
1760 #if defined(HAVE_FUTURE) 1762 PlusStatus vtkPlusNDITracker::ProbeSerialInternal()
1764 const int MAX_SERIAL_PORT_NUMBER = 20;
1765 std::vector<bool> deviceExists(MAX_SERIAL_PORT_NUMBER);
1766 std::fill(begin(deviceExists), end(deviceExists),
false);
1767 std::vector<std::future<void>> tasks;
1768 for (
int i = 0;
i < MAX_SERIAL_PORT_NUMBER;
i++)
1770 const char* dev = ndiSerialDeviceName(
i);
1773 LOG_DEBUG(
"Testing serial port: " << dev);
1774 std::string devName = std::string(dev);
1775 std::future<void> result = std::async([
this,
i, &deviceExists, devName]()
1777 int errnum = ndiSerialProbe(devName.c_str(), this->
CheckDSR);
1778 LOG_DEBUG(
"Serial port " << devName <<
" probe error (" << errnum <<
"): " << ndiErrorString(errnum));
1779 if (errnum == NDI_OKAY)
1781 deviceExists[
i] =
true;
1784 tasks.push_back(std::move(result));
1787 for (std::vector<std::future<void>>::size_type
i = 0;
i < tasks.size();
i++)
1791 for (
int i = 0;
i < MAX_SERIAL_PORT_NUMBER;
i++)
1794 if (deviceExists[
i] ==
true)
1796 const char* devicename = ndiSerialDeviceName(
i);
1800 this->
Device = ndiOpenSerial(devicename);
DataSourceContainer::const_iterator DataSourceContainerConstIterator
int TrackingFrequencyNumber
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
vtkStandardNewMacro(vtkPlusNDITracker)
PlusStatus SendSromToTracker(const NdiToolDescriptor &toolDescriptor)
PlusStatus InternalStartRecording()
NdiToolDescriptorsType NdiToolDescriptors
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
std::string Command(const char *format,...)
PlusStatus InternalUpdate()
void LogVolumeList(int selectedVolume, vtkPlusLogger::LogLevelType logLevel)
void LogVolumeListSFLIST(unsigned int numVolumes, int selectedVolume, vtkPlusLogger::LogLevelType logLevel)
virtual std::string GetDeviceId() const
PlusStatus SelectDataAveraging()
virtual PlusStatus ToolTimeStampedUpdate(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, unsigned long frameNumber, double unfilteredtimestamp, const igsioFieldMapType *customFields=NULL)
bool LeaveDeviceOpenAfterProbe
PlusStatus InternalConnectSerial()
uint32_t FirmwareMajorRevision
static int ConvertBaudToNDIEnum(int baudRate)
virtual std::string GetSdkVersion()
PlusStatus InternalConnectNetwork()
static vtkPlusConfig * GetInstance()
int HardwareDataAveragingDepth
PlusStatus InternalStopRecording()
void SetCustomProperty(const std::string &propertyName, const std::string &propertyValue)
PlusStatus SelectTrackingFrequency()
int MeasurementVolumeNumber
PlusStatus InternalDisconnect()
virtual uint32_t GetFirmwareMinorRevision()
PlusStatus SelectMeasurementVolume()
PlusStatus ClearVirtualSromInTracker(NdiToolDescriptor &toolDescriptor)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
void PrintSelf(ostream &os, vtkIndent indent)
PlusStatus InternalConnect()
virtual PlusStatus StopRecording()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
PlusStatus SelectMeasurementVolumeDeprecated()
PlusStatus ReadSromFromFile(NdiToolDescriptor &toolDescriptor, const char *filename)
virtual uint32_t GetFirmwareMajorRevision()
static std::string DATA_SOURCE_TYPE_TOOL_TAG
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
PlusStatus SelectTrackingFrequencyDeprecated()
bool StartThreadForInternalUpdates
DataSourceContainerConstIterator GetToolIteratorBegin() const
char CommandReply[VTK_NDI_REPLY_LEN]
std::string NetworkHostname
vtkIGSIORecursiveCriticalSection * CommandMutex
PlusStatus GetFirmwareRevision()
PlusStatus UpdatePortHandle(NdiToolDescriptor &toolDescriptor)
std::string GetDeviceSetConfigurationPath(const std::string &subPath)
uint32_t FirmwareMinorRevision
std::string GetToolReferenceFrameName() const
PlusStatus SetToolLED(const char *portName, int led, LedState state)
unsigned long LastFrameNumber
PlusStatus EnableToolPorts()
PlusStatus GetTool(const char *aToolSourceId, vtkPlusDataSource *&aTool) const
DataSourceContainerConstIterator GetToolIteratorEnd() const
PlusStatus CloseDevice(ndicapi *&device)
#define VTK_NDI_REPLY_LEN
Interface class for Northern Digital's tracking devices.
Interface to a 3D positioning tool, video source, or generalized data stream.