From 55fc18d0276daa74f3ab3c5de144441997601f42 Mon Sep 17 00:00:00 2001
From: Ember Chow <emberchow.businiess@iu.edu>
Date: Fri, 22 Jul 2022 14:04:01 -0400
Subject: [PATCH 1/5] fix some docstrings

---
 forcedimension/__init__.py | 88 ++++++++++++++++++++++----------------
 1 file changed, 51 insertions(+), 37 deletions(-)

diff --git a/forcedimension/__init__.py b/forcedimension/__init__.py
index 088ad8a..d8017de 100644
--- a/forcedimension/__init__.py
+++ b/forcedimension/__init__.py
@@ -238,8 +238,9 @@ def pos(self) -> Optional[ImmutableWrapper[MutFSeq]]:
 
         :rtype: Optional[MutableSequence[float]]
 
-        :returns: A mutable sequence of [x, y, z] where x, y, and z are the
-        end-effector's position given in [m].
+        :returns:
+            A mutable sequence of [x, y, z] where x, y, and z are the
+            end-effector's position given in [m].
         """
         self.check_threadex()
         return self._pos_view
@@ -266,8 +267,9 @@ def v(self) -> Optional[ImmutableWrapper[MutFSeq]]:
 
         :rtype: Optional[MutableSequence[float]]
 
-        :returns: A mutable sequence of [vx, vy, vz] where vx, vy, and vz are
-        the end-effector's linear velocity given in [m/s].
+        :returns:
+            A mutable sequence of [vx, vy, vz] where vx, vy, and vz are
+            the end-effector's linear velocity given in [m/s].
         """
         self.check_threadex()
         return self._v_view
@@ -280,8 +282,9 @@ def w(self) -> Optional[ImmutableWrapper[MutFSeq]]:
 
         :rtype: Optional[MutableSequence[float]]
 
-        :returns: A mutable sequence of [wx, wy, wz] where wx, wy, and wz are
-        the end-effector's linear velocity given in [rad/s].
+        :returns:
+            A mutable sequence of [wx, wy, wz] where wx, wy, and wz are
+            the end-effector's linear velocity given in [rad/s].
         """
         self.check_threadex()
         return self._w_view
@@ -294,8 +297,9 @@ def t(self) -> Optional[ImmutableWrapper[MutFSeq]]:
 
         :rtype: Optional[MutableSequence[float]]
 
-        :returns: A mutable sequence of [tx, ty, tz] where tx, ty, and tz are
-        the torque experienced by the end-effector in [Nm]
+        :returns:
+            A mutable sequence of [tx, ty, tz] where tx, ty, and tz are
+            the torque experienced by the end-effector in [Nm]
         """
         self.check_threadex()
         return self._t_view
@@ -308,8 +312,9 @@ def f(self) -> Optional[ImmutableWrapper[MutFSeq]]:
 
         :rtype: Optional[MutableSequence[float]]
 
-        :returns: A mutable sequence of [fx, fy, fz] where fx, fy, and fz are
-        the torque experienced by the end-effector in [N]
+        :returns:
+            A mutable sequence of [fx, fy, fz] where fx, fy, and fz are
+            the torque experienced by the end-effector in [N]
         """
 
         self.check_threadex()
@@ -692,11 +697,12 @@ def get_max_force(self) -> Optional[float]:
         Retrieve the current limit (in N) to the force magnitude that can be
         applied by the haptic device.
 
-        :returns: The current limit (in N) to the force magnitude that can be
-        applied by the haptic device to the end-effector. If there is no limit,
-        None is returned instead.
+        :returns:
+            The current limit (in N) to the force magnitude that can be
+            applied by the haptic device to the end-effector. If there is no
+            limit, None is returned instead.
 
-        rtype: Optional[float]
+        :rtype: Optional[float]
         """
 
         limit = dhd.getMaxForce(ID=cast(int, self._id))
@@ -708,9 +714,9 @@ def set_max_force(self, limit: Optional[float]) -> None:
         Define or disable a limit (in N) to the force magnitude that can be
         applied by the haptic device.
 
