├── .gitignore ├── Applications ├── ndiBasicExample.cxx └── ndiBasicExample.py ├── CMakeLists.txt ├── LICENSE ├── README.md ├── ndicapi.cxx ├── ndicapi.dox ├── ndicapi.h ├── ndicapi.txt ├── ndicapiConfig.cmake.in ├── ndicapiConfigVersion.cmake.in ├── ndicapiExport.h.in ├── ndicapi_math.cxx ├── ndicapi_math.h ├── ndicapi_serial.cxx ├── ndicapi_serial.h ├── ndicapi_serial_apple.cxx ├── ndicapi_serial_unix.cxx ├── ndicapi_serial_win32.cxx ├── ndicapi_socket.cxx ├── ndicapi_socket.h ├── ndicapi_socket_apple.cxx ├── ndicapi_socket_unix.cxx ├── ndicapi_socket_win32.cxx ├── ndicapi_thread.cxx ├── ndicapi_thread.h ├── ndicapimodule.cxx └── setup.py.in /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | CMakeLists.txt.user 3 | /ndicapiExport.h 4 | /build 5 | setup.py -------------------------------------------------------------------------------- /Applications/ndiBasicExample.cxx: -------------------------------------------------------------------------------- 1 | // A simple program that connects to an NDI tracker 2 | #include 3 | #include 4 | 5 | #include 6 | #if _MSC_VER >= 1700 7 | #include 8 | #include 9 | #include 10 | #endif 11 | 12 | #if _MSC_VER >= 1700 13 | //---------------------------------------------------------------------------- 14 | bool ParallelProbe(ndicapi*& outDevice, bool checkDSR) 15 | { 16 | const int MAX_SERIAL_PORT_NUMBER = 20; // the serial port is almost surely less than this number 17 | std::vector deviceExists(MAX_SERIAL_PORT_NUMBER); 18 | std::fill(begin(deviceExists), end(deviceExists), false); 19 | std::vector> tasks; 20 | std::mutex deviceNameMutex; 21 | for (int i = 0; i < MAX_SERIAL_PORT_NUMBER; i++) 22 | { 23 | std::future result = std::async([i, &deviceNameMutex, &deviceExists]() 24 | { 25 | std::string devName; 26 | { 27 | std::lock_guard guard(deviceNameMutex); 28 | devName = std::string(ndiSerialDeviceName(i)); 29 | } 30 | int errnum = ndiSerialProbe(devName.c_str(),checkDSR); 31 | if (errnum == NDI_OKAY) 32 | { 33 | deviceExists[i] = true; 34 | } 35 | }); 36 | tasks.push_back(std::move(result)); 37 | } 38 | for (int i = 0; i < MAX_SERIAL_PORT_NUMBER; i++) 39 | { 40 | tasks[i].wait(); 41 | } 42 | for (int i = 0; i < MAX_SERIAL_PORT_NUMBER; i++) 43 | { 44 | // use first device found 45 | if (deviceExists[i] == true) 46 | { 47 | char* devicename = ndiSerialDeviceName(i); 48 | outDevice = ndiOpenSerial(devicename); 49 | return true; 50 | } 51 | } 52 | 53 | return false; 54 | } 55 | #endif 56 | 57 | struct ndicapi; 58 | 59 | int main(int argc, char * argv[]) 60 | { 61 | bool checkDSR = false; 62 | ndicapi* device(nullptr); 63 | const char* name(nullptr); 64 | 65 | if(argc > 1) 66 | name = argv[1]; 67 | else 68 | { 69 | #if _MSC_VER >= 1700 70 | ParallelProbe(device,argc > 1 ? argv[1]: 0, checkDSR); 71 | #else 72 | { 73 | const int MAX_SERIAL_PORTS = 20; 74 | for (int i = 0; i < MAX_SERIAL_PORTS; ++i) 75 | { 76 | name = ndiSerialDeviceName(i); 77 | int result = ndiSerialProbe(name,checkDSR); 78 | if (result == NDI_OKAY) 79 | { 80 | break; 81 | } 82 | } 83 | } 84 | #endif 85 | } 86 | 87 | if (name != nullptr) 88 | { 89 | device = ndiOpenSerial(name); 90 | } 91 | 92 | if (device != nullptr) 93 | { 94 | const char* reply = ndiCommand(device, "INIT:"); 95 | if (strncmp(reply, "ERROR", strlen(reply)) == 0 || ndiGetError(device) != NDI_OKAY) 96 | { 97 | std::cerr << "Error when sending command: " << ndiErrorString(ndiGetError(device)) << std::endl; 98 | return EXIT_FAILURE; 99 | } 100 | 101 | reply = ndiCommand(device, "COMM:%d%03d%d", NDI_115200, NDI_8N1, NDI_NOHANDSHAKE); 102 | 103 | // Add your own commands here!!! 104 | 105 | 106 | ndiCloseSerial(device); 107 | } 108 | 109 | return EXIT_SUCCESS; 110 | } -------------------------------------------------------------------------------- /Applications/ndiBasicExample.py: -------------------------------------------------------------------------------- 1 | from ndicapy import ( 2 | ndiDeviceName, ndiProbe, NDI_OKAY, 3 | ndiOpen, ndiClose, ndiCommand, ndiGetError, 4 | ndiErrorString, NDI_115200, 5 | NDI_8N1, NDI_NOHANDSHAKE, 6 | ) 7 | 8 | 9 | MAX_SERIAL_PORTS = 20 10 | if __name__ == '__main__': 11 | name = '' 12 | for port_no in range(MAX_SERIAL_PORTS): 13 | name = ndiDeviceName(port_no) 14 | if not name: 15 | continue 16 | result = ndiProbe(name) 17 | if result == NDI_OKAY: 18 | break 19 | if result != NDI_OKAY: 20 | raise IOError( 21 | 'Could not find any NDI device in ' 22 | '{} serial port candidates checked. ' 23 | 'Please check the following:\n' 24 | '\t1) Is an NDI device connected to your computer?\n' 25 | '\t2) Is the NDI device switched on?\n' 26 | '\t3) Do you have sufficient privilege to connect to ' 27 | 'the device? (e.g. on Linux are you part of the "dialout" ' 28 | 'group?)'.format(MAX_SERIAL_PORTS) 29 | ) 30 | 31 | device = ndiOpen(name) 32 | if not device: 33 | raise IOError( 34 | 'Could not connect to NDI device found on ' 35 | '{}'.format(name) 36 | ) 37 | 38 | reply = ndiCommand(device, 'INIT:') 39 | error = ndiGetError(device) 40 | if reply.startswith('ERROR') or error != NDI_OKAY: 41 | raise IOError( 42 | 'Error when sending command: ' 43 | '{}'.format(ndiErrorString(error)) 44 | ) 45 | 46 | reply = ndiCommand( 47 | device, 48 | 'COMM:{:d}{:03d}{:d}'.format(NDI_115200, NDI_8N1, NDI_NOHANDSHAKE) 49 | ) 50 | 51 | # Add your own commands here!!! 52 | 53 | ndiClose(device) 54 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(ndicapi) 2 | CMAKE_MINIMUM_REQUIRED(VERSION 3.3.0) 3 | 4 | SET(ndicapi_VERSION 1.6.0) 5 | 6 | # -------------------------------------------------------------------------- 7 | # Configure output paths for libraries and executables. 8 | IF(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) 9 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") 10 | ENDIF() 11 | 12 | IF(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY) 13 | SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib") 14 | ENDIF() 15 | 16 | IF(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY) 17 | SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/share") 18 | ENDIF() 19 | 20 | IF(NOT DEFINED BUILD_SHARED_LIBS) 21 | SET(BUILD_SHARED_LIBS ON) 22 | ENDIF() 23 | OPTION(BUILD_SHARED_LIBS "Build shared libraries" ${BUILD_SHARED_LIBS}) 24 | 25 | # -------------------------------------------------------------------------- 26 | # Export variables 27 | SET(_targets ndicapi) 28 | 29 | # -------------------------------------------------------------------------- 30 | # Configure options 31 | OPTION(ndicapi_BUILD_APPLICATIONS "Build applications." OFF) 32 | 33 | # -------------------------------------------------------------------------- 34 | # Configure library 35 | SET(${PROJECT_NAME}_INCLUDE_DIRS 36 | ${CMAKE_CURRENT_SOURCE_DIR} 37 | ${CMAKE_CURRENT_BINARY_DIR} 38 | ) 39 | 40 | SET(${PROJECT_NAME}_SRCS 41 | ndicapi.cxx 42 | ndicapi_math.cxx 43 | ndicapi_serial.cxx 44 | ndicapi_thread.cxx 45 | ndicapi_socket.cxx 46 | ) 47 | 48 | CONFIGURE_FILE(ndicapiExport.h.in "${CMAKE_CURRENT_BINARY_DIR}/ndicapiExport.h" @ONLY) 49 | 50 | SET(${PROJECT_NAME}_HDRS 51 | ndicapi_math.h 52 | ndicapi_thread.h 53 | ndicapi_serial.h 54 | ndicapi.h 55 | ndicapi_socket.h 56 | ${CMAKE_CURRENT_BINARY_DIR}/ndicapiExport.h 57 | ) 58 | 59 | OPTION(BUILD_PYTHON "Ensure the python module will build." OFF) 60 | IF(BUILD_PYTHON) 61 | IF(NOT BUILD_SHARED_LIBS) 62 | MESSAGE(FATAL_ERROR 63 | "The Python extension only works with shared libraries" 64 | " (DLLs on Windows). Please enable building as a" 65 | " shared library (CMake option BUILD_SHARED_LIBS)." 66 | ) 67 | ENDIF() 68 | SET(SETUP_PY_FILEPATH ${CMAKE_CURRENT_SOURCE_DIR}/setup.py) 69 | CONFIGURE_FILE( 70 | ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in 71 | ${SETUP_PY_FILEPATH} 72 | ) 73 | MESSAGE( 74 | "Successfully generated ${SETUP_PY_FILEPATH} for the Python" 75 | " extension module. To install the Python extension module:" 76 | "\n\t0) Install the C++ library: make && make install" 77 | " (might need admin access)" 78 | "\n\t1) Go to ${CMAKE_CURRENT_SOURCE_DIR}" 79 | "\n\t2) Build and install the Python extension:" 80 | " python setup.py install (might require admin access)" 81 | ) 82 | ENDIF() 83 | 84 | FIND_PACKAGE(Threads) 85 | LIST(APPEND ${PROJECT_NAME}_LIBS 86 | ${CMAKE_THREAD_LIBS_INIT} 87 | ) 88 | 89 | # macro for CXX_STANDARD 90 | SET(NDICAPI_CXX_STANDARD 11) 91 | 92 | ADD_LIBRARY(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS} ${${PROJECT_NAME}_HDRS}) 93 | TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_LIBS}) 94 | SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD ${NDICAPI_CXX_STANDARD}) 95 | IF(NOT WIN32) 96 | SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") 97 | ENDIF() 98 | target_include_directories(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_INCLUDE_DIRS}) 99 | 100 | IF(MSVC) 101 | target_link_libraries(${PROJECT_NAME} PUBLIC wsock32 ws2_32) 102 | ENDIF() 103 | 104 | INSTALL(TARGETS ${PROJECT_NAME} EXPORT ndicapi 105 | RUNTIME DESTINATION bin COMPONENT RuntimeLibraries 106 | LIBRARY DESTINATION lib COMPONENT RuntimeLibraries 107 | ARCHIVE DESTINATION lib COMPONENT Development 108 | ) 109 | INSTALL(FILES ${${PROJECT_NAME}_HDRS} 110 | DESTINATION include COMPONENT Development 111 | ) 112 | GET_TARGET_PROPERTY(_library_type ndicapi TYPE) 113 | IF(${_library_type} STREQUAL SHARED_LIBRARY AND MSVC) 114 | INSTALL(FILES "$" OPTIONAL 115 | DESTINATION "bin" COMPONENT RuntimeLibraries 116 | ) 117 | ENDIF() 118 | 119 | #----------------------------------------------------------------------------- 120 | # CMake target details 121 | SET(${PROJECT_NAME}_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/ndicapiTargets.cmake") 122 | SET(${PROJECT_NAME}_LIBRARIES ndicapi) 123 | IF(BUILD_SHARED_LIBS) 124 | SET(CLEAR ${PROJECT_NAME}_STATIC) 125 | ELSE() 126 | SET(${PROJECT_NAME}_STATIC ON) 127 | ENDIF() 128 | 129 | IF(ndicapi_BUILD_APPLICATIONS) 130 | ADD_EXECUTABLE(ndiBasicExample Applications/ndiBasicExample.cxx) 131 | TARGET_LINK_LIBRARIES(ndiBasicExample PUBLIC ndicapi) 132 | SET_PROPERTY(TARGET ndiBasicExample PROPERTY CXX_STANDARD ${NDICAPI_CXX_STANDARD}) 133 | LIST(APPEND _targets ndiBasicExample) 134 | ENDIF() 135 | 136 | export(TARGETS ${_targets} 137 | FILE ${ndicapi_TARGETS_FILE} 138 | ) 139 | 140 | CONFIGURE_FILE(ndicapiConfig.cmake.in 141 | "${CMAKE_CURRENT_BINARY_DIR}/ndicapiConfig.cmake" @ONLY) 142 | 143 | CONFIGURE_FILE(ndicapiConfigVersion.cmake.in 144 | "${CMAKE_CURRENT_BINARY_DIR}/ndicapiConfigVersion.cmake" @ONLY) 145 | 146 | # Enable building of python module, configure the export file in the source directory as well 147 | CONFIGURE_FILE(ndicapiExport.h.in 148 | "${CMAKE_CURRENT_SOURCE_DIR}/ndicapiExport.h" @ONLY) 149 | 150 | # Export the package for use from the build-tree 151 | # (this registers the build-tree with a global CMake-registry) 152 | export(PACKAGE ndicapi) 153 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 PLUS Toolkit 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # History 2 | * Program: NDI Combined API C Interface Library 3 | * Creator: David Gobbi 4 | * Language: English 5 | * Authors: 6 | * David Gobbi 7 | * Andras Lasso 8 | * Adam Rankin 9 | * Version: 1.4 10 | * Date: 2005/07/01 11 | * Version: 1.5 12 | * Date: 2015/05/30 13 | * Version: 1.6 14 | * Date: 2016/03/08 15 | 16 | # Overview 17 | 18 | This package provides a portable C library that provides a straightforward interface to AURORA, POLARIS, and VEGA systems manufactured by Northern Digital Inc. This library is provided by the Plus library, and is not supported by Northern Digital Inc. 19 | 20 | The contents of this package have been built successfully under a wide range of compilers. It is a [CMake](https://cmake.org/download/) project and can be configured and built as such. 21 | 22 | ## Building 23 | To build, configure first using CMake, then build according to your chosen generator. 24 | 25 | ### Python 26 | To build the [Python][python] extension module of this library: 27 | 28 | 1. Build **and** install the C++ library first. 29 | 1. Then build and install the Python extension: `pip install .` (assuming the command is called in your repo clone directory) 30 | 31 | [python]: http://www.python.org 32 | 33 | You can test your installation by running `python -c 'import ndicapy'` 34 | 35 | ## Contents 36 | The main contents of this package are as follows: 37 | 38 | 1) A C library (libndicapi.a, ndicapi.lib/dll) that provides a set of C functions for communicating with an NDI device via the NDI Combined API. The documentation for this library is provided in the ndicapi_html directory. 39 | 40 | 2) Two C++ header files (ndicapi.h and ndicapi_math.h) that provide and interface, via libndicapi.a, to an NDI device via the NDICAPI Serial Communications API that predated the Combined API. Documentation is provided in the polaris_html directory. 41 | 42 | 4) A python interface to the ndicapi library. However, only the original POLARIS API is supported through python. The full ndicapi interface is not yet supported. -------------------------------------------------------------------------------- /ndicapi.cxx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlusToolkit/ndicapi/a8eadfccfd376321180849e452bb6dc340a6028e/ndicapi.cxx -------------------------------------------------------------------------------- /ndicapi.dox: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.2.8.1 2 | 3 | # This file describes the settings to be used by the documentation system 4 | # doxygen (www.doxygen.org) for a project 5 | # 6 | # All text after a hash (#) is considered a comment and will be ignored 7 | # The format is: 8 | # TAG = value [value, ...] 9 | # For lists items can also be appended using: 10 | # TAG += value [value, ...] 11 | # Values that contain spaces should be placed between quotes (" ") 12 | 13 | #--------------------------------------------------------------------------- 14 | # General configuration options 15 | #--------------------------------------------------------------------------- 16 | 17 | # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 18 | # by quotes) that should identify the project. 19 | 20 | PROJECT_NAME = NDICAPI 21 | 22 | # The PROJECT_NUMBER tag can be used to enter a project or revision number. 23 | # This could be handy for archiving the generated documentation or 24 | # if some version control system is used. 25 | 26 | PROJECT_NUMBER = 3.2 27 | 28 | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 29 | # base path where the generated documentation will be put. 30 | # If a relative path is entered, it will be relative to the location 31 | # where doxygen was started. If left blank the current directory will be used. 32 | 33 | OUTPUT_DIRECTORY = . 34 | 35 | # The OUTPUT_LANGUAGE tag is used to specify the language in which all 36 | # documentation generated by doxygen is written. Doxygen will use this 37 | # information to generate all constant output in the proper language. 38 | # The default language is English, other supported languages are: 39 | # Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, 40 | # German, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, 41 | # Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. 42 | 43 | OUTPUT_LANGUAGE = English 44 | 45 | # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 46 | # documentation are documented, even if no documentation was available. 47 | # Private class members and static file members will be hidden unless 48 | # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES 49 | 50 | EXTRACT_ALL = NO 51 | 52 | # If the EXTRACT_PRIVATE tag is set to YES all private members of a class 53 | # will be included in the documentation. 54 | 55 | EXTRACT_PRIVATE = NO 56 | 57 | # If the EXTRACT_STATIC tag is set to YES all static members of a file 58 | # will be included in the documentation. 59 | 60 | EXTRACT_STATIC = NO 61 | 62 | # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 63 | # undocumented members of documented classes, files or namespaces. 64 | # If set to NO (the default) these members will be included in the 65 | # various overviews, but no documentation section is generated. 66 | # This option has no effect if EXTRACT_ALL is enabled. 67 | 68 | HIDE_UNDOC_MEMBERS = NO 69 | 70 | # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 71 | # undocumented classes that are normally visible in the class hierarchy. 72 | # If set to NO (the default) these class will be included in the various 73 | # overviews. This option has no effect if EXTRACT_ALL is enabled. 74 | 75 | HIDE_UNDOC_CLASSES = NO 76 | 77 | # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 78 | # include brief member descriptions after the members that are listed in 79 | # the file and class documentation (similar to JavaDoc). 80 | # Set to NO to disable this. 81 | 82 | BRIEF_MEMBER_DESC = YES 83 | 84 | # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 85 | # the brief description of a member or function before the detailed description. 86 | # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 87 | # brief descriptions will be completely suppressed. 88 | 89 | REPEAT_BRIEF = NO 90 | 91 | # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 92 | # Doxygen will generate a detailed section even if there is only a brief 93 | # description. 94 | 95 | ALWAYS_DETAILED_SEC = NO 96 | 97 | # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 98 | # path before files name in the file list and in the header files. If set 99 | # to NO the shortest path that makes the file name unique will be used. 100 | 101 | FULL_PATH_NAMES = NO 102 | 103 | # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 104 | # can be used to strip a user defined part of the path. Stripping is 105 | # only done if one of the specified strings matches the left-hand part of 106 | # the path. It is allowed to use relative paths in the argument list. 107 | 108 | STRIP_FROM_PATH = 109 | 110 | # The INTERNAL_DOCS tag determines if documentation 111 | # that is typed after a \internal command is included. If the tag is set 112 | # to NO (the default) then the documentation will be excluded. 113 | # Set it to YES to include the internal documentation. 114 | 115 | INTERNAL_DOCS = NO 116 | 117 | # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 118 | # generate a class diagram (in Html and LaTeX) for classes with base or 119 | # super classes. Setting the tag to NO turns the diagrams off. 120 | 121 | CLASS_DIAGRAMS = YES 122 | 123 | # If the SOURCE_BROWSER tag is set to YES then a list of source files will 124 | # be generated. Documented entities will be cross-referenced with these sources. 125 | 126 | SOURCE_BROWSER = NO 127 | 128 | # Setting the INLINE_SOURCES tag to YES will include the body 129 | # of functions and classes directly in the documentation. 130 | 131 | INLINE_SOURCES = NO 132 | 133 | # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 134 | # doxygen to hide any special comment blocks from generated source code 135 | # fragments. Normal C and C++ comments will always remain visible. 136 | 137 | STRIP_CODE_COMMENTS = NO 138 | 139 | # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 140 | # file names in lower case letters. If set to YES upper case letters are also 141 | # allowed. This is useful if you have classes or files whose names only differ 142 | # in case and if your file system supports case sensitive file names. Windows 143 | # users are adviced to set this option to NO. 144 | 145 | CASE_SENSE_NAMES = YES 146 | 147 | # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 148 | # (but less readable) file names. This can be useful is your file systems 149 | # doesn't support long names like on DOS, Mac, or CD-ROM. 150 | 151 | SHORT_NAMES = NO 152 | 153 | # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 154 | # will show members with their full class and namespace scopes in the 155 | # documentation. If set to YES the scope will be hidden. 156 | 157 | HIDE_SCOPE_NAMES = NO 158 | 159 | # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 160 | # will generate a verbatim copy of the header file for each class for 161 | # which an include is specified. Set to NO to disable this. 162 | 163 | VERBATIM_HEADERS = YES 164 | 165 | # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 166 | # will put list of the files that are included by a file in the documentation 167 | # of that file. 168 | 169 | SHOW_INCLUDE_FILES = YES 170 | 171 | # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 172 | # will interpret the first line (until the first dot) of a JavaDoc-style 173 | # comment as the brief description. If set to NO, the JavaDoc 174 | # comments will behave just like the Qt-style comments (thus requiring an 175 | # explict @brief command for a brief description. 176 | 177 | JAVADOC_AUTOBRIEF = NO 178 | 179 | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 180 | # member inherits the documentation from any documented member that it 181 | # reimplements. 182 | 183 | INHERIT_DOCS = YES 184 | 185 | # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 186 | # is inserted in the documentation for inline members. 187 | 188 | INLINE_INFO = YES 189 | 190 | # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 191 | # will sort the (detailed) documentation of file and class members 192 | # alphabetically by member name. If set to NO the members will appear in 193 | # declaration order. 194 | 195 | SORT_MEMBER_DOCS = NO 196 | 197 | # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 198 | # tag is set to YES, then doxygen will reuse the documentation of the first 199 | # member in the group (if any) for the other members of the group. By default 200 | # all members of a group must be documented explicitly. 201 | 202 | DISTRIBUTE_GROUP_DOC = NO 203 | 204 | # The TAB_SIZE tag can be used to set the number of spaces in a tab. 205 | # Doxygen uses this value to replace tabs by spaces in code fragments. 206 | 207 | TAB_SIZE = 8 208 | 209 | # The ENABLED_SECTIONS tag can be used to enable conditional 210 | # documentation sections, marked by \if sectionname ... \endif. 211 | 212 | ENABLED_SECTIONS = 213 | 214 | # The GENERATE_TODOLIST tag can be used to enable (YES) or 215 | # disable (NO) the todo list. This list is created by putting \todo 216 | # commands in the documentation. 217 | 218 | GENERATE_TODOLIST = YES 219 | 220 | # The GENERATE_TESTLIST tag can be used to enable (YES) or 221 | # disable (NO) the test list. This list is created by putting \test 222 | # commands in the documentation. 223 | 224 | GENERATE_TESTLIST = YES 225 | 226 | # The GENERATE_BUGLIST tag can be used to enable (YES) or 227 | # disable (NO) the bug list. This list is created by putting \bug 228 | # commands in the documentation. 229 | 230 | GENERATE_BUGLIST = YES 231 | 232 | # This tag can be used to specify a number of aliases that acts 233 | # as commands in the documentation. An alias has the form "name=value". 234 | # For example adding "sideeffect=\par Side Effects:\n" will allow you to 235 | # put the command \sideeffect (or @sideeffect) in the documentation, which 236 | # will result in a user defined paragraph with heading "Side Effects:". 237 | # You can put \n's in the value part of an alias to insert newlines. 238 | 239 | ALIASES = 240 | 241 | # The MAX_INITIALIZER_LINES tag determines the maximum number of lines 242 | # the initial value of a variable or define consist of for it to appear in 243 | # the documentation. If the initializer consists of more lines than specified 244 | # here it will be hidden. Use a value of 0 to hide initializers completely. 245 | # The appearance of the initializer of individual variables and defines in the 246 | # documentation can be controlled using \showinitializer or \hideinitializer 247 | # command in the documentation regardless of this setting. 248 | 249 | MAX_INITIALIZER_LINES = 30 250 | 251 | # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 252 | # only. Doxygen will then generate output that is more tailored for C. 253 | # For instance some of the names that are used will be different. The list 254 | # of all members will be omitted, etc. 255 | 256 | OPTIMIZE_OUTPUT_FOR_C = YES 257 | 258 | # Set the SHOW_USED_FILES tag to NO to disable the list of files generated 259 | # at the bottom of the documentation of classes and structs. If set to YES the 260 | # list will mention the files that were used to generate the documentation. 261 | 262 | SHOW_USED_FILES = YES 263 | 264 | #--------------------------------------------------------------------------- 265 | # configuration options related to warning and progress messages 266 | #--------------------------------------------------------------------------- 267 | 268 | # The QUIET tag can be used to turn on/off the messages that are generated 269 | # by doxygen. Possible values are YES and NO. If left blank NO is used. 270 | 271 | QUIET = NO 272 | 273 | # The WARNINGS tag can be used to turn on/off the warning messages that are 274 | # generated by doxygen. Possible values are YES and NO. If left blank 275 | # NO is used. 276 | 277 | WARNINGS = YES 278 | 279 | # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 280 | # for undocumented members. If EXTRACT_ALL is set to YES then this flag will 281 | # automatically be disabled. 282 | 283 | WARN_IF_UNDOCUMENTED = YES 284 | 285 | # The WARN_FORMAT tag determines the format of the warning messages that 286 | # doxygen can produce. The string should contain the $file, $line, and $text 287 | # tags, which will be replaced by the file and line number from which the 288 | # warning originated and the warning text. 289 | 290 | WARN_FORMAT = 291 | 292 | # The WARN_LOGFILE tag can be used to specify a file to which warning 293 | # and error messages should be written. If left blank the output is written 294 | # to stderr. 295 | 296 | WARN_LOGFILE = 297 | 298 | #--------------------------------------------------------------------------- 299 | # configuration options related to the input files 300 | #--------------------------------------------------------------------------- 301 | 302 | # The INPUT tag can be used to specify the files and/or directories that contain 303 | # documented source files. You may enter file names like "myfile.cpp" or 304 | # directories like "/usr/src/myproject". Separate the files or directories 305 | # with spaces. 306 | 307 | INPUT = ndicapi.txt ndicapi.h ndicapi_math.h ndicapi_serial.h ndicapi_thread.h 308 | 309 | # If the value of the INPUT tag contains directories, you can use the 310 | # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 311 | # and *.h) to filter out the source-files in the directories. If left 312 | # blank all files are included. 313 | 314 | FILE_PATTERNS = 315 | 316 | # The RECURSIVE tag can be used to turn specify whether or not subdirectories 317 | # should be searched for input files as well. Possible values are YES and NO. 318 | # If left blank NO is used. 319 | 320 | RECURSIVE = NO 321 | 322 | # The EXCLUDE tag can be used to specify files and/or directories that should 323 | # excluded from the INPUT source files. This way you can easily exclude a 324 | # subdirectory from a directory tree whose root is specified with the INPUT tag. 325 | 326 | EXCLUDE = 327 | 328 | # If the value of the INPUT tag contains directories, you can use the 329 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 330 | # certain files from those directories. 331 | 332 | EXCLUDE_PATTERNS = 333 | 334 | # The EXAMPLE_PATH tag can be used to specify one or more files or 335 | # directories that contain example code fragments that are included (see 336 | # the \include command). 337 | 338 | EXAMPLE_PATH = 339 | 340 | # If the value of the EXAMPLE_PATH tag contains directories, you can use the 341 | # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 342 | # and *.h) to filter out the source-files in the directories. If left 343 | # blank all files are included. 344 | 345 | EXAMPLE_PATTERNS = 346 | 347 | # The IMAGE_PATH tag can be used to specify one or more files or 348 | # directories that contain image that are included in the documentation (see 349 | # the \image command). 350 | 351 | IMAGE_PATH = 352 | 353 | # The INPUT_FILTER tag can be used to specify a program that doxygen should 354 | # invoke to filter for each input file. Doxygen will invoke the filter program 355 | # by executing (via popen()) the command , where 356 | # is the value of the INPUT_FILTER tag, and is the name of an 357 | # input file. Doxygen will then use the output that the filter program writes 358 | # to standard output. 359 | 360 | INPUT_FILTER = 361 | 362 | # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 363 | # INPUT_FILTER) will be used to filter the input files when producing source 364 | # files to browse. 365 | 366 | FILTER_SOURCE_FILES = NO 367 | 368 | #--------------------------------------------------------------------------- 369 | # configuration options related to the alphabetical class index 370 | #--------------------------------------------------------------------------- 371 | 372 | # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 373 | # of all compounds will be generated. Enable this if the project 374 | # contains a lot of classes, structs, unions or interfaces. 375 | 376 | ALPHABETICAL_INDEX = NO 377 | 378 | # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 379 | # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 380 | # in which this list will be split (can be a number in the range [1..20]) 381 | 382 | COLS_IN_ALPHA_INDEX = 5 383 | 384 | # In case all classes in a project start with a common prefix, all 385 | # classes will be put under the same header in the alphabetical index. 386 | # The IGNORE_PREFIX tag can be used to specify one or more prefixes that 387 | # should be ignored while generating the index headers. 388 | 389 | IGNORE_PREFIX = 390 | 391 | #--------------------------------------------------------------------------- 392 | # configuration options related to the HTML output 393 | #--------------------------------------------------------------------------- 394 | 395 | # If the GENERATE_HTML tag is set to YES (the default) Doxygen will 396 | # generate HTML output. 397 | 398 | GENERATE_HTML = YES 399 | 400 | # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 401 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 402 | # put in front of it. If left blank `html' will be used as the default path. 403 | 404 | HTML_OUTPUT = ndicapi_html 405 | 406 | # The HTML_HEADER tag can be used to specify a personal HTML header for 407 | # each generated HTML page. If it is left blank doxygen will generate a 408 | # standard header. 409 | 410 | HTML_HEADER = 411 | 412 | # The HTML_FOOTER tag can be used to specify a personal HTML footer for 413 | # each generated HTML page. If it is left blank doxygen will generate a 414 | # standard footer. 415 | 416 | HTML_FOOTER = 417 | 418 | # The HTML_STYLESHEET tag can be used to specify a user defined cascading 419 | # style sheet that is used by each HTML page. It can be used to 420 | # fine-tune the look of the HTML output. If the tag is left blank doxygen 421 | # will generate a default style sheet 422 | 423 | HTML_STYLESHEET = 424 | 425 | # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 426 | # files or namespaces will be aligned in HTML using tables. If set to 427 | # NO a bullet list will be used. 428 | 429 | HTML_ALIGN_MEMBERS = YES 430 | 431 | # If the GENERATE_HTMLHELP tag is set to YES, additional index files 432 | # will be generated that can be used as input for tools like the 433 | # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 434 | # of the generated HTML documentation. 435 | 436 | GENERATE_HTMLHELP = NO 437 | 438 | # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 439 | # controls if a separate .chi index file is generated (YES) or that 440 | # it should be included in the master .chm file (NO). 441 | 442 | GENERATE_CHI = NO 443 | 444 | # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 445 | # controls whether a binary table of contents is generated (YES) or a 446 | # normal table of contents (NO) in the .chm file. 447 | 448 | BINARY_TOC = NO 449 | 450 | # The TOC_EXPAND flag can be set to YES to add extra items for group members 451 | # to the contents of the Html help documentation and to the tree view. 452 | 453 | TOC_EXPAND = NO 454 | 455 | # The DISABLE_INDEX tag can be used to turn on/off the condensed index at 456 | # top of each HTML page. The value NO (the default) enables the index and 457 | # the value YES disables it. 458 | 459 | DISABLE_INDEX = NO 460 | 461 | # This tag can be used to set the number of enum values (range [1..20]) 462 | # that doxygen will group on one line in the generated HTML documentation. 463 | 464 | ENUM_VALUES_PER_LINE = 4 465 | 466 | # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be 467 | # generated containing a tree-like index structure (just like the one that 468 | # is generated for HTML Help). For this to work a browser that supports 469 | # JavaScript and frames is required (for instance Netscape 4.0+ 470 | # or Internet explorer 4.0+). 471 | 472 | GENERATE_TREEVIEW = NO 473 | 474 | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 475 | # used to set the initial width (in pixels) of the frame in which the tree 476 | # is shown. 477 | 478 | TREEVIEW_WIDTH = 250 479 | 480 | #--------------------------------------------------------------------------- 481 | # configuration options related to the LaTeX output 482 | #--------------------------------------------------------------------------- 483 | 484 | # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 485 | # generate Latex output. 486 | 487 | GENERATE_LATEX = NO 488 | 489 | # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 490 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 491 | # put in front of it. If left blank `latex' will be used as the default path. 492 | 493 | LATEX_OUTPUT = ndicapi_latex 494 | 495 | # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 496 | # LaTeX documents. This may be useful for small projects and may help to 497 | # save some trees in general. 498 | 499 | COMPACT_LATEX = NO 500 | 501 | # The PAPER_TYPE tag can be used to set the paper type that is used 502 | # by the printer. Possible values are: a4, a4wide, letter, legal and 503 | # executive. If left blank a4wide will be used. 504 | 505 | PAPER_TYPE = letter 506 | 507 | # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 508 | # packages that should be included in the LaTeX output. 509 | 510 | EXTRA_PACKAGES = 511 | 512 | # The LATEX_HEADER tag can be used to specify a personal LaTeX header for 513 | # the generated latex document. The header should contain everything until 514 | # the first chapter. If it is left blank doxygen will generate a 515 | # standard header. Notice: only use this tag if you know what you are doing! 516 | 517 | LATEX_HEADER = 518 | 519 | # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 520 | # is prepared for conversion to pdf (using ps2pdf). The pdf file will 521 | # contain links (just like the HTML output) instead of page references 522 | # This makes the output suitable for online browsing using a pdf viewer. 523 | 524 | PDF_HYPERLINKS = YES 525 | 526 | # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 527 | # plain latex in the generated Makefile. Set this option to YES to get a 528 | # higher quality PDF documentation. 529 | 530 | USE_PDFLATEX = YES 531 | 532 | # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 533 | # command to the generated LaTeX files. This will instruct LaTeX to keep 534 | # running if errors occur, instead of asking the user for help. 535 | # This option is also used when generating formulas in HTML. 536 | 537 | LATEX_BATCHMODE = NO 538 | 539 | #--------------------------------------------------------------------------- 540 | # configuration options related to the RTF output 541 | #--------------------------------------------------------------------------- 542 | 543 | # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 544 | # The RTF output is optimised for Word 97 and may not look very pretty with 545 | # other RTF readers or editors. 546 | 547 | GENERATE_RTF = NO 548 | 549 | # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 550 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 551 | # put in front of it. If left blank `rtf' will be used as the default path. 552 | 553 | RTF_OUTPUT = 554 | 555 | # If the COMPACT_RTF tag is set to YES Doxygen generates more compact 556 | # RTF documents. This may be useful for small projects and may help to 557 | # save some trees in general. 558 | 559 | COMPACT_RTF = NO 560 | 561 | # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 562 | # will contain hyperlink fields. The RTF file will 563 | # contain links (just like the HTML output) instead of page references. 564 | # This makes the output suitable for online browsing using WORD or other 565 | # programs which support those fields. 566 | # Note: wordpad (write) and others do not support links. 567 | 568 | RTF_HYPERLINKS = NO 569 | 570 | # Load stylesheet definitions from file. Syntax is similar to doxygen's 571 | # config file, i.e. a series of assigments. You only have to provide 572 | # replacements, missing definitions are set to their default value. 573 | 574 | RTF_STYLESHEET_FILE = 575 | 576 | # Set optional variables used in the generation of an rtf document. 577 | # Syntax is similar to doxygen's config file. 578 | 579 | RTF_EXTENSIONS_FILE = 580 | 581 | #--------------------------------------------------------------------------- 582 | # configuration options related to the man page output 583 | #--------------------------------------------------------------------------- 584 | 585 | # If the GENERATE_MAN tag is set to YES (the default) Doxygen will 586 | # generate man pages 587 | 588 | GENERATE_MAN = NO 589 | 590 | # The MAN_OUTPUT tag is used to specify where the man pages will be put. 591 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 592 | # put in front of it. If left blank `man' will be used as the default path. 593 | 594 | MAN_OUTPUT = 595 | 596 | # The MAN_EXTENSION tag determines the extension that is added to 597 | # the generated man pages (default is the subroutine's section .3) 598 | 599 | MAN_EXTENSION = 600 | 601 | # If the MAN_LINKS tag is set to YES and Doxygen generates man output, 602 | # then it will generate one additional man file for each entity 603 | # documented in the real man page(s). These additional files 604 | # only source the real man page, but without them the man command 605 | # would be unable to find the correct page. The default is NO. 606 | 607 | MAN_LINKS = NO 608 | 609 | #--------------------------------------------------------------------------- 610 | # Configuration options related to the preprocessor 611 | #--------------------------------------------------------------------------- 612 | 613 | # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 614 | # evaluate all C-preprocessor directives found in the sources and include 615 | # files. 616 | 617 | ENABLE_PREPROCESSING = YES 618 | 619 | # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 620 | # names in the source code. If set to NO (the default) only conditional 621 | # compilation will be performed. Macro expansion can be done in a controlled 622 | # way by setting EXPAND_ONLY_PREDEF to YES. 623 | 624 | MACRO_EXPANSION = NO 625 | 626 | # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 627 | # then the macro expansion is limited to the macros specified with the 628 | # PREDEFINED and EXPAND_AS_PREDEFINED tags. 629 | 630 | EXPAND_ONLY_PREDEF = YES 631 | 632 | # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 633 | # in the INCLUDE_PATH (see below) will be search if a #include is found. 634 | 635 | SEARCH_INCLUDES = YES 636 | 637 | # The INCLUDE_PATH tag can be used to specify one or more directories that 638 | # contain include files that are not input files but should be processed by 639 | # the preprocessor. 640 | 641 | INCLUDE_PATH = 642 | 643 | # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 644 | # patterns (like *.h and *.hpp) to filter out the header-files in the 645 | # directories. If left blank, the patterns specified with FILE_PATTERNS will 646 | # be used. 647 | 648 | INCLUDE_FILE_PATTERNS = 649 | 650 | # The PREDEFINED tag can be used to specify one or more macro names that 651 | # are defined before the preprocessor is started (similar to the -D option of 652 | # gcc). The argument of the tag is a list of macros of the form: name 653 | # or name=definition (no spaces). If the definition and the = are 654 | # omitted =1 is assumed. 655 | 656 | PREDEFINED = _WIN32 657 | 658 | # If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 659 | # this tag can be used to specify a list of macro names that should be expanded. 660 | # The macro definition that is found in the sources will be used. 661 | # Use the PREDEFINED tag if you want to use a different macro definition. 662 | 663 | EXPAND_AS_DEFINED = 664 | 665 | #--------------------------------------------------------------------------- 666 | # Configuration::addtions related to external references 667 | #--------------------------------------------------------------------------- 668 | 669 | # The TAGFILES tag can be used to specify one or more tagfiles. 670 | 671 | TAGFILES = 672 | 673 | # When a file name is specified after GENERATE_TAGFILE, doxygen will create 674 | # a tag file that is based on the input files it reads. 675 | 676 | GENERATE_TAGFILE = 677 | 678 | # If the ALLEXTERNALS tag is set to YES all external classes will be listed 679 | # in the class index. If set to NO only the inherited external classes 680 | # will be listed. 681 | 682 | ALLEXTERNALS = NO 683 | 684 | # The PERL_PATH should be the absolute path and name of the perl script 685 | # interpreter (i.e. the result of `which perl'). 686 | 687 | PERL_PATH = 688 | 689 | #--------------------------------------------------------------------------- 690 | # Configuration options related to the dot tool 691 | #--------------------------------------------------------------------------- 692 | 693 | # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 694 | # available from the path. This tool is part of Graphviz, a graph visualization 695 | # toolkit from AT&T and Lucent Bell Labs. The other options in this section 696 | # have no effect if this option is set to NO (the default) 697 | 698 | HAVE_DOT = NO 699 | 700 | # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 701 | # will generate a graph for each documented class showing the direct and 702 | # indirect inheritance relations. Setting this tag to YES will force the 703 | # the CLASS_DIAGRAMS tag to NO. 704 | 705 | CLASS_GRAPH = YES 706 | 707 | # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 708 | # will generate a graph for each documented class showing the direct and 709 | # indirect implementation dependencies (inheritance, containment, and 710 | # class references variables) of the class with other documented classes. 711 | 712 | COLLABORATION_GRAPH = YES 713 | 714 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 715 | # tags are set to YES then doxygen will generate a graph for each documented 716 | # file showing the direct and indirect include dependencies of the file with 717 | # other documented files. 718 | 719 | INCLUDE_GRAPH = YES 720 | 721 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 722 | # HAVE_DOT tags are set to YES then doxygen will generate a graph for each 723 | # documented header file showing the documented files that directly or 724 | # indirectly include this file. 725 | 726 | INCLUDED_BY_GRAPH = YES 727 | 728 | # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 729 | # will graphical hierarchy of all classes instead of a textual one. 730 | 731 | GRAPHICAL_HIERARCHY = YES 732 | 733 | # The tag DOT_PATH can be used to specify the path where the dot tool can be 734 | # found. If left blank, it is assumed the dot tool can be found on the path. 735 | 736 | DOT_PATH = 737 | 738 | # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 739 | # (in pixels) of the graphs generated by dot. If a graph becomes larger than 740 | # this value, doxygen will try to truncate the graph, so that it fits within 741 | # the specified constraint. Beware that most browsers cannot cope with very 742 | # large images. 743 | 744 | MAX_DOT_GRAPH_WIDTH = 1024 745 | 746 | # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 747 | # (in pixels) of the graphs generated by dot. If a graph becomes larger than 748 | # this value, doxygen will try to truncate the graph, so that it fits within 749 | # the specified constraint. Beware that most browsers cannot cope with very 750 | # large images. 751 | 752 | MAX_DOT_GRAPH_HEIGHT = 1024 753 | 754 | # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 755 | # generate a legend page explaining the meaning of the various boxes and 756 | # arrows in the dot generated graphs. 757 | 758 | GENERATE_LEGEND = YES 759 | 760 | # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 761 | # remove the intermedate dot files that are used to generate 762 | # the various graphs. 763 | 764 | DOT_CLEANUP = YES 765 | 766 | #--------------------------------------------------------------------------- 767 | # Configuration::addtions related to the search engine 768 | #--------------------------------------------------------------------------- 769 | 770 | # The SEARCHENGINE tag specifies whether or not a search engine should be 771 | # used. If set to NO the values of all tags below this one will be ignored. 772 | 773 | SEARCHENGINE = NO 774 | 775 | # The CGI_NAME tag should be the name of the CGI script that 776 | # starts the search engine (doxysearch) with the correct parameters. 777 | # A script with this name will be generated by doxygen. 778 | 779 | CGI_NAME = 780 | 781 | # The CGI_URL tag should be the absolute URL to the directory where the 782 | # cgi binaries are located. See the documentation of your http daemon for 783 | # details. 784 | 785 | CGI_URL = 786 | 787 | # The DOC_URL tag should be the absolute URL to the directory where the 788 | # documentation is located. If left blank the absolute path to the 789 | # documentation, with file:// prepended to it, will be used. 790 | 791 | DOC_URL = 792 | 793 | # The DOC_ABSPATH tag should be the absolute path to the directory where the 794 | # documentation is located. If left blank the directory on the local machine 795 | # will be used. 796 | 797 | DOC_ABSPATH = 798 | 799 | # The BIN_ABSPATH tag must point to the directory where the doxysearch binary 800 | # is installed. 801 | 802 | BIN_ABSPATH = 803 | 804 | # The EXT_DOC_PATHS tag can be used to specify one or more paths to 805 | # documentation generated for other projects. This allows doxysearch to search 806 | # the documentation for these projects as well. 807 | 808 | EXT_DOC_PATHS = 809 | -------------------------------------------------------------------------------- /ndicapi.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlusToolkit/ndicapi/a8eadfccfd376321180849e452bb6dc340a6028e/ndicapi.h -------------------------------------------------------------------------------- /ndicapi.txt: -------------------------------------------------------------------------------- 1 | /*! \mainpage 2 | 3 | This library provides a set of C functions for communicating with 4 | measurement systems (also called tracking systems) from 5 | Northern Digital Inc. via the NDI Combined Application 6 | Programmers' Interface. 7 | 8 | This C API is based very closely on the serial communications API 9 | published by Northern Digital Inc. Its primary purpose is to provide 10 | a straightforward C-language programming interface that is portable 11 | across all common computing platforms. 12 | 13 | ========================================================================== 14 | 15 | Copyright (c) 2000-2005 Atamai, Inc. 16 | 17 | Use, modification and redistribution of the software, in source or 18 | binary forms, are permitted provided that the following terms and 19 | conditions are met: 20 | 21 | 1) Redistribution of the source code, in verbatim or modified 22 | form, must retain the above copyright notice, this license, 23 | the following disclaimer, and any notices that refer to this 24 | license and/or the following disclaimer. 25 | 26 | 2) Redistribution in binary form must include the above copyright 27 | notice, a copy of this license and the following disclaimer 28 | in the documentation or with other materials provided with the 29 | distribution. 30 | 31 | 3) Modified copies of the source code must be clearly marked as such, 32 | and must not be misrepresented as verbatim copies of the source code. 33 | 34 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 35 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 36 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 37 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 38 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 39 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 40 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 41 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 42 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 43 | POSSIBILITY OF SUCH DAMAGES. 44 | 45 | ======================================================================= 46 | 47 | */ 48 | -------------------------------------------------------------------------------- /ndicapiConfig.cmake.in: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------- 2 | # Configuration file for the Public Library for Ultrasound (PLUS) toolkit 3 | # 4 | # © Copyright 2016 The Laboratory for Percutaneous Surgery, Queen's University, Canada 5 | # 6 | # This file can be passed to a CMake FIND_PACKAGE call with the following syntax: 7 | # 8 | # FIND_PACKAGE(ndicapi ) 9 | # If NO_MODULE is included, set the variable ndicapi_DIR:PATH=@CMAKE_BINARY_DIR@ 10 | # 11 | # Or you can use the following variables to configure your CMake project: 12 | # ndicapi_INCLUDE_DIRS - include directories for common API headers 13 | # ndicapi_LIBRARIES - list of CMake targets produced by this build 14 | #----------------------------------------------------------------------------- 15 | 16 | # set the targets file 17 | INCLUDE(@ndicapi_TARGETS_FILE@) 18 | 19 | # Tell the user project where to find our headers and libraries 20 | SET(ndicapi_INCLUDE_DIRS "@ndicapi_INCLUDE_DIRS@") 21 | SET(ndicapi_LIBRARIES "@ndicapi_LIBRARIES@") -------------------------------------------------------------------------------- /ndicapiConfigVersion.cmake.in: -------------------------------------------------------------------------------- 1 | SET(PACKAGE_VERSION @ndicapi_VERSION@) # Check whether the requested PACKAGE_FIND_VERSION is compatible IF("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") SET(PACKAGE_VERSION_COMPATIBLE FALSE) ELSE() SET(PACKAGE_VERSION_COMPATIBLE TRUE) IF ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") SET(PACKAGE_VERSION_EXACT TRUE) ENDIF() ENDIF() -------------------------------------------------------------------------------- /ndicapiExport.h.in: -------------------------------------------------------------------------------- 1 | /*=Plus=header=begin====================================================== 2 | Program: Plus 3 | Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved. 4 | See License.txt for details. 5 | =========================================================Plus=header=end*/ 6 | 7 | // .NAME __ndicapiExport - manage Windows system differences 8 | // .SECTION Description 9 | // The __ndicapiExport manages DLL export syntax differences 10 | // between different operating systems. 11 | 12 | #ifndef __ndicapiExport_h 13 | #define __ndicapiExport_h 14 | 15 | #cmakedefine ndicapi_STATIC 16 | 17 | #if defined(WIN32) && !defined(ndicapi_STATIC) 18 | #if defined(ndicapi_EXPORTS) 19 | #define ndicapiExport __declspec( dllexport ) 20 | #else 21 | #define ndicapiExport __declspec( dllimport ) 22 | #endif 23 | #else 24 | #define ndicapiExport 25 | #endif 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /ndicapi_math.cxx: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | #include 36 | #include "ndicapi_math.h" 37 | 38 | //---------------------------------------------------------------------------- 39 | // Divide the transform 'trans' by the transform 'ref': 40 | // trans = trans * ref^(-1) 41 | ndicapiExport void ndiRelativeTransform(const double a[8], const double b[8], double c[8]) 42 | { 43 | double f, x, y, z, w1, x1, y1, z1, w2, x2, y2, z2; 44 | 45 | w1 = b[0]; 46 | x1 = b[1]; 47 | y1 = b[2]; 48 | z1 = b[3]; 49 | 50 | w2 = a[0]; 51 | x2 = a[1]; 52 | y2 = a[2]; 53 | z2 = a[3]; 54 | 55 | /* for rotation part of transformation: 56 | q = q1\q2 (divide on the right to get new orientation) */ 57 | c[0] = w1 * w2 + x1 * x2 + y1 * y2 + z1 * z2; 58 | c[1] = w1 * x2 - x1 * w2 - y1 * z2 + z1 * y2; 59 | c[2] = w1 * y2 + x1 * z2 - y1 * w2 - z1 * x2; 60 | c[3] = w1 * z2 - x1 * y2 + y1 * x2 - z1 * w2; 61 | 62 | /* several steps required to calculate new translation: */ 63 | 64 | /* distance between tools */ 65 | x = a[4] - b[4]; 66 | y = a[5] - b[5]; 67 | z = a[6] - b[6]; 68 | 69 | /* q = q1\q*q1 (apply inverse of reference tranformation to distance) */ 70 | 71 | /* first: qtmp = q1\q */ 72 | w2 = x1 * x + y1 * y + z1 * z; 73 | x2 = w1 * x - y1 * z + z1 * y; 74 | y2 = w1 * y + x1 * z - z1 * x; 75 | z2 = w1 * z - x1 * y + y1 * x; 76 | 77 | /* next: q = qtmp*q1 */ 78 | x = w2 * x1 + x2 * w1 + y2 * z1 - z2 * y1; 79 | y = w2 * y1 - x2 * z1 + y2 * w1 + z2 * x1; 80 | z = w2 * z1 + x2 * y1 - y2 * x1 + z2 * w1; 81 | 82 | /* find the normalization factor for q1 */ 83 | f = 1.0f / (w1 * w1 + x1 * x1 + y1 * y1 + z1 * z1); 84 | c[4] = x * f; 85 | c[5] = y * f; 86 | c[6] = z * f; 87 | 88 | c[7] = 0.0; 89 | } 90 | 91 | //---------------------------------------------------------------------------- 92 | // Converts the quaternion rotation + translation transform returned 93 | // by the NDICAPI into a 4x4 base-zero row-major matrix, following 94 | // the right-multiplication convention: 95 | // 96 | // / m_11 m_12 m_11 m_12 \ 97 | // [ x' y' z' 1 ] = [ x y z 1 ] | m_21 m_22 m_21 m_22 | 98 | // | m_31 m_32 m_31 m_32 | 99 | // \ m_41 m_42 m_41 m_42 / 100 | // 101 | // where m_11 == m[0][0], m_12 = m[0][1], etc. This is the 102 | // convention used by QuickDraw3D on the Macintosh and by 103 | // DirectDraw3D on the PC. 104 | // 105 | // This matrix can also be used in OpenGL without modification 106 | // even though OpenGL follows the left-multiplication convention, 107 | // because OpenGL uses a column-major storage model so references 108 | // to the matrix are automagically transposed. 109 | ndicapiExport void ndiTransformToMatrixf(const float trans[8], float matrix[16]) 110 | { 111 | float ww, xx, yy, zz, wx, wy, wz, xy, xz, yz, ss, rr, f; 112 | 113 | /* Determine some calculations done more than once. */ 114 | ww = trans[0] * trans[0]; 115 | xx = trans[1] * trans[1]; 116 | yy = trans[2] * trans[2]; 117 | zz = trans[3] * trans[3]; 118 | wx = trans[0] * trans[1]; 119 | wy = trans[0] * trans[2]; 120 | wz = trans[0] * trans[3]; 121 | xy = trans[1] * trans[2]; 122 | xz = trans[1] * trans[3]; 123 | yz = trans[2] * trans[3]; 124 | 125 | rr = xx + yy + zz; 126 | ss = (ww - rr) * 0.5f; 127 | /* Normalization factor */ 128 | f = 2.0f / (ww + rr); 129 | 130 | /* Fill in the matrix. */ 131 | matrix[0] = (ss + xx) * f; 132 | matrix[1] = (wz + xy) * f; 133 | matrix[2] = (-wy + xz) * f; 134 | matrix[3] = 0; 135 | matrix[4] = (-wz + xy) * f; 136 | matrix[5] = (ss + yy) * f; 137 | matrix[6] = (wx + yz) * f; 138 | matrix[7] = 0; 139 | matrix[8] = (wy + xz) * f; 140 | matrix[9] = (-wx + yz) * f; 141 | matrix[10] = (ss + zz) * f; 142 | matrix[11] = 0; 143 | matrix[12] = trans[4]; 144 | matrix[13] = trans[5]; 145 | matrix[14] = trans[6]; 146 | matrix[15] = 1; 147 | } 148 | 149 | //---------------------------------------------------------------------------- 150 | ndicapiExport void ndiTransformToMatrixfd(const float trans[8], double matrix[16]) 151 | { 152 | double ww, xx, yy, zz, wx, wy, wz, xy, xz, yz, ss, rr, f; 153 | 154 | /* Determine some calculations done more than once. */ 155 | ww = trans[0] * trans[0]; 156 | xx = trans[1] * trans[1]; 157 | yy = trans[2] * trans[2]; 158 | zz = trans[3] * trans[3]; 159 | wx = trans[0] * trans[1]; 160 | wy = trans[0] * trans[2]; 161 | wz = trans[0] * trans[3]; 162 | xy = trans[1] * trans[2]; 163 | xz = trans[1] * trans[3]; 164 | yz = trans[2] * trans[3]; 165 | 166 | rr = xx + yy + zz; 167 | ss = (ww - rr) * 0.5; 168 | /* Normalization factor */ 169 | f = 2.0 / (ww + rr); 170 | 171 | /* Fill in the matrix. */ 172 | matrix[0] = (ss + xx) * f; 173 | matrix[1] = (wz + xy) * f; 174 | matrix[2] = (-wy + xz) * f; 175 | matrix[3] = 0; 176 | matrix[4] = (-wz + xy) * f; 177 | matrix[5] = (ss + yy) * f; 178 | matrix[6] = (wx + yz) * f; 179 | matrix[7] = 0; 180 | matrix[8] = (wy + xz) * f; 181 | matrix[9] = (-wx + yz) * f; 182 | matrix[10] = (ss + zz) * f; 183 | matrix[11] = 0; 184 | matrix[12] = trans[4]; 185 | matrix[13] = trans[5]; 186 | matrix[14] = trans[6]; 187 | matrix[15] = 1; 188 | } 189 | 190 | //---------------------------------------------------------------------------- 191 | ndicapiExport void ndiTransformToMatrixd(const double trans[8], double matrix[16]) 192 | { 193 | double ww, xx, yy, zz, wx, wy, wz, xy, xz, yz, ss, rr, f; 194 | 195 | /* Determine some calculations done more than once. */ 196 | ww = trans[0] * trans[0]; 197 | xx = trans[1] * trans[1]; 198 | yy = trans[2] * trans[2]; 199 | zz = trans[3] * trans[3]; 200 | wx = trans[0] * trans[1]; 201 | wy = trans[0] * trans[2]; 202 | wz = trans[0] * trans[3]; 203 | xy = trans[1] * trans[2]; 204 | xz = trans[1] * trans[3]; 205 | yz = trans[2] * trans[3]; 206 | 207 | rr = xx + yy + zz; 208 | ss = (ww - rr) * 0.5; 209 | /* Normalization factor */ 210 | f = 2.0 / (ww + rr); 211 | 212 | /* Fill in the matrix. */ 213 | matrix[0] = (ss + xx) * f; 214 | matrix[1] = (wz + xy) * f; 215 | matrix[2] = (-wy + xz) * f; 216 | matrix[3] = 0; 217 | matrix[4] = (-wz + xy) * f; 218 | matrix[5] = (ss + yy) * f; 219 | matrix[6] = (wx + yz) * f; 220 | matrix[7] = 0; 221 | matrix[8] = (wy + xz) * f; 222 | matrix[9] = (-wx + yz) * f; 223 | matrix[10] = (ss + zz) * f; 224 | matrix[11] = 0; 225 | matrix[12] = trans[4]; 226 | matrix[13] = trans[5]; 227 | matrix[14] = trans[6]; 228 | matrix[15] = 1; 229 | } 230 | 231 | //---------------------------------------------------------------------------- 232 | // Extracts the roll,pitch,yaw rotation angles (in radians) from the 233 | // 4x4 transform matrix (note that these are _not_ the same as Euler 234 | // angles, which follow a different convention). 235 | // 236 | // The rotations are described by the following three matrices, the 237 | // product of which is the full rotation matrix. Please note that 238 | // the matrices follow the right-multiplication convention (see notes 239 | // for ndiTransformToMatrix() ). 240 | // 241 | // roll around x axis pitch around y axix yaw around z axis 242 | // 243 | // / 1 0 0 \ / cos(pch) 0 -sin(pch) \ / cos(rol) sin(rol) 0 \ 244 | // | 0 cos(yaw) sin(yaw) |*| 0 1 0 |*| -sin(rol) cos(rol) 0 | 245 | // \ 0 -sin(yaw) cos(yaw) / \ sin(pch) 0 cos(pch) / \ 0 0 1 / 246 | // 247 | // Pay careful attention to the above: according to the right-multiplication 248 | // convention, the order in which the rotations are applied are 1) roll 249 | // around x 2) pitch around y 3) yaw around z. 250 | // 251 | // This function was nabbed from the NDI ndicapi docs and heavily modified. 252 | ndicapiExport void ndiAnglesFromMatrixf(float outRotationAngles[3], const float rotationMatrix[16]) 253 | { 254 | float yaw, cosYaw, sinYaw; 255 | 256 | yaw = atan2f(rotationMatrix[1], rotationMatrix[0]); 257 | cosYaw = cosf(yaw); 258 | sinYaw = sinf(yaw); 259 | 260 | outRotationAngles[2] = (float)yaw; 261 | outRotationAngles[1] = (float)atan2f(-rotationMatrix[2], (cosYaw * rotationMatrix[0]) + (sinYaw * rotationMatrix[1])); 262 | outRotationAngles[0] = (float)atan2f((sinYaw * rotationMatrix[8]) - (cosYaw * rotationMatrix[9]), (-sinYaw * rotationMatrix[4]) + (cosYaw * rotationMatrix[5])); 263 | } 264 | 265 | //---------------------------------------------------------------------------- 266 | ndicapiExport void ndiAnglesFromMatrixd(double outRotationAngles[3], const double rotationMatrix[16]) 267 | { 268 | double yaw, cosYaw, sinYaw; 269 | 270 | yaw = atan2(rotationMatrix[1], rotationMatrix[0]); 271 | cosYaw = cos(yaw); 272 | sinYaw = sin(yaw); 273 | 274 | outRotationAngles[2] = yaw; 275 | outRotationAngles[1] = atan2(-rotationMatrix[2], (cosYaw * rotationMatrix[0]) + (sinYaw * rotationMatrix[1])); 276 | outRotationAngles[0] = atan2((sinYaw * rotationMatrix[8]) - (cosYaw * rotationMatrix[9]), (-sinYaw * rotationMatrix[4]) + (cosYaw * rotationMatrix[5])); 277 | } 278 | 279 | //---------------------------------------------------------------------------- 280 | // A very simple function to extract the translation portion of a 281 | // transformation matrix. 282 | ndicapiExport void ndiCoordsFromMatrixf(float coords[3], const float matrix[16]) 283 | { 284 | coords[0] = matrix[12]; 285 | coords[1] = matrix[13]; 286 | coords[2] = matrix[14]; 287 | } 288 | 289 | //---------------------------------------------------------------------------- 290 | ndicapiExport void ndiCoordsFromMatrixd(double coords[3], const double matrix[16]) 291 | { 292 | coords[0] = matrix[12]; 293 | coords[1] = matrix[13]; 294 | coords[2] = matrix[14]; 295 | } -------------------------------------------------------------------------------- /ndicapi_math.h: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | /*! \file ndicapi_math.h 36 | This file contains some math functions that are useful with the NDICAPI. 37 | */ 38 | 39 | #ifndef NDICAPI_MATH_H 40 | #define NDICAPI_MATH_H 1 41 | 42 | #include "ndicapiExport.h" 43 | #include 44 | 45 | /*=====================================================================*/ 46 | /*! \defgroup NdicapiMath Mathematical Functions 47 | 48 | These are some useful math functions. Note that the matrices are 49 | stored using the OpenGL convention: 50 | \f[ 51 | \left( 52 | \begin{array}{cccc} 53 | m[0] & m[4] & m[8] & m[12] \\ 54 | m[1] & m[5] & m[9] & m[13] \\ 55 | m[2] & m[6] & m[10] & m[14] \\ 56 | m[3] & m[7] & m[11] & m[15] \\ 57 | \end{array} 58 | \right) 59 | \f] 60 | */ 61 | 62 | #ifdef __cplusplus 63 | extern "C" { 64 | #endif 65 | 66 | /*! \ingroup NdicapiMath 67 | Find the position and orientation of a tool relative to a 68 | reference tool. This is done by quaternion division. 69 | 70 | \param a the original tool transformation 71 | \param b the reference tool transformation 72 | \param c the resulting relative transformation 73 | 74 | The pointer \em c can be the same as pointer \em a if you want to do 75 | the division in-place. 76 | */ 77 | ndicapiExport void ndiRelativeTransform(const double a[8], const double b[8], double c[8]); 78 | 79 | /*! \ingroup NdicapiMath 80 | Convert a quaternion transformation into a 4x4 float matrix. 81 | */ 82 | ndicapiExport void ndiTransformToMatrixf(const float trans[8], float matrix[16]); 83 | /*! \ingroup NdicapiMath 84 | Convert a quaternion transformation into a 4x4 double matrix. 85 | */ 86 | ndicapiExport void ndiTransformToMatrixfd(const float trans[8], double matrix[16]); 87 | /*! \ingroup NdicapiMath 88 | Convert a quaternion transformation into a 4x4 double matrix. 89 | */ 90 | ndicapiExport void ndiTransformToMatrixd(const double trans[8], double matrix[16]); 91 | 92 | /*! \ingroup NdicapiMath 93 | Extract rotation angles from a 4x4 float matrix. The order of the 94 | rotations is: 95 | -# roll around \em x axis 96 | -# pitch around \em y axis 97 | -# yaw around \em z axis 98 | */ 99 | ndicapiExport void ndiAnglesFromMatrixf(float angles[3], const float matrix[16]); 100 | /*! \ingroup NdicapiMath 101 | Extract rotation angles from a 4x4 double matrix. The order of the 102 | rotations is: 103 | -# roll around \em x axis 104 | -# pitch around \em y axis 105 | -# yaw around \em z axis 106 | */ 107 | ndicapiExport void ndiAnglesFromMatrixd(double angles[3], const double matrix[16]); 108 | 109 | /*! \ingroup NdicapiMath 110 | Extract position coordinates from a 4x4 float matrix. These have 111 | the same value as the position coordinates in the quaternion 112 | transformation. 113 | */ 114 | ndicapiExport void ndiCoordsFromMatrixf(float coords[3], const float matrix[16]); 115 | 116 | /*! \ingroup NdicapiMath 117 | Extract position coordinates from a 4x4 double matrix. These have 118 | the same value as the position coordinates in the quaternion 119 | transformation. 120 | */ 121 | ndicapiExport void ndiCoordsFromMatrixd(double coords[3], const double matrix[16]); 122 | 123 | #ifdef __cplusplus 124 | } 125 | #endif 126 | 127 | #endif -------------------------------------------------------------------------------- /ndicapi_serial.cxx: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | 36 | // This file contains the platform-dependent portions of the source code 37 | // that talk to the serial port. All these methods 38 | // are of the form ndiSerialXX(). 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "ndicapi_serial.h" 48 | 49 | // time out period in milliseconds 50 | #define TIMEOUT_PERIOD 5000 51 | 52 | #ifdef _WIN32 53 | #include "ndicapi_serial_win32.cxx" 54 | #elif defined(unix) || defined(__unix__) || defined(__linux__) 55 | #include "ndicapi_serial_unix.cxx" 56 | #elif defined(__APPLE__) 57 | #include "ndicapi_serial_apple.cxx" 58 | #endif -------------------------------------------------------------------------------- /ndicapi_serial.h: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Program: NDI Combined API C Interface Library 4 | Module: $RCSfile: ndicapi_serial.h,v $ 5 | Creator: David Gobbi 6 | Language: C 7 | Author: $Author: kcharbon $ 8 | Date: $Date: 2008/06/18 15:33:20 $ 9 | Version: $Revision: 1.6 $ 10 | 11 | ========================================================================== 12 | 13 | Copyright (c) 2000-2005 Atamai, Inc. 14 | 15 | Use, modification and redistribution of the software, in source or 16 | binary forms, are permitted provided that the following terms and 17 | conditions are met: 18 | 19 | 1) Redistribution of the source code, in verbatim or modified 20 | form, must retain the above copyright notice, this license, 21 | the following disclaimer, and any notices that refer to this 22 | license and/or the following disclaimer. 23 | 24 | 2) Redistribution in binary form must include the above copyright 25 | notice, a copy of this license and the following disclaimer 26 | in the documentation or with other materials provided with the 27 | distribution. 28 | 29 | 3) Modified copies of the source code must be clearly marked as such, 30 | and must not be misrepresented as verbatim copies of the source code. 31 | 32 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 33 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 34 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 35 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 36 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 37 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 38 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 39 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 40 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 41 | POSSIBILITY OF SUCH DAMAGES. 42 | 43 | =======================================================================*/ 44 | 45 | /*! \file ndicapi_serial.h 46 | This file contains the platform-dependent portions of the 47 | NDICAPI C API that talk to the serial port. 48 | */ 49 | 50 | #ifndef NDICAPI_SERIAL_H 51 | #define NDICAPI_SERIAL_H 52 | 53 | #include "ndicapiExport.h" 54 | 55 | /*=====================================================================*/ 56 | /*! \defgroup NDISerial NDI Serial Methods 57 | These are low-level methods that provide a platform-independent 58 | interface to the serial port. 59 | */ 60 | 61 | #ifdef __cplusplus 62 | extern "C" { 63 | #endif 64 | 65 | /*! \ingroup NDISerial 66 | \typedef NDIFileHandle 67 | The serial port handle is a platform-specific type, for which we use 68 | the typedef NDIFileHandle. On UNIX it is an int. 69 | */ 70 | 71 | #ifdef _WIN32 72 | 73 | #define _WINSOCKAPI_ 74 | #include 75 | typedef HANDLE NDIFileHandle; 76 | #define NDI_INVALID_HANDLE INVALID_HANDLE_VALUE 77 | 78 | #elif defined(linux) || defined(__linux__) 79 | 80 | typedef int NDIFileHandle; 81 | #define NDI_INVALID_HANDLE -1 82 | 83 | #define NDI_DEVICE0 "/dev/ttyS0" 84 | #define NDI_DEVICE1 "/dev/ttyS1" 85 | #define NDI_DEVICE2 "/dev/ttyUSB0" 86 | #define NDI_DEVICE3 "/dev/ttyUSB1" 87 | #define NDI_DEVICE4 "/dev/ttyUSB2" 88 | #define NDI_DEVICE5 "/dev/ttyUSB3" 89 | #define NDI_DEVICE6 "/dev/ttyUSB4" 90 | #define NDI_DEVICE7 "/dev/ttyUSB5" 91 | 92 | #elif defined(__APPLE__) 93 | 94 | typedef int NDIFileHandle; 95 | #define NDI_INVALID_HANDLE -1 96 | 97 | 98 | 99 | #elif defined(sgi) 100 | 101 | typedef int NDIFileHandle; 102 | #define NDI_INVALID_HANDLE -1 103 | 104 | #define NDI_DEVICE0 "/dev/ttyd1" 105 | #define NDI_DEVICE1 "/dev/ttyd2" 106 | #define NDI_DEVICE2 "/dev/ttyd3" 107 | #define NDI_DEVICE3 "/dev/ttyd4" 108 | #define NDI_DEVICE4 "/dev/ttyd5" 109 | #define NDI_DEVICE5 "/dev/ttyd6" 110 | #define NDI_DEVICE6 "/dev/ttyd7" 111 | #define NDI_DEVICE7 "/dev/ttyd8" 112 | 113 | #elif defined(macintosh) 114 | 115 | typedef long NDIFileHandle; 116 | #define NDI_INVALID_HANDLE -1 117 | 118 | /* macros to extract input and output file handles */ 119 | #define output_file(serial_port) ((short)((serial_port & 0xff00) >> 16)); 120 | #define input_file(serial_port) ((short)((serial_port & 0x00ff) >> 0)); 121 | 122 | #define NDI_DEVICE0 "\p.A" 123 | #define NDI_DEVICE1 "\p.B" 124 | 125 | #endif 126 | 127 | /*! \ingroup NDISerial 128 | Open the specified serial port device. 129 | A return value of NDI_INVALID_HANDLE means that an error occurred. 130 | The serial port will be set to 9600 baud, 8N1, no handshake. 131 | 132 | The macros NDI_DEVICE0 through NDI_DEVICE3 will expand to valid device 133 | names for the first four serial ports, e.g. "/dev/ttyS0" on linux. 134 | 135 | The type of the handle is platform-specific. 136 | */ 137 | ndicapiExport NDIFileHandle ndiSerialOpen(const char* device); 138 | 139 | /*! \ingroup NDISerial 140 | Close the serial port. It is wise to send a "COMM 00000\r" command 141 | to the NDICAPI before you close the port, otherwise the next time the 142 | serial port is opened you will have to reset the NDICAPI before you can 143 | resume communication with it. 144 | */ 145 | ndicapiExport void ndiSerialClose(NDIFileHandle serial_port); 146 | 147 | /*! \ingroup NDISerial 148 | Check whether the DSR signel is set. If the return value is zero, 149 | then the DSR is not set which means that either the device has been 150 | unplugged from the serial port or has been turned off. 151 | */ 152 | ndicapiExport int ndiSerialCheckDSR(NDIFileHandle serial_port); 153 | 154 | /*! \ingroup NDISerial 155 | Send a 300ms break to the serial port to reset the NDICAPI. 156 | After you call this function, you must also call 157 | ndiSerialComm(file, 9600, "8N1", 0) to reset the 158 | serial port back to the default NDICAPI communication parameters. 159 | The NDICAPI will beep and send the text "RESETBE6F\r", which 160 | must be read with ndiSerialRead(). 161 | 162 | The return value of this function will be if the call was successful. 163 | A negative return value means that an IO error occurred. 164 | */ 165 | ndicapiExport int ndiSerialBreak(NDIFileHandle serial_port); 166 | 167 | /*! \ingroup NDISerial 168 | Flush out the serial I/O buffers. The following options are available: 169 | - NDI_IFLUSH: discard the contents of the input buffer 170 | - NDI_OFLUSH: discard the contents of the output buffer 171 | - NDI_IOFLUSH: discard the contents of both buffers. 172 | 173 |

