Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ jobs:
-DCMAKE_BUILD_TYPE=Release
-DBUILD_SHARED_LIBS=${{ matrix.build-shared }}
-DBUILD_TESTING=OFF
-DNETFT_BUILD_CLI=OFF
-DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/build/cmake-316-install
- name: Build and install core
run: |
Expand Down
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ All notable changes to this project are documented in this file.

### Fixed

- Update the pinned native core to netft-cpp 0.3.1 so fail-stop clients do not receive
stalled or backward FT-sequence samples before the corresponding fault.
- Update the pinned native core to netft-cpp 0.3.3, including lifecycle-safe
client destruction from a sample callback.
- Exclude the upstream legacy CLI sources from the Python package's private core snapshot.

## 2.1.0 - 2026-07-29
Expand Down
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ option(PYNETFT_BUILD_TESTING "Build pyNetFT native tests" OFF)

set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(NETFT_BUILD_CLI OFF CACHE BOOL "" FORCE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

pyNetFT is a synchronous, typed Python client for ATI Industrial Automation Net F/T Ethernet force/torque sensors. It discovers the sensor calibration, streams RDT measurements through a native C++ core, and exposes raw counts, physical measurements, health, and recovery information without requiring NumPy.

- **Tested native core:** the protocol and recovery implementation is pinned to [netft-cpp 0.3.1](https://github.com/netft/netft-cpp/releases/tag/v0.3.1) and is exercised with offline fake sensors and native sanitizers.
- **Tested native core:** the protocol and recovery implementation is pinned to [netft-cpp 0.3.3](https://github.com/netft/netft-cpp/releases/tag/v0.3.3) and is exercised with offline fake sensors and native sanitizers.
- **Sensor-aware data:** calibration, force and torque units, configuration revisions, sequence progress, and faults remain visible to the application.
- **Self-contained typed wheels:** Linux, macOS, and Windows wheels include the native core and a minimal static HTTP-only curl build, plus inline type information for Python 3.10–3.14.

Expand Down
21 changes: 1 addition & 20 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
cmake_minimum_required(VERSION 3.16)

project(netft VERSION 0.3.1 LANGUAGES CXX)
project(netft VERSION 0.3.3 LANGUAGES CXX)

include(CTest)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

option(NETFT_SANITIZERS "Enable address and undefined behavior sanitizers" OFF)
option(NETFT_BUILD_CLI "Build the netft command-line tool" ON)

add_library(netft_sanitizers INTERFACE)
if(NETFT_SANITIZERS)
Expand Down Expand Up @@ -68,17 +67,6 @@ target_link_libraries(netft
$<BUILD_INTERFACE:netft_sanitizers>
)

if(NETFT_BUILD_CLI)
add_library(netft_cli_lib STATIC app/cli.cpp)
target_compile_features(netft_cli_lib PUBLIC cxx_std_17)
target_include_directories(netft_cli_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/app)
target_link_libraries(netft_cli_lib PUBLIC netft::netft)

add_executable(netft_cli app/main.cpp)
set_target_properties(netft_cli PROPERTIES OUTPUT_NAME netft)
target_link_libraries(netft_cli PRIVATE netft_cli_lib)
endif()

install(
DIRECTORY include/netft
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
Expand All @@ -90,13 +78,6 @@ install(
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
if(NETFT_BUILD_CLI)
install(
TARGETS netft_cli
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()

set(netft_cmake_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/netft")
configure_package_config_file(
cmake/netftConfig.cmake.in
Expand Down
10 changes: 5 additions & 5 deletions core/SNAPSHOT.sha256
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
c493d94026a5eb53f0589341d33915b8180c34bd712f2f9f2191e41ca48dd8f5 CMakeLists.txt
3db6fdfbb62d6073fa3f77784235cfe2eff06a1f102fb1d0f3a3f6da02dafa01 CMakeLists.txt
c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 LICENSE
e78f98877ffe87b93dcec3d30d9c59337d3fa0e2e473ecc7134994a0c3bb7092 UPSTREAM
926aedecaf33e0d9a178360ea455ee9cbdd54537f89d75835409fdb28fdcd908 UPSTREAM
40701f04e67bb18052b6c8f1db60cf5d41baab09e5396f5a88c1eb14ad1a7139 cmake/netftConfig.cmake.in
ebb4c53b7e7e65880580a7649e1c1a142e3a9db1fdec7d108d2d7dde0ad0d36d include/netft/client.hpp
e4a52fe7c7e13de95a29bdbd688d295a4a8ddc1805276274b0c14d4092f7253d include/netft/client.hpp
4f7fb383da5456fd8477e1981f4ff3eba9b82ec3a98f3c395e7d482faf75c112 include/netft/discovery.hpp
1beed1a22ad16aa801e0cceb0950548a32d263e01f260a86e72ec58d8f8d1a74 include/netft/export.hpp
912892bcb8bb5f95392c9c74983d91aab103b7adc5735505b0ac97e1012893b1 include/netft/status.hpp
a7c899858aa7a0a28780504f14c1ecdaebb375607119a03500903f3782f45a68 include/netft/types.hpp
e8a68945aaebfd19a1cb1f5cf71f4666d997fa351a41e9adcd137b50a7eb3ae7 src/client.cpp
7199f02fa0fd88059323f507edbf073b2a4827c692d1fd824893cbad8ea9215b src/client.cpp
a7e0bcba7a8cd5ccb1ab04658ea735f2b6a3f2bac81c3bce95578e3c14349650 src/detail/client_impl.cpp
5d194b6b6cb8b04e742ee3e1508ac7b8e7972b5bbc7a02c94003d1f402dfccf1 src/detail/client_impl.hpp
b202cc6e250866e681d16b480911f77d865d9187300111f8482bc4a8b0424b34 src/detail/client_impl.hpp
ad8744385642693bb4666c428a5dbd0d6eff350b0079a6c9ff720512e89b6a53 src/detail/fault_latch.cpp
be488c557e17044948cd62e6de07bf54862d389a584b40b78336479cecdaf23c src/detail/fault_latch.hpp
f5953a7fc4fd5eee56f7aa3568fe7417010e3e767cfbb0ee5922ee5f8aa2a9aa src/detail/protocol.cpp
Expand Down
4 changes: 2 additions & 2 deletions core/UPSTREAM
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
repository=https://github.com/netft/netft-cpp
tag=v0.3.1
commit=859eeda8b077093f9bc49d9c1e5506c334647e7b
tag=v0.3.3
commit=3259b8576b16fb150b51e9ef9090366c5e6efcba
Comment thread
han-xudong marked this conversation as resolved.
paths=CMakeLists.txt,LICENSE,cmake,include,src
4 changes: 4 additions & 0 deletions core/include/netft/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class NETFT_API Client {
using SampleCallback = std::function<void(const Sample &)>;

explicit Client(Config config);
// Destruction is synchronous except when initiated by the sample callback.
// In that case worker shutdown and storage reclamation are deferred because
// a callback cannot join its own thread. The callback must not access the
// Client after initiating destruction.
~Client();
Client(const Client &) = delete;
Client &operator=(const Client &) = delete;
Expand Down
55 changes: 54 additions & 1 deletion core/src/client.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,67 @@
#include "netft/client.hpp"

#include <condition_variable>
#include <deque>
#include <mutex>
#include <thread>
#include <utility>

#include "detail/client_impl.hpp"

namespace netft {
namespace {

template <typename Value> class DeferredDestroyer {
public:
DeferredDestroyer() : worker_(&DeferredDestroyer::run, this) {}

void enqueue(std::unique_ptr<Value> value) {
{
std::scoped_lock lock(mutex_);
pending_.push_back(std::move(value));
}
condition_.notify_one();
}

private:
void run() noexcept {
for (;;) {
std::unique_ptr<Value> value;
{
std::unique_lock<std::mutex> lock(mutex_);
condition_.wait(lock, [&] { return !pending_.empty(); });
value = std::move(pending_.front());
pending_.pop_front();
}
value->stop();
}
}

std::mutex mutex_;
std::condition_variable condition_;
std::deque<std::unique_ptr<Value>> pending_;
std::thread worker_;
};

template <typename Value> DeferredDestroyer<Value> &deferred_destroyer() {
// Callbacks can outlive static teardown. Keeping this worker alive for the
// process lifetime avoids both destruction-order races and lost enqueues.
static auto *instance = new DeferredDestroyer<Value>;
return *instance;
}

} // namespace

Client::Client(Config config) : impl_(std::make_unique<Impl>(std::move(config))) {}

Client::~Client() { stop(); }
Client::~Client() {
if (impl_ && impl_->called_from_worker_thread()) {
impl_->stop();
deferred_destroyer<Impl>().enqueue(std::move(impl_));
return;
}
stop();
}

void Client::start(SampleCallback callback) { impl_->start(std::move(callback)); }

Expand Down
5 changes: 5 additions & 0 deletions core/src/detail/client_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class NETFT_LOCAL Client::Impl {

void start(SampleCallback callback);
void stop() noexcept;
[[nodiscard]] bool called_from_worker_thread() const noexcept {
std::scoped_lock lifecycle_lock(lifecycle_mutex_);
return !worker_exited_.load(std::memory_order_acquire) &&
active_worker_id_ == std::this_thread::get_id();
}
void bias();
bool wait_for_first_sample(std::chrono::duration<double> timeout);
bool faulted() const noexcept;
Expand Down
Loading