-        :param Optional[float] limit: The desired limit (in N) to the force
-        magnitude that can be applied. If the limit is None, the force limit is
-        disabled.
+        :param Optional[float] limit:
+            The desired limit (in N) to the force magnitude that can be
+            applied. If the limit is None, the force limit is disabled.
         """
         if limit is None:
             err = dhd.setMaxForce(ID=cast(int, self._id), limit=-1.0)
@@ -728,9 +734,10 @@ def get_max_torque(self) -> Optional[float]:
         Retrieve the current limit (in Nm) to the torque magnitude that can be
         applied by the haptic device.
 
-        :returns: The current limit (in Nm) to the force magnitude that can be
-        applied by the haptic device to the end-effector. If there is no limit,
-        None is returned instead.
+        :returns:
+            The current limit (in Nm) to the force magnitude that can be
+            applied by the haptic device to the end-effector. If there is no
+            limit, None is returned instead.
 
         rtype: Optional[float]
         """
@@ -744,9 +751,9 @@ def set_max_torque(self, limit: Optional[float]) -> None:
         Define or disable a limit (in N) to the force magnitude that can be
         applied by the haptic device.
 
-        :param Optional[float] limit: The desired limit (in N) to the force
-        magnitude that can be applied. If the limit is None, the force limit is
-        disabled.
+        :param Optional[float] limit:
+            The desired limit (in N) to the force magnitude that can be
+            applied. If the limit is None, the force limit is disabled.
         """
         if limit is None:
             err = dhd.setMaxTorque(ID=cast(int, self._id), limit=-1.0)
@@ -785,7 +792,7 @@ def get_button(self, button_id: int = 0) -> bool:
 
         See Also
         --------
-        :class:forcedimension.dhd.dhd.constants.NovintButtonID
+        :class:forcedimension.dhd.constants.NovintButtonID
         """
         return bool(self._buttons & cast(int, 1 << button_id))
 
@@ -811,6 +818,12 @@ class Gripper:
     case, a Gripper object will be instantiated as well containing methods to
     get kinematic information about the Gripper.
     """
+    _enc: int
+    _angle: float
+    _gap: float
+    _v: float
+    _w: float
+    _fg: float
 
     def __init__(
             self,
@@ -827,12 +840,12 @@ def __init__(
 
         VecType = vecgen
 
-        self._enc: int = 0
-        self._angle: float = nan
-        self._gap: float = nan
-        self._v: float = nan
-        self._w: float = nan
-        self._fg: float = nan
+        self._enc = 0
+        self._angle = nan
+        self._gap = nan
+        self._v = nan
+        self._w = nan
+        self._fg = nan
 
         self._thumb_pos: MutFSeq = VecType()
         self._finger_pos: MutFSeq = VecType()
@@ -883,11 +896,12 @@ def get_max_force(self) -> Optional[float]:
         Retrieve the current limit (in N) to the force magnitude that can be
         applied by the haptic device.
 
-        :returns: The current limit (in N) to the force magnitude that can be
-        applied by the haptic device to the end-effector. If there is no limit,
-        None is returned instead.
+        :returns:
+            The current limit (in N) to the force magnitude that can be
+            applied by the haptic device to the end-effector. If there is no
+            limit, None is returned instead.
 
-        rtype: Optional[float]
+        :rtype: Optional[float]
         """
 
         limit = dhd.getMaxGripperForce(ID=cast(int, self._id))
@@ -899,9 +913,9 @@ def set_max_force(self, limit: Optional[float]) -> None:
         Define or disable a limit (in N) to the force magnitude that can be
         applied by the haptic device.
 
-        :param Optional[float] limit: The desired limit (in N) to the force
-        magnitude that can be applied. If the limit is None, the force limit is
-        disabled.
+        :param Optional[float] limit:
+            The desired limit (in N) to the force magnitude that can be
+            applied. If the limit is None, the force limit is disabled.
         """
         if limit is None:
             err = dhd.setMaxGripperForce(ID=cast(int, self._id), limit=-1.0)

From 9934edae8ae11cf0d0d4bf34b8617f884f396516 Mon Sep 17 00:00:00 2001
From: Ember Chow <emberchow.businiess@iu.edu>
Date: Fri, 22 Jul 2022 14:41:40 -0400
Subject: [PATCH 2/5] another couple docstrings tweaks

---
 forcedimension/__init__.py           | 22 +++++++++++++++-------
 forcedimension/dhd/os_independent.py |  8 --------
 2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/forcedimension/__init__.py b/forcedimension/__init__.py
index d8017de..041594a 100644
--- a/forcedimension/__init__.py
+++ b/forcedimension/__init__.py
@@ -1,3 +1,10 @@
+"""
+.. module::forcedimension
+   :platform: Windows, Unix
+   :synopsis: ForceDimensionSDK high level wrappers.
+
+.. moduleauthor:: Ember "Emmy" Chow <emberchow.business@gmail.com>
+"""
 from math import nan
 from threading import Condition, Lock, Thread
 from time import monotonic, sleep
@@ -558,7 +565,7 @@ def submit(self):
 
         See Also
         --------
-        :func:HapticDevice.req
+        :func:`HapticDevice.req`
 
         """
         self._req = False