The return value of this function will be if the call was successful. 174 | A negative return value means that an IO error occurred. 175 | */ 176 | ndicapiExport int ndiSerialFlush(NDIFileHandle serial_port, int flushtype); 177 | 178 | #define NDI_IFLUSH 0x1 179 | #define NDI_OFLUSH 0x2 180 | #define NDI_IOFLUSH 0x3 181 | 182 | /*! \ingroup NDISerial 183 | Change the baud rate and other comm parameters. 184 | 185 | The baud rate should be one of 9600, 14400, 19200, 38400, 57600, 115200. 186 | 187 | The mode string should be one of "8N1", "7O2" etc. The first character 188 | is the number of data bits (7 or 8), the second character is the parity 189 | (N, O or E for none, odd or even), and the the third character is the 190 | number of stop bits (1 or 2). 191 | 192 | The handshake value should be 0 or 1 depending on whether hardware 193 | handshaking is desired. 194 | 195 | The default setting for the NDICAPI (i.e. after a power-on or a reset) 196 | is (9600, "8N1", 0). A commonly used setting is (115200, "8N1", 1). 197 | 198 | Before this function is called you should send a COMM command to the 199 | ndicapi and read the "OKAY" reply. 200 | 201 | The return value will be 0 if the call was successful. 202 | A negative return value means that an IO error occurred, or that 203 | the specified parameters are not available for this serial port. 204 | */ 205 | ndicapiExport int ndiSerialComm(NDIFileHandle serial_port, int baud, const char* mode, 206 | int handshake); 207 | 208 | /*! \ingroup NDISerial 209 | Change the timeout for the serial port in milliseconds. 210 | The default is 5 seconds, but this might be too long for certain 211 | applications. 212 | 213 | The return value will be 0 if the call was successful. 214 | A negative return value signals failure. 215 | */ 216 | ndicapiExport int ndiSerialTimeout(NDIFileHandle serial_port, int milliseconds); 217 | 218 | /*! \ingroup NDISerial 219 | Write a stream of 'n' characters from the string 'text' to the serial 220 | port. The number of characters actually written is returned. 221 | The NDICAPI expects all commands to end with a carriage return. 222 | 223 | The serial port input buffers are flushed before the information is 224 | written, because leftover bytes in the input buffer are likely due 225 | to an error on a previous communication. 226 | 227 | If the return value is negative, then an IO error occurred. 228 | If the return value is less than 'n', then a timeout error occurred. 229 | */ 230 | ndicapiExport int ndiSerialWrite(NDIFileHandle serial_port, const char* text, int n); 231 | 232 | /*! \ingroup NDISerial 233 | Read characters from the serial port until a carriage return is 234 | received. A maximum of 'n' characters will be read. The number 235 | of characters actually read is returned. The resulting string will 236 | not be null-terminated. 237 | 238 | If the return value is negative, then an IO error occurred. 239 | If the return value is zero, then a timeout error occurred. 240 | If the return value is equal to 'n' and the final character 241 | is not a carriage return (i.e. reply[n-1] != '\r'), then the 242 | read was incomplete and there are more characters waiting to 243 | be read. 244 | */ 245 | ndicapiExport int ndiSerialRead(NDIFileHandle serial_port, char* reply, int n, bool isBinary, int* errorCode); 246 | 247 | /*! \ingroup NDISerial 248 | Sleep for the specified number of milliseconds. The actual sleep time 249 | is likely to last for 10ms longer than the specifed time due to 250 | task scheduling overhead. The return value is always zero. 251 | */ 252 | ndicapiExport int ndiSerialSleep(NDIFileHandle serial_port, int milliseconds); 253 | 254 | #ifdef __cplusplus 255 | } 256 | #endif 257 | 258 | #endif -------------------------------------------------------------------------------- /ndicapi_serial_apple.cxx: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | 36 | // This file contains the platform-dependent portions of the source code 37 | // that talk to the serial port. All these methods 38 | // are of the form ndiSerialXX(). 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | //---------------------------------------------------------------------------- 56 | // Some static variables to keep track of which ports are open, so that 57 | // we can restore the comm parameters (baud rate etc) when they are closed. 58 | // Restoring the comm parameters is just part of being a good neighbor. 59 | 60 | #define NDI_MAX_SAVE_STATE 4 61 | static int ndi_open_handles[4] = { -1, -1, -1, -1 }; 62 | 63 | static struct termios ndi_save_termios[4]; 64 | 65 | //---------------------------------------------------------------------------- 66 | ndicapiExport int ndiSerialOpen(const char* device) 67 | { 68 | static struct flock fl = { F_WRLCK, 0, 0, 0 }; /* for file locking */ 69 | static struct flock fu = { F_UNLCK, 0, 0, 0 }; /* for file unlocking */ 70 | int serial_port; 71 | struct termios t; 72 | int i; 73 | 74 | /* port is readable/writable and is (for now) non-blocking */ 75 | serial_port = open(device, O_RDWR | O_NOCTTY | O_NDELAY); 76 | 77 | if (serial_port == -1) 78 | { 79 | return -1; /* bail out on error */ 80 | } 81 | 82 | /* restore blocking now that the port is open (we just didn't want */ 83 | /* the port to block while we were trying to open it) */ 84 | fcntl(serial_port, F_SETFL, 0); 85 | 86 | /* get I/O information */ 87 | if (tcgetattr(serial_port, &t) == -1) 88 | { 89 | fcntl(serial_port, F_SETLK, &fu); 90 | close(serial_port); 91 | return -1; 92 | } 93 | 94 | /* save the serial port state so that it can be restored when 95 | the serial port is closed in ndiSerialClose() */ 96 | for (i = 0; i < NDI_MAX_SAVE_STATE; i++) 97 | { 98 | if (ndi_open_handles[i] == serial_port || ndi_open_handles[i] == -1) 99 | { 100 | ndi_open_handles[i] = serial_port; 101 | tcgetattr(serial_port, &ndi_save_termios[i]); 102 | break; 103 | } 104 | } 105 | 106 | /* clear everything specific to terminals */ 107 | t.c_lflag = 0; 108 | t.c_iflag = 0; 109 | t.c_oflag = 0; 110 | 111 | t.c_cc[VMIN] = 0; /* use constant, not interval timeout */ 112 | t.c_cc[VTIME] = TIMEOUT_PERIOD / 100; /* wait for 5 secs max */ 113 | 114 | if (tcsetattr(serial_port, TCSANOW, &t) == -1) /* set I/O information */ 115 | { 116 | if (i < NDI_MAX_SAVE_STATE) /* if we saved the state, forget the state */ 117 | { 118 | ndi_open_handles[i] = -1; 119 | } 120 | fcntl(serial_port, F_SETLK, &fu); 121 | close(serial_port); 122 | return -1; 123 | } 124 | 125 | tcflush(serial_port, TCIOFLUSH); /* flush the buffers for good luck */ 126 | 127 | return serial_port; 128 | } 129 | 130 | //---------------------------------------------------------------------------- 131 | ndicapiExport void ndiSerialClose(int serial_port) 132 | { 133 | static struct flock fu = { F_UNLCK, 0, 0, 0 }; /* for file unlocking */ 134 | int i; 135 | 136 | /* restore the comm port state to from before it was opened */ 137 | for (i = 0; i < NDI_MAX_SAVE_STATE; i++) 138 | { 139 | if (ndi_open_handles[i] == serial_port && ndi_open_handles[i] != -1) 140 | { 141 | tcsetattr(serial_port, TCSANOW, &ndi_save_termios[i]); 142 | ndi_open_handles[i] = -1; 143 | break; 144 | } 145 | } 146 | 147 | /* release our lock on the serial port */ 148 | fcntl(serial_port, F_SETLK, &fu); 149 | 150 | close(serial_port); 151 | } 152 | 153 | //---------------------------------------------------------------------------- 154 | ndicapiExport int ndiSerialCheckDSR(int serial_port) 155 | { 156 | /* if called failed for any reason, return success for robustness */ 157 | return 1; 158 | } 159 | 160 | //---------------------------------------------------------------------------- 161 | ndicapiExport int ndiSerialBreak(int serial_port) 162 | { 163 | tcflush(serial_port, TCIOFLUSH); /* clear input/output buffers */ 164 | tcsendbreak(serial_port, 0); /* send the break */ 165 | 166 | return 0; 167 | } 168 | 169 | //---------------------------------------------------------------------------- 170 | ndicapiExport int ndiSerialFlush(int serial_port, int buffers) 171 | { 172 | int flushtype = TCIOFLUSH; 173 | 174 | if (buffers == NDI_IFLUSH) 175 | { 176 | flushtype = TCIFLUSH; 177 | } 178 | else if (buffers == NDI_OFLUSH) 179 | { 180 | flushtype = TCOFLUSH; 181 | } 182 | 183 | tcflush(serial_port, flushtype); /* clear input/output buffers */ 184 | 185 | return 0; 186 | } 187 | 188 | //---------------------------------------------------------------------------- 189 | ndicapiExport int ndiSerialComm(int serial_port, int baud, const char mode[4], int handshake) 190 | { 191 | struct termios t; 192 | int newbaud; 193 | 194 | switch (baud) 195 | { 196 | case 9600: 197 | newbaud = B9600; 198 | break; 199 | case 14400: 200 | return -1; 201 | case 19200: 202 | newbaud = B19200; 203 | break; 204 | case 38400: 205 | newbaud = B38400; 206 | break; 207 | case 57600: 208 | newbaud = B57600; 209 | break; 210 | case 115200: 211 | newbaud = B115200; 212 | break; 213 | case 230400: 214 | newbaud = B230400; 215 | break; 216 | default: 217 | return -1; 218 | } 219 | 220 | tcgetattr(serial_port, &t); /* get I/O information */ 221 | t.c_cflag &= ~CSIZE; /* clear flags */ 222 | 223 | cfsetispeed(&t, newbaud); 224 | cfsetospeed(&t, newbaud); 225 | 226 | if (mode[0] == '8') /* set data bits */ 227 | { 228 | t.c_cflag |= CS8; 229 | } 230 | else if (mode[0] == '7') 231 | { 232 | t.c_cflag |= CS7; 233 | } 234 | else 235 | { 236 | return -1; 237 | } 238 | 239 | if (mode[1] == 'N') /* set parity */ 240 | { 241 | t.c_cflag &= ~PARENB; 242 | t.c_cflag &= ~PARODD; 243 | } 244 | else if (mode[1] == 'O') 245 | { 246 | t.c_cflag |= PARENB; 247 | t.c_cflag |= PARODD; 248 | } 249 | else if (mode[1] == 'E') 250 | { 251 | t.c_cflag |= PARENB; 252 | t.c_cflag &= ~PARODD; 253 | } 254 | else 255 | { 256 | return -1; 257 | } 258 | 259 | if (mode[2] == '1') /* set stop bits */ 260 | { 261 | t.c_cflag &= ~CSTOPB; 262 | } 263 | else if (mode[2] == '2') 264 | { 265 | t.c_cflag |= CSTOPB; 266 | } 267 | else 268 | { 269 | return -1; 270 | } 271 | 272 | if (handshake) 273 | { 274 | t.c_cflag |= CRTSCTS; 275 | } 276 | else 277 | { 278 | t.c_cflag &= ~CRTSCTS; 279 | } 280 | 281 | return tcsetattr(serial_port, TCSADRAIN, &t); /* set I/O information */ 282 | } 283 | 284 | //---------------------------------------------------------------------------- 285 | ndicapiExport int ndiSerialTimeout(int serial_port, int milliseconds) 286 | { 287 | struct termios t; 288 | 289 | if (tcgetattr(serial_port, &t) == -1) 290 | { 291 | return -1; 292 | } 293 | 294 | t.c_cc[VMIN] = 0; /* use constant, not interval timeout */ 295 | t.c_cc[VTIME] = milliseconds / 100; /* wait time is in 10ths of a second */ 296 | 297 | if (tcsetattr(serial_port, TCSANOW, &t) == -1) 298 | { 299 | return -1; 300 | } 301 | 302 | return 0; 303 | } 304 | 305 | //---------------------------------------------------------------------------- 306 | ndicapiExport int ndiSerialWrite(int serial_port, const char* text, int n) 307 | { 308 | int i = 0; 309 | int m; 310 | 311 | while (n > 0) 312 | { 313 | if ((m = write(serial_port, &text[i], n)) == -1) 314 | { 315 | if (errno == EAGAIN) /* system canceled us, retry */ 316 | { 317 | m = 0; 318 | } 319 | else 320 | { 321 | return -1; /* IO error occurred */ 322 | } 323 | } 324 | 325 | n -= m; /* n is number of chars left to write */ 326 | i += m; /* i is the number of chars written */ 327 | } 328 | 329 | return i; /* return the number of characters written */ 330 | } 331 | 332 | //---------------------------------------------------------------------------- 333 | ndicapiExport int ndiSerialRead(int serial_port, char* reply, int numberOfBytesToRead, bool isBinary, int* errorCode) 334 | { 335 | int totalNumberOfBytesRead = 0; 336 | int totalNumberOfBytesToRead = numberOfBytesToRead; 337 | int numberOfBytesRead; 338 | bool binarySizeCalculated = false; 339 | 340 | do 341 | { 342 | if ((numberOfBytesRead = read(serial_port, &reply[totalNumberOfBytesRead], numberOfBytesToRead)) == -1) 343 | { 344 | if (errno == EAGAIN) /* canceled, so retry */ 345 | { 346 | numberOfBytesRead = 0; 347 | } 348 | else 349 | { 350 | return -1; /* IO error occurred */ 351 | } 352 | } 353 | else if (numberOfBytesRead == 0) /* no characters read, must have timed out */ 354 | { 355 | return 0; 356 | } 357 | 358 | totalNumberOfBytesRead += numberOfBytesRead; 359 | if ((!isBinary && reply[totalNumberOfBytesRead - 1] == '\r') /* done when carriage return received (ASCII) or when ERROR... received (binary)*/ 360 | || (isBinary && strncmp(reply, "ERROR", 5) == 0 && reply[totalNumberOfBytesRead - 1] == '\r')) 361 | { 362 | break; 363 | } 364 | 365 | if (isBinary && !binarySizeCalculated && reply[0] == (char)0xc4 && reply[1] == (char)0xa5) 366 | { 367 | // recalculate n based on the reply length (reported from ndi device) and the amount of data received so far 368 | unsigned short size = ((unsigned char)reply[2] | (unsigned char)reply[3] << 8) + 8; // 8 bytes -> 2 for Start Sequence (a5c4), 2 for reply length, 2 for header CRC, 2 for CRC16 369 | totalNumberOfBytesToRead = size; 370 | } 371 | } 372 | while (totalNumberOfBytesRead != totalNumberOfBytesToRead); 373 | 374 | return totalNumberOfBytesRead; 375 | } 376 | 377 | //---------------------------------------------------------------------------- 378 | ndicapiExport int ndiSerialSleep(int serial_port, int milliseconds) 379 | { 380 | #ifdef USE_NANOSLEEP 381 | struct timespec sleep_time, dummy; 382 | sleep_time.tv_sec = milliseconds / 1000; 383 | sleep_time.tv_nsec = (milliseconds - sleep_time.tv_sec * 1000) * 1000000; 384 | nanosleep(&sleep_time, &dummy); 385 | #else /* use usleep instead */ 386 | /* some unices like IRIX can't usleep for more than 1 second, 387 | so break usleep into 500 millisecond chunks */ 388 | while (milliseconds > 500) 389 | { 390 | usleep(500000); 391 | milliseconds -= 500; 392 | } 393 | usleep(milliseconds * 1000); 394 | #endif 395 | 396 | return 0; 397 | } -------------------------------------------------------------------------------- /ndicapi_serial_unix.cxx: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | 36 | // This file contains the platform-dependent portions of the source code 37 | // that talk to the serial port. All these methods 38 | // are of the form ndiSerialXX(). 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | //---------------------------------------------------------------------------- 56 | // Some static variables to keep track of which ports are open, so that 57 | // we can restore the comm parameters (baud rate etc) when they are closed. 58 | // Restoring the comm parameters is just part of being a good neighbor. 59 | 60 | #define NDI_MAX_SAVE_STATE 4 61 | static int ndi_open_handles[4] = { -1, -1, -1, -1 }; 62 | 63 | static struct termios ndi_save_termios[4]; 64 | 65 | //---------------------------------------------------------------------------- 66 | ndicapiExport int ndiSerialOpen(const char* device) 67 | { 68 | static struct flock fl = { F_WRLCK, 0, 0, 0 }; /* for file locking */ 69 | static struct flock fu = { F_UNLCK, 0, 0, 0 }; /* for file unlocking */ 70 | int serial_port; 71 | struct termios t; 72 | int i; 73 | 74 | /* port is readable/writable and is (for now) non-blocking */ 75 | serial_port = open(device, O_RDWR | O_NOCTTY | O_NDELAY); 76 | 77 | if (serial_port == -1) 78 | { 79 | return -1; /* bail out on error */ 80 | } 81 | 82 | /* restore blocking now that the port is open (we just didn't want */ 83 | /* the port to block while we were trying to open it) */ 84 | fcntl(serial_port, F_SETFL, 0); 85 | 86 | /* get exclusive lock on the serial port */ 87 | /* on many unices, this has no effect for device files */ 88 | if (fcntl(serial_port, F_SETLK, &fl)) 89 | { 90 | close(serial_port); 91 | return -1; 92 | } 93 | 94 | /* get I/O information */ 95 | if (tcgetattr(serial_port, &t) == -1) 96 | { 97 | fcntl(serial_port, F_SETLK, &fu); 98 | close(serial_port); 99 | return -1; 100 | } 101 | 102 | /* save the serial port state so that it can be restored when 103 | the serial port is closed in ndiSerialClose() */ 104 | for (i = 0; i < NDI_MAX_SAVE_STATE; i++) 105 | { 106 | if (ndi_open_handles[i] == serial_port || ndi_open_handles[i] == -1) 107 | { 108 | ndi_open_handles[i] = serial_port; 109 | tcgetattr(serial_port, &ndi_save_termios[i]); 110 | break; 111 | } 112 | } 113 | 114 | /* clear everything specific to terminals */ 115 | t.c_lflag = 0; 116 | t.c_iflag = 0; 117 | t.c_oflag = 0; 118 | 119 | t.c_cc[VMIN] = 0; /* use constant, not interval timeout */ 120 | t.c_cc[VTIME] = TIMEOUT_PERIOD / 100; /* wait for 5 secs max */ 121 | 122 | if (tcsetattr(serial_port, TCSANOW, &t) == -1) /* set I/O information */ 123 | { 124 | if (i < NDI_MAX_SAVE_STATE) /* if we saved the state, forget the state */ 125 | { 126 | ndi_open_handles[i] = -1; 127 | } 128 | fcntl(serial_port, F_SETLK, &fu); 129 | close(serial_port); 130 | return -1; 131 | } 132 | 133 | tcflush(serial_port, TCIOFLUSH); /* flush the buffers for good luck */ 134 | 135 | return serial_port; 136 | } 137 | 138 | //---------------------------------------------------------------------------- 139 | ndicapiExport void ndiSerialClose(int serial_port) 140 | { 141 | static struct flock fu = { F_UNLCK, 0, 0, 0 }; /* for file unlocking */ 142 | int i; 143 | 144 | /* restore the comm port state to from before it was opened */ 145 | for (i = 0; i < NDI_MAX_SAVE_STATE; i++) 146 | { 147 | if (ndi_open_handles[i] == serial_port && ndi_open_handles[i] != -1) 148 | { 149 | tcsetattr(serial_port, TCSANOW, &ndi_save_termios[i]); 150 | ndi_open_handles[i] = -1; 151 | break; 152 | } 153 | } 154 | 155 | /* release our lock on the serial port */ 156 | fcntl(serial_port, F_SETLK, &fu); 157 | 158 | close(serial_port); 159 | } 160 | 161 | //---------------------------------------------------------------------------- 162 | ndicapiExport int ndiSerialCheckDSR(int serial_port) 163 | { 164 | #if defined(linux) || defined(__linux__) 165 | int bits; 166 | /* get the bits to see if DSR is set (i.e. if device is connected) */ 167 | if (ioctl(serial_port, TIOCMGET, &bits) >= 0) 168 | { 169 | return ((bits & TIOCM_DSR) != 0); 170 | } 171 | #endif 172 | /* if called failed for any reason, return success for robustness */ 173 | return 1; 174 | } 175 | 176 | //---------------------------------------------------------------------------- 177 | ndicapiExport int ndiSerialBreak(int serial_port) 178 | { 179 | tcflush(serial_port, TCIOFLUSH); /* clear input/output buffers */ 180 | tcsendbreak(serial_port, 0); /* send the break */ 181 | 182 | return 0; 183 | } 184 | 185 | //---------------------------------------------------------------------------- 186 | ndicapiExport int ndiSerialFlush(int serial_port, int buffers) 187 | { 188 | int flushtype = TCIOFLUSH; 189 | 190 | if (buffers == NDI_IFLUSH) 191 | { 192 | flushtype = TCIFLUSH; 193 | } 194 | else if (buffers == NDI_OFLUSH) 195 | { 196 | flushtype = TCOFLUSH; 197 | } 198 | 199 | tcflush(serial_port, flushtype); /* clear input/output buffers */ 200 | 201 | return 0; 202 | } 203 | 204 | //---------------------------------------------------------------------------- 205 | ndicapiExport int ndiSerialComm(int serial_port, int baud, const char mode[4], int handshake) 206 | { 207 | struct termios t; 208 | int newbaud; 209 | 210 | #if defined(linux) || defined(__linux__) 211 | switch (baud) 212 | { 213 | case 9600: 214 | newbaud = B9600; 215 | break; 216 | case 14400: 217 | return -1; 218 | case 19200: 219 | newbaud = B19200; 220 | break; 221 | case 38400: 222 | newbaud = B38400; 223 | break; 224 | case 57600: 225 | newbaud = B57600; 226 | break; 227 | case 115200: 228 | newbaud = B115200; 229 | break; 230 | case 230400: 231 | newbaud = B230400; 232 | break; 233 | default: 234 | return -1; 235 | } 236 | #elif defined(sgi) && defined(__NEW_MAX_BAUD) 237 | switch (baud) 238 | { 239 | case 9600: 240 | newbaud = 9600; 241 | break; 242 | case 14400: 243 | return -1; 244 | case 19200: 245 | newbaud = 19200; 246 | break; 247 | case 38400: 248 | newbaud = 38400; 249 | break; 250 | case 57600: 251 | newbaud = 57600; 252 | break; 253 | case 115200: 254 | newbaud = 115200; 255 | break; 256 | default: 257 | return -1; 258 | } 259 | #else 260 | switch (baud) 261 | { 262 | case 9600: 263 | newbaud = B9600; 264 | break; 265 | case 14400: 266 | return -1; 267 | case 19200: 268 | newbaud = B19200; 269 | break; 270 | case 38400: 271 | newbaud = B38400; 272 | break; 273 | case 57600: 274 | return -1; 275 | case 115200: 276 | return -1; 277 | default: 278 | return -1; 279 | } 280 | #endif 281 | 282 | tcgetattr(serial_port, &t); /* get I/O information */ 283 | t.c_cflag &= ~CSIZE; /* clear flags */ 284 | 285 | #if defined(linux) || defined(__linux__) 286 | t.c_cflag &= ~CBAUD; 287 | t.c_cflag |= newbaud; /* set baud rate */ 288 | #elif defined(sgi) && defined(__NEW_MAX_BAUD) 289 | t.c_ospeed = newbaud; 290 | #else 291 | t.c_cflag &= ~CBAUD; 292 | t.c_cflag |= newbaud; /* set baud rate */ 293 | #endif 294 | 295 | if (mode[0] == '8') /* set data bits */ 296 | { 297 | t.c_cflag |= CS8; 298 | } 299 | else if (mode[0] == '7') 300 | { 301 | t.c_cflag |= CS7; 302 | } 303 | else 304 | { 305 | return -1; 306 | } 307 | 308 | if (mode[1] == 'N') /* set parity */ 309 | { 310 | t.c_cflag &= ~PARENB; 311 | t.c_cflag &= ~PARODD; 312 | } 313 | else if (mode[1] == 'O') 314 | { 315 | t.c_cflag |= PARENB; 316 | t.c_cflag |= PARODD; 317 | } 318 | else if (mode[1] == 'E') 319 | { 320 | t.c_cflag |= PARENB; 321 | t.c_cflag &= ~PARODD; 322 | } 323 | else 324 | { 325 | return -1; 326 | } 327 | 328 | if (mode[2] == '1') /* set stop bits */ 329 | { 330 | t.c_cflag &= ~CSTOPB; 331 | } 332 | else if (mode[2] == '2') 333 | { 334 | t.c_cflag |= CSTOPB; 335 | } 336 | else 337 | { 338 | return -1; 339 | } 340 | 341 | if (handshake) 342 | { 343 | #ifdef sgi 344 | t.c_cflag |= CNEW_RTSCTS; /* enable hardware handshake */ 345 | #else 346 | t.c_cflag |= CRTSCTS; 347 | #endif 348 | } 349 | else 350 | { 351 | #ifdef sgi 352 | t.c_cflag &= ~CNEW_RTSCTS; /* turn off hardware handshake */ 353 | #else 354 | t.c_cflag &= ~CRTSCTS; 355 | #endif 356 | } 357 | 358 | return tcsetattr(serial_port, TCSADRAIN, &t); /* set I/O information */ 359 | } 360 | 361 | //---------------------------------------------------------------------------- 362 | ndicapiExport int ndiSerialTimeout(int serial_port, int milliseconds) 363 | { 364 | struct termios t; 365 | 366 | if (tcgetattr(serial_port, &t) == -1) 367 | { 368 | return -1; 369 | } 370 | 371 | t.c_cc[VMIN] = 0; /* use constant, not interval timout */ 372 | t.c_cc[VTIME] = milliseconds / 100; /* wait time is in 10ths of a second */ 373 | 374 | if (tcsetattr(serial_port, TCSANOW, &t) == -1) 375 | { 376 | return -1; 377 | } 378 | 379 | return 0; 380 | } 381 | 382 | //---------------------------------------------------------------------------- 383 | ndicapiExport int ndiSerialWrite(int serial_port, const char* text, int n) 384 | { 385 | int i = 0; 386 | int m; 387 | 388 | while (n > 0) 389 | { 390 | if ((m = write(serial_port, &text[i], n)) == -1) 391 | { 392 | if (errno == EAGAIN) /* system canceled us, retry */ 393 | { 394 | m = 0; 395 | } 396 | else 397 | { 398 | return -1; /* IO error occurred */ 399 | } 400 | } 401 | 402 | n -= m; /* n is number of chars left to write */ 403 | i += m; /* i is the number of chars written */ 404 | } 405 | 406 | return i; /* return the number of characters written */ 407 | } 408 | 409 | //---------------------------------------------------------------------------- 410 | ndicapiExport int ndiSerialRead(int serial_port, char* reply, int numberOfBytesToRead, bool isBinary, int* errorCode) 411 | { 412 | int totalNumberOfBytesRead = 0; 413 | int totalNumberOfBytesToRead = numberOfBytesToRead; 414 | int numberOfBytesRead; 415 | bool binarySizeCalculated = false; 416 | 417 | do 418 | { 419 | if ((numberOfBytesRead = read(serial_port, &reply[totalNumberOfBytesRead], numberOfBytesToRead)) == -1) 420 | { 421 | if (errno == EAGAIN) /* canceled, so retry */ 422 | { 423 | numberOfBytesRead = 0; 424 | } 425 | else 426 | { 427 | return -1; /* IO error occurred */ 428 | } 429 | } 430 | else if (numberOfBytesRead == 0) /* no characters read, must have timed out */ 431 | { 432 | return 0; 433 | } 434 | 435 | totalNumberOfBytesRead += numberOfBytesRead; 436 | if ((!isBinary && reply[totalNumberOfBytesRead - 1] == '\r') /* done when carriage return received (ASCII) or when ERROR... received (binary)*/ 437 | || (isBinary && strncmp(reply, "ERROR", 5) == 0 && reply[totalNumberOfBytesRead - 1] == '\r')) 438 | { 439 | break; 440 | } 441 | 442 | if (isBinary && !binarySizeCalculated && reply[0] == (char)0xc4 && reply[1] == (char)0xa5) 443 | { 444 | // recalculate n based on the reply length (reported from ndi device) and the amount of data received so far 445 | unsigned short size = ((unsigned char)reply[2] | (unsigned char)reply[3] << 8) + 8; // 8 bytes -> 2 for Start Sequence (a5c4), 2 for reply length, 2 for header CRC, 2 for CRC16 446 | totalNumberOfBytesToRead = size; 447 | } 448 | } 449 | while (totalNumberOfBytesRead != totalNumberOfBytesToRead); 450 | 451 | return totalNumberOfBytesRead; 452 | } 453 | 454 | //---------------------------------------------------------------------------- 455 | ndicapiExport int ndiSerialSleep(int serial_port, int milliseconds) 456 | { 457 | #ifdef USE_NANOSLEEP 458 | struct timespec sleep_time, dummy; 459 | sleep_time.tv_sec = milliseconds / 1000; 460 | sleep_time.tv_nsec = (milliseconds - sleep_time.tv_sec * 1000) * 1000000; 461 | nanosleep(&sleep_time, &dummy); 462 | #else /* use usleep instead */ 463 | /* some unices like IRIX can't usleep for more than 1 second, 464 | so break usleep into 500 millisecond chunks */ 465 | while (milliseconds > 500) 466 | { 467 | usleep(500000); 468 | milliseconds -= 500; 469 | } 470 | usleep(milliseconds * 1000); 471 | #endif 472 | 473 | return 0; 474 | } 475 | -------------------------------------------------------------------------------- /ndicapi_serial_win32.cxx: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | 36 | // This file contains the Windows portions of the source code 37 | // that talk to the serial port. All these methods 38 | // are of the form ndiSerialXX(). 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | // USB versions of NDI tracking can communicate at baud rate 921600 but is not defined in WinBase.h 45 | #ifndef CBR_921600 46 | #define CBR_921600 921600 47 | #endif 48 | 49 | #include "ndicapi.h" 50 | 51 | //---------------------------------------------------------------------------- 52 | // Some static variables to keep track of which ports are open, so that 53 | // we can restore the comm parameters (baud rate etc) when they are closed. 54 | // Restoring the comm parameters is just part of being a good neighbor. 55 | 56 | #define NDI_MAX_SAVE_STATE 4 57 | static HANDLE ndi_open_handles[4] = { INVALID_HANDLE_VALUE, 58 | INVALID_HANDLE_VALUE, 59 | INVALID_HANDLE_VALUE, 60 | INVALID_HANDLE_VALUE 61 | }; 62 | 63 | static COMMTIMEOUTS ndi_save_timeouts[4]; 64 | static DCB ndi_save_dcb[4]; 65 | 66 | //---------------------------------------------------------------------------- 67 | ndicapiExport HANDLE ndiSerialOpen(const char* device) 68 | { 69 | static COMMTIMEOUTS default_ctmo = { MAXDWORD, MAXDWORD, 70 | TIMEOUT_PERIOD, 71 | 2, 72 | TIMEOUT_PERIOD 73 | }; 74 | HANDLE serial_port; 75 | DCB comm_settings; 76 | int i; 77 | 78 | serial_port = CreateFile(device, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 79 | 80 | if (serial_port == INVALID_HANDLE_VALUE) 81 | { 82 | return INVALID_HANDLE_VALUE; 83 | } 84 | 85 | // Save the serial port state so that it can be restored when 86 | // the serial port is closed in ndiSerialClose() 87 | for (i = 0; i < NDI_MAX_SAVE_STATE; i++) 88 | { 89 | if (ndi_open_handles[i] == serial_port || ndi_open_handles[i] == INVALID_HANDLE_VALUE) 90 | { 91 | ndi_open_handles[i] = serial_port; 92 | GetCommTimeouts(serial_port, &ndi_save_timeouts[i]); 93 | GetCommState(serial_port, &ndi_save_dcb[i]); 94 | break; 95 | } 96 | } 97 | 98 | if (SetupComm(serial_port, 1600, 1600) == FALSE) /* set buffer size */ 99 | { 100 | if (i < NDI_MAX_SAVE_STATE) /* if we saved the state, forget the state */ 101 | { 102 | ndi_open_handles[i] = INVALID_HANDLE_VALUE; 103 | } 104 | CloseHandle(serial_port); 105 | return INVALID_HANDLE_VALUE; 106 | } 107 | 108 | if (GetCommState(serial_port, &comm_settings) == FALSE) 109 | { 110 | if (i < NDI_MAX_SAVE_STATE) /* if we saved the state, forget the state */ 111 | { 112 | ndi_open_handles[i] = INVALID_HANDLE_VALUE; 113 | } 114 | CloseHandle(serial_port); 115 | return INVALID_HANDLE_VALUE; 116 | } 117 | 118 | comm_settings.fOutX = FALSE; /* no S/W handshake */ 119 | comm_settings.fInX = FALSE; 120 | comm_settings.fAbortOnError = FALSE; /* don't need to clear errors */ 121 | comm_settings.fOutxDsrFlow = FALSE; /* no modem-style flow stuff*/ 122 | comm_settings.fDtrControl = DTR_CONTROL_ENABLE; 123 | 124 | if (SetCommState(serial_port, &comm_settings) == FALSE) 125 | { 126 | if (i < NDI_MAX_SAVE_STATE) /* if we saved the state, forget the state */ 127 | { 128 | ndi_open_handles[i] = INVALID_HANDLE_VALUE; 129 | } 130 | CloseHandle(serial_port); 131 | return INVALID_HANDLE_VALUE; 132 | } 133 | 134 | if (SetCommTimeouts(serial_port, &default_ctmo) == FALSE) 135 | { 136 | SetCommState(serial_port, &comm_settings); 137 | if (i < NDI_MAX_SAVE_STATE) /* if we saved the state, forget the state */ 138 | { 139 | SetCommState(serial_port, &ndi_save_dcb[i]); 140 | ndi_open_handles[i] = INVALID_HANDLE_VALUE; 141 | } 142 | CloseHandle(serial_port); 143 | return INVALID_HANDLE_VALUE; 144 | } 145 | 146 | return serial_port; 147 | } 148 | 149 | //---------------------------------------------------------------------------- 150 | ndicapiExport void ndiSerialClose(HANDLE serial_port) 151 | { 152 | int i; 153 | 154 | /* restore the comm port state to from before it was opened */ 155 | for (i = 0; i < NDI_MAX_SAVE_STATE; i++) 156 | { 157 | if (ndi_open_handles[i] == serial_port && 158 | ndi_open_handles[i] != INVALID_HANDLE_VALUE) 159 | { 160 | SetCommTimeouts(serial_port, &ndi_save_timeouts[i]); 161 | SetCommState(serial_port, &ndi_save_dcb[i]); 162 | ndi_open_handles[i] = INVALID_HANDLE_VALUE; 163 | break; 164 | } 165 | } 166 | 167 | CloseHandle(serial_port); 168 | } 169 | 170 | //---------------------------------------------------------------------------- 171 | ndicapiExport int ndiSerialCheckDSR(HANDLE serial_port) 172 | { 173 | DWORD bits; 174 | /* get the bits to see if DSR is set (i.e. if device is connected) */ 175 | GetCommModemStatus(serial_port, &bits); 176 | return ((bits & MS_DSR_ON) != 0); 177 | } 178 | 179 | //---------------------------------------------------------------------------- 180 | ndicapiExport int ndiSerialBreak(HANDLE serial_port) 181 | { 182 | DWORD dumb; 183 | 184 | ClearCommError(serial_port, &dumb, NULL); /* clear error */ 185 | PurgeComm(serial_port, PURGE_TXCLEAR | PURGE_RXCLEAR); /* clear buffers */ 186 | 187 | SetCommBreak(serial_port); 188 | Sleep(300); /* hold break for 0.3 seconds */ 189 | ClearCommBreak(serial_port); 190 | 191 | return 0; 192 | } 193 | 194 | //---------------------------------------------------------------------------- 195 | ndicapiExport int ndiSerialFlush(HANDLE serial_port, int buffers) 196 | { 197 | DWORD dumb; 198 | DWORD flushtype = PURGE_TXCLEAR | PURGE_RXCLEAR; 199 | 200 | if (buffers == NDI_IFLUSH) 201 | { 202 | flushtype = PURGE_RXCLEAR; 203 | } 204 | else if (buffers == NDI_OFLUSH) 205 | { 206 | flushtype = PURGE_TXCLEAR; 207 | } 208 | 209 | ClearCommError(serial_port, &dumb, NULL); /* clear error */ 210 | PurgeComm(serial_port, flushtype); /* clear buffers */ 211 | 212 | return 0; 213 | } 214 | 215 | //---------------------------------------------------------------------------- 216 | ndicapiExport int ndiSerialComm(HANDLE serial_port, int baud, const char* mode, 217 | int handshake) 218 | { 219 | DCB comm_settings; 220 | int newbaud; 221 | switch (baud) 222 | { 223 | case 9600: 224 | newbaud = CBR_9600; 225 | break; 226 | case 14400: 227 | newbaud = CBR_14400; 228 | break; 229 | case 19200: 230 | newbaud = CBR_19200; 231 | break; 232 | case 38400: 233 | newbaud = CBR_38400; 234 | break; 235 | case 57600: 236 | newbaud = CBR_57600; 237 | break; 238 | case 115200: 239 | newbaud = CBR_115200; 240 | break; 241 | case 921600: 242 | newbaud = CBR_921600; 243 | break; 244 | case 1228739: 245 | newbaud = CBR_19200; //19.2k is aliased to 1.2Mbit in the Window's version of the NDI USB virtual com port driver 246 | break; 247 | case 230400: 248 | newbaud = 230400; 249 | break; 250 | default: 251 | return -1; 252 | } 253 | 254 | GetCommState(serial_port, &comm_settings); 255 | 256 | comm_settings.BaudRate = newbaud; /* speed */ 257 | 258 | if (handshake) /* set handshaking */ 259 | { 260 | comm_settings.fOutxCtsFlow = TRUE; /* on */ 261 | comm_settings.fRtsControl = RTS_CONTROL_HANDSHAKE; 262 | } 263 | else 264 | { 265 | comm_settings.fOutxCtsFlow = FALSE; /* off */ 266 | comm_settings.fRtsControl = RTS_CONTROL_DISABLE; 267 | } 268 | 269 | if (mode[0] == '8') /* data bits */ 270 | { 271 | comm_settings.ByteSize = 8; 272 | } 273 | else if (mode[0] == '7') 274 | { 275 | comm_settings.ByteSize = 7; 276 | } 277 | else 278 | { 279 | return -1; 280 | } 281 | 282 | if (mode[1] == 'N') /* set parity */ 283 | { 284 | comm_settings.Parity = NOPARITY; 285 | } 286 | else if (mode[1] == 'O') 287 | { 288 | comm_settings.Parity = ODDPARITY; 289 | } 290 | else if (mode[1] == 'E') 291 | { 292 | comm_settings.Parity = EVENPARITY; 293 | } 294 | else 295 | { 296 | return -1; 297 | } 298 | 299 | if (mode[2] == '1') /* set stop bits */ 300 | { 301 | comm_settings.StopBits = ONESTOPBIT; 302 | } 303 | else if (mode[2] == '2') 304 | { 305 | comm_settings.StopBits = TWOSTOPBITS; 306 | } 307 | else 308 | { 309 | return -1; 310 | } 311 | 312 | int result = SetCommState(serial_port, &comm_settings); 313 | 314 | return result > 0 ? 0 : -1; 315 | } 316 | 317 | //---------------------------------------------------------------------------- 318 | ndicapiExport int ndiSerialTimeout(HANDLE serial_port, int milliseconds) 319 | { 320 | COMMTIMEOUTS ctmo; 321 | 322 | if (GetCommTimeouts(serial_port, &ctmo) == FALSE) 323 | { 324 | return -1; 325 | } 326 | 327 | ctmo.ReadIntervalTimeout = MAXDWORD; 328 | ctmo.ReadTotalTimeoutMultiplier = MAXDWORD; 329 | ctmo.ReadTotalTimeoutConstant = milliseconds; 330 | ctmo.WriteTotalTimeoutConstant = milliseconds; 331 | 332 | if (SetCommTimeouts(serial_port, &ctmo) == FALSE) 333 | { 334 | return -1; 335 | } 336 | 337 | return 0; 338 | } 339 | 340 | //---------------------------------------------------------------------------- 341 | ndicapiExport int ndiSerialWrite(HANDLE serial_port, const char* text, int n) 342 | { 343 | DWORD m, dumb; 344 | int i = 0; 345 | 346 | while (n > 0) 347 | { 348 | if (WriteFile(serial_port, &text[i], n, &m, NULL) == FALSE) 349 | { 350 | if (GetLastError() == ERROR_OPERATION_ABORTED) /* system canceled us */ 351 | { 352 | ClearCommError(serial_port, &dumb, NULL); /* so clear error and retry */ 353 | } 354 | else 355 | { 356 | return -1; /* IO error occurred */ 357 | } 358 | } 359 | else if (m == 0) /* no characters written, must have timed out */ 360 | { 361 | return i; 362 | } 363 | 364 | n -= m; /* n is number of chars left to write */ 365 | i += m; /* i is the number of chars written */ 366 | } 367 | 368 | return i; /* return the number of characters written */ 369 | } 370 | 371 | //---------------------------------------------------------------------------- 372 | ndicapiExport int ndiSerialRead(HANDLE serial_port, char* reply, int numberOfBytesToRead, bool isBinary, int* errorCode) 373 | { 374 | int totalNumberOfBytesRead = 0; 375 | int totalNumberOfBytesToRead = numberOfBytesToRead; 376 | DWORD numberOfBytesRead; 377 | bool binarySizeCalculated = false; 378 | 379 | do 380 | { 381 | if (ReadFile(serial_port, &reply[totalNumberOfBytesRead], numberOfBytesToRead, &numberOfBytesRead, NULL) == FALSE) 382 | { 383 | if (GetLastError() == ERROR_OPERATION_ABORTED) /* canceled */ 384 | { 385 | DWORD dummyVariable; 386 | ClearCommError(serial_port, &dummyVariable, NULL); /* so clear error and retry */ 387 | } 388 | else 389 | { 390 | return -1; /* IO error occurred */ 391 | } 392 | } 393 | else if (numberOfBytesRead == 0) /* no characters read, must have timed out */ 394 | { 395 | return 0; 396 | } 397 | 398 | totalNumberOfBytesRead += numberOfBytesRead; 399 | if (!isBinary && reply[totalNumberOfBytesRead - 1] == '\r' /* done when carriage return received (ASCII) or when ERROR... received (binary)*/ 400 | || isBinary && strncmp(reply, "ERROR", 5) == 0 && reply[totalNumberOfBytesRead - 1] == '\r') 401 | { 402 | if (strncmp(reply, "ERROR", 5) == 0) 403 | { 404 | unsigned long err = ndiHexToUnsignedLong(&reply[5], 2); 405 | if (errorCode != NULL) 406 | { 407 | *errorCode = static_cast(err); 408 | } 409 | } 410 | break; 411 | } 412 | 413 | if (isBinary && !binarySizeCalculated && reply[0] == (char)0xc4 && reply[1] == (char)0xa5) 414 | { 415 | // recalculate n based on the reply length (reported from ndi device) and the amount of data received so far 416 | unsigned short size = ((unsigned char)reply[2] | (unsigned char)reply[3] << 8) + 8; // 8 bytes -> 2 for Start Sequence (a5c4), 2 for reply length, 2 for header CRC, 2 for CRC16 417 | totalNumberOfBytesToRead = size; 418 | } 419 | } 420 | while (totalNumberOfBytesRead != totalNumberOfBytesToRead); 421 | 422 | return totalNumberOfBytesRead; 423 | } 424 | 425 | //---------------------------------------------------------------------------- 426 | ndicapiExport int ndiSerialSleep(HANDLE serial_port, int milliseconds) 427 | { 428 | Sleep(milliseconds); 429 | 430 | return 0; 431 | } -------------------------------------------------------------------------------- /ndicapi_socket.cxx: -------------------------------------------------------------------------------- 1 | /*=Plus=header=begin====================================================== 2 | Program: Plus 3 | Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved. 4 | See License.md for details. 5 | =========================================================Plus=header=end*/ 6 | 7 | // This file contains the platform-dependent portions of the source code 8 | // that talk to the socket. All these methods 9 | // are of the form ndiSocketXX(). 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "ndicapi_socket.h" 19 | 20 | // time out period in milliseconds 21 | #define TIMEOUT_PERIOD_MS 500 22 | 23 | #ifdef _WIN32 24 | #include "ndicapi_socket_win32.cxx" 25 | #elif defined(unix) || defined(__unix__) || defined(__linux__) 26 | #include "ndicapi_socket_unix.cxx" 27 | #elif defined(__APPLE__) 28 | #include "ndicapi_socket_apple.cxx" 29 | #endif -------------------------------------------------------------------------------- /ndicapi_socket.h: -------------------------------------------------------------------------------- 1 | /*=Plus=header=begin====================================================== 2 | Program: Plus 3 | Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved. 4 | See License.md for details. 5 | =========================================================Plus=header=end*/ 6 | 7 | /*! \file ndicapi_socket.h 8 | This file contains the platform-dependent portions of the 9 | NDICAPI C API that talk to the serial port. 10 | */ 11 | 12 | #ifndef NDICAPI_SOCKET_H 13 | #define NDICAPI_SOCKET_H 14 | 15 | #include "ndicapiExport.h" 16 | 17 | /*=====================================================================*/ 18 | /*! \defgroup NDISocket NDI Socket Methods 19 | These are low-level methods that provide a platform-independent 20 | interface to the network. 21 | */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /*! \ingroup NDISocket 28 | \typedef NDISocketHandle 29 | The socket handle is a platform-specific type, for which we use the typedef NDISocketHandle. 30 | */ 31 | #ifdef _WIN32 32 | #include 33 | typedef SOCKET NDISocketHandle; 34 | #define NDI_INVALID_SOCKET INVALID_SOCKET 35 | #elif defined(unix) || defined(__unix__) || defined(__APPLE__) 36 | typedef int NDISocketHandle; 37 | #define NDI_INVALID_HANDLE -1 38 | #elif defined(macintosh) 39 | typedef long NDISocketHandle; 40 | #define NDI_INVALID_HANDLE -1 41 | #endif 42 | 43 | /*! \ingroup NDISocket 44 | Open the specified socket. 45 | A return value of false means that an error occurred. 46 | 47 | /return Connected or not 48 | /param hostname URL to connect to 49 | /param port Port to connect to 50 | /param outSocket variable to store the created socket 51 | */ 52 | ndicapiExport bool ndiSocketOpen(const char* hostname, int port, NDISocketHandle& outSocket); 53 | 54 | /*! \ingroup NDISocket 55 | Close the socket. 56 | */ 57 | ndicapiExport void ndiSocketClose(NDISocketHandle socket); 58 | 59 | /*! \ingroup NDISocket 60 | Flush out the serial I/O buffers. The following options are available: 61 | - NDI_IFLUSH: discard the contents of the input buffer 62 | - NDI_OFLUSH: discard the contents of the output buffer 63 | - NDI_IOFLUSH: discard the contents of both buffers. 64 | 65 |

