diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..794d66c6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +# CI Workflow for Golden Gate +name: CI + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-linux-macos: + name: GG-Build ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: ['ubuntu-latest', 'macos-latest'] + + steps: + # Checks-out the repository under $GITHUB_WORKSPACE, so that the job can access it + - uses: actions/checkout@v2 + # Needed for Conda + - uses: goanpeca/setup-miniconda@v1 + with: + activate-environment: gg + environment-file: environment.yml + auto-activate-base: false + + # Runs a single command using the runners shell (so that conda can be properyl activated) + - shell: bash -l {0} + name: Run a multi-line script + run: | + echo Hello, world! + echo Line two + conda info + conda list + inv -l diff --git a/Brewfile b/Brewfile index efbb64a6..b583a779 100644 --- a/Brewfile +++ b/Brewfile @@ -1,7 +1,7 @@ tap "homebrew/cask" tap "homebrew/homebrew-bundle" -tap "JuulLabs-OSS/mynewt" tap "homebrew/cask-drivers" +tap "JuulLabs-OSS/mynewt" brew "mynewt-newt@1.7" brew "carthage" diff --git a/README.md b/README.md index b263288e..d6c21001 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ Project Golden Gate Golden Gate is a portable cross-platform framework that offers reliable and secure network communication between different combinations of embedded -devices, mobile applications and desktop applications. +devices, mobile applications and desktop applications over Bluetooth Low Energy. + The framework provides developers with a familiar model, allowing them to implement their functionality the same way they would in other networked environments, leveraging familiar standards like CoAP, WebSockets, HTTP, MQTT, @@ -53,4 +54,4 @@ own communicating applications and services. Where To Start -------------- -Visit the online documentation (or build the doc from within the project). \ No newline at end of file +[Visit the online documentation](https://fitbit.github.io/golden-gate/) (or build the doc from within the project). \ No newline at end of file diff --git a/docs/src/platforms/android.md b/docs/src/platforms/android.md index 8133cff5..f38b47c1 100644 --- a/docs/src/platforms/android.md +++ b/docs/src/platforms/android.md @@ -97,4 +97,4 @@ $ inv android.build Run The Host App ---------------- -See the [Android Host App](../apps/android/host_app.md) documentation. \ No newline at end of file +See the [Android Host App](https://fitbit.github.io/golden-gate/apps/android/host_app.html) documentation. \ No newline at end of file diff --git a/docs/src/platforms/ios.md b/docs/src/platforms/ios.md index 9a2ce2de..10c51c07 100644 --- a/docs/src/platforms/ios.md +++ b/docs/src/platforms/ios.md @@ -38,4 +38,4 @@ Run The Host App ---------------- In XCode, click Run (the "Play" icon). -See the [iOS Host App](../apps/ios/host_app.md) documentation for details. \ No newline at end of file +See the [iOS Host App](https://fitbit.github.io/golden-gate/apps/ios/host_app.html) documentation for details. \ No newline at end of file diff --git a/external/smo/c/lib/fb_smo.c b/external/smo/c/lib/fb_smo.c index b4576f09..1edcb2c0 100644 --- a/external/smo/c/lib/fb_smo.c +++ b/external/smo/c/lib/fb_smo.c @@ -156,9 +156,10 @@ Fb_Smo_ReplaceObject(Fb_Smo* old, Fb_Smo* new) if (new != NULL) { if (old->name != NULL) { - new->name = new->allocator->allocate_memory(new->allocator, strlen(old->name) + 1); + size_t buffer_size = strlen(old->name) + 1; + new->name = new->allocator->allocate_memory(new->allocator, buffer_size); if (new->name != NULL) { - strcpy(new->name, old->name); + strncpy(new->name, old->name, buffer_size); } else { // Destroy new object Fb_Smo_Destroy(new); diff --git a/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequest.kt b/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequest.kt index 315f4e4c..a4753044 100644 --- a/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequest.kt +++ b/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequest.kt @@ -22,8 +22,6 @@ interface OutgoingRequest : OutgoingMessage, BaseRequest { * of fixed size. In GG we use 1024 bytes. On the tracker some Coap resources accept larger data payloads * in a single block. In this case we need to force a non-blockwise request. Here is an example of this * type of resource: - * - * https://wiki.fitbit.com/pages/viewpage.action?pageId=109586801 */ val forceNonBlockwise: Boolean diff --git a/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequestBuilder.kt b/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequestBuilder.kt index 722d2e00..a77bbb83 100644 --- a/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequestBuilder.kt +++ b/platform/android/goldengate/GoldenGateBindings/src/main/kotlin/com/fitbit/goldengate/bindings/coap/data/OutgoingRequestBuilder.kt @@ -43,10 +43,7 @@ class OutgoingRequestBuilder( /** * Flag to treat the request as non-blockwise. In a blockwise request data is sent in chuncks(blocks) * of fixed size. In GG we use 1024 bytes. On the tracker some Coap resources accept larger data payloads - * in a single block. In this case we need to force a non-blockwise request. Here is an example of this - * type of resource: - * - * https://wiki.fitbit.com/pages/viewpage.action?pageId=109586801 + * in a single block. In this case we need to force a non-blockwise request. */ fun forceNonBlockwise(value: Boolean): OutgoingRequestBuilder { forceNonBlockwise = value diff --git a/platform/android/goldengate/gradle.properties b/platform/android/goldengate/gradle.properties index 97e3156a..b629a3e5 100644 --- a/platform/android/goldengate/gradle.properties +++ b/platform/android/goldengate/gradle.properties @@ -22,7 +22,7 @@ ANDROIDX_LEGACY_SUPPORT_V4_VERSION = 1.0.0 ANDROIDX_RECYCLEVIEW_VERSION = 1.1.0 ANDROIDX_CONSTRAINTLAYOUT_VERSION = 1.1.3 ANDROID_MATERIAL_VERSION = 1.1.0 -BITGATT_VERSION = bugfix~maven-publish-SNAPSHOT +BITGATT_VERSION = v0.9.1 TIMBER_VERSION = 4.7.1 RXJAVA_VERSION = 2.2.12 RXANDROID_VERSION = 2.1.1 diff --git a/platform/mynewt/libs/gg/connmgr/include/gg_connmgr.h b/platform/mynewt/libs/gg/connmgr/include/gg_connmgr.h index 0387b9fd..1c35180f 100644 --- a/platform/mynewt/libs/gg/connmgr/include/gg_connmgr.h +++ b/platform/mynewt/libs/gg/connmgr/include/gg_connmgr.h @@ -10,10 +10,6 @@ * * @date 2017-11-13 * - * @details - * Detailed information can be found at this link: - * https://wiki.fitbit.com/display/firmware/BLE+Connection+Manager - * */ #ifndef __CONNECTION_MANAGER_H__ diff --git a/platform/mynewt/libs/gg/connmgr/src/gg_connmgr.c b/platform/mynewt/libs/gg/connmgr/src/gg_connmgr.c index 32a5699c..b62de48f 100644 --- a/platform/mynewt/libs/gg/connmgr/src/gg_connmgr.c +++ b/platform/mynewt/libs/gg/connmgr/src/gg_connmgr.c @@ -10,10 +10,6 @@ * * @date 2017-11-13 * - * @details - * Detailed information can be found at this link: - * https://wiki.fitbit.com/display/firmware/BLE+Connection+Manager - * */ /*---------------------------------------------------------------------- diff --git a/tasks/android/__init__.py b/tasks/android/__init__.py index 42e78fed..b9ed273b 100644 --- a/tasks/android/__init__.py +++ b/tasks/android/__init__.py @@ -14,7 +14,7 @@ def build(_ctx): '''Build All Android tasks''' @task -def test(ctx, coverage=True, sonarqube=False): +def test(ctx, coverage=True, sonarqube=''): '''Runs tests''' bindings_dir = os.path.join(ctx.C.PLATFORM_DIR, "android", "goldengate", "GoldenGateBindings") coverage_dir = os.path.join(bindings_dir, '.externalNativeBuild', 'cmake', 'debug', @@ -46,7 +46,7 @@ def test(ctx, coverage=True, sonarqube=False): tasks.append(remoteapi_command) tasks.append(link_controller_command) if sonarqube: - tasks.append("sonarqube -Dsonar.host.url=https://sonarqube.site-ops.fitbit.com") + tasks.append(f'sonarqube -Dsonar.host.url={sonarqube}') with ctx.cd(root_dir): ctx.run("./gradlew " + " ".join(tasks)) diff --git a/tasks/cmake.py b/tasks/cmake.py index dc9be48a..0a58390d 100644 --- a/tasks/cmake.py +++ b/tasks/cmake.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 import os +import sys import subprocess def build(ctx, build_dir, profile, toolchain_file=None, @@ -17,8 +18,8 @@ def build(ctx, build_dir, profile, toolchain_file=None, cmd = [cmake_wrapper] + cmd # check if Ninja is available, and use the Ninja generator if it is, unless a - # custom generator was requested - if not generator: + # custom generator was requested, or the host is Windows + if not generator and sys.platform != 'win32': try: subprocess.check_output(['ninja', '--version']) cmd.append('-GNinja') diff --git a/tasks/native.py b/tasks/native.py index 0d993ebc..5d73d631 100644 --- a/tasks/native.py +++ b/tasks/native.py @@ -17,7 +17,8 @@ def detect_profile(): '''Automatically detect the profile based on the host platform''' profile = { 'Darwin': 'macOS_cmdline', - 'Linux': 'linux' + 'Linux': 'linux', + 'Windows': 'windows' }.get(platform.system()) if not profile: raise exceptions.PlatformError("Host platform not supported for native build") @@ -26,7 +27,7 @@ def detect_profile(): @task(help={ "debug": "Build the Debug build instead of the Release build", "coverage": "Generate a code coverage report", - "sonarqube": "Enable Sonarqube", + "sonarqube": "Enable Sonarqube scanning", "sanitize": "Enable a sanitizer ('address', ...). You can use this option multiple times, one for each sanitizer.", "cmakegen": "Override CMake generator (e.g. 'Xcode', run `cmake --help` for a list of supported generators)" }, iterable=['sanitize']) @@ -71,8 +72,8 @@ def clean(ctx): '''Blow away the build directory''' ctx.run("rm -rf {}".format(ctx.C.BUILD_DIR_NATIVE)) -@task -def test(ctx, coverage=False, sonarqube=False, output_on_failure=True, verbose=False, file_name=None, skip_build=True): +@task(help={"sonarqube": "Sonarqube host URL"}) +def test(ctx, coverage=False, sonarqube='', output_on_failure=True, verbose=False, file_name=None, skip_build=True): '''Run GoldenGate XP tests Note: please run "inv native.build" to build the unit tests first @@ -91,7 +92,7 @@ def test(ctx, coverage=False, sonarqube=False, output_on_failure=True, verbose=F Note: Please build the unit tests with -c option. i.e. inv native.build -c For more information: https://gcovr.com - $ inv native.test -c -s + $ inv native.test -c -s Same as above, plus a Sonarqube report. ''' @@ -162,4 +163,4 @@ def test(ctx, coverage=False, sonarqube=False, output_on_failure=True, verbose=F ctx.run("gcov {}".format(c_file)) # Run the scanner - ctx.run("sonar-scanner") + ctx.run(f'sonar-scanner -Dsonar.host.url={sonarqube}') diff --git a/xp/CMakeSettings.json b/xp/CMakeSettings.json index 83a6b327..54918c5a 100644 --- a/xp/CMakeSettings.json +++ b/xp/CMakeSettings.json @@ -1,15 +1,16 @@ -{ +{ "configurations": [ { - "name": "x86-Debug", - "generator": "Ninja", - "configurationType": "Debug", - "inheritEnvironments": [ "msvc_x86" ], - "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", - "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", - "cmakeCommandArgs": "-L -C${projectDir}\\config\\profiles\\windows.cmake", - "buildCommandArgs": "-v", - "ctestCommandArgs": "" + "name": "x86-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x86" ], + "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", + "cmakeCommandArgs": "-L -C${projectDir}\\config\\profiles\\windows.cmake", + "buildCommandArgs": "-v", + "ctestCommandArgs": "", + "variables": [] }, { "name": "x86-Release", @@ -18,9 +19,10 @@ "inheritEnvironments": [ "msvc_x86" ], "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", - "cmakeCommandArgs": "-L", + "cmakeCommandArgs": "-L -C${projectDir}\\config\\profiles\\windows.cmake", "buildCommandArgs": "-v", - "ctestCommandArgs": "" + "ctestCommandArgs": "", + "variables": [] }, { "name": "x64-Debug", @@ -29,9 +31,10 @@ "inheritEnvironments": [ "msvc_x64_x64" ], "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", - "cmakeCommandArgs": "", + "cmakeCommandArgs": "-L -C${projectDir}\\config\\profiles\\windows.cmake", "buildCommandArgs": "-v", - "ctestCommandArgs": "" + "ctestCommandArgs": "", + "variables": [] }, { "name": "x64-Release", @@ -40,9 +43,10 @@ "inheritEnvironments": [ "msvc_x64_x64" ], "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", - "cmakeCommandArgs": "", + "cmakeCommandArgs": "-L -C${projectDir}\\config\\profiles\\windows.cmake", "buildCommandArgs": "-v", - "ctestCommandArgs": "" + "ctestCommandArgs": "", + "variables": [] } ] -} +} \ No newline at end of file diff --git a/xp/apps/coap-client/gg_coap_client.c b/xp/apps/coap-client/gg_coap_client.c index 3443a10d..8312fc30 100644 --- a/xp/apps/coap-client/gg_coap_client.c +++ b/xp/apps/coap-client/gg_coap_client.c @@ -786,7 +786,6 @@ main(int argc, char** argv) // setup a listener Client listener; memset(&listener, 0, sizeof(Client)); - listener.output_file = output_file; GG_SET_INTERFACE(&listener, Client, GG_CoapResponseListener); GG_SET_INTERFACE(&listener, Client, GG_CoapBlockwiseResponseListener); @@ -810,6 +809,7 @@ main(int argc, char** argv) return 1; } } + listener.output_file = output_file; // make the request result = SendRequest(endpoint, diff --git a/xp/common/ports/windows/gg_windows_time.c b/xp/common/ports/windows/gg_windows_time.c index f6529db6..4d1137f0 100644 --- a/xp/common/ports/windows/gg_windows_time.c +++ b/xp/common/ports/windows/gg_windows_time.c @@ -31,19 +31,19 @@ GG_Timestamp GG_System_GetCurrentTimestamp(void) { - static uint64_t timer_frequency = 0; - if (timer_frequency == 0) { + static double timer_frequency = 0.0; // timer frequency in units per nanoseconds + if (timer_frequency == 0.0) { // initialize the frequency LARGE_INTEGER _timer_frequency; if (QueryPerformanceFrequency(&_timer_frequency)) { - timer_frequency = (uint64_t)_timer_frequency.QuadPart; + timer_frequency = (double)_timer_frequency.QuadPart / (double)GG_NANOSECONDS_PER_SECOND; } } // get the current timer LARGE_INTEGER now; if (timer_frequency && QueryPerformanceCounter(&now)) { - return (GG_NANOSECONDS_PER_SECOND * (uint64_t)now.QuadPart) / timer_frequency; + return (GG_Timestamp)((double)now.QuadPart / timer_frequency); } else { // something went wrong return 0; diff --git a/xp/config/profiles/windows.cmake b/xp/config/profiles/windows.cmake index 1b064657..09524401 100644 --- a/xp/config/profiles/windows.cmake +++ b/xp/config/profiles/windows.cmake @@ -11,6 +11,7 @@ set(GG_CONFIG_LWIP_PORT "windows" CACHE STRING "") set(GG_CONFIG_DEFAULT_SOCKETS_MODULE "Lwip" CACHE STRING "") set(GG_CONFIG_ENABLE_ANNOTATIONS FALSE CACHE BOOL "") set(GG_CONFIG_ENABLE_THREAD_GUARDS TRUE CACHE BOOL "") +set(GG_CONFIG_ENABLE_TCP TRUE CACHE BOOL "") # Apps selection set(GG_APPS_ENABLE_GATTLINK_SELFTEST_APP FALSE CACHE BOOL "") diff --git a/xp/loop/ports/bsd/gg_bsd_select_loop.c b/xp/loop/ports/bsd/gg_bsd_select_loop.c index bc576f3c..e62a080b 100644 --- a/xp/loop/ports/bsd/gg_bsd_select_loop.c +++ b/xp/loop/ports/bsd/gg_bsd_select_loop.c @@ -82,6 +82,7 @@ typedef ssize_t GG_ssize_t; #if defined(GG_CONFIG_ENABLE_BSD_SOCKETPAIR_EMULATION) #if GG_CONFIG_PLATFORM == GG_PLATFORM_BISON #define INADDR_LOOPBACK 0x7f000001 +#elif GG_CONFIG_PLATFORM == GG_PLATFORM_WINDOWS #else #include #include diff --git a/xp/lwip/CMakeLists.txt b/xp/lwip/CMakeLists.txt index 04093411..fd934c24 100644 --- a/xp/lwip/CMakeLists.txt +++ b/xp/lwip/CMakeLists.txt @@ -48,6 +48,10 @@ if (GG_PORTS_ENABLE_LWIP) add_library(gg-lwip ${LWIP_SRC_FILES} ${LWIP_PORT_FILE}) + if (GG_CONFIG_ENABLE_TCP) + target_compile_definitions(gg-lwip PRIVATE GG_CONFIG_ENABLE_TCP) + endif() + if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "GNU") target_compile_options(gg-lwip PRIVATE -Wno-conversion -Wno-format-nonliteral -Wno-newline-eof -Wno-missing-variable-declarations -Wno-unused-macros -Wno-packed -Wno-covered-switch-default -Wno-gnu-empty-initializer -Wno-zero-length-array -Wno-unused-variable -Wno-type-limits -Wno-unused-parameter) endif() diff --git a/xp/lwip/lwipopts.h.in b/xp/lwip/lwipopts.h.in index cbee3090..b20a0b41 100644 --- a/xp/lwip/lwipopts.h.in +++ b/xp/lwip/lwipopts.h.in @@ -131,7 +131,7 @@ #define MEMP_NUM_TCP_PCB_LISTEN 0 /** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.TCP * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_SEG 0 @@ -371,7 +371,11 @@ /** * LWIP_TCP==1: Turn on TCP. */ +#if defined(GG_CONFIG_ENABLE_TCP) +#define LWIP_TCP 1 +#else #define LWIP_TCP 0 +#endif /* ---------------------------------- diff --git a/xp/module/ports/windows/gg_winsock.c b/xp/module/ports/windows/gg_winsock.c index ae52e802..794db32d 100644 --- a/xp/module/ports/windows/gg_winsock.c +++ b/xp/module/ports/windows/gg_winsock.c @@ -26,7 +26,7 @@ //---------------------------------------------------------------------- static void -GG_WINSOCK_Cleanup(void) +GG_WINSOCK_Cleanup(void* _ignored) { WSACleanup(); } diff --git a/xp/services/blast/gg_blast_service.c b/xp/services/blast/gg_blast_service.c index 736746d0..322e3374 100644 --- a/xp/services/blast/gg_blast_service.c +++ b/xp/services/blast/gg_blast_service.c @@ -152,7 +152,7 @@ GG_BlastService_HandleRequest(GG_RemoteSmoHandler* _self, return GG_FAILURE; } - rc = Fb_Smo_AddChild(result_smo, "throughput", strlen("throughput"), throughput_smo); + rc = Fb_Smo_AddChild(result_smo, "throughput", (unsigned int)strlen("throughput"), throughput_smo); if (rc != FB_SMO_SUCCESS) { Fb_Smo_Destroy(result_smo); Fb_Smo_Destroy(throughput_smo); diff --git a/xp/sockets/ports/lwip/CMakeLists.txt b/xp/sockets/ports/lwip/CMakeLists.txt index 9306b0a4..9a1e17e0 100644 --- a/xp/sockets/ports/lwip/CMakeLists.txt +++ b/xp/sockets/ports/lwip/CMakeLists.txt @@ -17,7 +17,9 @@ if (GG_PORTS_ENABLE_LWIP_SOCKETS) target_sources(gg-sockets PRIVATE ${PORT_DIR}/gg_lwip_sockets.c ${PORT_DIR}/gg_lwip_sockets.h) # silence some warnings, because of LwIP headers that are not 100% clean - set_source_files_properties(${PORT_DIR}/gg_lwip_sockets.c PROPERTIES COMPILE_FLAGS -Wno-conversion) + if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "GNU") + set_source_files_properties(${PORT_DIR}/gg_lwip_sockets.c PROPERTIES COMPILE_FLAGS -Wno-conversion) + endif() else() target_sources(gg-sockets PRIVATE ${PORT_DIR}/gg_lwip_netconn_sockets.c ${PORT_DIR}/gg_lwip_sockets.h) diff --git a/xp/utils/gg_data_probe.c b/xp/utils/gg_data_probe.c index 5cfd8e61..6f9812bb 100644 --- a/xp/utils/gg_data_probe.c +++ b/xp/utils/gg_data_probe.c @@ -361,7 +361,7 @@ GG_DataProbe_AccumulateWithTime(GG_DataProbe* self, size_t byte_count, GG_Timest GG_DataProbeReport* report = &self->report; // Update total stats - self->total_bytes_count += byte_count; + self->total_bytes_count += (uint32_t)byte_count; GG_LOG_FINEST("Probe total bytes: %u", (int)self->total_bytes_count); @@ -397,7 +397,7 @@ GG_DataProbe_AccumulateWithTime(GG_DataProbe* self, size_t byte_count, GG_Timest self->num_samples++; } - target_sample->byte_count = byte_count; + target_sample->byte_count = (double)byte_count; target_sample->time = time; }