@@ -739,7 +746,7 @@ def get_max_torque(self) -> Optional[float]:
             applied by the haptic device to the end-effector. If there is no
             limit, None is returned instead.
 
-        rtype: Optional[float]
+        :rtype: Optional[float]
         """
 
         limit = dhd.getMaxTorque(ID=cast(int, self._id))
@@ -785,14 +792,15 @@ def get_button(self, button_id: int = 0) -> bool:
         """
         See if the button on the device is being pressed.
 
+        See Also
+        --------
+        :class:`forcedimension.dhd.constants.NovintButtonID`
+
+
         :param int button_id: The button to check
 
         :rtype: bool
-        :returns: True if the button is being pressed, False otherwise.
-
-        See Also
-        --------
-        :class:forcedimension.dhd.constants.NovintButtonID
+        :returns: True if the button is being pressed, False otherwise
         """
         return bool(self._buttons & cast(int, 1 << button_id))
 
diff --git a/forcedimension/dhd/os_independent.py b/forcedimension/dhd/os_independent.py
index 3e04744..7a316ec 100644
--- a/forcedimension/dhd/os_independent.py
+++ b/forcedimension/dhd/os_independent.py
@@ -1,11 +1,3 @@
-"""
-.. module::expert
-   :platform: Windows, Unix
-   :synopsis: libdhd "OS Independent SDK" Python libdhd
-
-.. moduleauthor:: Ember "Emmy" Chow <emberchow.business@gmail.com>
-"""
-
 from ctypes import c_bool, c_byte, c_double
 from forcedimension import runtime
 

From e260bd0af19bcd1f5d5a4711a3e7e8f1cb264d08 Mon Sep 17 00:00:00 2001
From: Ember Chow <emberchow.businiess@iu.edu>
Date: Tue, 16 May 2023 20:39:46 -0700
Subject: [PATCH 3/5] Patch dhdSleep

---
 forcedimension/__init__.py           | 2 +-
 forcedimension/dhd/os_independent.py | 5 ++---
 pyproject.toml                       | 4 ++--
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/forcedimension/__init__.py b/forcedimension/__init__.py
index 088ad8a..d3a79b3 100644
--- a/forcedimension/__init__.py
+++ b/forcedimension/__init__.py
@@ -23,7 +23,7 @@
 )
 
 
-__version__ = '0.1.5'
+__version__ = '0.1.6'
 
 
 DefaultVecType = EuclidianVector
diff --git a/forcedimension/dhd/os_independent.py b/forcedimension/dhd/os_independent.py
index 3e04744..7276ee9 100644
--- a/forcedimension/dhd/os_independent.py
+++ b/forcedimension/dhd/os_independent.py
@@ -68,7 +68,7 @@ def getTime() -> float:
 
 
 _libdhd.dhdSleep.argtypes = [c_double]
-_libdhd.dhd.restype = None
+_libdhd.dhdSleep.restype = None
 
 
 def sleep(sec: float) -> None:
@@ -81,5 +81,4 @@ def sleep(sec: float) -> None:
 
 
 def startThread():
-    # TODO implement startThread
-    pass
+    raise NotImplementedError()
diff --git a/pyproject.toml b/pyproject.toml
index 7b26c38..d8651fc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
 
 [project]
 name = "forcedimension"
-version = "0.1.5"
-authors = [ 
+version = "0.1.6"
+authors = [
     { name="Ember Chow", email="emberchow.business@gmail.com" },
 ]
 description = "Python Bindings for the ForceDimension SDK"

From d8ed1a219bfa8fda77d60e5de7e2561bd313f6d1 Mon Sep 17 00:00:00 2001
From: Ember Chow <emberchow.businiess@iu.edu>
Date: Tue, 20 Jun 2023 15:52:58 -0700
Subject: [PATCH 4/5] Added getForceAndTorqueAndGripperForce

---
 forcedimension/dhd/__init__.py | 97 ++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/forcedimension/dhd/__init__.py b/forcedimension/dhd/__init__.py
index 57b2d8a..7a8f129 100644
--- a/forcedimension/dhd/__init__.py
+++ b/forcedimension/dhd/__init__.py
@@ -2536,6 +2536,103 @@ def setForceAndTorqueAndGripperForce(f: FloatVectorLike,
     )
 
 
+_libdhd.dhdGetForceAndTorqueAndGripperForce.argtypes = [
+    c_double,
+    c_double,
+    c_double,
+    c_double,
+    c_double,
+    c_double,
+    c_double,
+    c_byte
+]
+_libdhd.dhdGetForceAndTorqueAndGripperForce.restype = c_int
+
+def getForceAndTorqueAndGripperForce(
+    ID: int = -1,
+    f_out: Optional[MutableFloatVectorLike] = None,
+    t_out: Optional[MutableFloatVectorLike] = None
+) -> Tuple[
+    Union[MutableFloatVectorLike, List[float]],
+    Union[MutableFloatVectorLike, List[float]],
+    float,
+    int
+]:
+    """
+    Retrieve the force and torque vectors applied to the device end-effector.
+
+    :param int ID:
+         Device ID (see multiple devices section for details), defaults to -1.
+
+    :param Optional[MutableFloatVectorLike] f_out:
+        An output buffer to store the applied forces on the end-effector. If
+        specified, the return will contain a reference to this buffer rather to
+        a newly allocated list, optional.
+
+    :param Optional[MutableFloatVectorLike] t_out:
+        An output buffer to store the applied torques on the end-effector. If
+        specified, the return will contain a reference to this buffer rather to
+        a newly allocated list, optional.
+
+    :raises ValueError:
+        If ``ID`` is not implicitly convertible to C char.
+
+    :returns:
+        A tuple in the form  ``([fx, fy, fz], [tx, ty, tz], fg, err)``.
+        ``[fx, fy, fz]`` are translation forces applied to the end-effector
+        (in [N])  about the X, Y, and Z axes, respectively. ``[tx, ty, tz]``
+        refers to the torques applied to the end-effector (in [Nm]) about
+        the X, Y, and Z axes.  ``fg`` refers to the gripper force (in [Nm]).
+        ``err`` is 0, on success, -1 otherwise.
+
+    :rtype:
+        Tuple
+        [
+        Union[MutableFloatVectorLike, List[float]],
+        Union[MutableFloatVectorLike, List[float]],
+        int
+        ]
+
+    """
+
+    fx = c_double()
+    fy = c_double()
+    fz = c_double()
+
+    tx = c_double()
+    ty = c_double()
+    tz = c_double()
+
+    fg = c_double()
+
+    err = _libdhd.dhdGetForceAndTorqueAndGripperForce(
+        byref(fx), byref(fy), byref(fz),
+        byref(tx), byref(ty), byref(tz),
+        byref(fg),
+        ID
+    )
+
+    if f_out is None:
+        f_ret = [fx.value, fy.value, fz.value]
+    else:
+        f_ret = f_out
+
+        f_out[0] = fx.value
+        f_out[1] = fy.value
+        f_out[2] = fz.value
+
+    if t_out is None:
+        t_ret = [tx.value, ty.value, tz.value]
+    else:
+        t_ret = t_out
+
+        t_out[0] = tx.value
+        t_out[1] = ty.value
+        t_out[2] = tz.value
+
+    return (f_ret, t_ret, fg.value, err)
+
+
 _libdhd.dhdConfigLinearVelocity.argtypes = [c_int, c_int, c_byte]
 _libdhd.dhdConfigLinearVelocity.restype = c_int
 

From 2174f53dbf1d76e5451d689c59f67d34aff3ec7f Mon Sep 17 00:00:00 2001
From: Ember Chow <emberchow.businiess@iu.edu>
Date: Tue, 20 Jun 2023 16:00:20 -0700
Subject: [PATCH 5/5] fix typing of getForceAndTorqueAndGripperForce

---
 forcedimension/dhd/__init__.py | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/forcedimension/dhd/__init__.py b/forcedimension/dhd/__init__.py
index 7a8f129..dd13672 100644
--- a/forcedimension/dhd/__init__.py
+++ b/forcedimension/dhd/__init__.py
@@ -2537,13 +2537,13 @@ def setForceAndTorqueAndGripperForce(f: FloatVectorLike,
 
 
 _libdhd.dhdGetForceAndTorqueAndGripperForce.argtypes = [
-    c_double,
-    c_double,
-    c_double,
-    c_double,
-    c_double,
-    c_double,
-    c_double,
+    POINTER(c_double),
+    POINTER(c_double),
+    POINTER(c_double),
+    POINTER(c_double),
+    POINTER(c_double),
+    POINTER(c_double),
+    POINTER(c_double),
     c_byte
 ]
 _libdhd.dhdGetForceAndTorqueAndGripperForce.restype = c_int