diff --git a/.github/workflows/compile-and-test.yml b/.github/workflows/compile-and-test.yml new file mode 100644 index 0000000..8b9525c --- /dev/null +++ b/.github/workflows/compile-and-test.yml @@ -0,0 +1,64 @@ +name: Compile and test Release & Debug builds +# using https://levelup.gitconnected.com/utilizing-github-actions-to-build-and-test-on-multiple-platforms-a7fe3aa6ce2a + +on: + push: + branches: [ PR_cmake ] + + pull_request: + branches: [ PR_cmake ] + + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + build_and_test: + name: > + Build and test a ${{ matrix.build }} version of ITM on + ${{ matrix.os }} with ${{ matrix.compiler }}. + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + compiler: [ g++-10 ] + build: [Release] + include: + - os: ubuntu-latest + target: Linux + # - os: macos-latest + # target: Macos + - os: windows-latest + compiler: cl + target: Windows + build: Release + # # - os: windows-latest + # compiler: cl + # target: Windows + # build: Debug + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Linux/MacOS compile + if: ${{ matrix.os != 'windows-latest' }} + uses: lukka/run-cmake@v3 + with: + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + buildDirectory: "${{ github.workspace }}/build" + buildWithCMake: true + + - name: Add msbuild to PATH + if: ${{ matrix.os == 'windows-latest' }} + uses: microsoft/setup-msbuild@v1.0.2 + + - name: Compile for Windows + if: ${{ matrix.os == 'windows-latest' }} + uses: lukka/run-cmake@v3 + with: + cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt' + buildDirectory: "${{ github.workspace }}/build" + buildWithCMake: true \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5ecdadb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,78 @@ +# +# Cmake for a shared library using directions at https://stackoverflow.com/questions/17511496/how-to-create-a-shared-library-with-cmake +# +cmake_minimum_required(VERSION 3.16) + +project(itmlib VERSION 1.3 DESCRIPTION "NTIA Irregular Terrain Model library") + +SET(itmlib_SRC + src/ComputeDeltaH.cpp + src/DiffractionLoss.cpp + src/FindHorizons.cpp + src/FreeSpaceLoss.cpp + src/FresnelIntegral.cpp + src/H0Function.cpp + src/InitializeArea.cpp + src/InitializePointToPoint.cpp + src/InverseComplementaryCumulativeDistributionFunction.cpp + src/itm_area.cpp + src/itm_p2p.cpp + src/KnifeEdgeDiffraction.cpp + src/LinearLeastSquaresFit.cpp + src/LineOfSightLoss.cpp + src/LongleyRice.cpp + src/QuickPfl.cpp + src/SigmaHFunction.cpp + src/SmoothEarthDiffraction.cpp + src/TerrainRoughness.cpp + src/TroposcatterLoss.cpp + src/ValidateInputs.cpp + src/Variability.cpp +) + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS YES CACHE BOOL "Export all symbols") + +# +# run cmake -DBUILD_SHARED_LIBS=ON if you want shared libs +# See https://cgold.readthedocs.io/en/latest/tutorials/libraries/static-shared.html +# +add_library(itmlib ${itmlib_SRC}) + +set_target_properties(itmlib PROPERTIES VERSION ${PROJECT_VERSION}) +set_target_properties(itmlib PROPERTIES SOVERSION 0) +add_compile_definitions( + ITMLIB_VERSION="${PROJECT_VERSION}.0") + +# Use C++14 -- needed because of initializers +set_property(TARGET itmlib PROPERTY CXX_STANDARD 14) + +set_target_properties(itmlib PROPERTIES PUBLIC_HEADER include/itm.h) +set_target_properties(itmlib PROPERTIES PUBLIC_HEADER include/Enums.h) +set_target_properties(itmlib PROPERTIES PUBLIC_HEADER include/Errors.h) +set_target_properties(itmlib PROPERTIES PUBLIC_HEADER include/Warnigns.h) + +# Only Cmake 3.20+ provides platform independent way to construct paths +IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER_EQUAL 3.20) + cmake_path(APPEND itminclude "${CMAKE_SOURCE_DIR}" "include") +ELSE (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER_EQUAL 3.20) + set(itminclude "${CMAKE_SOURCE_DIR}/include") +ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER_EQUAL 3.20) + +# +# inclue the include directory +# +target_include_directories(itmlib PRIVATE ${itminclude}) + +include(GNUInstallDirs) +install(TARGETS itmlib + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/itmlib + ) + +# pkg_check_modules() + +configure_file(itmlib.pc.in itmlib.pc @ONLY) + +install(FILES ${CMAKE_BINARY_DIR}/itmlib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) + +add_subdirectory(win32/ITMDrvr) diff --git a/include/itm.h b/include/itm.h index 7ad1fbc..5887e22 100644 --- a/include/itm.h +++ b/include/itm.h @@ -7,7 +7,11 @@ using namespace std; // Export the DLL functions as "C" and not C++ -#define DLLEXPORT extern "C" __declspec(dllexport) +#ifdef _WIN32 +# define DLLEXPORT extern "C" __declspec(dllexport) +#else +# define DLLEXPORT extern "C" +#endif #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define DIM(x, y) (((x) > (y)) ? (x - y) : (0)) diff --git a/itmlib.pc.in b/itmlib.pc.in new file mode 100644 index 0000000..ab4f27a --- /dev/null +++ b/itmlib.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ + +Requires: +Libs: -L${libdir} -litmlib +Cflags: -I${includedir} \ No newline at end of file diff --git a/src/ComputeDeltaH.cpp b/src/ComputeDeltaH.cpp index 0f4aae4..20f4b3a 100644 --- a/src/ComputeDeltaH.cpp +++ b/src/ComputeDeltaH.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/DiffractionLoss.cpp b/src/DiffractionLoss.cpp index dc3a669..ccfac0b 100644 --- a/src/DiffractionLoss.cpp +++ b/src/DiffractionLoss.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/FindHorizons.cpp b/src/FindHorizons.cpp index 7beb29a..8b28df5 100644 --- a/src/FindHorizons.cpp +++ b/src/FindHorizons.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/FreeSpaceLoss.cpp b/src/FreeSpaceLoss.cpp index 0981ec7..c92fed1 100644 --- a/src/FreeSpaceLoss.cpp +++ b/src/FreeSpaceLoss.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/FresnelIntegral.cpp b/src/FresnelIntegral.cpp index 0726d1b..57760f3 100644 --- a/src/FresnelIntegral.cpp +++ b/src/FresnelIntegral.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/H0Function.cpp b/src/H0Function.cpp index b1ae842..b9efda7 100644 --- a/src/H0Function.cpp +++ b/src/H0Function.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/InitializeArea.cpp b/src/InitializeArea.cpp index 8d1ffc8..e70d189 100644 --- a/src/InitializeArea.cpp +++ b/src/InitializeArea.cpp @@ -1,5 +1,5 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" +#include "itm.h" +#include "Enums.h" /*============================================================================= | diff --git a/src/InitializePointToPoint.cpp b/src/InitializePointToPoint.cpp index b001477..4fd5400 100644 --- a/src/InitializePointToPoint.cpp +++ b/src/InitializePointToPoint.cpp @@ -1,5 +1,5 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" +#include "itm.h" +#include "Enums.h" /*============================================================================= | diff --git a/src/InverseComplementaryCumulativeDistributionFunction.cpp b/src/InverseComplementaryCumulativeDistributionFunction.cpp index 68b0436..db8011d 100644 --- a/src/InverseComplementaryCumulativeDistributionFunction.cpp +++ b/src/InverseComplementaryCumulativeDistributionFunction.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/KnifeEdgeDiffraction.cpp b/src/KnifeEdgeDiffraction.cpp index 4cec35c..061ce4a 100644 --- a/src/KnifeEdgeDiffraction.cpp +++ b/src/KnifeEdgeDiffraction.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/LineOfSightLoss.cpp b/src/LineOfSightLoss.cpp index e8c7a73..23b9553 100644 --- a/src/LineOfSightLoss.cpp +++ b/src/LineOfSightLoss.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/LinearLeastSquaresFit.cpp b/src/LinearLeastSquaresFit.cpp index 65f2829..076a58c 100644 --- a/src/LinearLeastSquaresFit.cpp +++ b/src/LinearLeastSquaresFit.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/LongleyRice.cpp b/src/LongleyRice.cpp index 6de72ab..181112d 100644 --- a/src/LongleyRice.cpp +++ b/src/LongleyRice.cpp @@ -1,7 +1,7 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" -#include "..\include\Errors.h" -#include "..\include\Warnings.h" +#include "itm.h" +#include "Enums.h" +#include "Errors.h" +#include "Warnings.h" /*============================================================================= | diff --git a/src/QuickPfl.cpp b/src/QuickPfl.cpp index 6f4c942..104130c 100644 --- a/src/QuickPfl.cpp +++ b/src/QuickPfl.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/SigmaHFunction.cpp b/src/SigmaHFunction.cpp index 066b4ea..4b309ef 100644 --- a/src/SigmaHFunction.cpp +++ b/src/SigmaHFunction.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/SmoothEarthDiffraction.cpp b/src/SmoothEarthDiffraction.cpp index 25b480e..6327c24 100644 --- a/src/SmoothEarthDiffraction.cpp +++ b/src/SmoothEarthDiffraction.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/TerrainRoughness.cpp b/src/TerrainRoughness.cpp index d4acc35..36c0570 100644 --- a/src/TerrainRoughness.cpp +++ b/src/TerrainRoughness.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/TroposcatterLoss.cpp b/src/TroposcatterLoss.cpp index b2e4fd0..d6ce298 100644 --- a/src/TroposcatterLoss.cpp +++ b/src/TroposcatterLoss.cpp @@ -1,4 +1,4 @@ -#include "..\include\itm.h" +#include "itm.h" /*============================================================================= | diff --git a/src/ValidateInputs.cpp b/src/ValidateInputs.cpp index c300fb7..1510bc4 100644 --- a/src/ValidateInputs.cpp +++ b/src/ValidateInputs.cpp @@ -1,7 +1,7 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" -#include "..\include\Errors.h" -#include "..\include\Warnings.h" +#include "itm.h" +#include "Enums.h" +#include "Errors.h" +#include "Warnings.h" /*============================================================================= | diff --git a/src/Variability.cpp b/src/Variability.cpp index fa1d699..ccd51d4 100644 --- a/src/Variability.cpp +++ b/src/Variability.cpp @@ -1,6 +1,6 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" -#include "..\include\Warnings.h" +#include "itm.h" +#include "Enums.h" +#include "Warnings.h" /*============================================================================= | diff --git a/src/itm_area.cpp b/src/itm_area.cpp index 756ece7..5733806 100644 --- a/src/itm_area.cpp +++ b/src/itm_area.cpp @@ -1,6 +1,6 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" -#include "..\include\Errors.h" +#include "itm.h" +#include "Enums.h" +#include "Errors.h" /*============================================================================= | diff --git a/src/itm_p2p.cpp b/src/itm_p2p.cpp index 41becdc..d296016 100644 --- a/src/itm_p2p.cpp +++ b/src/itm_p2p.cpp @@ -1,6 +1,6 @@ -#include "..\include\itm.h" -#include "..\include\Enums.h" -#include "..\include\Errors.h" +#include "itm.h" +#include "Enums.h" +#include "Errors.h" /*============================================================================= | diff --git a/win32/ITMDrvr/AreaMode.cpp b/win32/ITMDrvr/AreaMode.cpp index c5d6400..f2f9366 100644 --- a/win32/ITMDrvr/AreaMode.cpp +++ b/win32/ITMDrvr/AreaMode.cpp @@ -5,13 +5,13 @@ #include "Common.h" // ITM DLL Functions -typedef int(__stdcall *itm_area_tls_ex_func)(double h_tx__meter, double h_rx__meter, +typedef int(WIN32_STDCALL *itm_area_tls_ex_func)(double h_tx__meter, double h_rx__meter, int tx_site_criteria, int rx_site_criteria, double d__km, double delta_h__meter, int climate, double N_0, double f__mhz, int pol, double epsilon, double sigma, int mdvar, double time, double location, double situation, double *A__db, long *warnings, struct IntermediateValues *interValues); -typedef int(__stdcall *itm_area_cr_ex_func)(double h_tx__meter, double h_rx__meter, +typedef int(WIN32_STDCALL *itm_area_cr_ex_func)(double h_tx__meter, double h_rx__meter, int tx_site_criteria, int rx_site_criteria, double d__km, double delta_h__meter, int climate, double N_0, double f__mhz, int pol, double epsilon, double sigma, int mdvar, double confidence, double reliability, double *A__db, @@ -130,6 +130,7 @@ int CallAreaMode(DrvrParams* params, AreaParams* area_params, IntermediateValues | Returns: rtn - Return error code | *===========================================================================*/ + #ifdef _WIN32 int LoadAreaFunctions(HINSTANCE hLib) { itm_area_tls_ex = (itm_area_tls_ex_func)GetProcAddress((HMODULE)hLib, "ITM_AREA_TLS_Ex"); if (itm_area_tls_ex == nullptr) @@ -141,6 +142,13 @@ int LoadAreaFunctions(HINSTANCE hLib) { return SUCCESS; } +#else +int LoadAreaFunctions(void *) { + itm_area_tls_ex = (itm_area_tls_ex_func) &ITM_AREA_TLS_Ex; + itm_area_cr_ex = (itm_area_cr_ex_func) &ITM_AREA_CR_Ex; + return SUCCESS; +} +#endif /*============================================================================= | @@ -167,22 +175,22 @@ int ParseAreaInputFile(const char* in_file, AreaParams* area_params) { transform(key.begin(), key.end(), key.begin(), ::tolower); if (key.compare(TAG__HTX) == 0) { - if (ParseDouble(value.c_str(), &area_params->h_tx__meter) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->h_tx__meter) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_HTX, TAG__HTX); } } else if (key.compare(TAG__HRX) == 0) { - if (ParseDouble(value.c_str(), &area_params->h_rx__meter) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->h_rx__meter) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_HRX, TAG__HRX); } } else if (key.compare(TAG__TX_SITE) == 0) { - if (ParseInteger(value.c_str(), &area_params->tx_site_criteria) == ERROR) { + if (ParseInteger(value.c_str(), &area_params->tx_site_criteria) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_TX_SITE, TAG__TX_SITE); } } else if (key.compare(TAG__RX_SITE) == 0) { - if (ParseInteger(value.c_str(), &area_params->rx_site_criteria) == ERROR) { + if (ParseInteger(value.c_str(), &area_params->rx_site_criteria) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_RX_SITE, TAG__RX_SITE); } } @@ -193,7 +201,7 @@ int ParseAreaInputFile(const char* in_file, AreaParams* area_params) { string str = value.substr(s, e); double p; - if (ParseDouble(str.c_str(), &p) == ERROR) { + if (ParseDouble(str.c_str(), &p) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_DKM, TAG__DKM); } @@ -236,52 +244,52 @@ int ParseAreaInputFile(const char* in_file, AreaParams* area_params) { } } else if (key.compare(TAG__DELTAH) == 0) { - if (ParseDouble(value.c_str(), &area_params->delta_h__meter) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->delta_h__meter) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_DELTAH, TAG__DELTAH); } } else if (key.compare(TAG__CLIMATE) == 0) { - if (ParseInteger(value.c_str(), &area_params->climate) == ERROR) { + if (ParseInteger(value.c_str(), &area_params->climate) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_CLIMATE, TAG__CLIMATE); } } else if (key.compare("n_0") == 0) { - if (ParseDouble(value.c_str(), &area_params->N_0) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->N_0) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_N0, TAG__N0); } } else if (key.compare(TAG__FREQ) == 0) { - if (ParseDouble(value.c_str(), &area_params->f__mhz) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->f__mhz) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_FREQ, TAG__FREQ); } } else if (key.compare(TAG__POL) == 0) { - if (ParseInteger(value.c_str(), &area_params->pol) == ERROR) { + if (ParseInteger(value.c_str(), &area_params->pol) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_POL, TAG__POL); } } else if (key.compare(TAG__EPSILON) == 0) { - if (ParseDouble(value.c_str(), &area_params->epsilon) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->epsilon) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_EPSILON, TAG__EPSILON); } } else if (key.compare(TAG__SIGMA) == 0) { - if (ParseDouble(value.c_str(), &area_params->sigma) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->sigma) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_SIGMA, TAG__SIGMA); } } else if (key.compare(TAG__MDVAR) == 0) { - if (ParseInteger(value.c_str(), &area_params->mdvar) == ERROR) { + if (ParseInteger(value.c_str(), &area_params->mdvar) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_MDVAR, TAG__MDVAR); } } else if (key.compare(TAG__TIME) == 0) { - if (ParseDouble(value.c_str(), &area_params->time) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->time) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_TIME, TAG__TIME); } } else if (key.compare(TAG__LOCATION) == 0) { - if (ParseDouble(value.c_str(), &area_params->location) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->location) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_LOCATION, TAG__LOCATION); } } @@ -292,7 +300,7 @@ int ParseAreaInputFile(const char* in_file, AreaParams* area_params) { string str = value.substr(s, e); double situation; - if (ParseDouble(str.c_str(), &situation) == ERROR) { + if (ParseDouble(str.c_str(), &situation) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_SITUATION, TAG__SITUATION); } @@ -307,7 +315,7 @@ int ParseAreaInputFile(const char* in_file, AreaParams* area_params) { string str = value.substr(s, e); double confidence; - if (ParseDouble(str.c_str(), &confidence) == ERROR) { + if (ParseDouble(str.c_str(), &confidence) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_CONFIDENCE, TAG__CONFIDENCE); } @@ -316,7 +324,7 @@ int ParseAreaInputFile(const char* in_file, AreaParams* area_params) { } while (e != value.npos); } else if (key.compare(TAG__RELIABILITY) == 0) { - if (ParseDouble(value.c_str(), &area_params->reliability) == ERROR) { + if (ParseDouble(value.c_str(), &area_params->reliability) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_RELIABILITY, TAG__RELIABILITY); } } diff --git a/win32/ITMDrvr/AreaMode.h b/win32/ITMDrvr/AreaMode.h index d58c777..1b0a9a6 100644 --- a/win32/ITMDrvr/AreaMode.h +++ b/win32/ITMDrvr/AreaMode.h @@ -8,4 +8,9 @@ int ValidateAreaInputs(AreaParams* area_params); int CallAreaMode(DrvrParams* params, AreaParams* area_params, IntermediateValues* inter_vals, vector* A__db, vector* A_fs__db, long* warnings); void WriteAreaInputs(FILE* fp, AreaParams* area_params); + +#ifdef _WIN32 int LoadAreaFunctions(HINSTANCE hLib); +#else +int LoadAreaFunctions(void *); +#endif diff --git a/win32/ITMDrvr/CMakeLists.txt b/win32/ITMDrvr/CMakeLists.txt new file mode 100644 index 0000000..44ab382 --- /dev/null +++ b/win32/ITMDrvr/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.9) + +SET(ITMDRVR_SRC + AreaMode.cpp + Common.cpp + ITMDrvr.cpp + PointToPointMode.cpp + Reporting.cpp +) + + +add_executable(itmdrvr ${ITMDRVR_SRC}) +target_include_directories(itmdrvr PRIVATE + ${itminclude} +) + +# Use C++14 +set_property(TARGET itmdrvr PROPERTY CXX_STANDARD 14) + +target_link_libraries(itmdrvr itmlib) + +# +# Use UNICODE in windows +# + +if (WIN32) + ADD_DEFINITIONS(-DUNICODE) + ADD_DEFINITIONS(-D_UNICODE) + target_link_libraries(itmdrvr version) +endif (WIN32) + diff --git a/win32/ITMDrvr/Common.cpp b/win32/ITMDrvr/Common.cpp index 5055779..25b758e 100644 --- a/win32/ITMDrvr/Common.cpp +++ b/win32/ITMDrvr/Common.cpp @@ -19,12 +19,12 @@ int ParseInteger(const char* str, int* value) { *value = ::stoi(str, &t, 10); } catch (...) { // error parsing the input string value - return ERROR; + return ITM_ERROR; } // verify the entire string was parsed, and a trailing char wasn't omitted if (strlen(str) != t) - return ERROR; + return ITM_ERROR; return SUCCESS; } @@ -46,7 +46,7 @@ int ParseDouble(const char* str, double* value) { } catch (...) { // error parsing the input string value - return ERROR; + return ITM_ERROR; } return SUCCESS; diff --git a/win32/ITMDrvr/Common.h b/win32/ITMDrvr/Common.h index 53eaa50..270f07b 100644 --- a/win32/ITMDrvr/Common.h +++ b/win32/ITMDrvr/Common.h @@ -3,3 +3,13 @@ int ParseInteger(const char* str, int* value); int ParseDouble(const char* str, double* value); int ParsingErrorHelper(int err, const char* msg); + +#ifdef _WIN32 +# define WIN32_STDCALL __stdcall +#else +# define WIN32_STDCALL +# define fprintf_s fprintf +# define printf_s printf +# define fwprintf_s fwprintf +# define wprintf_s wprintf +#endif diff --git a/win32/ITMDrvr/ITMDrvr.cpp b/win32/ITMDrvr/ITMDrvr.cpp index 61bedbe..72a50c0 100644 --- a/win32/ITMDrvr/ITMDrvr.cpp +++ b/win32/ITMDrvr/ITMDrvr.cpp @@ -4,9 +4,11 @@ #include "Labels.h" #include "Tags.h" #include "Reporting.h" -#include "..\..\include\Enums.h" -#include "..\..\include\Errors.h" -#include "..\..\include\Warnings.h" +#include "Common.h" + +#include "Enums.h" +#include "Errors.h" +#include "Warnings.h" int dllVerMajor = NOT_SET; int dllVerMinor = NOT_SET; @@ -14,8 +16,7 @@ int drvrVerMajor = NOT_SET; int drvrVerMinor = NOT_SET; int drvrVerDrvr = NOT_SET; -wchar_t buf[TIME_SIZE]; - +char timebuf[TIME_SIZE]; /*============================================================================= | | Description: Main function of the ITM driver executable @@ -27,7 +28,27 @@ int main(int argc, char** argv) { // Get the time time_t t = time(NULL); - _wctime_s(buf, TIME_SIZE, &t); + +#ifdef _WIN32 + // + // Originally, this code use _wctime_s to get the time in a wchar + // format. There are two problems: + // + // According to https://stackoverflow.com/questions/34343181/no-output-when-using-fprintf-after-fwprintf + // you can not mix wide/narrow output in the same file. + // Because of this, on Linux/MacOS a fwprintf produces + // no output. Thus, we convert to narrow for both platforms. + // + // second, _wctime_s is are wrappers for + // + wchar_t buf[TIME_SIZE]; + _wctime64_s(buf, TIME_SIZE, &t); + std::mbstate_t state = std::mbstate_t(); + const wchar_t *bufptr = buf; + wcsrtombs(timebuf, &bufptr, TIME_SIZE, &state); +#else + strncpy(timebuf, ctime(&t), TIME_SIZE); +#endif rtn = ParseArguments(argc, argv, ¶ms); if (rtn == DRVR__RETURN_SUCCESS) @@ -70,7 +91,12 @@ int main(int argc, char** argv) { // print results to file FILE* fp; +#ifdef _WIN32 int err = fopen_s(&fp, params.out_file, "w"); +#else + fp = fopen(params.out_file, "w"); + int err = errno; +#endif if (err != 0) { printf_s("Error opening output file. Exiting.\n"); return err; @@ -78,7 +104,8 @@ int main(int argc, char** argv) { else { fprintf_s(fp, "itm.dll Version v%i.%i\n", dllVerMajor, dllVerMinor); fprintf_s(fp, "ITMDrvr.exe Version v%i.%i.%i\n", drvrVerMajor, drvrVerMinor, drvrVerDrvr); - fwprintf_s(fp, L"Date Generated %s", buf); + fprintf(fp, "Date Generated %s", timebuf); + fprintf_s(fp, "Input Arguments "); for (int i = 1; i < argc; i++) { fprintf_s(fp, "%s ", argv[i]); @@ -103,7 +130,7 @@ int main(int argc, char** argv) { } else { fprintf_s(fp, "Results\n"); - fprintf_s(fp, "ITM Warning Flags 0x%.4X ", warnings); + fprintf_s(fp, "ITM Warning Flags 0x%.4X ", (int) warnings); PrintWarningMessages(fp, warnings); fprintf_s(fp, "ITM Return Code %-12i ", rtn); PrintErrorMsgLabel(fp, rtn); @@ -198,15 +225,15 @@ int ParseArguments(int argc, char** argv, DrvrParams* params) { Lowercase(argv[i]); if (Match("-i", argv[i])) { - sprintf_s(params->in_file, "%s", argv[i + 1]); + snprintf(params->in_file, DRVR_PARAMS_SIZE, "%s", argv[i + 1]); i++; } else if (Match("-o", argv[i])) { - sprintf_s(params->out_file, "%s", argv[i + 1]); + snprintf(params->out_file, DRVR_PARAMS_SIZE, "%s", argv[i + 1]); i++; } else if (Match("-t", argv[i])) { - sprintf_s(params->terrain_file, "%s", argv[i + 1]); + snprintf(params->terrain_file, DRVR_PARAMS_SIZE, "%s", argv[i + 1]); i++; } else if (Match("-mode", argv[i])) @@ -310,7 +337,7 @@ void Version() { printf_s("Institute for Telecommunications Sciences - Boulder, CO\n"); printf_s("\tITM Driver Version: %i.%i\n", drvrVerMajor, drvrVerMinor); printf_s("\tITM DLL Version: %i.%i\n", dllVerMajor, dllVerMinor); - wprintf_s(L"Time: %s", buf); + printf_s("Time: %s", timebuf); printf_s("*******************************************************\n"); } @@ -402,10 +429,14 @@ int Validate_RequiredErrMsgHelper(const char* opt, int err) { | *===========================================================================*/ int LoadDLL() { +#ifndef _WIN32 + void *hLib = NULL; +#else HINSTANCE hLib = LoadLibrary(TEXT("itm.dll")); if (hLib == NULL) return DRVRERR__DLL_LOADING; +#endif GetDLLVersionInfo(); GetDrvrVersionInfo(); @@ -434,6 +465,10 @@ int LoadDLL() { | *===========================================================================*/ void GetDLLVersionInfo() { +#ifndef _WIN32 + sscanf(ITMLIB_VERSION, "%d.%d", + &dllVerMajor, &dllVerMinor); +#else DWORD verHandle = NULL; UINT size = 0; LPBYTE lpBuffer = NULL; @@ -461,7 +496,7 @@ void GetDLLVersionInfo() { delete[] verData; } - +#endif return; } @@ -476,6 +511,10 @@ void GetDLLVersionInfo() { *===========================================================================*/ void GetDrvrVersionInfo() { +#ifndef _WIN32 + sscanf(ITMLIB_VERSION, "%d.%d.%d", + &drvrVerMajor, &drvrVerMinor, &drvrVerDrvr); +#else DWORD verHandle = NULL; UINT size = 0; LPBYTE lpBuffer = NULL; @@ -507,6 +546,6 @@ void GetDrvrVersionInfo() delete[] verData; } - +#endif return; -} \ No newline at end of file +} diff --git a/win32/ITMDrvr/ITMDrvr.h b/win32/ITMDrvr/ITMDrvr.h index 4f56ea0..223fb8a 100644 --- a/win32/ITMDrvr/ITMDrvr.h +++ b/win32/ITMDrvr/ITMDrvr.h @@ -2,10 +2,17 @@ #include #include #include -#include +#ifdef _WIN32 +# include +#else +# define DLLEXPORT extern "C" +#endif #include #include #include +#include // snprintf in Windows +#include // _wctime_s in Windows +#include // for _wctime_s in Windows using namespace std; @@ -25,7 +32,7 @@ using namespace std; /////////////////////////////////////////////// #define NOT_SET -1 -#define ERROR -1 +#define ITM_ERROR -1 // disambiguage for windows wingdi.h #define SUCCESS 0 #define SUCCESS_WITH_WARNINGS 1 #define DRVR__RETURN_SUCCESS 1000 @@ -83,10 +90,11 @@ using namespace std; // DATA STRUCTURES /////////////////////////////////////////////// +#define DRVR_PARAMS_SIZE 256 struct DrvrParams { - char terrain_file[256] = { 0 }; // Terrain file - char in_file[256] = { 0 }; // Input file - char out_file[256] = { 0 }; // Output file + char terrain_file[DRVR_PARAMS_SIZE] = { 0 }; // Terrain file + char in_file[DRVR_PARAMS_SIZE] = { 0 }; // Input file + char out_file[DRVR_PARAMS_SIZE] = { 0 }; // Output file int mode = NOT_SET; // Mode (P2P, AREA) bool DBG = false; // Dump intermediate values to file? @@ -138,6 +146,11 @@ struct AreaParams { int mode = NOT_SET; }; +#ifdef _WIN32 +// +// Duplicates specification in itm.h +// and that version is used in non-WIN32 builds +// struct IntermediateValues { double theta_hzn[2]; // Terminal horizon angles @@ -150,6 +163,9 @@ struct IntermediateValues double d__km; // Path distance, in km int mode; // Mode of propagation value }; +#else +# include "itm.h" +#endif // // FUNCTIONS diff --git a/win32/ITMDrvr/PointToPointMode.cpp b/win32/ITMDrvr/PointToPointMode.cpp index 632dfc6..63939ee 100644 --- a/win32/ITMDrvr/PointToPointMode.cpp +++ b/win32/ITMDrvr/PointToPointMode.cpp @@ -5,12 +5,12 @@ #include "Common.h" // ITM DLL Functions -typedef int(__stdcall *itm_p2p_tls_ex_func)(double h_tx__meter, double h_rx__meter, +typedef int(WIN32_STDCALL *itm_p2p_tls_ex_func)(double h_tx__meter, double h_rx__meter, double pfl[], int climate, double N_0, double f__mhz, int pol, double epsilon, double sigma, int mdvar, double time, double location, double situation, double *A__db, long *warnings, struct IntermediateValues *interValues); -typedef int(__stdcall *itm_p2p_cr_ex_func)(double h_tx__meter, double h_rx__meter, +typedef int(WIN32_STDCALL *itm_p2p_cr_ex_func)(double h_tx__meter, double h_rx__meter, double pfl[], int climate, double N_0, double f__mhz, int pol, double epsilon, double sigma, int mdvar, double confidence, double reliability, double *A__db, long *warnings, struct IntermediateValues *interValues); @@ -111,6 +111,7 @@ int CallP2PMode(DrvrParams* params, P2PParams* p2p_params, IntermediateValues* i | Returns: rtn - Return error code | *===========================================================================*/ + #ifdef _WIN32 int LoadP2PFunctions(HINSTANCE hLib) { itm_p2p_tls_ex = (itm_p2p_tls_ex_func)GetProcAddress((HMODULE)hLib, "ITM_P2P_TLS_Ex"); if (itm_p2p_tls_ex == nullptr) @@ -119,9 +120,15 @@ int LoadP2PFunctions(HINSTANCE hLib) { itm_p2p_cr_ex = (itm_p2p_cr_ex_func)GetProcAddress((HMODULE)hLib, "ITM_P2P_CR_Ex"); if (itm_p2p_cr_ex == nullptr) return DRVRERR__GET_P2P_CR_FUNC_LOADING; - return SUCCESS; } +#else +int LoadP2PFunctions(void *) { + itm_p2p_tls_ex = (itm_p2p_tls_ex_func) &ITM_P2P_TLS_Ex; + itm_p2p_cr_ex = (itm_p2p_cr_ex_func) &ITM_P2P_CR_Ex; + return SUCCESS; +} +#endif /*============================================================================= | @@ -148,62 +155,62 @@ int ParseP2PInputFile(const char* in_file, P2PParams *p2p_params) { transform(key.begin(), key.end(), key.begin(), ::tolower); if (key.compare(TAG__HTX) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->h_tx__meter) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->h_tx__meter) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_HTX, TAG__HTX); } } else if (key.compare(TAG__HRX) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->h_rx__meter) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->h_rx__meter) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_HRX, TAG__HRX); } } else if (key.compare(TAG__CLIMATE) == 0) { - if (ParseInteger(value.c_str(), &p2p_params->climate) == ERROR) { + if (ParseInteger(value.c_str(), &p2p_params->climate) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_CLIMATE, TAG__CLIMATE); } } else if (key.compare("n_0") == 0) { - if (ParseDouble(value.c_str(), &p2p_params->N_0) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->N_0) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_N0, TAG__N0); } } else if (key.compare(TAG__FREQ) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->f__mhz) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->f__mhz) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_FREQ, TAG__FREQ); } } else if (key.compare(TAG__POL) == 0) { - if (ParseInteger(value.c_str(), &p2p_params->pol) == ERROR) { + if (ParseInteger(value.c_str(), &p2p_params->pol) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_POL, TAG__POL); } } else if (key.compare(TAG__EPSILON) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->epsilon) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->epsilon) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_EPSILON, TAG__EPSILON); } } else if (key.compare(TAG__SIGMA) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->sigma) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->sigma) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_SIGMA, TAG__SIGMA); } } else if (key.compare(TAG__MDVAR) == 0) { - if (ParseInteger(value.c_str(), &p2p_params->mdvar) == ERROR) { + if (ParseInteger(value.c_str(), &p2p_params->mdvar) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_MDVAR, TAG__MDVAR); } } else if (key.compare(TAG__TIME) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->time) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->time) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_TIME, TAG__TIME); } } else if (key.compare(TAG__LOCATION) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->location) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->location) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_LOCATION, TAG__LOCATION); } } else if (key.compare(TAG__SITUATION) == 0) { - if (ParseDouble(value.c_str(), &p2p_params->situation) == ERROR) { + if (ParseDouble(value.c_str(), &p2p_params->situation) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_SITUATION, TAG__SITUATION); } } @@ -214,7 +221,7 @@ int ParseP2PInputFile(const char* in_file, P2PParams *p2p_params) { string str = value.substr(s, e); double confidence; - if (ParseDouble(str.c_str(), &confidence) == ERROR) { + if (ParseDouble(str.c_str(), &confidence) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_CONFIDENCE, TAG__CONFIDENCE); } @@ -229,7 +236,7 @@ int ParseP2PInputFile(const char* in_file, P2PParams *p2p_params) { string str = value.substr(s, e); double reliability; - if (ParseDouble(str.c_str(), &reliability) == ERROR) { + if (ParseDouble(str.c_str(), &reliability) == ITM_ERROR) { return ParsingErrorHelper(DRVRERR__PARSE_RELIABILITY, TAG__RELIABILITY); } diff --git a/win32/ITMDrvr/PointToPointMode.h b/win32/ITMDrvr/PointToPointMode.h index 574d486..a0d668e 100644 --- a/win32/ITMDrvr/PointToPointMode.h +++ b/win32/ITMDrvr/PointToPointMode.h @@ -7,5 +7,12 @@ int ParseP2PInputFile(const char* in_file, P2PParams *p2p_params); int ValidateP2PInputs(P2PParams* p2p_params); int CallP2PMode(DrvrParams* params, P2PParams* p2p_params, IntermediateValues* inter_vals, vector* A__db, long* warnings); void WriteP2PInputs(FILE* fp, P2PParams* p2p_params); -int LoadP2PFunctions(HINSTANCE hLib); void ParseTerrainFile(const char* terrain_file, vector* pfl); + + +#ifdef _WIN32 +int LoadP2PFunctions(HINSTANCE hLib); +#else +int LoadP2PFunctions(void *); +#endif + diff --git a/win32/ITMDrvr/Reporting.cpp b/win32/ITMDrvr/Reporting.cpp index e411a9c..1e51282 100644 --- a/win32/ITMDrvr/Reporting.cpp +++ b/win32/ITMDrvr/Reporting.cpp @@ -1,8 +1,9 @@ #include "Reporting.h" +#include "Common.h" #include "Labels.h" -#include "..\..\include\Enums.h" -#include "..\..\include\Errors.h" -#include "..\..\include\Warnings.h" +#include "Enums.h" +#include "Errors.h" +#include "Warnings.h" bool need_buffer = false; diff --git a/win32/ITMDrvr/Reporting.h b/win32/ITMDrvr/Reporting.h index 74255f2..8eb6c2e 100644 --- a/win32/ITMDrvr/Reporting.h +++ b/win32/ITMDrvr/Reporting.h @@ -2,7 +2,11 @@ #include #include #include -#include +#ifdef _WIN32 +# include +#else +# define DLLEXPORT extern "C" +#endif #include #include #include