The return value of this function will be if the call was successful. 66 | */ 67 | ndicapiExport bool ndiSocketFlush(NDISocketHandle socket, int flushtype); 68 | 69 | #define NDI_IFLUSH 0x1 70 | #define NDI_OFLUSH 0x2 71 | #define NDI_IOFLUSH 0x3 72 | 73 | /*! \ingroup NDISocket 74 | Change the timeout for the socket in milliseconds. 75 | The default is 0.5 seconds, but this might be too long for certain applications. 76 | 77 | The return value will be true if the call was successful. 78 | */ 79 | ndicapiExport bool ndiSocketTimeout(NDISocketHandle socket, int milliseconds); 80 | 81 | /*! \ingroup NDISocket 82 | Write a stream of 'n' characters from the string 'text' to the socket. 83 | The number of characters actually written is returned. 84 | 85 | If the return value is negative, then an IO error occurred. 86 | If the return value is less than 'n', then a timeout error occurred. 87 | */ 88 | ndicapiExport int ndiSocketWrite(NDISocketHandle socket, const char* text, int n); 89 | 90 | /*! \ingroup NDISocket 91 | Read characters from the serial port until a carriage return is 92 | received. A maximum of 'n' characters will be read. The number 93 | of characters actually read is returned. The resulting string will 94 | not be null-terminated. 95 | 96 | If the return value is negative, then an IO error occurred. 97 | If the return value is zero, then a timeout error occurred. 98 | If the return value is equal to 'n' and the final character 99 | is not a carriage return (i.e. reply[n-1] != '\r'), then the 100 | read was incomplete and there are more characters waiting to 101 | be read. 102 | */ 103 | ndicapiExport int ndiSocketRead(NDISocketHandle socket, char* reply, int numberOfBytesToRead, bool isBinary, int* outErrorCode); 104 | 105 | /*! \ingroup NDISocket 106 | Sleep the socket 107 | */ 108 | ndicapiExport bool ndiSocketSleep(NDISocketHandle socket, int milliseconds); 109 | 110 | #ifdef __cplusplus 111 | } 112 | #endif 113 | 114 | #endif -------------------------------------------------------------------------------- /ndicapi_socket_apple.cxx: -------------------------------------------------------------------------------- 1 | /*=Plus=header=begin====================================================== 2 | Program: Plus 3 | Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved. 4 | See License.md for details. 5 | =========================================================Plus=header=end*/ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //---------------------------------------------------------------------------- 17 | ndicapiExport bool ndiSocketOpen(const char* hostname, int port, NDISocketHandle& outSocket) 18 | { 19 | NDISocketHandle sock = socket(AF_INET, SOCK_STREAM, 0); 20 | 21 | // Eliminate windows 0.2 second delay sending (buffering) data. 22 | int on = 1; 23 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on))) 24 | { 25 | return false; 26 | } 27 | 28 | struct hostent* hp; 29 | hp = gethostbyname(hostname); 30 | if (!hp) 31 | { 32 | unsigned long addr = inet_addr(hostname); 33 | hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET); 34 | } 35 | 36 | if (!hp) 37 | { 38 | return false; 39 | } 40 | 41 | struct sockaddr_in name; 42 | name.sin_family = AF_INET; 43 | memcpy(&name.sin_addr, hp->h_addr, hp->h_length); 44 | name.sin_port = htons(port); 45 | 46 | int r = connect(sock, reinterpret_cast(&name), sizeof(name)); 47 | 48 | if (r < 0) 49 | { 50 | shutdown(sock, 2); 51 | close(sock); 52 | return false; 53 | } 54 | 55 | outSocket = sock; 56 | return true; 57 | } 58 | 59 | //---------------------------------------------------------------------------- 60 | ndicapiExport void ndiSocketClose(NDISocketHandle socket) 61 | { 62 | shutdown(socket, 2); 63 | close(socket); 64 | } 65 | 66 | //---------------------------------------------------------------------------- 67 | ndicapiExport bool ndiSocketFlush(NDISocketHandle socket, int flushtype) 68 | { 69 | return true; 70 | } 71 | 72 | //---------------------------------------------------------------------------- 73 | ndicapiExport bool ndiSocketTimeout(NDISocketHandle socket, int timeoutMs) 74 | { 75 | if (timeoutMs > 0) 76 | { 77 | setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*) & (timeoutMs), sizeof(timeoutMs)); 78 | return true; 79 | } 80 | return false; 81 | } 82 | 83 | //---------------------------------------------------------------------------- 84 | ndicapiExport int ndiSocketWrite(NDISocketHandle socket, const char* data, int length) 85 | { 86 | if (length == 0) 87 | { 88 | // nothing to send. 89 | return 0; 90 | } 91 | 92 | const char* buffer = reinterpret_cast(data); 93 | int total = 0; 94 | do 95 | { 96 | int flags; 97 | 98 | // On unix boxes if the client disconnects and the server attempts 99 | // to send data through the socket then the application crashes 100 | // due to SIGPIPE signal. Disable the signal to prevent crash. 101 | #if defined(MSG_NOSIGNAL) 102 | flags = MSG_NOSIGNAL; 103 | #else 104 | #if defined(SO_NOSIGPIPE) // Mac OS X 105 | int set = 1; 106 | setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); 107 | #endif 108 | flags = 0; 109 | #endif 110 | int n = send(socket, buffer + total, length - total, flags); 111 | if (n < 0) 112 | { 113 | return -1; 114 | } 115 | total += n; 116 | } 117 | while (total < length); 118 | return total; 119 | } 120 | 121 | //---------------------------------------------------------------------------- 122 | ndicapiExport int ndiSocketRead(NDISocketHandle socket, char* reply, int numberOfBytesToRead, bool isBinary, int* outErrorCode) 123 | { 124 | int totalNumberOfBytesRead = 0; 125 | int totalNumberOfBytesToRead = numberOfBytesToRead; 126 | int numberOfBytesRead; 127 | bool binarySizeCalculated = false; 128 | 129 | do 130 | { 131 | numberOfBytesRead = recv(socket, reply + totalNumberOfBytesRead, numberOfBytesToRead, 0); 132 | 133 | if (numberOfBytesRead < 1) 134 | { 135 | return -1; 136 | } 137 | 138 | totalNumberOfBytesRead += numberOfBytesRead; 139 | if (!isBinary && reply[totalNumberOfBytesRead - 1] == '\r' /* done when carriage return received (ASCII) or when ERROR... received (binary)*/ 140 | || isBinary && strncmp(reply, "ERROR", 5) == 0 && reply[totalNumberOfBytesRead - 1] == '\r') 141 | { 142 | break; 143 | } 144 | 145 | if (isBinary && !binarySizeCalculated && reply[0] == (char)0xc4 && reply[1] == (char)0xa5) 146 | { 147 | // recalculate n based on the reply length (reported from ndi device) and the amount of data received so far 148 | unsigned short size = ((unsigned char)reply[2] | (unsigned char)reply[3] << 8) + 8; // 8 bytes -> 2 for Start Sequence (a5c4), 2 for reply length, 2 for header CRC, 2 for CRC16 149 | totalNumberOfBytesToRead = size; 150 | } 151 | } 152 | while (totalNumberOfBytesRead != totalNumberOfBytesToRead); 153 | 154 | return totalNumberOfBytesRead; 155 | } 156 | 157 | //---------------------------------------------------------------------------- 158 | ndicapiExport bool ndiSocketSleep(NDISocketHandle socket, int milliseconds) 159 | { 160 | #if _POSIX_C_SOURCE >= 199309L 161 | struct timespec ts; 162 | ts.tv_sec = milliseconds / 1000; 163 | ts.tv_nsec = (milliseconds % 1000) * 1000000; 164 | nanosleep(&ts, NULL); 165 | #else 166 | usleep(milliseconds * 1000); 167 | #endif 168 | return true; 169 | } 170 | -------------------------------------------------------------------------------- /ndicapi_socket_unix.cxx: -------------------------------------------------------------------------------- 1 | /*=Plus=header=begin====================================================== 2 | Program: Plus 3 | Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved. 4 | See License.md for details. 5 | =========================================================Plus=header=end*/ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //---------------------------------------------------------------------------- 17 | ndicapiExport bool ndiSocketOpen(const char* hostname, int port, NDISocketHandle& outSocket) 18 | { 19 | NDISocketHandle sock = socket(AF_INET, SOCK_STREAM, 0); 20 | 21 | // Eliminate windows 0.2 second delay sending (buffering) data. 22 | int on = 1; 23 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on))) 24 | { 25 | return false; 26 | } 27 | 28 | struct hostent* hp; 29 | hp = gethostbyname(hostname); 30 | if (!hp) 31 | { 32 | unsigned long addr = inet_addr(hostname); 33 | hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET); 34 | } 35 | 36 | if (!hp) 37 | { 38 | return false; 39 | } 40 | 41 | struct sockaddr_in name; 42 | name.sin_family = AF_INET; 43 | memcpy(&name.sin_addr, hp->h_addr, hp->h_length); 44 | name.sin_port = htons(port); 45 | 46 | int r = connect(sock, reinterpret_cast(&name), sizeof(name)); 47 | 48 | if (r < 0) 49 | { 50 | shutdown(sock, 2); 51 | close(sock); 52 | return false; 53 | } 54 | 55 | outSocket = sock; 56 | return true; 57 | } 58 | 59 | //---------------------------------------------------------------------------- 60 | ndicapiExport void ndiSocketClose(NDISocketHandle socket) 61 | { 62 | shutdown(socket, 2); 63 | close(socket); 64 | } 65 | 66 | //---------------------------------------------------------------------------- 67 | ndicapiExport bool ndiSocketFlush(NDISocketHandle socket, int flushtype) 68 | { 69 | return true; 70 | } 71 | 72 | //---------------------------------------------------------------------------- 73 | ndicapiExport bool ndiSocketTimeout(NDISocketHandle socket, int timeoutMs) 74 | { 75 | if (timeoutMs > 0) 76 | { 77 | setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*) & (timeoutMs), sizeof(timeoutMs)); 78 | return true; 79 | } 80 | return false; 81 | } 82 | 83 | //---------------------------------------------------------------------------- 84 | ndicapiExport int ndiSocketWrite(NDISocketHandle socket, const char* data, int length) 85 | { 86 | if (length == 0) 87 | { 88 | // nothing to send. 89 | return 0; 90 | } 91 | 92 | const char* buffer = reinterpret_cast(data); 93 | int total = 0; 94 | do 95 | { 96 | int flags; 97 | 98 | // On unix boxes if the client disconnects and the server attempts 99 | // to send data through the socket then the application crashes 100 | // due to SIGPIPE signal. Disable the signal to prevent crash. 101 | #if defined(MSG_NOSIGNAL) // For Linux > 2.2 102 | flags = MSG_NOSIGNAL; 103 | #else 104 | flags = 0; 105 | #endif 106 | int n = send(socket, buffer + total, length - total, flags); 107 | if (n < 0) 108 | { 109 | return -1; 110 | } 111 | total += n; 112 | } 113 | while (total < length); 114 | return total; 115 | } 116 | 117 | //---------------------------------------------------------------------------- 118 | ndicapiExport int ndiSocketRead(NDISocketHandle socket, char* reply, int numberOfBytesToRead, bool isBinary, int* outErrorCode) 119 | { 120 | int totalNumberOfBytesRead = 0; 121 | int totalNumberOfBytesToRead = numberOfBytesToRead; 122 | int numberOfBytesRead; 123 | bool binarySizeCalculated = false; 124 | 125 | do 126 | { 127 | numberOfBytesRead = recv(socket, reply + totalNumberOfBytesRead, numberOfBytesToRead, 0); 128 | 129 | if (numberOfBytesRead < 1) 130 | { 131 | return -1; 132 | } 133 | 134 | totalNumberOfBytesRead += numberOfBytesRead; 135 | if ((!isBinary && reply[totalNumberOfBytesRead - 1] == '\r') /* done when carriage return received (ASCII) or when ERROR... received (binary)*/ 136 | || (isBinary && strncmp(reply, "ERROR", 5) == 0 && reply[totalNumberOfBytesRead - 1] == '\r')) 137 | { 138 | break; 139 | } 140 | 141 | if (isBinary && !binarySizeCalculated && reply[0] == (char)0xc4 && reply[1] == (char)0xa5) 142 | { 143 | // recalculate n based on the reply length (reported from ndi device) and the amount of data received so far 144 | unsigned short size = ((unsigned char)reply[2] | (unsigned char)reply[3] << 8) + 8; // 8 bytes -> 2 for Start Sequence (a5c4), 2 for reply length, 2 for header CRC, 2 for CRC16 145 | totalNumberOfBytesToRead = size; 146 | } 147 | } 148 | while (totalNumberOfBytesRead != totalNumberOfBytesToRead); 149 | 150 | return totalNumberOfBytesRead; 151 | } 152 | 153 | //---------------------------------------------------------------------------- 154 | ndicapiExport bool ndiSocketSleep(NDISocketHandle socket, int milliseconds) 155 | { 156 | #if _POSIX_C_SOURCE >= 199309L 157 | struct timespec ts; 158 | ts.tv_sec = milliseconds / 1000; 159 | ts.tv_nsec = (milliseconds % 1000) * 1000000; 160 | nanosleep(&ts, NULL); 161 | #else 162 | usleep(milliseconds * 1000); 163 | #endif 164 | return true; 165 | } 166 | -------------------------------------------------------------------------------- /ndicapi_socket_win32.cxx: -------------------------------------------------------------------------------- 1 | /*=Plus=header=begin====================================================== 2 | Program: Plus 3 | Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved. 4 | See License.md for details. 5 | =========================================================Plus=header=end*/ 6 | 7 | #include 8 | 9 | //---------------------------------------------------------------------------- 10 | ndicapiExport bool ndiSocketOpen(const char* hostname, int port, NDISocketHandle& outSocket) 11 | { 12 | // Declare variables 13 | WSADATA wsaData; 14 | 15 | // Initialize Winsock 16 | int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 17 | if (iResult != NO_ERROR) 18 | { 19 | return false; 20 | } 21 | 22 | NDISocketHandle sock = socket(AF_INET, SOCK_STREAM, 0); 23 | // Eliminate windows 0.2 second delay sending (buffering) data. 24 | int on = 1; 25 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on))) 26 | { 27 | return false; 28 | } 29 | 30 | struct hostent* hp; 31 | hp = gethostbyname(hostname); 32 | if (!hp) 33 | { 34 | unsigned long addr = inet_addr(hostname); 35 | hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET); 36 | } 37 | 38 | if (!hp) 39 | { 40 | return false; 41 | } 42 | 43 | struct sockaddr_in name; 44 | name.sin_family = AF_INET; 45 | memcpy(&name.sin_addr, hp->h_addr, hp->h_length); 46 | name.sin_port = htons(port); 47 | 48 | int r = connect(sock, reinterpret_cast(&name), sizeof(name)); 49 | 50 | if (r < 0) 51 | { 52 | closesocket(sock); 53 | return false; 54 | } 55 | 56 | outSocket = sock; 57 | return true; 58 | } 59 | 60 | //---------------------------------------------------------------------------- 61 | ndicapiExport void ndiSocketClose(NDISocketHandle socket) 62 | { 63 | if (socket < 0) 64 | { 65 | return; 66 | } 67 | closesocket(socket); 68 | } 69 | 70 | //---------------------------------------------------------------------------- 71 | ndicapiExport bool ndiSocketFlush(NDISocketHandle socket, int flushtype) 72 | { 73 | return true; 74 | } 75 | 76 | //---------------------------------------------------------------------------- 77 | ndicapiExport bool ndiSocketTimeout(NDISocketHandle socket, int timeoutMs) 78 | { 79 | if (timeoutMs > 0) 80 | { 81 | setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*) & (timeoutMs), sizeof(timeoutMs)); 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | //---------------------------------------------------------------------------- 88 | ndicapiExport int ndiSocketWrite(NDISocketHandle socket, const char* data, int length) 89 | { 90 | if (length == 0) 91 | { 92 | // nothing to send. 93 | return 0; 94 | } 95 | const char* buffer = reinterpret_cast(data); 96 | int total = 0; 97 | do 98 | { 99 | int flags = 0; 100 | 101 | int n = send(socket, buffer + total, length - total, flags); 102 | if (n < 0) 103 | { 104 | return -1; 105 | } 106 | total += n; 107 | } 108 | while (total < length); 109 | return total; 110 | } 111 | 112 | //---------------------------------------------------------------------------- 113 | ndicapiExport int ndiSocketRead(NDISocketHandle socket, char* reply, int numberOfBytesToRead, bool isBinary, int* outErrorCode) 114 | { 115 | int totalNumberOfBytesRead = 0; 116 | int totalNumberOfBytesToRead = numberOfBytesToRead; 117 | int numberOfBytesRead; 118 | bool binarySizeCalculated = false; 119 | 120 | do 121 | { 122 | int trys = 0; 123 | numberOfBytesRead = recv(socket, reply + totalNumberOfBytesRead, numberOfBytesToRead, 0); 124 | 125 | if (numberOfBytesRead == SOCKET_ERROR) 126 | { 127 | *outErrorCode = WSAGetLastError(); 128 | if ((*outErrorCode == WSAENOBUFS) && (trys++ < 1000)) 129 | { 130 | Sleep(1); 131 | continue; 132 | } 133 | if (*outErrorCode == WSAETIMEDOUT) 134 | { 135 | // NDI handles 0 bytes returned as a timeout 136 | return 0; 137 | } 138 | return -1; 139 | } 140 | else if (numberOfBytesRead == 0) 141 | { 142 | // Connection has been closed 143 | return 0; 144 | } 145 | 146 | totalNumberOfBytesRead += numberOfBytesRead; 147 | if (!isBinary && reply[totalNumberOfBytesRead - 1] == '\r' /* done when carriage return received (ASCII) or when ERROR... received (binary)*/ 148 | || isBinary && strncmp(reply, "ERROR", 5) == 0 && reply[totalNumberOfBytesRead - 1] == '\r') 149 | { 150 | break; 151 | } 152 | 153 | if (isBinary && !binarySizeCalculated && reply[0] == (char)0xc4 && reply[1] == (char)0xa5) 154 | { 155 | // recalculate n based on the reply length (reported from ndi device) and the amount of data received so far 156 | unsigned short size = ((unsigned char)reply[2] | (unsigned char)reply[3] << 8) + 8; // 8 bytes -> 2 for Start Sequence (a5c4), 2 for reply length, 2 for header CRC, 2 for CRC16 157 | totalNumberOfBytesToRead = size; 158 | } 159 | } 160 | while (totalNumberOfBytesRead != totalNumberOfBytesToRead); 161 | 162 | return totalNumberOfBytesRead; 163 | } 164 | 165 | //---------------------------------------------------------------------------- 166 | ndicapiExport bool ndiSocketSleep(NDISocketHandle socket, int milliseconds) 167 | { 168 | Sleep(milliseconds); 169 | return true; 170 | } -------------------------------------------------------------------------------- /ndicapi_thread.cxx: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | #include "ndicapi_thread.h" 36 | #include 37 | 38 | // The interface is modeled after the Windows threading interface, 39 | // but the only real difference from POSIX threads is the "Event" 40 | // type which does not exists in POSIX threads (more information is 41 | // provided below) 42 | 43 | #ifdef _WIN32 44 | 45 | //---------------------------------------------------------------------------- 46 | ndicapiExport HANDLE ndiMutexCreate() 47 | { 48 | return CreateMutex(0, FALSE, 0); 49 | } 50 | 51 | //---------------------------------------------------------------------------- 52 | ndicapiExport void ndiMutexDestroy(HANDLE mutex) 53 | { 54 | CloseHandle(mutex); 55 | } 56 | 57 | //---------------------------------------------------------------------------- 58 | ndicapiExport void ndiMutexLock(HANDLE mutex) 59 | { 60 | WaitForSingleObject(mutex, INFINITE); 61 | } 62 | 63 | //---------------------------------------------------------------------------- 64 | ndicapiExport void ndiMutexUnlock(HANDLE mutex) 65 | { 66 | ReleaseMutex(mutex); 67 | } 68 | 69 | #elif defined(unix) || defined(__unix__) || defined(__APPLE__) 70 | 71 | //---------------------------------------------------------------------------- 72 | ndicapiExport pthread_mutex_t* ndiMutexCreate() 73 | { 74 | pthread_mutex_t* mutex; 75 | mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); 76 | pthread_mutex_init(mutex, 0); 77 | return mutex; 78 | } 79 | 80 | //---------------------------------------------------------------------------- 81 | ndicapiExport void ndiMutexDestroy(pthread_mutex_t* mutex) 82 | { 83 | pthread_mutex_destroy(mutex); 84 | free(mutex); 85 | } 86 | 87 | //---------------------------------------------------------------------------- 88 | ndicapiExport void ndiMutexLock(pthread_mutex_t* mutex) 89 | { 90 | pthread_mutex_lock(mutex); 91 | } 92 | 93 | //---------------------------------------------------------------------------- 94 | ndicapiExport void ndiMutexUnlock(pthread_mutex_t* mutex) 95 | { 96 | pthread_mutex_unlock(mutex); 97 | } 98 | 99 | #endif 100 | 101 | #ifdef _WIN32 102 | 103 | //---------------------------------------------------------------------------- 104 | ndicapiExport HANDLE ndiEventCreate() 105 | { 106 | return CreateEvent(0, FALSE, FALSE, 0); 107 | } 108 | 109 | //---------------------------------------------------------------------------- 110 | ndicapiExport void ndiEventDestroy(HANDLE event) 111 | { 112 | CloseHandle(event); 113 | } 114 | 115 | //---------------------------------------------------------------------------- 116 | ndicapiExport void ndiEventSignal(HANDLE event) 117 | { 118 | SetEvent(event); 119 | } 120 | 121 | //---------------------------------------------------------------------------- 122 | ndicapiExport int ndiEventWait(HANDLE event, int milliseconds) 123 | { 124 | if (milliseconds < 0) 125 | { 126 | WaitForSingleObject(event, INFINITE); 127 | } 128 | else 129 | { 130 | if (WaitForSingleObject(event, milliseconds) == WAIT_TIMEOUT) 131 | { 132 | return 1; 133 | } 134 | } 135 | return 0; 136 | } 137 | 138 | #elif defined(unix) || defined(__unix__) || defined(__APPLE__) 139 | 140 | // There is no equivalent of an 'event' in POSIX threads, so we define 141 | // our own event type consisting of a boolean variable (to say whether 142 | // an event has occurred), a cond, an a mutex for locking the cond 143 | // and the variable. 144 | 145 | //---------------------------------------------------------------------------- 146 | ndicapiExport pl_cond_and_mutex_t* ndiEventCreate() 147 | { 148 | pl_cond_and_mutex_t* event; 149 | event = (pl_cond_and_mutex_t*)malloc(sizeof(pl_cond_and_mutex_t)); 150 | event->signalled = 0; 151 | pthread_cond_init(&event->cond, 0); 152 | pthread_mutex_init(&event->mutex, 0); 153 | return event; 154 | } 155 | 156 | //---------------------------------------------------------------------------- 157 | ndicapiExport void ndiEventDestroy(pl_cond_and_mutex_t* event) 158 | { 159 | pthread_cond_destroy(&event->cond); 160 | pthread_mutex_destroy(&event->mutex); 161 | free(event); 162 | } 163 | 164 | //---------------------------------------------------------------------------- 165 | // Setting the event is simple: lock, set the variable, signal the cond, 166 | // and unlock. 167 | ndicapiExport void ndiEventSignal(pl_cond_and_mutex_t* event) 168 | { 169 | pthread_mutex_lock(&event->mutex); 170 | event->signalled = 1; 171 | pthread_cond_signal(&event->cond); 172 | pthread_mutex_unlock(&event->mutex); 173 | } 174 | 175 | //---------------------------------------------------------------------------- 176 | // Waiting for the event is simple if we don't want a timed wait: 177 | // lock, check the variable, wait until the variable becomes set, 178 | // unset the variable, unlock. 179 | // Note that the event can be received by only one thread. 180 | // 181 | // If a timed wait is needed, then there is a little bit of 182 | // hassle because the pthread_cond_timedwait() wait is until 183 | // an absolute time, so we must get the current time and then 184 | // do a little math as well as a conversion from one time structure 185 | // to another time structure. 186 | ndicapiExport int ndiEventWait(pl_cond_and_mutex_t* event, int milliseconds) 187 | { 188 | int timedout = 0; 189 | 190 | if (milliseconds < 0) /* do infinite wait */ 191 | { 192 | pthread_mutex_lock(&event->mutex); 193 | if (event->signalled == 0) 194 | { 195 | pthread_cond_wait(&event->cond, &event->mutex); 196 | } 197 | event->signalled = 0; 198 | pthread_mutex_unlock(&event->mutex); 199 | } 200 | else /* do timed wait */ 201 | { 202 | struct timeval tv; 203 | struct timespec ts; 204 | 205 | pthread_mutex_lock(&event->mutex); 206 | if (event->signalled == 0) 207 | { 208 | /* all the time stuff is used to check for timeouts */ 209 | gettimeofday(&tv, 0); 210 | tv.tv_sec += milliseconds / 1000; /* msec to sec */ 211 | tv.tv_usec += (milliseconds % 1000) * 1000; /* msec to usec */ 212 | if (tv.tv_usec >= 1000000) /* if usec overflow */ 213 | { 214 | tv.tv_usec -= 1000000; 215 | tv.tv_sec += 1; 216 | } 217 | /* convert timeval to timespec */ 218 | ts.tv_sec = tv.tv_sec; 219 | ts.tv_nsec = tv.tv_usec * 1000; 220 | 221 | #ifdef PTHREAD_COND_TIMEDWAIT_USES_TIMEVAL 222 | timedout = (pthread_cond_timedwait(&event->cond, &event->mutex, &tv) == ETIMEDOUT); 223 | #else 224 | timedout = (pthread_cond_timedwait(&event->cond, &event->mutex, &ts) == ETIMEDOUT); 225 | #endif 226 | } 227 | if (!timedout) 228 | { 229 | event->signalled = 0; 230 | } 231 | pthread_mutex_unlock(&event->mutex); 232 | } 233 | 234 | return timedout; 235 | } 236 | 237 | #endif 238 | 239 | #ifdef _WIN32 240 | 241 | //---------------------------------------------------------------------------- 242 | ndicapiExport HANDLE ndiThreadSplit(void* thread_func(void* userdata), void* userdata) 243 | { 244 | DWORD thread_id; 245 | return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&thread_func, userdata, 0, &thread_id); 246 | } 247 | 248 | //---------------------------------------------------------------------------- 249 | ndicapiExport void ndiThreadJoin(HANDLE Thread) 250 | { 251 | WaitForSingleObject(Thread, INFINITE); 252 | } 253 | 254 | #elif defined(unix) || defined(__unix__) || defined(__APPLE__) 255 | 256 | //---------------------------------------------------------------------------- 257 | ndicapiExport pthread_t ndiThreadSplit(void* thread_func(void* userdata), void* userdata) 258 | { 259 | pthread_t Thread; 260 | if (pthread_create(&Thread, 0, thread_func, userdata)) 261 | { 262 | return 0; 263 | } 264 | return Thread; 265 | } 266 | 267 | //---------------------------------------------------------------------------- 268 | ndicapiExport void ndiThreadJoin(pthread_t Thread) 269 | { 270 | pthread_join(Thread, 0); 271 | } 272 | 273 | #endif -------------------------------------------------------------------------------- /ndicapi_thread.h: -------------------------------------------------------------------------------- 1 | /*======================================================================= 2 | 3 | Copyright (c) 2000-2005 Atamai, Inc. 4 | 5 | Use, modification and redistribution of the software, in source or 6 | binary forms, are permitted provided that the following terms and 7 | conditions are met: 8 | 9 | 1) Redistribution of the source code, in verbatim or modified 10 | form, must retain the above copyright notice, this license, 11 | the following disclaimer, and any notices that refer to this 12 | license and/or the following disclaimer. 13 | 14 | 2) Redistribution in binary form must include the above copyright 15 | notice, a copy of this license and the following disclaimer 16 | in the documentation or with other materials provided with the 17 | distribution. 18 | 19 | 3) Modified copies of the source code must be clearly marked as such, 20 | and must not be misrepresented as verbatim copies of the source code. 21 | 22 | THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" 23 | WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY 26 | MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE 27 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES 28 | (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE 29 | OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF 30 | THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGES. 32 | 33 | =======================================================================*/ 34 | 35 | /*! \file ndicapi_thread.h 36 | This file contains the platform-dependent portions of the 37 | NDICAPI C API for doing thread handling. 38 | */ 39 | 40 | #ifndef NDICAPI_THREAD_H 41 | #define NDICAPI_THREAD_H 42 | 43 | #include "ndicapiExport.h" 44 | 45 | /*=====================================================================*/ 46 | /*! \defgroup NDIThread NDI Thread Methods 47 | These are low-level methods that provide a platform-independent 48 | multithreading. 49 | */ 50 | 51 | 52 | #ifdef _WIN32 53 | 54 | #include 55 | #include 56 | #include 57 | 58 | typedef HANDLE NDIThread; 59 | typedef HANDLE NDIMutex; 60 | typedef HANDLE NDIEvent; 61 | 62 | #elif defined(unix) || defined(__unix__) || defined(__APPLE__) 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | 71 | typedef struct 72 | { 73 | int signalled; 74 | pthread_cond_t cond; 75 | pthread_mutex_t mutex; 76 | } pl_cond_and_mutex_t; 77 | typedef pthread_t NDIThread; 78 | typedef pthread_mutex_t* NDIMutex; 79 | typedef pl_cond_and_mutex_t* NDIEvent; 80 | 81 | #endif 82 | 83 | #ifdef __cplusplus 84 | extern "C" { 85 | #endif 86 | 87 | ndicapiExport NDIMutex ndiMutexCreate(); 88 | ndicapiExport void ndiMutexDestroy(NDIMutex mutex); 89 | ndicapiExport void ndiMutexLock(NDIMutex mutex); 90 | ndicapiExport void ndiMutexUnlock(NDIMutex mutex); 91 | 92 | ndicapiExport NDIEvent ndiEventCreate(); 93 | ndicapiExport void ndiEventDestroy(NDIEvent event); 94 | ndicapiExport void ndiEventSignal(NDIEvent event); 95 | ndicapiExport int ndiEventWait(NDIEvent event, int milliseconds); 96 | 97 | ndicapiExport NDIThread ndiThreadSplit(void* thread_func(void* userdata), void* userdata); 98 | ndicapiExport void ndiThreadJoin(NDIThread Thread); 99 | 100 | #ifdef __cplusplus 101 | } 102 | #endif 103 | 104 | #endif -------------------------------------------------------------------------------- /ndicapimodule.cxx: -------------------------------------------------------------------------------- 1 | // Local includes 2 | #include "ndicapi.h" 3 | #include "ndicapi_math.h" 4 | 5 | // Export includes 6 | #include "ndicapiExport.h" 7 | 8 | // Python includes 9 | #include 10 | 11 | // Conditional definitions for Python-version-based compilation 12 | #if PY_MAJOR_VERSION >= 3 13 | #define MOD_ERROR_VAL NULL 14 | #define MOD_SUCCESS_VAL(val) val 15 | #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) 16 | #define MOD_DEF(ob, name, doc, methods) \ 17 | static struct PyModuleDef moduledef = { \ 18 | PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ 19 | ob = PyModule_Create(&moduledef); 20 | #define PyInt_FromLong PyLong_FromLong 21 | #define PyInt_Check PyLong_Check 22 | #define PyInt_AsLong PyLong_AsLong 23 | #define PyString_FromString PyUnicode_FromString 24 | #define PyString_FromStringAndSize PyUnicode_FromStringAndSize 25 | #define PyString_Format PyUnicode_Format 26 | #define PyString_AsString PyUnicode_AsUTF8 27 | #define PyIntObject PyLongObject 28 | //#define PY_INT_OBJECT_OB_IVAL(ob) PyLong_AsLong((PyObject*)(ob)) 29 | #if PY_MINOR_VERSION < 12 30 | #define PY_INT_OBJECT_OB_IVAL(ob) ob->ob_digit[0] 31 | #else 32 | #define PY_INT_OBJECT_OB_IVAL(ob) ob->long_value.ob_digit[0] 33 | #endif 34 | #define cmpfunc PyAsyncMethods* 35 | #else 36 | #define MOD_ERROR_VAL 37 | #define MOD_SUCCESS_VAL(val) 38 | #define MOD_INIT(name) void init##name(void) 39 | #define MOD_DEF(ob, name, doc, methods) \ 40 | ob = Py_InitModule3(name, methods, doc); 41 | #define PY_INT_OBJECT_OB_IVAL(ob) ob->ob_ival 42 | #endif 43 | 44 | //-------------------------------------------------------------- 45 | // PyNdicapi structure 46 | typedef struct 47 | { 48 | PyObject_HEAD 49 | ndicapi* pl_ndicapi; 50 | } PyNdicapi; 51 | 52 | static void PyNdicapi_PyDelete(PyObject* self) 53 | { 54 | ndicapi* pol; 55 | 56 | pol = ((PyNdicapi*)self)->pl_ndicapi; 57 | ndiCloseSerial(pol); 58 | PyMem_DEL(self); 59 | } 60 | 61 | static char* PyNdicapi_PrintHelper(PyObject* self, char* space) 62 | { 63 | ndicapi* pol; 64 | 65 | pol = ((PyNdicapi*)self)->pl_ndicapi; 66 | 67 | sprintf(space, "", (void*)pol, ndiGetSerialDeviceName(pol)); 68 | 69 | return space; 70 | } 71 | 72 | static int PyNdicapi_PyPrint(PyObject* self, FILE* fp, int dummy) 73 | { 74 | char space[256]; 75 | 76 | PyNdicapi_PrintHelper(self, space); 77 | fprintf(fp, "%s", space); 78 | return 0; 79 | } 80 | 81 | static PyObject* PyNdicapi_PyString(PyObject* self) 82 | { 83 | char space[256]; 84 | 85 | PyNdicapi_PrintHelper(self, space); 86 | return PyString_FromString(space); 87 | } 88 | 89 | static PyObject* PyNdicapi_PyRepr(PyObject* self) 90 | { 91 | char space[256]; 92 | 93 | PyNdicapi_PrintHelper(self, space); 94 | return PyString_FromString(space); 95 | } 96 | 97 | static PyObject* PyNdicapi_PyGetAttr(PyObject* self, char* name) 98 | { 99 | ndicapi* pol; 100 | 101 | pol = ((PyNdicapi*)self)->pl_ndicapi; 102 | PyErr_SetString(PyExc_AttributeError, name); 103 | return NULL; 104 | } 105 | 106 | static PyTypeObject PyNdicapiType = 107 | { 108 | PyVarObject_HEAD_INIT(NULL, 0) /* (&PyType_Type) */ 109 | "ndicapi", /* tp_name */ 110 | sizeof(PyNdicapi), /* tp_basicsize */ 111 | 0, /* tp_itemsize */ 112 | (destructor)PyNdicapi_PyDelete, /* tp_dealloc */ 113 | (printfunc)PyNdicapi_PyPrint, /* tp_print */ 114 | (getattrfunc)PyNdicapi_PyGetAttr, /* tp_getattr */ 115 | 0, /* tp_setattr */ 116 | (cmpfunc)0, /* tp_compare */ 117 | (reprfunc)PyNdicapi_PyRepr, /* tp_repr */ 118 | 0, /* tp_as_number */ 119 | 0, /* tp_as_sequence */ 120 | 0, /* tp_as_mapping */ 121 | (hashfunc)0, /* tp_hash */ 122 | (ternaryfunc)0, /* tp_call */ 123 | (reprfunc)PyNdicapi_PyString, /* tp_string */ 124 | (getattrofunc)0, /* tp_getattro */ 125 | (setattrofunc)0, /* tp_setattro */ 126 | 0, /* tp_as_buffer */ 127 | 0, /* tp_flags */ 128 | "ndicapi: interface to an NDICAPI serial tracking system" /* tp_doc */ 129 | }; 130 | 131 | int PyNdicapi_Check(PyObject* obj) 132 | { 133 | return (obj->ob_type == &PyNdicapiType); 134 | } 135 | 136 | /*================================================================= 137 | bitfield type: this code is a ripoff of the python integer type 138 | that prints itself as a hexadecimal value 139 | */ 140 | 141 | typedef struct 142 | { 143 | PyObject_HEAD 144 | unsigned long ob_ival; 145 | } PyNDIBitfieldObject; 146 | 147 | PyObject* PyNDIBitfield_FromUnsignedLong(unsigned long ival); 148 | 149 | static void 150 | bitfield_dealloc(PyIntObject* v) 151 | { 152 | PyMem_DEL(v); 153 | } 154 | 155 | static int 156 | bitfield_print(PyIntObject* v, FILE* fp, int flags/* Not used but required by interface */) 157 | { 158 | fprintf(fp, "0x%lX", (unsigned long)PY_INT_OBJECT_OB_IVAL(v)); 159 | return 0; 160 | } 161 | 162 | static PyObject* 163 | bitfield_repr(PyIntObject* v) 164 | { 165 | char buf[20]; 166 | sprintf(buf, "0x%lX", (unsigned long)PY_INT_OBJECT_OB_IVAL(v)); 167 | return PyString_FromString(buf); 168 | } 169 | 170 | static int 171 | bitfield_compare(PyIntObject* v, PyIntObject* w) 172 | { 173 | register unsigned long i = PY_INT_OBJECT_OB_IVAL(v); 174 | register unsigned long j = PY_INT_OBJECT_OB_IVAL(w); 175 | return (i < j) ? -1 : (i > j) ? 1 : 0; 176 | } 177 | 178 | static int 179 | bitfield_nonzero(PyIntObject* v) 180 | { 181 | return PY_INT_OBJECT_OB_IVAL(v) != 0; 182 | } 183 | 184 | static PyObject* 185 | bitfield_invert(PyIntObject* v) 186 | { 187 | return PyNDIBitfield_FromUnsignedLong(~(PY_INT_OBJECT_OB_IVAL(v))); 188 | } 189 | 190 | static PyObject* 191 | bitfield_lshift(PyIntObject* v, PyIntObject* w) 192 | { 193 | register long a, b; 194 | a = PY_INT_OBJECT_OB_IVAL(v); 195 | b = PY_INT_OBJECT_OB_IVAL(w); 196 | if (b < 0) 197 | { 198 | PyErr_SetString(PyExc_ValueError, "negative shift count"); 199 | return NULL; 200 | } 201 | if (a == 0 || b == 0) 202 | { 203 | Py_INCREF(v); 204 | return (PyObject*) v; 205 | } 206 | if (b >= 8 * (long)sizeof(long)) 207 | { 208 | return PyNDIBitfield_FromUnsignedLong(0L); 209 | } 210 | a = (unsigned long)a << b; 211 | return PyNDIBitfield_FromUnsignedLong(a); 212 | } 213 | 214 | static PyObject* 215 | bitfield_rshift(PyIntObject* v, PyIntObject* w) 216 | { 217 | register long a, b; 218 | a = PY_INT_OBJECT_OB_IVAL(v); 219 | b = PY_INT_OBJECT_OB_IVAL(w); 220 | if (b < 0) 221 | { 222 | PyErr_SetString(PyExc_ValueError, "negative shift count"); 223 | return NULL; 224 | } 225 | if (a == 0 || b == 0) 226 | { 227 | Py_INCREF(v); 228 | return (PyObject*) v; 229 | } 230 | if (b >= 8 * (long)sizeof(long)) 231 | { 232 | if (a < 0) 233 | { a = -1; } 234 | else 235 | { a = 0; } 236 | } 237 | else 238 | { 239 | if (a < 0) 240 | { a = ~(~(unsigned long)a >> b); } 241 | else 242 | { a = (unsigned long)a >> b; } 243 | } 244 | return PyNDIBitfield_FromUnsignedLong(a); 245 | } 246 | 247 | static PyObject* 248 | bitfield_and(PyIntObject* v, PyIntObject* w) 249 | { 250 | register unsigned long a, b; 251 | a = PY_INT_OBJECT_OB_IVAL(v); 252 | b = PY_INT_OBJECT_OB_IVAL(w); 253 | return PyNDIBitfield_FromUnsignedLong(a & b); 254 | } 255 | 256 | static PyObject* 257 | bitfield_xor(PyIntObject* v, PyIntObject* w) 258 | { 259 | register unsigned long a, b; 260 | a = PY_INT_OBJECT_OB_IVAL(v); 261 | b = PY_INT_OBJECT_OB_IVAL(w); 262 | return PyNDIBitfield_FromUnsignedLong(a ^ b); 263 | } 264 | 265 | static PyObject* 266 | bitfield_or(PyIntObject* v, PyIntObject* w) 267 | { 268 | register unsigned long a, b; 269 | a = PY_INT_OBJECT_OB_IVAL(v); 270 | b = PY_INT_OBJECT_OB_IVAL(w); 271 | return PyNDIBitfield_FromUnsignedLong(a | b); 272 | } 273 | 274 | static int 275 | bitfield_coerce(PyObject** pv, PyObject** pw) 276 | { 277 | if (PyInt_Check(*pw)) 278 | { 279 | *pw = PyNDIBitfield_FromUnsignedLong(PyInt_AsLong(*pw)); 280 | Py_INCREF(*pv); 281 | return 0; 282 | } 283 | else if (PyLong_Check(*pw)) 284 | { 285 | *pw = PyNDIBitfield_FromUnsignedLong(PyLong_AsLong(*pw)); 286 | Py_INCREF(*pv); 287 | return 0; 288 | } 289 | return 1; /* Can't do it */ 290 | } 291 | 292 | static PyObject* 293 | bitfield_int(PyIntObject* v) 294 | { 295 | return PyInt_FromLong(PY_INT_OBJECT_OB_IVAL(v)); 296 | } 297 | 298 | static PyObject* 299 | bitfield_long(PyIntObject* v) 300 | { 301 | return PyLong_FromLong(PY_INT_OBJECT_OB_IVAL(v)); 302 | } 303 | 304 | static PyObject* 305 | bitfield_float(PyIntObject* v) 306 | { 307 | return PyFloat_FromDouble((double)(PY_INT_OBJECT_OB_IVAL(v))); 308 | } 309 | 310 | static PyObject* 311 | bitfield_oct(PyIntObject* v) 312 | { 313 | char buf[100]; 314 | long x = PY_INT_OBJECT_OB_IVAL(v); 315 | if (x == 0) 316 | { strcpy(buf, "0"); } 317 | else 318 | { sprintf(buf, "0%lo", x); } 319 | return PyString_FromString(buf); 320 | } 321 | 322 | static PyObject* 323 | bitfield_hex(PyIntObject* v) 324 | { 325 | char buf[100]; 326 | long x = PY_INT_OBJECT_OB_IVAL(v); 327 | sprintf(buf, "0x%lx", x); 328 | return PyString_FromString(buf); 329 | } 330 | 331 | static PyNumberMethods bitfield_as_number = 332 | { 333 | (binaryfunc)0, /*nb_add*/ 334 | (binaryfunc)0, /*nb_subtract*/ 335 | (binaryfunc)0, /*nb_multiply*/ 336 | #if PY_MAJOR_VERSION <= 2 337 | (binaryfunc)0, /*nb_divide*/ 338 | #endif 339 | (binaryfunc)0, /*nb_remainder*/ 340 | (binaryfunc)0, /*nb_divmod*/ 341 | (ternaryfunc)0, /*nb_power*/ 342 | (unaryfunc)0, /*nb_negative*/ 343 | (unaryfunc)0, /*nb_positive*/ 344 | (unaryfunc)0, /*nb_absolute*/ 345 | (inquiry)bitfield_nonzero, /*nb_nonzero*/ 346 | (unaryfunc)bitfield_invert, /*nb_invert*/ 347 | (binaryfunc)bitfield_lshift, /*nb_lshift*/ 348 | (binaryfunc)bitfield_rshift, /*nb_rshift*/ 349 | (binaryfunc)bitfield_and, /*nb_and*/ 350 | (binaryfunc)bitfield_xor, /*nb_xor*/ 351 | (binaryfunc)bitfield_or, /*nb_or*/ 352 | #if PY_MAJOR_VERSION <= 2 353 | (coercion)bitfield_coerce, /*nb_coerce*/ 354 | #endif 355 | (unaryfunc)bitfield_int, /*nb_int*/ 356 | #if PY_MAJOR_VERSION >= 3 357 | (void *)0, /*nb_reserved*/ 358 | #endif 359 | #if PY_MAJOR_VERSION <= 2 360 | (unaryfunc)bitfield_long, /*nb_long*/ 361 | #endif 362 | (unaryfunc)bitfield_float, /*nb_float*/ 363 | #if PY_MAJOR_VERSION <= 2 364 | (unaryfunc)bitfield_oct, /*nb_oct*/ 365 | (unaryfunc)bitfield_hex, /*nb_hex*/ 366 | #endif 367 | }; 368 | 369 | PyTypeObject PyNDIBitfield_Type = 370 | { 371 | PyVarObject_HEAD_INIT(NULL, 0) /* (&PyType_Type) */ 372 | "bitfield", 373 | sizeof(PyIntObject), 374 | 0, 375 | (destructor)bitfield_dealloc, /*tp_dealloc*/ 376 | (printfunc)bitfield_print, /*tp_print*/ 377 | 0, /*tp_getattr*/ 378 | 0, /*tp_setattr*/ 379 | (cmpfunc)bitfield_compare, /*tp_compare*/ 380 | (reprfunc)bitfield_repr, /*tp_repr*/ 381 | &bitfield_as_number, /*tp_as_number*/ 382 | 0, /*tp_as_sequence*/ 383 | 0, /*tp_as_mapping*/ 384 | (hashfunc)0, /*tp_hash*/ 385 | }; 386 | 387 | PyObject* PyNDIBitfield_FromUnsignedLong(unsigned long ival) 388 | { 389 | return PyLong_FromUnsignedLong(ival); 390 | 391 | /* The implementation below has been commented out, 392 | * as it leads to double memory deallocation. The 393 | * PyNDIBitfieldObject does not seem to be used 394 | * anywhere else in the entire codebase either. So 395 | * the assumption is that the above implementation 396 | * of this function should not break any features. 397 | * 398 | PyNDIBitfieldObject* v; 399 | v = PyObject_NEW(PyNDIBitfieldObject, &PyNDIBitfield_Type); 400 | 401 | v->ob_ival = ival; 402 | return (PyObject*) v; 403 | */ 404 | } 405 | 406 | /*================================================================= 407 | helper functions 408 | */ 409 | 410 | static PyObject* _ndiErrorHelper(int errnum, PyObject* rval) 411 | { 412 | char errtext[512]; 413 | 414 | if (errnum) 415 | { 416 | Py_DECREF(rval); 417 | if ((errnum & 0xff) == errnum) 418 | { 419 | sprintf(errtext, "POLARIS %#4.2x: %s", errnum, ndiErrorString(errnum)); 420 | } 421 | else 422 | { 423 | sprintf(errtext, "Error %#6.4x: %s", errnum, ndiErrorString(errnum)); 424 | } 425 | PyErr_SetString(PyExc_IOError, errtext); 426 | return NULL; 427 | } 428 | 429 | return rval; 430 | } 431 | 432 | static int _ndiConverter(PyObject* obj, ndicapi** polptr) 433 | { 434 | if (PyNdicapi_Check(obj)) 435 | { 436 | *polptr = ((PyNdicapi*)obj)->pl_ndicapi; 437 | } 438 | else 439 | { 440 | PyErr_SetString(PyExc_ValueError, "expected an NDICAPI object."); 441 | return 0; 442 | } 443 | return 1; 444 | } 445 | 446 | static PyObject* _PyString_FromChar(char value) 447 | { 448 | return PyString_FromStringAndSize(&value, 1); 449 | } 450 | 451 | /*================================================================= 452 | methods 453 | */ 454 | 455 | static PyObject* Py_ndiHexToUnsignedLong(PyObject* module, PyObject* args) 456 | { 457 | char* cp; 458 | int n; 459 | unsigned long result; 460 | 461 | if (PyArg_ParseTuple(args, "si:plHexToUnsignedLong", &cp, &n)) 462 | { 463 | result = ndiHexToUnsignedLong(cp, n); 464 | return PyNDIBitfield_FromUnsignedLong(result); 465 | } 466 | 467 | return NULL; 468 | } 469 | 470 | static PyObject* Py_ndiSignedToLong(PyObject* module, PyObject* args) 471 | { 472 | char* cp; 473 | int n; 474 | long result; 475 | 476 | if (PyArg_ParseTuple(args, "si:plSignedToLong", &cp, &n)) 477 | { 478 | result = ndiSignedToLong(cp, n); 479 | return PyInt_FromLong(result); 480 | } 481 | 482 | return NULL; 483 | } 484 | 485 | static PyObject* Py_ndiHexEncode(PyObject* module, PyObject* args) 486 | { 487 | char* result; 488 | void* data; 489 | char* cp; 490 | int m, n; 491 | PyObject* obj; 492 | 493 | if (PyArg_ParseTuple(args, "s#i:plHexEncode", &data, &m, &n)) 494 | { 495 | cp = (char*)malloc(2 * n); 496 | if (m < n) 497 | { 498 | PyErr_SetString(PyExc_ValueError, "data string is not long enough"); 499 | free(cp); 500 | return NULL; 501 | } 502 | result = ndiHexEncode(cp, data, n); 503 | obj = PyString_FromStringAndSize(result, 2 * n); 504 | free(cp); 505 | return obj; 506 | } 507 | 508 | return NULL; 509 | } 510 | 511 | static PyObject* Py_ndiHexDecode(PyObject* module, PyObject* args) 512 | { 513 | void* result; 514 | void* data; 515 | char* cp; 516 | int m, n; 517 | PyObject* obj; 518 | 519 | if (PyArg_ParseTuple(args, "s#i:plHexDecode", &cp, &m, &n)) 520 | { 521 | data = malloc(n); 522 | if (m < 2 * n) 523 | { 524 | PyErr_SetString(PyExc_ValueError, "encoded string is not long enough"); 525 | free(data); 526 | return NULL; 527 | } 528 | result = ndiHexEncode((char*)data, cp, n); 529 | obj = PyString_FromStringAndSize((char*)result, n); 530 | free(data); 531 | return obj; 532 | } 533 | 534 | return NULL; 535 | } 536 | 537 | static PyObject* Py_ndiGetError(PyObject* module, PyObject* args) 538 | { 539 | ndicapi* pol; 540 | int result; 541 | 542 | if (PyArg_ParseTuple(args, "O&:plGetError", &_ndiConverter, &pol)) 543 | { 544 | result = ndiGetError(pol); 545 | return PyNDIBitfield_FromUnsignedLong(result); 546 | } 547 | 548 | return NULL; 549 | } 550 | 551 | static PyObject* Py_ndiErrorString(PyObject* module, PyObject* args) 552 | { 553 | int errnum; 554 | const char* result; 555 | 556 | if (PyArg_ParseTuple(args, "i:plErrorString", &errnum)) 557 | { 558 | result = ndiErrorString(errnum); 559 | return PyString_FromString(result); 560 | } 561 | 562 | return NULL; 563 | } 564 | 565 | static PyObject* Py_ndiDeviceName(PyObject* module, PyObject* args) 566 | { 567 | int n; 568 | const char* result; 569 | 570 | if (PyArg_ParseTuple(args, "i:plDeviceName", &n)) 571 | { 572 | result = ndiSerialDeviceName(n); 573 | if (result) 574 | { 575 | return PyString_FromString(result); 576 | } 577 | else 578 | { 579 | Py_INCREF(Py_None); 580 | return Py_None; 581 | } 582 | } 583 | 584 | return NULL; 585 | } 586 | 587 | static PyObject* Py_ndiProbe(PyObject* module, PyObject* args) 588 | { 589 | char* device; 590 | int result; 591 | 592 | if (PyArg_ParseTuple(args, "s:plProbe", &device)) 593 | { 594 | result = ndiSerialProbe(device, false); 595 | return PyNDIBitfield_FromUnsignedLong(result); 596 | } 597 | 598 | return NULL; 599 | } 600 | 601 | static PyObject* Py_ndiOpen(PyObject* module, PyObject* args) 602 | { 603 | ndicapi* pol; 604 | char* device; 605 | PyNdicapi* self; 606 | 607 | if (PyArg_ParseTuple(args, "s:plOpen", &device)) 608 | { 609 | pol = ndiOpenSerial(device); 610 | if (pol == NULL) 611 | { 612 | Py_INCREF(Py_None); 613 | return Py_None; 614 | } 615 | self = PyObject_NEW(PyNdicapi, &PyNdicapiType); 616 | self->pl_ndicapi = pol; 617 | Py_INCREF(self); 618 | return (PyObject*)self; 619 | } 620 | 621 | return NULL; 622 | } 623 | 624 | /* Open a networked tracker*/ 625 | static PyObject* Py_ndiOpenNetwork(PyObject* module, PyObject* args) 626 | { 627 | ndicapi* pol; 628 | char* hostname; 629 | int port; 630 | PyNdicapi* self; 631 | 632 | if (PyArg_ParseTuple(args, "si:plOpenNetwork", &hostname, &port)) 633 | { 634 | pol = ndiOpenNetwork(hostname, port); 635 | if (pol == NULL) 636 | { 637 | Py_INCREF(Py_None); 638 | return Py_None; 639 | } 640 | self = PyObject_NEW(PyNdicapi, &PyNdicapiType); 641 | self->pl_ndicapi = pol; 642 | Py_INCREF(self); 643 | return (PyObject*)self; 644 | } 645 | 646 | return NULL; 647 | } 648 | 649 | static PyObject* Py_ndiGetDeviceName(PyObject* module, PyObject* args) 650 | { 651 | ndicapi* pol; 652 | char* result; 653 | 654 | if (PyArg_ParseTuple(args, "O&:plGetDeviceName", &_ndiConverter, &pol)) 655 | { 656 | result = ndiGetSerialDeviceName(pol); 657 | if (result == NULL) 658 | { 659 | Py_INCREF(Py_None); 660 | return Py_None; 661 | } 662 | return PyString_FromString(result); 663 | } 664 | 665 | return NULL; 666 | } 667 | 668 | static PyObject* Py_ndiClose(PyObject* module, PyObject* args) 669 | { 670 | ndicapi* pol; 671 | 672 | if (PyArg_ParseTuple(args, "O&:plClose", &_ndiConverter, &pol)) 673 | { 674 | ndiSerialClose(pol->SerialDevice); 675 | Py_INCREF(Py_None); 676 | return Py_None; 677 | } 678 | 679 | return NULL; 680 | } 681 | 682 | /* close a networked tracker */ 683 | static PyObject* Py_ndiCloseNetwork(PyObject* module, PyObject* args) 684 | { 685 | ndicapi* pol; 686 | 687 | if (PyArg_ParseTuple(args, "O&:plClose", &_ndiConverter, &pol)) 688 | { 689 | ndiCloseNetwork(pol); 690 | Py_INCREF(Py_None); 691 | return Py_None; 692 | } 693 | 694 | return NULL; 695 | } 696 | 697 | static PyObject* Py_ndiSetThreadMode(PyObject* module, PyObject* args) 698 | { 699 | ndicapi* pol; 700 | int mode; 701 | 702 | if (PyArg_ParseTuple(args, "O&i:plSetThreadMode", &_ndiConverter, &pol, 703 | &mode)) 704 | { 705 | ndiSetThreadMode(pol, mode); 706 | Py_INCREF(Py_None); 707 | return Py_None; 708 | } 709 | 710 | return NULL; 711 | } 712 | 713 | static PyObject* Py_ndiCommand(PyObject* module, PyObject* args) 714 | { 715 | int n; 716 | ndicapi* pol; 717 | char* format; 718 | char* result; 719 | PyObject* initial; 720 | PyObject* remainder; 721 | PyObject* newstring = NULL; 722 | PyObject* obj; 723 | 724 | if ((n = PySequence_Length(args)) < 2) 725 | { 726 | PyErr_SetString(PyExc_TypeError, 727 | "plCommand requires at least 2 arguments"); 728 | return NULL; 729 | } 730 | 731 | remainder = PySequence_GetSlice(args, 2, n); 732 | initial = PySequence_GetSlice(args, 0, 2); 733 | 734 | if (!PyArg_ParseTuple(initial, "O&z:plCommand", 735 | &_ndiConverter, &pol, &format)) 736 | { 737 | Py_DECREF(initial); 738 | Py_DECREF(remainder); 739 | return NULL; 740 | } 741 | 742 | if (format != NULL) 743 | { 744 | obj = PySequence_GetItem(args, 1); 745 | newstring = PyString_Format(obj, remainder); 746 | Py_DECREF(obj); 747 | Py_DECREF(initial); 748 | Py_DECREF(remainder); 749 | 750 | if (newstring == NULL) 751 | { 752 | return NULL; 753 | } 754 | 755 | result = ndiCommand(pol, "%s", PyString_AsString(newstring)); 756 | } 757 | else 758 | { 759 | result = ndiCommand(pol, NULL); 760 | } 761 | 762 | if (newstring != NULL) 763 | { 764 | Py_DECREF(newstring); 765 | } 766 | 767 | if (result == NULL) 768 | { 769 | Py_INCREF(Py_None); 770 | obj = Py_None; 771 | } 772 | else 773 | { 774 | obj = PyString_FromString(result); 775 | } 776 | 777 | return _ndiErrorHelper(ndiGetError(pol), obj); 778 | } 779 | 780 | static PyObject* Py_ndiCommand2(PyObject* module, const char* format, PyObject* args) 781 | { 782 | int i, n; 783 | PyObject* newargs; 784 | PyObject* obj; 785 | 786 | if ((n = PySequence_Length(args)) < 1) 787 | { 788 | PyErr_SetString(PyExc_TypeError, 789 | "plCommand requires at least 2 arguments"); 790 | return NULL; 791 | } 792 | 793 | newargs = PyTuple_New(n + 1); 794 | obj = PySequence_GetItem(args, 0); 795 | Py_INCREF(obj); 796 | PyTuple_SET_ITEM(newargs, 0, obj); 797 | 798 | if (format != NULL) 799 | { 800 | obj = PyString_FromString(format); 801 | } 802 | else 803 | { 804 | Py_INCREF(Py_None); 805 | obj = Py_None; 806 | } 807 | PyTuple_SET_ITEM(newargs, 1, obj); 808 | 809 | for (i = 1; i < n; i++) 810 | { 811 | obj = PySequence_GetItem(args, i); 812 | Py_INCREF(obj); 813 | PyTuple_SET_ITEM(newargs, i + 1, obj); 814 | } 815 | 816 | obj = Py_ndiCommand(module, newargs); 817 | 818 | Py_DECREF(newargs); 819 | 820 | return obj; 821 | } 822 | 823 | #define PyCommandMacro(name,format) \ 824 | static PyObject *Py_##name(PyObject *module, PyObject *args) \ 825 | { \ 826 | return Py_ndiCommand2(module, format, args); \ 827 | } 828 | 829 | PyCommandMacro(ndiRESET, NULL) 830 | PyCommandMacro(ndiINIT, "INIT:") 831 | PyCommandMacro(ndiCOMM, "COMM:%d%03d%d") 832 | PyCommandMacro(ndiPVWR, "PVWR:%c%04X%.128s") 833 | PyCommandMacro(ndiPVCLR, "PVCLR:%c") 834 | PyCommandMacro(ndiPINIT, "PINIT:%c") 835 | PyCommandMacro(ndiPENA, "PENA:%c%c") 836 | PyCommandMacro(ndiPDIS, "PDIS:%c") 837 | PyCommandMacro(ndiTSTART, "TSTART:") 838 | PyCommandMacro(ndiTSTOP, "TSTOP:") 839 | PyCommandMacro(ndiGX, "GX:%04X") 840 | PyCommandMacro(ndiBX, "BX:%04X") 841 | PyCommandMacro(ndiTX, "TX:%04X") 842 | PyCommandMacro(ndiLED, "LED:%c%d%c") 843 | PyCommandMacro(ndiBEEP, "BEEP:%i") 844 | PyCommandMacro(ndiVER, "VER:%d") 845 | PyCommandMacro(ndiVSEL, "VSEL:%d") 846 | PyCommandMacro(ndiSFLIST, "SFLIST:%02X") 847 | PyCommandMacro(ndiPSTAT, "PSTAT:%04X") 848 | PyCommandMacro(ndiSSTAT, "SSTAT:%04X") 849 | 850 | PyCommandMacro(ndiPPRD, "PPRD:%c%04X") 851 | PyCommandMacro(ndiPPWR, "PPWR:%c%04X%.128s") 852 | PyCommandMacro(ndiPURD, "PURD:%c%04X") 853 | PyCommandMacro(ndiPUWR, "PPWR:%c%04X%.128s") 854 | PyCommandMacro(ndiPSEL, "PSEL:%c%s") 855 | PyCommandMacro(ndiPSRCH, "PSRCH:%c") 856 | PyCommandMacro(ndiPVTIP, "PVTIP:%c%d%d") 857 | PyCommandMacro(ndiTCTST, "TCTST:%c") 858 | PyCommandMacro(ndiTTCFG, "TTCFG:%c") 859 | 860 | PyCommandMacro(ndiDSTART, "DSTART:") 861 | PyCommandMacro(ndiDSTOP, "DSTOP:") 862 | PyCommandMacro(ndiIRINIT, "IRINIT:") 863 | PyCommandMacro(ndiIRCHK, "IRCHK:%04X") 864 | PyCommandMacro(ndiIRED, "IRED:%c%08X") 865 | PyCommandMacro(ndi3D, "3D:%c%d") 866 | 867 | 868 | static PyObject* Py_ndiPVWRFromFile(PyObject* module, PyObject* args) 869 | { 870 | int port; 871 | int result; 872 | char* filename; 873 | ndicapi* pol; 874 | 875 | if (PyArg_ParseTuple(args, "O&is:plPVWRFromFile", 876 | &_ndiConverter, &pol, &port, &filename)) 877 | { 878 | result = ndiPVWRFromFile(pol, port, filename); 879 | return PyNDIBitfield_FromUnsignedLong(result); 880 | } 881 | 882 | return NULL; 883 | } 884 | 885 | static PyObject* Py_ndiGetGXTransform(PyObject* module, PyObject* args) 886 | { 887 | char port; 888 | int result; 889 | double transform[8]; 890 | ndicapi* pol; 891 | 892 | if (PyArg_ParseTuple(args, "O&c:plGetGXTransform", 893 | &_ndiConverter, &pol, &port)) 894 | { 895 | result = ndiGetGXTransform(pol, port, transform); 896 | 897 | if (result == NDI_MISSING) 898 | { 899 | return PyString_FromString("MISSING"); 900 | } 901 | else if (result == NDI_DISABLED) 902 | { 903 | return PyString_FromString("DISABLED"); 904 | } 905 | 906 | return Py_BuildValue("(dddddddd)", transform[0], transform[1], 907 | transform[2], transform[3], transform[4], 908 | transform[5], transform[6], transform[7]); 909 | } 910 | 911 | return NULL; 912 | } 913 | 914 | static PyObject* Py_ndiGetBXTransform(PyObject* module, PyObject* args) 915 | { 916 | char port; 917 | int result; 918 | float transform[8]; 919 | ndicapi* pol; 920 | 921 | if (PyArg_ParseTuple(args, "O&c:plGetBXTransform", 922 | &_ndiConverter, &pol, &port)) 923 | { 924 | result = ndiGetBXTransform(pol, port, transform); 925 | 926 | if (result == NDI_MISSING) 927 | { 928 | return PyString_FromString("MISSING"); 929 | } 930 | else if (result == NDI_DISABLED) 931 | { 932 | return PyString_FromString("DISABLED"); 933 | } 934 | 935 | return Py_BuildValue("(dddddddd)", transform[0], transform[1], 936 | transform[2], transform[3], transform[4], 937 | transform[5], transform[6], transform[7]); 938 | } 939 | 940 | return NULL; 941 | } 942 | 943 | static PyObject* Py_ndiGetTXTransform(PyObject* module, PyObject* args) 944 | { 945 | char port; 946 | int result; 947 | double transform[8]; 948 | ndicapi* pol; 949 | 950 | if (PyArg_ParseTuple(args, "O&c:plGetTXTransform", 951 | &_ndiConverter, &pol, &port)) 952 | { 953 | result = ndiGetTXTransform(pol, port, transform); 954 | 955 | if (result == NDI_MISSING) 956 | { 957 | return PyString_FromString("MISSING"); 958 | } 959 | else if (result == NDI_DISABLED) 960 | { 961 | return PyString_FromString("DISABLED"); 962 | } 963 | 964 | return Py_BuildValue("(dddddddd)", transform[0], transform[1], 965 | transform[2], transform[3], transform[4], 966 | transform[5], transform[6], transform[7]); 967 | } 968 | 969 | return NULL; 970 | } 971 | 972 | static PyObject* Py_ndiGetGXPortStatus(PyObject* module, PyObject* args) 973 | { 974 | char port; 975 | int result; 976 | ndicapi* pol; 977 | 978 | if (PyArg_ParseTuple(args, "O&c:plGetGXPortStatus", 979 | &_ndiConverter, &pol, &port)) 980 | { 981 | result = ndiGetGXPortStatus(pol, port); 982 | return PyNDIBitfield_FromUnsignedLong(result); 983 | } 984 | 985 | return NULL; 986 | } 987 | 988 | 989 | static PyObject* Py_ndiGetBXPortStatus(PyObject* module, PyObject* args) 990 | { 991 | char port; 992 | int result; 993 | ndicapi* pol; 994 | 995 | if (PyArg_ParseTuple(args, "O&c:plGetBXPortStatus", 996 | &_ndiConverter, &pol, &port)) 997 | { 998 | result = ndiGetBXPortStatus(pol, port); 999 | return PyNDIBitfield_FromUnsignedLong(result); 1000 | } 1001 | 1002 | return NULL; 1003 | } 1004 | 1005 | static PyObject* Py_ndiGetTXPortStatus(PyObject* module, PyObject* args) 1006 | { 1007 | char port; 1008 | int result; 1009 | ndicapi* pol; 1010 | 1011 | if (PyArg_ParseTuple(args, "O&c:plGetTXPortStatus", 1012 | &_ndiConverter, &pol, &port)) 1013 | { 1014 | result = ndiGetTXPortStatus(pol, port); 1015 | return PyNDIBitfield_FromUnsignedLong(result); 1016 | } 1017 | 1018 | return NULL; 1019 | } 1020 | 1021 | 1022 | static PyObject* Py_ndiGetGXSystemStatus(PyObject* module, PyObject* args) 1023 | { 1024 | int result; 1025 | ndicapi* pol; 1026 | 1027 | if (PyArg_ParseTuple(args, "O&:plGetGXSystemStatus", 1028 | &_ndiConverter, &pol)) 1029 | { 1030 | result = ndiGetGXSystemStatus(pol); 1031 | return PyNDIBitfield_FromUnsignedLong(result); 1032 | } 1033 | 1034 | return NULL; 1035 | } 1036 | 1037 | 1038 | static PyObject* Py_ndiGetBXSystemStatus(PyObject* module, PyObject* args) 1039 | { 1040 | int result; 1041 | ndicapi* pol; 1042 | 1043 | if (PyArg_ParseTuple(args, "O&:plGetBXSystemStatus", 1044 | &_ndiConverter, &pol)) 1045 | { 1046 | result = ndiGetBXSystemStatus(pol); 1047 | return PyNDIBitfield_FromUnsignedLong(result); 1048 | } 1049 | 1050 | return NULL; 1051 | } 1052 | 1053 | static PyObject* Py_ndiGetTXSystemStatus(PyObject* module, PyObject* args) 1054 | { 1055 | int result; 1056 | ndicapi* pol; 1057 | 1058 | if (PyArg_ParseTuple(args, "O&:plGetTXSystemStatus", 1059 | &_ndiConverter, &pol)) 1060 | { 1061 | result = ndiGetTXSystemStatus(pol); 1062 | return PyNDIBitfield_FromUnsignedLong(result); 1063 | } 1064 | 1065 | return NULL; 1066 | } 1067 | 1068 | 1069 | 1070 | static PyObject* Py_ndiGetGXToolInfo(PyObject* module, PyObject* args) 1071 | { 1072 | char port; 1073 | int result; 1074 | ndicapi* pol; 1075 | 1076 | if (PyArg_ParseTuple(args, "O&c:plGetGXToolInfo", 1077 | &_ndiConverter, &pol, &port)) 1078 | { 1079 | result = ndiGetGXToolInfo(pol, port); 1080 | return PyNDIBitfield_FromUnsignedLong(result); 1081 | } 1082 | 1083 | return NULL; 1084 | } 1085 | 1086 | static PyObject* Py_ndiGetGXMarkerInfo(PyObject* module, PyObject* args) 1087 | { 1088 | char port; 1089 | char marker; 1090 | int result; 1091 | ndicapi* pol; 1092 | 1093 | if (PyArg_ParseTuple(args, "O&ci:plGetGXMarkerInfo", 1094 | &_ndiConverter, &pol, &port, &marker)) 1095 | { 1096 | result = ndiGetGXMarkerInfo(pol, port, marker); 1097 | return PyNDIBitfield_FromUnsignedLong(result); 1098 | } 1099 | 1100 | return NULL; 1101 | } 1102 | 1103 | static PyObject* Py_ndiGetGXSingleStray(PyObject* module, PyObject* args) 1104 | { 1105 | char port; 1106 | int result; 1107 | double coord[3]; 1108 | ndicapi* pol; 1109 | 1110 | if (PyArg_ParseTuple(args, "O&c:plGetGXSingleStray", 1111 | &_ndiConverter, &pol, &port)) 1112 | { 1113 | result = ndiGetGXSingleStray(pol, port, coord); 1114 | 1115 | if (result == NDI_MISSING) 1116 | { 1117 | return PyString_FromString("MISSING"); 1118 | } 1119 | else if (result == NDI_DISABLED) 1120 | { 1121 | return PyString_FromString("DISABLED"); 1122 | } 1123 | 1124 | return Py_BuildValue("(ddd)", coord[0], coord[1], coord[2]); 1125 | } 1126 | 1127 | return NULL; 1128 | } 1129 | 1130 | static PyObject* Py_ndiGetGXFrame(PyObject* module, PyObject* args) 1131 | { 1132 | char port; 1133 | unsigned long result; 1134 | ndicapi* pol; 1135 | 1136 | if (PyArg_ParseTuple(args, "O&c:plGetGXFrame", 1137 | &_ndiConverter, &pol, &port)) 1138 | { 1139 | result = ndiGetGXFrame(pol, port); 1140 | return PyLong_FromUnsignedLong(result); 1141 | } 1142 | 1143 | return NULL; 1144 | } 1145 | 1146 | static PyObject* Py_ndiGetBXFrame(PyObject* module, PyObject* args) 1147 | { 1148 | char port; 1149 | unsigned long result; 1150 | ndicapi* pol; 1151 | 1152 | if (PyArg_ParseTuple(args, "O&c:plGetBXFrame", 1153 | &_ndiConverter, &pol, &port)) 1154 | { 1155 | result = ndiGetBXFrame(pol, port); 1156 | return PyLong_FromUnsignedLong(result); 1157 | } 1158 | 1159 | return NULL; 1160 | } 1161 | 1162 | static PyObject* Py_ndiGetTXFrame(PyObject* module, PyObject* args) 1163 | { 1164 | char port; 1165 | unsigned long result; 1166 | ndicapi* pol; 1167 | 1168 | if (PyArg_ParseTuple(args, "O&c:plGetTXFrame", 1169 | &_ndiConverter, &pol, &port)) 1170 | { 1171 | result = ndiGetTXFrame(pol, port); 1172 | return PyLong_FromUnsignedLong(result); 1173 | } 1174 | 1175 | return NULL; 1176 | } 1177 | 1178 | 1179 | static PyObject* Py_ndiGetGXNumberOfPassiveStrays(PyObject* module, 1180 | PyObject* args) 1181 | { 1182 | int result; 1183 | ndicapi* pol; 1184 | 1185 | if (PyArg_ParseTuple(args, "O&:plGetGXNumberOfPassiveStrays", 1186 | &_ndiConverter, &pol)) 1187 | { 1188 | result = ndiGetGXNumberOfPassiveStrays(pol); 1189 | return PyInt_FromLong(result); 1190 | } 1191 | 1192 | return NULL; 1193 | } 1194 | 1195 | static PyObject* Py_ndiGetGXPassiveStray(PyObject* module, PyObject* args) 1196 | { 1197 | int result; 1198 | int i; 1199 | double coord[3]; 1200 | ndicapi* pol; 1201 | 1202 | if (PyArg_ParseTuple(args, "O&i:plGetGXPassiveStray", 1203 | &_ndiConverter, &pol, &i)) 1204 | { 1205 | result = ndiGetGXPassiveStray(pol, i, coord); 1206 | 1207 | if (result == NDI_MISSING) 1208 | { 1209 | return PyString_FromString("MISSING"); 1210 | } 1211 | else if (result == NDI_DISABLED) 1212 | { 1213 | return PyString_FromString("DISABLED"); 1214 | } 1215 | 1216 | return Py_BuildValue("(ddd)", coord[0], coord[1], coord[2]); 1217 | } 1218 | 1219 | return NULL; 1220 | } 1221 | 1222 | static PyObject* Py_ndiGetPSTATPortStatus(PyObject* module, PyObject* args) 1223 | { 1224 | char port; 1225 | int result; 1226 | ndicapi* pol; 1227 | 1228 | if (PyArg_ParseTuple(args, "O&c:plGetPSTATPortStatus", 1229 | &_ndiConverter, &pol, &port)) 1230 | { 1231 | result = ndiGetPSTATPortStatus(pol, port); 1232 | return PyNDIBitfield_FromUnsignedLong(result); 1233 | } 1234 | 1235 | return NULL; 1236 | } 1237 | 1238 | static PyObject* Py_ndiGetPSTATToolInfo(PyObject* module, PyObject* args) 1239 | { 1240 | char port; 1241 | char result[30]; 1242 | ndicapi* pol; 1243 | 1244 | if (PyArg_ParseTuple(args, "O&c:plGetPSTATToolInfo", 1245 | &_ndiConverter, &pol, &port)) 1246 | { 1247 | if (ndiGetPSTATToolInfo(pol, port, result) != NDI_UNOCCUPIED) 1248 | { 1249 | return PyString_FromStringAndSize(result, 30); 1250 | } 1251 | return PyString_FromString("UNOCCUPIED"); 1252 | } 1253 | 1254 | return NULL; 1255 | } 1256 | 1257 | static PyObject* Py_ndiGetPSTATCurrentTest(PyObject* module, PyObject* args) 1258 | { 1259 | char port; 1260 | unsigned long result; 1261 | ndicapi* pol; 1262 | 1263 | if (PyArg_ParseTuple(args, "O&c:plGetPSTATCurrentTest", 1264 | &_ndiConverter, &pol, &port)) 1265 | { 1266 | result = ndiGetPSTATCurrentTest(pol, port); 1267 | return PyLong_FromUnsignedLong(result); 1268 | } 1269 | 1270 | return NULL; 1271 | } 1272 | 1273 | static PyObject* Py_ndiGetPSTATPartNumber(PyObject* module, PyObject* args) 1274 | { 1275 | char port; 1276 | char result[20]; 1277 | ndicapi* pol; 1278 | 1279 | if (PyArg_ParseTuple(args, "O&c:plGetPSTATPartNumber", 1280 | &_ndiConverter, &pol, &port)) 1281 | { 1282 | if (ndiGetPSTATPartNumber(pol, port, result) != NDI_OKAY) 1283 | { 1284 | Py_INCREF(Py_None); 1285 | return Py_None; 1286 | } 1287 | return PyString_FromStringAndSize(result, 20); 1288 | } 1289 | 1290 | return NULL; 1291 | } 1292 | 1293 | static PyObject* Py_ndiGetPSTATAccessories(PyObject* module, PyObject* args) 1294 | { 1295 | char port; 1296 | int result; 1297 | ndicapi* pol; 1298 | 1299 | if (PyArg_ParseTuple(args, "O&c:plGetPSTATAccessories", 1300 | &_ndiConverter, &pol, &port)) 1301 | { 1302 | result = ndiGetPSTATAccessories(pol, port); 1303 | return PyNDIBitfield_FromUnsignedLong(result); 1304 | } 1305 | 1306 | return NULL; 1307 | } 1308 | 1309 | static PyObject* Py_ndiGetPSTATMarkerType(PyObject* module, PyObject* args) 1310 | { 1311 | char port; 1312 | int result; 1313 | ndicapi* pol; 1314 | 1315 | if (PyArg_ParseTuple(args, "O&c:plGetPSTATMarkerType", 1316 | &_ndiConverter, &pol, &port)) 1317 | { 1318 | result = ndiGetPSTATMarkerType(pol, port); 1319 | return PyNDIBitfield_FromUnsignedLong(result); 1320 | } 1321 | 1322 | return NULL; 1323 | } 1324 | 1325 | static PyObject* Py_ndiGetSSTATControl(PyObject* module, PyObject* args) 1326 | { 1327 | int result; 1328 | ndicapi* pol; 1329 | 1330 | if (PyArg_ParseTuple(args, "O&:plGetSSTATControl", 1331 | &_ndiConverter, &pol)) 1332 | { 1333 | result = ndiGetSSTATControl(pol); 1334 | return PyNDIBitfield_FromUnsignedLong(result); 1335 | } 1336 | 1337 | return NULL; 1338 | } 1339 | 1340 | static PyObject* Py_ndiGetSSTATSensors(PyObject* module, PyObject* args) 1341 | { 1342 | int result; 1343 | ndicapi* pol; 1344 | 1345 | if (PyArg_ParseTuple(args, "O&:plGetSSTATSensors", 1346 | &_ndiConverter, &pol)) 1347 | { 1348 | result = ndiGetSSTATSensors(pol); 1349 | return PyNDIBitfield_FromUnsignedLong(result); 1350 | } 1351 | 1352 | return NULL; 1353 | } 1354 | 1355 | static PyObject* Py_ndiGetSSTATTIU(PyObject* module, PyObject* args) 1356 | { 1357 | int result; 1358 | ndicapi* pol; 1359 | 1360 | if (PyArg_ParseTuple(args, "O&:plGetSSTATTIU", 1361 | &_ndiConverter, &pol)) 1362 | { 1363 | result = ndiGetSSTATTIU(pol); 1364 | return PyNDIBitfield_FromUnsignedLong(result); 1365 | } 1366 | 1367 | return NULL; 1368 | } 1369 | 1370 | static PyObject* Py_ndiGetIRCHKDetected(PyObject* module, PyObject* args) 1371 | { 1372 | int result; 1373 | ndicapi* pol; 1374 | 1375 | if (PyArg_ParseTuple(args, "O&:plGetIRCHKDetected", 1376 | &_ndiConverter, &pol)) 1377 | { 1378 | result = ndiGetIRCHKDetected(pol); 1379 | return PyNDIBitfield_FromUnsignedLong(result); 1380 | } 1381 | 1382 | return NULL; 1383 | } 1384 | 1385 | static PyObject* Py_ndiGetIRCHKNumberOfSources(PyObject* module, PyObject* args) 1386 | { 1387 | int result; 1388 | int side; 1389 | ndicapi* pol; 1390 | 1391 | if (PyArg_ParseTuple(args, "O&i:plGetIRCHKNumberOfSources", 1392 | &_ndiConverter, &pol, &side)) 1393 | { 1394 | result = ndiGetIRCHKNumberOfSources(pol, side); 1395 | return PyInt_FromLong(result); 1396 | } 1397 | 1398 | return NULL; 1399 | } 1400 | 1401 | static PyObject* Py_ndiGetIRCHKSourceXY(PyObject* module, PyObject* args) 1402 | { 1403 | int result; 1404 | int side; 1405 | int i; 1406 | double xy[2]; 1407 | ndicapi* pol; 1408 | 1409 | if (PyArg_ParseTuple(args, "O&ii:plGetIRCHKSourceXY", 1410 | &_ndiConverter, &pol, &side, &i)) 1411 | { 1412 | result = ndiGetIRCHKSourceXY(pol, side, i, xy); 1413 | if (result != NDI_OKAY) 1414 | { 1415 | Py_INCREF(Py_None); 1416 | return Py_None; 1417 | } 1418 | return Py_BuildValue("(ff)", xy[0], xy[1]); 1419 | } 1420 | 1421 | return NULL; 1422 | } 1423 | 1424 | static PyObject* Py_ndiGetPHRQHandle (PyObject* module, PyObject* args) 1425 | { 1426 | int result; 1427 | ndicapi* pol; 1428 | 1429 | if (PyArg_ParseTuple(args, "O&:plGetPHRQHandle", 1430 | &_ndiConverter, &pol)) 1431 | { 1432 | result = ndiGetPHRQHandle(pol); 1433 | return PyInt_FromLong(result); 1434 | } 1435 | return NULL; 1436 | } 1437 | 1438 | static PyObject* Py_ndiGetPHSRNumberOfHandles (PyObject* module, PyObject* args) 1439 | { 1440 | int result; 1441 | ndicapi* pol; 1442 | 1443 | if (PyArg_ParseTuple(args, "O&:plGetPHSRNumberOfHandles", 1444 | &_ndiConverter, &pol)) 1445 | { 1446 | result = ndiGetPHSRNumberOfHandles(pol); 1447 | return PyInt_FromLong(result); 1448 | } 1449 | return NULL; 1450 | } 1451 | 1452 | static PyObject* Py_ndiGetPHSRHandle (PyObject* module, PyObject* args) 1453 | { 1454 | int result; 1455 | ndicapi* pol; 1456 | int i; 1457 | 1458 | if (PyArg_ParseTuple(args, "O&i:plGetPHSRHandle", 1459 | &_ndiConverter, &pol, &i)) 1460 | { 1461 | result = ndiGetPHSRHandle(pol,i); 1462 | return PyInt_FromLong(result); 1463 | } 1464 | return NULL; 1465 | } 1466 | 1467 | static PyObject* Py_ndiRelativeTransform(PyObject* module, PyObject* args) 1468 | { 1469 | double a[8]; 1470 | double b[8]; 1471 | 1472 | if (PyArg_ParseTuple(args, "(dddddddd)(dddddddd):ndiRelativeTransform", 1473 | &a[0], &a[1], &a[2], &a[3], 1474 | &a[4], &a[5], &a[6], &a[7], 1475 | &b[0], &b[1], &b[2], &b[3], 1476 | &b[4], &b[5], &b[6], &b[7])) 1477 | { 1478 | ndiRelativeTransform(a, b, a); 1479 | 1480 | return Py_BuildValue("(dddddddd)", a[0], a[1], a[2], a[3], 1481 | a[4], a[5], a[6], a[7]); 1482 | } 1483 | 1484 | return NULL; 1485 | } 1486 | 1487 | static PyObject* Py_ndiTransformToMatrixd(PyObject* module, PyObject* args) 1488 | { 1489 | double a[8]; 1490 | double c[16]; 1491 | 1492 | if (PyArg_ParseTuple(args, "(dddddddd):ndiTransformToMatrixd", 1493 | &a[0], &a[1], &a[2], &a[3], 1494 | &a[4], &a[5], &a[6], &a[7])) 1495 | { 1496 | ndiTransformToMatrixd(a, c); 1497 | 1498 | return Py_BuildValue("(dddddddddddddddd)", 1499 | c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], 1500 | c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); 1501 | } 1502 | 1503 | return NULL; 1504 | } 1505 | 1506 | static PyObject* Py_ndiTransformToMatrixf(PyObject* module, PyObject* args) 1507 | { 1508 | float a[8]; 1509 | float c[16]; 1510 | 1511 | if (PyArg_ParseTuple(args, "(ffffffff):ndiTransformToMatrixf", 1512 | &a[0], &a[1], &a[2], &a[3], 1513 | &a[4], &a[5], &a[6], &a[7])) 1514 | { 1515 | ndiTransformToMatrixf(a, c); 1516 | 1517 | return Py_BuildValue("(ffffffffffffffff)", 1518 | c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], 1519 | c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); 1520 | } 1521 | 1522 | return NULL; 1523 | } 1524 | 1525 | static PyObject* Py_ndiAnglesFromMatrixd(PyObject* module, PyObject* args) 1526 | { 1527 | double a[16]; 1528 | double c[3]; 1529 | 1530 | if (PyArg_ParseTuple(args, "(dddddddddddddddd):ndiAnglesFromMatrixd", 1531 | &a[0], &a[1], &a[2], &a[3], 1532 | &a[4], &a[5], &a[6], &a[7], 1533 | &a[8], &a[9], &a[10], &a[11], 1534 | &a[12], &a[13], &a[14], &a[15])) 1535 | { 1536 | ndiAnglesFromMatrixd(c, a); 1537 | 1538 | return Py_BuildValue("(ddd)", c[0], c[1], c[2]); 1539 | } 1540 | 1541 | return NULL; 1542 | } 1543 | 1544 | static PyObject* Py_ndiAnglesFromMatrixf(PyObject* module, PyObject* args) 1545 | { 1546 | float a[16]; 1547 | float c[3]; 1548 | 1549 | if (PyArg_ParseTuple(args, "(ffffffffffffffff):ndiAnglesFromMatrixf", 1550 | &a[0], &a[1], &a[2], &a[3], 1551 | &a[4], &a[5], &a[6], &a[7], 1552 | &a[8], &a[9], &a[10], &a[11], 1553 | &a[12], &a[13], &a[14], &a[15])) 1554 | { 1555 | ndiAnglesFromMatrixf(c, a); 1556 | 1557 | return Py_BuildValue("(fff)", c[0], c[1], c[2]); 1558 | } 1559 | 1560 | return NULL; 1561 | } 1562 | 1563 | static PyObject* Py_ndiCoordsFromMatrixd(PyObject* module, PyObject* args) 1564 | { 1565 | double a[16]; 1566 | double c[3]; 1567 | 1568 | if (PyArg_ParseTuple(args, "(dddddddddddddddd):ndiCoordsFromMatrixd", 1569 | &a[0], &a[1], &a[2], &a[3], 1570 | &a[4], &a[5], &a[6], &a[7], 1571 | &a[8], &a[9], &a[10], &a[11], 1572 | &a[12], &a[13], &a[14], &a[15])) 1573 | { 1574 | ndiCoordsFromMatrixd(c, a); 1575 | 1576 | return Py_BuildValue("(ddd)", c[0], c[1], c[2]); 1577 | } 1578 | 1579 | return NULL; 1580 | } 1581 | 1582 | static PyObject* Py_ndiCoordsFromMatrixf(PyObject* module, PyObject* args) 1583 | { 1584 | float a[16]; 1585 | float c[3]; 1586 | 1587 | if (PyArg_ParseTuple(args, "(ffffffffffffffff):ndiCoordsFromMatrixf", 1588 | &a[0], &a[1], &a[2], &a[3], 1589 | &a[4], &a[5], &a[6], &a[7], 1590 | &a[8], &a[9], &a[10], &a[11], 1591 | &a[12], &a[13], &a[14], &a[15])) 1592 | { 1593 | ndiCoordsFromMatrixf(c, a); 1594 | 1595 | return Py_BuildValue("(fff)", c[0], c[1], c[2]); 1596 | } 1597 | 1598 | return NULL; 1599 | } 1600 | 1601 | /*================================================================= 1602 | Module definition 1603 | */ 1604 | #define Py_NDIMethodMacro(name) {#name, Py_##name, METH_VARARGS} 1605 | 1606 | static PyMethodDef NdicapiMethods[] = 1607 | { 1608 | Py_NDIMethodMacro(ndiHexToUnsignedLong), 1609 | Py_NDIMethodMacro(ndiSignedToLong), 1610 | Py_NDIMethodMacro(ndiHexEncode), 1611 | Py_NDIMethodMacro(ndiHexDecode), 1612 | 1613 | Py_NDIMethodMacro(ndiDeviceName), 1614 | Py_NDIMethodMacro(ndiProbe), 1615 | Py_NDIMethodMacro(ndiOpen), 1616 | Py_NDIMethodMacro(ndiOpenNetwork), 1617 | Py_NDIMethodMacro(ndiGetDeviceName), 1618 | Py_NDIMethodMacro(ndiClose), 1619 | Py_NDIMethodMacro(ndiCloseNetwork), 1620 | Py_NDIMethodMacro(ndiSetThreadMode), 1621 | Py_NDIMethodMacro(ndiCommand), 1622 | 1623 | Py_NDIMethodMacro(ndiGetError), 1624 | Py_NDIMethodMacro(ndiErrorString), 1625 | 1626 | Py_NDIMethodMacro(ndiRESET), 1627 | Py_NDIMethodMacro(ndiINIT), 1628 | Py_NDIMethodMacro(ndiCOMM), 1629 | 1630 | Py_NDIMethodMacro(ndiPVWRFromFile), 1631 | 1632 | Py_NDIMethodMacro(ndiPVWR), 1633 | Py_NDIMethodMacro(ndiPVCLR), 1634 | Py_NDIMethodMacro(ndiPINIT), 1635 | Py_NDIMethodMacro(ndiPENA), 1636 | Py_NDIMethodMacro(ndiPDIS), 1637 | Py_NDIMethodMacro(ndiTSTART), 1638 | Py_NDIMethodMacro(ndiTSTOP), 1639 | Py_NDIMethodMacro(ndiGX), 1640 | 1641 | Py_NDIMethodMacro(ndiGetGXTransform), 1642 | Py_NDIMethodMacro(ndiGetGXPortStatus), 1643 | Py_NDIMethodMacro(ndiGetGXSystemStatus), 1644 | Py_NDIMethodMacro(ndiGetGXToolInfo), 1645 | Py_NDIMethodMacro(ndiGetGXMarkerInfo), 1646 | Py_NDIMethodMacro(ndiGetGXSingleStray), 1647 | Py_NDIMethodMacro(ndiGetGXFrame), 1648 | Py_NDIMethodMacro(ndiGetGXNumberOfPassiveStrays), 1649 | Py_NDIMethodMacro(ndiGetGXPassiveStray), 1650 | 1651 | Py_NDIMethodMacro(ndiBX), 1652 | 1653 | Py_NDIMethodMacro(ndiGetBXTransform), 1654 | Py_NDIMethodMacro(ndiGetBXPortStatus), 1655 | Py_NDIMethodMacro(ndiGetBXSystemStatus), 1656 | //Py_NDIMethodMacro(ndiGetBXToolInfo), 1657 | //Py_NDIMethodMacro(ndiGetBXMarkerInfo), 1658 | //Py_NDIMethodMacro(ndiGetBXSingleStray), 1659 | Py_NDIMethodMacro(ndiGetBXFrame), 1660 | //Py_NDIMethodMacro(ndiGetBXNumberOfPassiveStrays), 1661 | //Py_NDIMethodMacro(ndiGetBXPassiveStray), 1662 | 1663 | Py_NDIMethodMacro(ndiTX), 1664 | 1665 | Py_NDIMethodMacro(ndiGetTXTransform), 1666 | Py_NDIMethodMacro(ndiGetTXPortStatus), 1667 | Py_NDIMethodMacro(ndiGetTXSystemStatus), 1668 | //Py_NDIMethodMacro(ndiGetTXToolInfo), 1669 | //Py_NDIMethodMacro(ndiGetTXMarkerInfo), 1670 | //Py_NDIMethodMacro(ndiGetTXSingleStray), 1671 | Py_NDIMethodMacro(ndiGetTXFrame), 1672 | //Py_NDIMethodMacro(ndiGetTXNumberOfPassiveStrays), 1673 | //Py_NDIMethodMacro(ndiGetTXPassiveStray), 1674 | 1675 | 1676 | Py_NDIMethodMacro(ndiLED), 1677 | Py_NDIMethodMacro(ndiBEEP), 1678 | Py_NDIMethodMacro(ndiVER), 1679 | Py_NDIMethodMacro(ndiSFLIST), 1680 | Py_NDIMethodMacro(ndiVSEL), 1681 | Py_NDIMethodMacro(ndiPSTAT), 1682 | 1683 | Py_NDIMethodMacro(ndiGetPSTATPortStatus), 1684 | Py_NDIMethodMacro(ndiGetPSTATToolInfo), 1685 | Py_NDIMethodMacro(ndiGetPSTATCurrentTest), 1686 | Py_NDIMethodMacro(ndiGetPSTATPartNumber), 1687 | Py_NDIMethodMacro(ndiGetPSTATAccessories), 1688 | Py_NDIMethodMacro(ndiGetPSTATMarkerType), 1689 | 1690 | Py_NDIMethodMacro(ndiSSTAT), 1691 | 1692 | Py_NDIMethodMacro(ndiGetSSTATControl), 1693 | Py_NDIMethodMacro(ndiGetSSTATSensors), 1694 | Py_NDIMethodMacro(ndiGetSSTATTIU), 1695 | 1696 | Py_NDIMethodMacro(ndiPPRD), 1697 | Py_NDIMethodMacro(ndiPPWR), 1698 | Py_NDIMethodMacro(ndiPURD), 1699 | Py_NDIMethodMacro(ndiPUWR), 1700 | Py_NDIMethodMacro(ndiPSEL), 1701 | Py_NDIMethodMacro(ndiPSRCH), 1702 | Py_NDIMethodMacro(ndiPVTIP), 1703 | Py_NDIMethodMacro(ndiTCTST), 1704 | Py_NDIMethodMacro(ndiTTCFG), 1705 | 1706 | Py_NDIMethodMacro(ndiDSTART), 1707 | Py_NDIMethodMacro(ndiDSTOP), 1708 | Py_NDIMethodMacro(ndiIRINIT), 1709 | Py_NDIMethodMacro(ndiIRCHK), 1710 | 1711 | Py_NDIMethodMacro(ndiGetIRCHKDetected), 1712 | Py_NDIMethodMacro(ndiGetIRCHKNumberOfSources), 1713 | Py_NDIMethodMacro(ndiGetIRCHKSourceXY), 1714 | 1715 | Py_NDIMethodMacro(ndiGetPHRQHandle), 1716 | Py_NDIMethodMacro(ndiGetPHSRNumberOfHandles), 1717 | Py_NDIMethodMacro(ndiGetPHSRHandle), 1718 | 1719 | Py_NDIMethodMacro(ndiIRED), 1720 | Py_NDIMethodMacro(ndi3D), 1721 | 1722 | Py_NDIMethodMacro(ndiRelativeTransform), 1723 | Py_NDIMethodMacro(ndiTransformToMatrixd), 1724 | Py_NDIMethodMacro(ndiTransformToMatrixf), 1725 | Py_NDIMethodMacro(ndiAnglesFromMatrixd), 1726 | Py_NDIMethodMacro(ndiAnglesFromMatrixf), 1727 | Py_NDIMethodMacro(ndiCoordsFromMatrixd), 1728 | Py_NDIMethodMacro(ndiCoordsFromMatrixf), 1729 | 1730 | {NULL, NULL} 1731 | }; 1732 | 1733 | #ifdef __cplusplus 1734 | extern "C" { 1735 | #endif 1736 | 1737 | #define Py_NDIBitfieldMacro(a) \ 1738 | PyDict_SetItemString(dict, #a, PyNDIBitfield_FromUnsignedLong(a)) 1739 | #define Py_NDIConstantMacro(a) \ 1740 | PyDict_SetItemString(dict, #a, PyInt_FromLong(a)) 1741 | #define Py_NDIErrcodeMacro(a) \ 1742 | PyDict_SetItemString(dict, #a, PyNDIBitfield_FromUnsignedLong(a)) 1743 | #define Py_NDICharMacro(a) \ 1744 | PyDict_SetItemString(dict, #a, _PyString_FromChar(a)) 1745 | 1746 | ndicapiExport MOD_INIT(ndicapy) 1747 | { 1748 | PyObject* module = NULL; 1749 | PyObject* dict = NULL; 1750 | 1751 | #if PY_MAJOR_VERSION <= 2 1752 | PyNdicapiType.ob_type = &PyType_Type; 1753 | PyNDIBitfield_Type.ob_type = &PyType_Type; 1754 | #else 1755 | #if PY_MINOR_VERSION < 11 1756 | Py_TYPE(&PyNdicapiType) = &PyType_Type; 1757 | Py_TYPE(&PyNDIBitfield_Type) = &PyType_Type; 1758 | #else 1759 | Py_SET_TYPE(&PyNdicapiType, &PyType_Type); 1760 | Py_SET_TYPE(&PyNDIBitfield_Type, &PyType_Type); 1761 | #endif 1762 | #endif 1763 | 1764 | MOD_DEF(module, "ndicapy", NULL, NdicapiMethods); 1765 | if (module == NULL) 1766 | return MOD_ERROR_VAL; 1767 | dict = PyModule_GetDict(module); 1768 | if (dict == NULL) 1769 | return MOD_ERROR_VAL; 1770 | 1771 | Py_NDIConstantMacro(NDICAPI_MAJOR_VERSION); 1772 | Py_NDIConstantMacro(NDICAPI_MINOR_VERSION); 1773 | 1774 | Py_NDIConstantMacro(NDI_OKAY); 1775 | 1776 | Py_NDIErrcodeMacro(NDI_INVALID); 1777 | Py_NDIErrcodeMacro(NDI_TOO_LONG); 1778 | Py_NDIErrcodeMacro(NDI_TOO_SHORT); 1779 | Py_NDIErrcodeMacro(NDI_BAD_COMMAND_CRC); 1780 | Py_NDIErrcodeMacro(NDI_INTERN_TIMEOUT); 1781 | Py_NDIErrcodeMacro(NDI_COMM_FAIL); 1782 | Py_NDIErrcodeMacro(NDI_PARAMETERS); 1783 | Py_NDIErrcodeMacro(NDI_INVALID_PORT); 1784 | Py_NDIErrcodeMacro(NDI_INVALID_MODE); 1785 | Py_NDIErrcodeMacro(NDI_INVALID_LED); 1786 | Py_NDIErrcodeMacro(NDI_LED_STATE); 1787 | Py_NDIErrcodeMacro(NDI_BAD_MODE); 1788 | Py_NDIErrcodeMacro(NDI_NO_TOOL); 1789 | Py_NDIErrcodeMacro(NDI_PORT_NOT_INIT); 1790 | Py_NDIErrcodeMacro(NDI_PORT_DISABLED); 1791 | Py_NDIErrcodeMacro(NDI_INITIALIZATION); 1792 | Py_NDIErrcodeMacro(NDI_TSTOP_FAIL); 1793 | Py_NDIErrcodeMacro(NDI_TSTART_FAIL); 1794 | Py_NDIErrcodeMacro(NDI_PINIT_FAIL); 1795 | Py_NDIErrcodeMacro(NDI_INVALID_PS_PARAM); 1796 | Py_NDIErrcodeMacro(NDI_INIT_FAIL); 1797 | Py_NDIErrcodeMacro(NDI_DSTART_FAIL); 1798 | Py_NDIErrcodeMacro(NDI_DSTOP_FAIL); 1799 | Py_NDIErrcodeMacro(NDI_RESERVED18); 1800 | Py_NDIErrcodeMacro(NDI_FIRMWARE_VER); 1801 | Py_NDIErrcodeMacro(NDI_INTERNAL); 1802 | Py_NDIErrcodeMacro(NDI_RESERVED1B); 1803 | Py_NDIErrcodeMacro(NDI_IRED_FAIL); 1804 | Py_NDIErrcodeMacro(NDI_RESERVED1D); 1805 | Py_NDIErrcodeMacro(NDI_SROM_READ); 1806 | Py_NDIErrcodeMacro(NDI_SROM_WRITE); 1807 | Py_NDIErrcodeMacro(NDI_RESERVED20); 1808 | Py_NDIErrcodeMacro(NDI_PORT_CURRENT); 1809 | Py_NDIErrcodeMacro(NDI_WAVELENGTH); 1810 | Py_NDIErrcodeMacro(NDI_PARAMETER_RANGE); 1811 | Py_NDIErrcodeMacro(NDI_VOLUME); 1812 | Py_NDIErrcodeMacro(NDI_FEATURES); 1813 | Py_NDIErrcodeMacro(NDI_RESERVED26); 1814 | Py_NDIErrcodeMacro(NDI_RESERVED27); 1815 | Py_NDIErrcodeMacro(NDI_TOO_MANY_TOOLS); 1816 | Py_NDIErrcodeMacro(NDI_RESERVED29); 1817 | Py_NDIErrcodeMacro(NDI_HEAP_FULL); 1818 | Py_NDIErrcodeMacro(NDI_HANDLE_NOT_ALLOC); 1819 | Py_NDIErrcodeMacro(NDI_HANDLE_EMPTY); 1820 | Py_NDIErrcodeMacro(NDI_HANDLES_FULL); 1821 | Py_NDIErrcodeMacro(NDI_INCOMP_FIRM_VER); 1822 | Py_NDIErrcodeMacro(NDI_INV_PORT_DESC); 1823 | Py_NDIErrcodeMacro(NDI_PORT_HAS_HANDLE); 1824 | Py_NDIErrcodeMacro(NDI_RESERVED31); 1825 | Py_NDIErrcodeMacro(NDI_INVALID_OP); 1826 | Py_NDIErrcodeMacro(NDI_NO_FEATURE); 1827 | Py_NDIErrcodeMacro(NDI_NO_USER_PARAM); 1828 | Py_NDIErrcodeMacro(NDI_BAD_VALUE); 1829 | Py_NDIErrcodeMacro(NDI_USER_PARAM_VALUE_RANGE); 1830 | Py_NDIErrcodeMacro(NDI_USER_PARAM_INDEX_RANGE); 1831 | Py_NDIErrcodeMacro(NDI_BAD_USER_PARAM_SIZE); 1832 | Py_NDIErrcodeMacro(NDI_PERM_DENIED); 1833 | Py_NDIErrcodeMacro(NDI_RESERVED3A); 1834 | Py_NDIErrcodeMacro(NDI_FILE_NOT_FOUND); 1835 | Py_NDIErrcodeMacro(NDI_FERR_WRITE); 1836 | Py_NDIErrcodeMacro(NDI_FERR_READ); 1837 | Py_NDIErrcodeMacro(NDI_RESERVED3E); 1838 | Py_NDIErrcodeMacro(NDI_RESERVED3F); 1839 | Py_NDIErrcodeMacro(NDI_DEF_FILE_ERR); 1840 | Py_NDIErrcodeMacro(NDI_BAD_CHARACTERISTICS); 1841 | Py_NDIErrcodeMacro(NDI_NO_DEVICE); 1842 | 1843 | Py_NDIErrcodeMacro(NDI_ENVIRONMENT); 1844 | 1845 | //Py_NDIErrcodeMacro(NDI_EPROM_READ); 1846 | //Py_NDIErrcodeMacro(NDI_EPROM_WRITE); 1847 | //Py_NDIErrcodeMacro(NDI_EPROM_ERASE); 1848 | 1849 | Py_NDIErrcodeMacro(NDI_BAD_CRC); 1850 | Py_NDIErrcodeMacro(NDI_OPEN_ERROR); 1851 | Py_NDIErrcodeMacro(NDI_BAD_COMM); 1852 | Py_NDIErrcodeMacro(NDI_TIMEOUT); 1853 | Py_NDIErrcodeMacro(NDI_WRITE_ERROR); 1854 | Py_NDIErrcodeMacro(NDI_READ_ERROR); 1855 | Py_NDIErrcodeMacro(NDI_PROBE_FAIL); 1856 | 1857 | Py_NDIConstantMacro(NDI_9600); 1858 | Py_NDIConstantMacro(NDI_14400); 1859 | Py_NDIConstantMacro(NDI_19200); 1860 | Py_NDIConstantMacro(NDI_38400); 1861 | Py_NDIConstantMacro(NDI_57600); 1862 | Py_NDIConstantMacro(NDI_115200); 1863 | Py_NDIConstantMacro(NDI_921600); 1864 | Py_NDIConstantMacro(NDI_1228739); 1865 | Py_NDIConstantMacro(NDI_230400); 1866 | 1867 | Py_NDIConstantMacro(NDI_8N1); 1868 | Py_NDIConstantMacro(NDI_8N2); 1869 | Py_NDIConstantMacro(NDI_8O1); 1870 | Py_NDIConstantMacro(NDI_8O2); 1871 | Py_NDIConstantMacro(NDI_8E1); 1872 | Py_NDIConstantMacro(NDI_8E2); 1873 | Py_NDIConstantMacro(NDI_7N1); 1874 | Py_NDIConstantMacro(NDI_7N2); 1875 | Py_NDIConstantMacro(NDI_7O1); 1876 | Py_NDIConstantMacro(NDI_7O2); 1877 | Py_NDIConstantMacro(NDI_7E1); 1878 | Py_NDIConstantMacro(NDI_7E2); 1879 | 1880 | Py_NDIConstantMacro(NDI_NOHANDSHAKE); 1881 | Py_NDIConstantMacro(NDI_HANDSHAKE); 1882 | 1883 | Py_NDICharMacro(NDI_STATIC); 1884 | Py_NDICharMacro(NDI_DYNAMIC); 1885 | Py_NDICharMacro(NDI_BUTTON_BOX); 1886 | 1887 | Py_NDIBitfieldMacro(NDI_XFORMS_AND_STATUS); 1888 | Py_NDIBitfieldMacro(NDI_ADDITIONAL_INFO); 1889 | Py_NDIBitfieldMacro(NDI_SINGLE_STRAY); 1890 | Py_NDIBitfieldMacro(NDI_FRAME_NUMBER); 1891 | Py_NDIBitfieldMacro(NDI_PASSIVE); 1892 | Py_NDIBitfieldMacro(NDI_PASSIVE_EXTRA); 1893 | Py_NDIBitfieldMacro(NDI_PASSIVE_STRAY); 1894 | 1895 | Py_NDIConstantMacro(NDI_DISABLED); 1896 | Py_NDIConstantMacro(NDI_MISSING); 1897 | 1898 | Py_NDIBitfieldMacro(NDI_TOOL_IN_PORT); 1899 | Py_NDIBitfieldMacro(NDI_SWITCH_1_ON); 1900 | Py_NDIBitfieldMacro(NDI_SWITCH_2_ON); 1901 | Py_NDIBitfieldMacro(NDI_SWITCH_3_ON); 1902 | Py_NDIBitfieldMacro(NDI_INITIALIZED); 1903 | Py_NDIBitfieldMacro(NDI_ENABLED); 1904 | Py_NDIBitfieldMacro(NDI_OUT_OF_VOLUME); 1905 | Py_NDIBitfieldMacro(NDI_PARTIALLY_IN_VOLUME); 1906 | Py_NDIBitfieldMacro(NDI_CURRENT_DETECT); 1907 | 1908 | Py_NDIBitfieldMacro(NDI_COMM_SYNC_ERROR); 1909 | Py_NDIBitfieldMacro(NDI_TOO_MUCH_EXTERNAL_INFRARED); 1910 | Py_NDIBitfieldMacro(NDI_COMM_CRC_ERROR); 1911 | 1912 | Py_NDIBitfieldMacro(NDI_BAD_TRANSFORM_FIT); 1913 | Py_NDIBitfieldMacro(NDI_NOT_ENOUGH_MARKERS); 1914 | Py_NDIBitfieldMacro(NDI_TOOL_FACE_USED); 1915 | 1916 | Py_NDIBitfieldMacro(NDI_MARKER_MISSING); 1917 | Py_NDIBitfieldMacro(NDI_MARKER_EXCEEDED_MAX_ANGLE); 1918 | Py_NDIBitfieldMacro(NDI_MARKER_EXCEEDED_MAX_ERROR); 1919 | Py_NDIBitfieldMacro(NDI_MARKER_USED); 1920 | 1921 | Py_NDICharMacro(NDI_BLANK); 1922 | Py_NDICharMacro(NDI_FLASH); 1923 | Py_NDICharMacro(NDI_SOLID); 1924 | 1925 | Py_NDIBitfieldMacro(NDI_BASIC); 1926 | Py_NDIBitfieldMacro(NDI_TESTING); 1927 | Py_NDIBitfieldMacro(NDI_PART_NUMBER); 1928 | Py_NDIBitfieldMacro(NDI_ACCESSORIES); 1929 | Py_NDIBitfieldMacro(NDI_MARKER_TYPE); 1930 | 1931 | Py_NDIConstantMacro(NDI_UNOCCUPIED); 1932 | 1933 | Py_NDIBitfieldMacro(NDI_TOOL_IN_PORT_SWITCH); 1934 | Py_NDIBitfieldMacro(NDI_SWITCH_1); 1935 | Py_NDIBitfieldMacro(NDI_SWITCH_2); 1936 | Py_NDIBitfieldMacro(NDI_SWITCH_3); 1937 | Py_NDIBitfieldMacro(NDI_TOOL_TRACKING_LED); 1938 | Py_NDIBitfieldMacro(NDI_LED_1); 1939 | Py_NDIBitfieldMacro(NDI_LED_2); 1940 | Py_NDIBitfieldMacro(NDI_LED_3); 1941 | 1942 | Py_NDIBitfieldMacro(NDI_950NM); 1943 | Py_NDIBitfieldMacro(NDI_850NM); 1944 | 1945 | Py_NDIBitfieldMacro(NDI_NDI_ACTIVE); 1946 | Py_NDIBitfieldMacro(NDI_NDI_CERAMIC); 1947 | Py_NDIBitfieldMacro(NDI_PASSIVE_ANY); 1948 | Py_NDIBitfieldMacro(NDI_PASSIVE_SPHERE); 1949 | Py_NDIBitfieldMacro(NDI_PASSIVE_DISC); 1950 | 1951 | Py_NDIBitfieldMacro(NDI_CONTROL); 1952 | Py_NDIBitfieldMacro(NDI_SENSORS); 1953 | Py_NDIBitfieldMacro(NDI_TIU); 1954 | 1955 | Py_NDIBitfieldMacro(NDI_EPROM_CODE_CHECKSUM); 1956 | Py_NDIBitfieldMacro(NDI_EPROM_SYSTEM_CHECKSUM); 1957 | 1958 | Py_NDIBitfieldMacro(NDI_LEFT_ROM_CHECKSUM); 1959 | Py_NDIBitfieldMacro(NDI_LEFT_SYNC_TYPE_1); 1960 | Py_NDIBitfieldMacro(NDI_LEFT_SYNC_TYPE_2); 1961 | Py_NDIBitfieldMacro(NDI_RIGHT_ROM_CHECKSUM); 1962 | Py_NDIBitfieldMacro(NDI_RIGHT_SYNC_TYPE_1); 1963 | Py_NDIBitfieldMacro(NDI_RIGHT_SYNC_TYPE_2); 1964 | 1965 | Py_NDIBitfieldMacro(NDI_ROM_CHECKSUM); 1966 | Py_NDIBitfieldMacro(NDI_OPERATING_VOLTAGES); 1967 | Py_NDIBitfieldMacro(NDI_MARKER_SEQUENCING); 1968 | Py_NDIBitfieldMacro(NDI_SYNC); 1969 | Py_NDIBitfieldMacro(NDI_COOLING_FAN); 1970 | Py_NDIBitfieldMacro(NDI_INTERNAL_ERROR); 1971 | 1972 | Py_NDIBitfieldMacro(NDI_DETECTED); 1973 | Py_NDIBitfieldMacro(NDI_SOURCES); 1974 | 1975 | Py_NDIConstantMacro(NDI_LEFT); 1976 | Py_NDIConstantMacro(NDI_RIGHT); 1977 | 1978 | return MOD_SUCCESS_VAL(module); 1979 | } 1980 | 1981 | #ifdef __cplusplus 1982 | } 1983 | #endif 1984 | -------------------------------------------------------------------------------- /setup.py.in: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | import sys 3 | 4 | 5 | mac_indicator = 'darwin' 6 | linux_indicator = 'linux' 7 | windows_indicator = 'win' 8 | platform = sys.platform 9 | cxx_library_dir = "@CMAKE_INSTALL_PREFIX@/lib" 10 | 11 | extra_link_args = [] 12 | if platform.startswith(mac_indicator): 13 | extra_link_args.append('-Wl') # pass the following options to linker 14 | extra_link_args.append('-rpath') # tell linker to resolve RPATH to: 15 | extra_link_args.append(cxx_library_dir) # cxx_library_dir, on Mac 16 | 17 | ndicapy = Extension('ndicapy', 18 | sources=[ 19 | 'ndicapi.cxx', 20 | 'ndicapi_math.cxx', 21 | 'ndicapi_serial.cxx', 22 | 'ndicapi_thread.cxx', 23 | 'ndicapimodule.cxx', 24 | ], 25 | libraries=['ndicapi'], 26 | extra_link_args=extra_link_args, 27 | library_dirs=[cxx_library_dir], 28 | runtime_library_dirs=[cxx_library_dir], 29 | ) 30 | 31 | setup(name='ndicapi', 32 | version='3.2', 33 | description='This package allows interfacing with NDI tracking devices', 34 | ext_modules=[ndicapy] 35 | ) 36 | --------------------------------------------------------------------------------