Skip to content

Commit

Permalink
[FX-325][FX-322][FX-323][FX-324] V11.0.9 (#120)
Browse files Browse the repository at this point in the history
* Bumps version to 11.0.9.

* Adds windows dlls path to constants.py.

* Passes timeout to get_c_library.

* Checks for and downloaded win dlls from s3.

* Adds the bootloading keyword to open.

* Adds minimum_required_version to v12-specific functionality.

* Fixes a bug with win dlls.

* Lints.

---------

Co-authored-by: Jared <jcoughlin@dephy.com>
  • Loading branch information
jcoughlin11 and Jared authored Oct 2, 2023
1 parent cf8e33c commit 207be38
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 55 deletions.
2 changes: 1 addition & 1 deletion flexsea/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "11.0.8"
__version__ = "11.0.9"
36 changes: 33 additions & 3 deletions flexsea/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class Device:
then the traceback limit is set to 0. If ``True``, Python's
default traceback limit is used.
s3Timeout : int, optional
Time, in seconds, spent trying to connect to S3 before an
exception is raised.
Attributes
----------
Expand Down Expand Up @@ -160,6 +164,7 @@ def __init__(
logLevel: int = 4,
interactive: bool = True,
debug: bool = False,
s3Timeout: int = 60,
) -> None:
if not debug:
sys.tracebacklimit = 0
Expand All @@ -175,7 +180,7 @@ def __init__(
self.interactive = interactive

self.firmwareVersion = validate_given_firmware_version(
firmwareVersion, self.interactive
firmwareVersion, self.interactive, s3Timeout
)

if libFile:
Expand All @@ -197,7 +202,9 @@ def __init__(
self.id: int = 0
self.streamingFrequency: int = 0

(self._clib, self.libFile) = get_c_library(self.firmwareVersion, self.libFile)
(self._clib, self.libFile) = get_c_library(
self.firmwareVersion, self.libFile, s3Timeout
)

self._fields: List[str] | None = None
self._gains: dict = {}
Expand Down Expand Up @@ -238,20 +245,41 @@ def __del__(self) -> None:
# -----
# open
# -----
def open(self) -> None:
def open(self, bootloading: bool = False) -> None:
"""
Establish a connection to a device.
This is needed in order to send commands to the device and/or
receive data from the device via serial communication through
the COM port.
Parameters
----------
bootloading : bool (optional)
This keyword is really onlymeant to be used by the
bootloader and a user of `flexsea` should not have to use
it at all.
Starting with v12.0.0, a development version number was
introduced. We can only connect to the device if both the
firmware version (e.g., 12.0.0) and the development version
(e.g., 2.0.0) match. If only the firmware version matches,
we can connect to the device, but not send motor commands,
only the bootloading command.
"""
if self.connected:
print("Already connected.")
return

port = self.port.encode("utf-8")

if bootloading and self.firmwareVersion >= Version("12.0.0"):
try:
self.id = self._clib.fxOpenLimited(port)
except AttributeError as err:
msg = "Error, unable to connect to device. Your library is missing "
msg += "the `fxOpenLimited` function."
raise RuntimeError(msg) from err

self.id = self._clib.fxOpen(port, self.baudRate, self.logLevel)

if self.id in (self._INVALID_DEVICE.value, -1):
Expand Down Expand Up @@ -1578,6 +1606,7 @@ def libVersion(self) -> str:
# log files
# -----

@minimum_required_version("12.0.0")
@requires_status("connected")
def set_file_name(self, name) -> None:
"""
Expand All @@ -1590,6 +1619,7 @@ def set_file_name(self, name) -> None:
"""
return self._clib.fxSetLoggerName(name.encode("utf-8"), self.id)

@minimum_required_version("12.0.0")
@requires_status("connected")
def set_file_size(self, size) -> None:
"""
Expand Down
5 changes: 5 additions & 0 deletions flexsea/utilities/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
# specs, api specs, and bootloader tools
dephyPublicFilesBucket = "dephy-public-files"

# On Windows, several dll files from mingw are needed in order for the
# library to work correctly
winDllsDir = "win_dlls"
winDllsPath = dephyPath.joinpath(winDllsDir)


# ============================================
# Version Configuration
Expand Down
162 changes: 112 additions & 50 deletions flexsea/utilities/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
from pathlib import Path
from typing import Tuple
import zipfile

from botocore.exceptions import EndpointConnectionError
from semantic_version import Version
Expand All @@ -16,7 +17,9 @@
# ============================================
# get_c_library
# ============================================
def get_c_library(firmwareVersion: Version, libFile: Path | None) -> Tuple:
def get_c_library(
firmwareVersion: Version, libFile: Path | None, timeout: int = 60
) -> Tuple:
"""
Loads the correct C library for interacting with the device.
Expand All @@ -33,6 +36,10 @@ def get_c_library(firmwareVersion: Version, libFile: Path | None) -> Tuple:
libFile : Path, None
The path to the local library file to load.
timeout : int, optional
Time, in seconds, spent trying to connect to S3 before an
exception is raised.
Raises
------
EndpointConnectionError
Expand All @@ -52,23 +59,25 @@ def get_c_library(firmwareVersion: Version, libFile: Path | None) -> Tuple:
libFile.parent.mkdir(parents=True, exist_ok=True)
libObj = f"{fxc.libsDir}/{firmwareVersion}/{_os}/{libFile.name}"
try:
s3_download(libObj, fxc.dephyPublicFilesBucket, str(libFile), None)
s3_download(
libObj, fxc.dephyPublicFilesBucket, str(libFile), None, timeout
)
except EndpointConnectionError as err:
msg = "Error: could not connect to the internet to download the "
msg += "necessary C library file. Please connect to the internet and "
msg += "try again."
print(msg)
raise err

clib = _load_clib(libFile)
clib = _load_clib(libFile, timeout)

return (_set_prototypes(clib, firmwareVersion), libFile)


# ============================================
# _load_clib
# ============================================
def _load_clib(libFile: Path) -> c.CDLL:
def _load_clib(libFile: Path, timeout: int = 60) -> c.CDLL:
"""
Uses ctypes to actually create an interface to the library file. If
we're on Windows, we have to additionally add several directories to
Expand All @@ -79,22 +88,47 @@ def _load_clib(libFile: Path) -> c.CDLL:
libFile = str(libFile)

if "win" in get_os():
try:
for extraPath in os.environ["PATH"].split(";"):
if os.path.exists(extraPath) and "mingw" in extraPath:
os.add_dll_directory(extraPath)
os.add_dll_directory(libFile)
except OSError as err:
msg = f"Error loading precompiled library: `{libFile}`\n"
msg += "The most likely cause is a mismatch between the Python, pip and "
msg += "shell architectures.\nPlease ensure all three are either 32 or 64 "
msg += "bit.\nKeep different versions isolated by virtual environments.\n"
print(msg)
raise err
_add_windows_dlls(libFile, timeout)

return c.cdll.LoadLibrary(libFile)


# ============================================
# _add_windows_dlls
# ============================================
def _add_windows_dlls(libFile: str, timeout: int = 60) -> None:
"""
There are several dlls that are required for the precompiled C lib
to work on Windows. These dlls come packaged with Git Bash, but if
you're not using Git Bash and you don't have MinGW on your PATH,
then trying to use the library will error out. As such, here we
make sure that the necessary dlls are on the system and add them
to the PATH. If they are not, we download them from S3 and then
add them to the PATH.
"""
opSys = get_os()
dllZip = fxc.dephyPath.joinpath("bootloader_tools", opSys, "win_dlls.zip")
base = dllZip.name.split(".")[0]
extractedDest = Path(os.path.dirname(dllZip)).joinpath(base)

if not dllZip.exists():
obj = str(Path("bootloader_tools").joinpath(opSys, "win_dlls.zip").as_posix())
bucket = fxc.dephyPublicFilesBucket
s3_download(obj, bucket, str(dllZip), timeout=timeout)
with zipfile.ZipFile(dllZip, "r") as archive:
archive.extractall(extractedDest)
os.add_dll_directory(extractedDest.joinpath("git_bash_mingw64", "bin"))
try:
os.add_dll_directory(libFile)
except OSError as err:
msg = f"Error loading precompiled library: `{libFile}`\n"
msg += "The most likely cause is a mismatch between the Python, pip and "
msg += "shell architectures.\nPlease ensure all three are either 32 or 64 "
msg += "bit.\nKeep different versions isolated by virtual environments.\n"
print(msg)
raise err


# ============================================
# _set_prototypes
# ============================================
Expand All @@ -104,6 +138,18 @@ def _set_prototypes(clib: c.CDLL, firmwareVersion: Version) -> c.CDLL:
clib.fxOpen.argtypes = [c.c_char_p, c.c_uint, c.c_uint]
clib.fxOpen.restype = c.c_int

# Limited open
if firmwareVersion >= Version("12.0.0"):
try:
clib.fxOpenLimited.argtypes = [c.c_char_p]
clib.fxOpenLimited.restype = c.c_int
# v12 changed how versioning works and employs a development version
# that we do not have access to. Further, the libs were uploaded to S3
# all under 12.0.0 regardless of development version, so there are some
# version 12s that don't have this function
except AttributeError:
pass

# Close
clib.fxClose.argtypes = [
c.c_uint,
Expand All @@ -114,11 +160,19 @@ def _set_prototypes(clib: c.CDLL, firmwareVersion: Version) -> c.CDLL:
clib.fxStartStreaming.argtypes = [c.c_uint, c.c_uint, c.c_bool]
clib.fxStartStreaming.restype = c.c_int

# files
clib.fxSetLoggerName.argtypes = [c.c_char_p]
clib.fxSetLoggerName.restype = None
clib.fxSetLoggerSize.argtypes = [c.c_int]
clib.fxSetLoggerSize.restype = None
# Log file specification
if firmwareVersion >= Version("12.0.0"):
try:
clib.fxSetLoggerName.argtypes = [c.c_char_p]
clib.fxSetLoggerName.restype = None
clib.fxSetLoggerSize.argtypes = [c.c_int]
clib.fxSetLoggerSize.restype = None
# v12 changed how versioning works and employs a development version
# that we do not have access to. Further, the libs were uploaded to S3
# all under 12.0.0 regardless of development version, so there are some
# version 12s that don't have this function
except AttributeError:
pass

# Start streaming with safety
if firmwareVersion >= Version("9.1.2"):
Expand Down Expand Up @@ -278,35 +332,43 @@ def _set_prototypes(clib: c.CDLL, firmwareVersion: Version) -> c.CDLL:
clib.fxSetUVLO.argtypes = [c.c_uint, c.c_uint]
clib.fxSetUVLO.restype = c.c_int

# Get num utts
clib.fxGetNumUtts.argtypes = []
clib.fxGetNumUtts.restype = c.c_int

# Set utts
clib.fxSetUTT.argtypes = [c.c_uint, c.POINTER(c.c_int), c.c_uint, c.c_byte]
clib.fxSetUTT.restype = c.c_int

# Reset utts
clib.fxSetUTTsToDefault.argtypes = [
c.c_uint,
]
clib.fxSetUTTsToDefault.restype = c.c_int

# Save utts
clib.fxSaveUTTToMemory.argtypes = [
c.c_uint,
]
clib.fxSaveUTTToMemory.restype = c.c_int

# Request utts
clib.fxRequestUTT.argtypes = [
c.c_uint,
]
clib.fxRequestUTT.restype = c.c_int

# Get last received utts
clib.fxGetLastReceivedUTT.argtypes = [c.c_uint, c.POINTER(c.c_int), c.c_uint]
clib.fxGetLastReceivedUTT.restype = c.c_int
# Somehow, it appears 10.1 doesn't have these
try:
# Get num utts
clib.fxGetNumUtts.argtypes = []
clib.fxGetNumUtts.restype = c.c_int

# Set utts
clib.fxSetUTT.argtypes = [c.c_uint, c.POINTER(c.c_int), c.c_uint, c.c_byte]
clib.fxSetUTT.restype = c.c_int

# Reset utts
clib.fxSetUTTsToDefault.argtypes = [
c.c_uint,
]
clib.fxSetUTTsToDefault.restype = c.c_int

# Save utts
clib.fxSaveUTTToMemory.argtypes = [
c.c_uint,
]
clib.fxSaveUTTToMemory.restype = c.c_int

# Request utts
clib.fxRequestUTT.argtypes = [
c.c_uint,
]
clib.fxRequestUTT.restype = c.c_int

# Get last received utts
clib.fxGetLastReceivedUTT.argtypes = [
c.c_uint,
c.POINTER(c.c_int),
c.c_uint,
]
clib.fxGetLastReceivedUTT.restype = c.c_int
except AttributeError:
print("Warning: could not find UTT methods in library.")

# IMU Calibration
clib.fxSetImuCalibration.argtypes = [
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "flexsea"
version = "11.0.8"
version = "11.0.9"
description = ""
authors = ["Jared <jcoughlin@dephy.com>"]
readme = "README.md"
Expand Down

0 comments on commit 207be38

Please sign in to comment.