Author SHA1 Message Date
Paul Hollinsky f16ee630ee Checksum failure logging to stderr for debugging 2019-11-06 10:24:55 -05:00
2612 changed files with 36844 additions and 469158 deletions
+1 -7
View File
@@ -8,10 +8,4 @@ CMakeSettings.json
third-party/concurrentqueue/benchmarks
third-party/concurrentqueue/tests
*.bak
.vs
.cache
*.wav
*.orig
examples/csharp/bin
examples/csharp/obj
test/system
.vs
-516
View File
@@ -1,516 +0,0 @@
variables:
DEBIAN_FRONTEND: noninteractive
stages:
- build
- unit_test
- hardware_test
- deploy
#-------------------------------------------------------------------------------
# Windows
#-------------------------------------------------------------------------------
build windows/x64:
stage: build
script:
- CMD.EXE /C ci\build-windows64.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- icsneo-windows
unit_test windows/x64:
stage: unit_test
script:
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x64
needs:
- build windows/x64
tags:
- icsneo-windows
timeout: 5m
build windows/x86:
stage: build
script:
- CMD.EXE /C ci\build-windows32.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- icsneo-windows
unit_test windows/x86:
stage: unit_test
script:
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x86
needs:
- build windows/x86
tags:
- icsneo-windows
timeout: 5m
#-------------------------------------------------------------------------------
# Ubuntu
#-------------------------------------------------------------------------------
.build_linux_ubuntu_gcc: &build_linux_ubuntu_gcc
stage: build
script:
- apt update -y
- apt upgrade -y
- apt install -y g++ ninja-build cmake libusb-1.0-0-dev libpcap-dev git
- sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_ubuntu_gcc: &test_linux_ubuntu_gcc
stage: unit_test
script:
- apt update -y
- apt upgrade -y
- apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
.build_linux_ubuntu_clang: &build_linux_ubuntu_clang
stage: build
script:
- apt update -y
- apt upgrade -y
- apt install -y clang lld ninja-build cmake libusb-1.0-0-dev libpcap-dev git
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_ubuntu_clang: &test_linux_ubuntu_clang
stage: unit_test
script:
- apt update -y
- apt upgrade -y
- apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/ubuntu/2004/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:20.04
unit_test linux/ubuntu/2004/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:20.04
dependencies:
- build linux/ubuntu/2004/amd64/gcc
needs:
- build linux/ubuntu/2004/amd64/gcc
build linux/ubuntu/2004/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:20.04
unit_test linux/ubuntu/2004/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:20.04
dependencies:
- build linux/ubuntu/2004/amd64/clang
needs:
- build linux/ubuntu/2004/amd64/clang
build linux/ubuntu/2204/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/gcc
needs:
- build linux/ubuntu/2204/amd64/gcc
build linux/ubuntu/2204/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/clang
needs:
- build linux/ubuntu/2204/amd64/clang
#-------------------------------------------------------------------------------
# Fedora
#-------------------------------------------------------------------------------
.build_linux_fedora_gcc: &build_linux_fedora_gcc
stage: build
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y g++ libpcap-devel cmake ninja-build libusb1-devel git
- sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_fedora_gcc: &test_linux_fedora_gcc
stage: unit_test
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
.build_linux_fedora_clang: &build_linux_fedora_clang
stage: build
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y clang lld libpcap-devel cmake ninja-build libusb1-devel git
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_fedora_clang: &test_linux_fedora_clang
stage: unit_test
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/fedora/37/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:37
unit_test linux/fedora/37/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:37
dependencies:
- build linux/fedora/37/amd64/gcc
needs:
- build linux/fedora/37/amd64/gcc
build linux/fedora/37/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:37
unit_test linux/fedora/37/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:37
dependencies:
- build linux/fedora/37/amd64/clang
needs:
- build linux/fedora/37/amd64/clang
build linux/fedora/38/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:38
unit_test linux/fedora/38/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:38
dependencies:
- build linux/fedora/38/amd64/gcc
needs:
- build linux/fedora/38/amd64/gcc
build linux/fedora/38/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:38
unit_test linux/fedora/38/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:38
dependencies:
- build linux/fedora/38/amd64/clang
needs:
- build linux/fedora/38/amd64/clang
build linux/fedora/39/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:39
unit_test linux/fedora/39/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:39
dependencies:
- build linux/fedora/39/amd64/gcc
needs:
- build linux/fedora/39/amd64/gcc
build linux/fedora/39/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:39
unit_test linux/fedora/39/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:39
dependencies:
- build linux/fedora/39/amd64/clang
needs:
- build linux/fedora/39/amd64/clang
.hw_test: &hw_test
stage: hardware_test
tags:
- libicsneo_hil
timeout: 5m
script:
- echo $GUEST_OS_TAG
- echo $DEVICE_PORT
- /opt/libvirt-driver/prepare.sh
- /opt/libvirt-driver/run.sh
after_script:
- /opt/libvirt-driver/cleanup.sh
allow_failure: true
.fedora38_needs: &fedora38_needs
needs:
- job: build linux/fedora/38/amd64/clang
artifacts: true
hardware_test fedora38-red2:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_A
hardware_test fedora38-vcan42:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_D
hardware_test fedora38-fire3:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_B
hardware_test fedora38-vcan42-EL:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_C
.ubuntu2204_needs: &ubuntu2204_needs
needs:
- job: build linux/ubuntu/2204/amd64/clang
artifacts: true
hardware_test ubuntu2204-red2:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_A
hardware_test ubuntu2204-vcan42:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_D
hardware_test ubuntu2204-fire3:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_B
hardware_test ubuntu2204-vcan42-EL:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_C
.win10_needs: &win10_needs
needs:
- job: build windows/x64
artifacts: true
hardware_test win10-red2:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_A
hardware_test win10-vcan42:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_D
hardware_test win10-fire3:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_B
hardware_test win10-vcan42-EL:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_C
#-------------------------------------------------------------------------------
# Python Module
#-------------------------------------------------------------------------------
build python/linux/amd64:
stage: build
tags:
- linux-build
image: python:3.12
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- curl -sSL https://get.docker.com/ | sh
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/linux/arm64:
stage: build
tags:
- arm64-linux-build
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/macos:
stage: build
tags:
- macos-arm64
variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_ARCHS: arm64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/install:$CI_PROJECT_DIR/libusb/install
MACOSX_DEPLOYMENT_TARGET: 10.14
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/windows:
stage: build
tags:
- libicsneo-win-x64
variables:
CIBW_ARCHS: AMD64
CIBW_ENVIRONMENT: CMAKE_GENERATOR=Ninja
script:
- cmd /c ci\build-wheel-windows.bat
artifacts:
paths:
- wheelhouse
deploy python/pypi:
stage: deploy
variables:
TWINE_USERNAME: __token__
TWINE_PASSWORD: $PYPI_TOKEN
tags:
- linux-build
image: python:3.12
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- python3 -m pip install -U twine
- twine upload wheelhouse/*
dependencies:
- build python/linux/amd64
- build python/linux/arm64
- build python/macos
- build python/windows
needs:
- build python/linux/amd64
- build python/linux/arm64
- build python/macos
- build python/windows
-15
View File
@@ -1,15 +0,0 @@
version: 2
build:
os: "ubuntu-24.04"
tools:
python: "3.12"
apt_packages:
- doxygen
python:
install:
- requirements: docs/icsneopy/requirements.txt
sphinx:
configuration: docs/conf.py
+1 -1
View File
@@ -4,7 +4,7 @@ KERNEL=="ttyUSB?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
KERNEL=="ttyACM?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
# neoVI ION/PLASMA PIDs are not in the latest ftdi_sio driver so lets make a
# rule to add it when we see a new unclaimed device.
# rule to add it when we see a new unclaimed device.
# PLASMA = 0x0801, ION = 0x0901
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", \
ATTRS{idVendor}=="093c", ATTRS{idProduct}=="0801", \
+54 -355
View File
@@ -1,37 +1,13 @@
cmake_minimum_required(VERSION 3.12)
project(libicsneo VERSION 0.3.0)
cmake_minimum_required(VERSION 3.2)
project(libicsneo VERSION 0.2.0)
cmake_policy(SET CMP0074 NEW)
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
option(LIBICSNEO_BUILD_UNIT_TESTS "Build unit tests." OFF)
option(LIBICSNEO_BUILD_SYSTEM_TESTS "Build system tests." OFF)
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
# Device Drivers
# You almost certainly don't want firmio for your build,
# it is only relevant for communication between Linux and
# CoreMini from the onboard processor of the device.
option(LIBICSNEO_ENABLE_FIRMIO "Enable communication between Linux and CoreMini within the same device" OFF)
option(LIBICSNEO_ENABLE_RAW_ETHERNET "Enable devices which communicate over raw ethernet" ON)
option(LIBICSNEO_ENABLE_CDCACM "Enable devices which communicate over USB CDC ACM" ON)
option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX" ON)
option(LIBICSNEO_ENABLE_TCP "Enable devices which communicate over TCP" OFF)
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
set(CMAKE_CXX_STANDARD 11)
include(GNUInstallDirs)
@@ -45,15 +21,10 @@ if(MSVC)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html
# Still supported until a suitable replacement is standardized
add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
endif()
find_package(Threads REQUIRED)
# doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
@@ -68,7 +39,7 @@ if(LIBICSNEO_BUILD_DOCS)
if(DOXYGEN_FOUND)
message("Will build Doxygen based documentation")
add_custom_target(libicsneo_doxygen
add_custom_target(libicsneo_doxygen ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen"
@@ -96,7 +67,7 @@ if(LIBICSNEO_BUILD_DOCS)
"${ICSNEO_DOCS_DIR}/conf.py"
@ONLY)
add_custom_target(libicsneo_sphinx ALL
add_custom_target(libicsneo_sphinx
${SPHINX_EXECUTABLE}
-q -b html
-c "${ICSNEO_DOCS_DIR}"
@@ -109,202 +80,36 @@ if(LIBICSNEO_BUILD_DOCS)
endif()
endif()
if(WIN32)
set(PLATFORM_SRC
platform/windows/registry.cpp
)
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/windows/pcap.cpp
platform/windows/internal/pcapdll.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/windows/vcp.cpp
)
endif()
else() # Darwin or Linux
set(PLATFORM_SRC)
if(LIBICSNEO_ENABLE_FIRMIO)
list(APPEND PLATFORM_SRC
platform/posix/firmio.cpp
)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/posix/pcap.cpp
)
endif()
if(LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/posix/ftdi.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC
platform/posix/cdcacm.cpp
)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
list(APPEND PLATFORM_SRC
platform/posix/darwin/cdcacmdarwin.cpp
)
else() # Linux or other
list(APPEND PLATFORM_SRC
platform/posix/linux/cdcacmlinux.cpp
)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
message(WARNING
"There is no CDCACM platform port defined for ${CMAKE_SYSTEM_NAME}!\n"
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly."
)
endif()
endif()
endif()
file(GLOB PLATFORM_SRC_EXTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/*.cpp)
file(GLOB PLATFORM_SRC_INTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/internal/*.cpp)
set(PLATFORM_SRC ${PLATFORM_SRC_EXTERNAL} ${PLATFORM_SRC_INTERNAL})
else()
file(GLOB PLATFORM_SRC ${CMAKE_CURRENT_SOURCE_DIR}/platform/posix/*.cpp)
endif()
if(LIBICSNEO_ENABLE_FTD3XX)
if(NOT FTD3XX_ROOT) # allow system override
include(FetchContent)
if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.3.0.10-win-x64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=459e635496ab47d6069c9d3515fdd6d82cba3d95e7ae34f794d66ffdf336e9d1")
elseif(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.3.0.10-win-i686.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=ce4259ae11772d6ede7d217172156fa392f329b29d9455131f4126a2fb89dad1")
elseif(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-macos-universal2.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=0904ac5eda8e1dc4b5aac3714383bcc7792b42dfeb585dce6cbfb8b67b8c0c51")
elseif(UNIX)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-x64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cf66bf299fc722f050cdd3c36998a670f1df69f7c0df18afa73707277067114b")
endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-aarch64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=66341b5112b9841e959e81400b51711be96fec91894477c5cbfc29b10a0c00a6")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-armhf.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cec1f959b48a11eb6b829ed43c81b6ba1c0bcf3e797bafcc84a6376e5ffc3c47")
endif()
endif()
endif()
if(NOT LIBICSNEO_FTD3XX_URL)
message(FATAL_ERROR "Unsupported platform for FTD3XX driver")
endif()
FetchContent_Declare(
ftdi3xx
URL ${LIBICSNEO_FTD3XX_URL}
URL_HASH ${LIBICSNEO_FTD3XX_URL_HASH}
)
FetchContent_GetProperties(ftdi3xx)
if(NOT ftdi3xx_POPULATED)
FetchContent_Populate(ftdi3xx)
endif()
set(FTD3XX_ROOT "${ftdi3xx_SOURCE_DIR}")
endif()
find_package(FTD3XX REQUIRED)
list(APPEND PLATFORM_SRC
platform/ftd3xx.cpp
)
endif()
if(LIBICSNEO_ENABLE_TCP)
list(APPEND PLATFORM_SRC
platform/tcp.cpp
)
endif()
if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# Extensions
set(LIBICSNEO_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
foreach(EXT_PATH ${LIBICSNEO_EXTENSION_DIRS})
get_filename_component(EXT_DIR ${EXT_PATH} NAME)
message("Adding extension " ${EXT_DIR})
add_subdirectory(${EXT_PATH} ${CMAKE_CURRENT_BINARY_DIR}/${EXT_DIR})
endforeach()
set(SRC_FILES
set(COMMON_SRC
communication/message/flexray/control/flexraycontrolmessage.cpp
communication/message/callback/streamoutput/a2bwavoutput.cpp
communication/message/a2bmessage.cpp
communication/message/apperrormessage.cpp
communication/message/neomessage.cpp
communication/message/ethphymessage.cpp
communication/message/linmessage.cpp
communication/message/livedatamessage.cpp
communication/message/tc10statusmessage.cpp
communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp
communication/packet/ethernetpacket.cpp
communication/packet/versionpacket.cpp
communication/packet/iso9141packet.cpp
communication/packet/ethphyregpacket.cpp
communication/packet/livedatapacket.cpp
communication/packet/logicaldiskinfopacket.cpp
communication/packet/wivicommandpacket.cpp
communication/packet/i2cpacket.cpp
communication/packet/linpacket.cpp
communication/packet/mdiopacket.cpp
communication/packet/scriptstatuspacket.cpp
communication/packet/componentversionpacket.cpp
communication/packet/supportedfeaturespacket.cpp
communication/packet/genericbinarystatuspacket.cpp
communication/packet/hardwareinfopacket.cpp
communication/decoder.cpp
communication/encoder.cpp
communication/ethernetpacketizer.cpp
communication/packetizer.cpp
communication/multichannelcommunication.cpp
communication/communication.cpp
communication/driver.cpp
communication/livedata.cpp
communication/ringbuffer.cpp
communication/icommunication.cpp
device/extensions/flexray/extension.cpp
device/extensions/flexray/controller.cpp
device/idevicesettings.cpp
device/devicefinder.cpp
device/device.cpp
device/neodevice.cpp
disk/diskreaddriver.cpp
disk/diskwritedriver.cpp
disk/nulldiskdriver.cpp
disk/neomemorydiskdriver.cpp
disk/plasiondiskreaddriver.cpp
disk/extextractordiskreaddriver.cpp
disk/fat.cpp
disk/vsa/vsa.cpp
disk/vsa/vsa02.cpp
disk/vsa/vsa03.cpp
disk/vsa/vsa04.cpp
disk/vsa/vsa05.cpp
disk/vsa/vsa06.cpp
disk/vsa/vsa07.cpp
disk/vsa/vsa08.cpp
disk/vsa/vsa09.cpp
disk/vsa/vsa0b.cpp
disk/vsa/vsa0c.cpp
disk/vsa/vsa0d.cpp
disk/vsa/vsa0e.cpp
disk/vsa/vsa0f.cpp
disk/vsa/vsa6a.cpp
disk/vsa/vsaparser.cpp
${PLATFORM_SRC}
)
set(SRC_FILES ${COMMON_SRC} ${PLATFORM_SRC})
# Generate build info header
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
@@ -332,18 +137,6 @@ endif()
configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h)
configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES})
message("Including " ${EXTINC})
list(APPEND LIBICSNEO_EXT_CODE_INCS_LIST "#include \"${EXTINC}\"")
endforeach()
list(JOIN LIBICSNEO_EXT_CODE_INCS_LIST "\n" LIBICSNEO_EXT_CODE_INCS)
foreach(EXTCLASS ${LIBICSNEO_EXTENSION_CLASSES})
list(APPEND LIBICSNEO_EXT_CODE_LIST "device->addExtension(std::make_shared<${EXTCLASS}>(*device))\;")
endforeach()
list(JOIN LIBICSNEO_EXT_CODE_LIST "\n\t" LIBICSNEO_EXT_CODE)
configure_file(include/icsneo/device/extensions/builtin.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/extensions/builtin.h)
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
add_library(icsneocpp
@@ -353,84 +146,34 @@ add_library(icsneocpp
api/icsneocpp/version.cpp
${SRC_FILES}
)
message("Include paths " ${LIBICSNEO_EXTENSION_INCLUDE_PATHS})
target_include_directories(icsneocpp
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${LIBICSNEO_EXTENSION_INCLUDE_PATHS}
)
target_link_libraries(icsneocpp PUBLIC Threads::Threads)
set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
if(LIBICSNEO_ENABLE_FIRMIO)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FIRMIO)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_RAW_ETHERNET)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
endif()
if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
endif()
if(LIBICSNEO_ENABLE_FTD3XX)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTD3XX)
target_link_libraries(icsneocpp PRIVATE FTD3XX::FTD3XX)
endif()
if(LIBICSNEO_ENABLE_TCP)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_TCP)
if(WIN32)
target_link_libraries(icsneocpp PRIVATE ws2_32 iphlpapi)
endif()
endif()
# fatfs
add_subdirectory(third-party/fatfs)
set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PRIVATE fatfs)
# libftdi
if(LIBICSNEO_ENABLE_FTDI)
if(NOT WIN32)
target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
set(LIBFTDI_LINK_PYTHON_LIBRARY OFF CACHE INTERNAL "")
set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi)
target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
if(NOT WIN32)
target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
set(LIBFTDI_LINK_PYTHON_LIBRARY OFF CACHE INTERNAL "")
set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi)
endif(NOT WIN32)
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
endif(NOT WIN32)
endif(LIBICSNEO_ENABLE_FTDI)
# pcap
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
if(WIN32)
if(LIBICSNEO_NPCAP_INCLUDE_DIR STREQUAL "")
target_include_directories(icsneocpp PUBLIC AFTER third-party/winpcap/include)
add_definitions(-DWPCAP -DHAVE_REMOTE -DWIN32_LEAN_AND_MEAN)
else()
target_include_directories(icsneocpp PUBLIC AFTER ${LIBICSNEO_NPCAP_INCLUDE_DIR})
add_definitions(-DNPCAP -DWIN32_LEAN_AND_MEAN)
endif()
else()
find_package(PCAP REQUIRED)
target_include_directories(icsneocpp PUBLIC ${PCAP_INCLUDE_DIR})
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
endif(WIN32)
endif(LIBICSNEO_ENABLE_RAW_ETHERNET)
# winpcap
if(WIN32)
target_include_directories(icsneocpp PUBLIC AFTER third-party/winpcap/include)
add_definitions(-DWPCAP -DHAVE_REMOTE -DWIN32_LEAN_AND_MEAN)
endif(WIN32)
if(LIBICSNEO_BUILD_ICSNEOC)
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
@@ -456,7 +199,6 @@ if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
)
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
target_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
@@ -464,7 +206,6 @@ if(LIBICSNEO_BUILD_ICSNEOLEGACY)
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
platform/windows/icsneolegacy.def
)
target_include_directories(icsneolegacy
PUBLIC
@@ -477,80 +218,38 @@ if(LIBICSNEO_BUILD_ICSNEOLEGACY)
target_compile_features(icsneolegacy PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC)
add_library(icsneolegacy-static STATIC
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
)
target_include_directories(icsneolegacy-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneolegacy-static PUBLIC icsneocpp)
target_compile_features(icsneolegacy-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneolegacy-static PUBLIC ICSNEOC_BUILD_STATIC)
# libftdi
if(NOT WIN32)
find_package(Threads)
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
find_package(PCAP REQUIRED)
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
endif()
add_subdirectory(bindings)
# googletest
if(LIBICSNEO_BUILD_UNIT_TESTS)
if(LIBICSNEO_BUILD_TESTS)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
if (NOT TARGET gtest)
add_subdirectory(third-party/googletest-master)
endif()
endif()
add_subdirectory(third-party/googletest-master)
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
add_executable(libicsneo-unit-tests
test/unit/main.cpp
test/unit/diskdriverreadtest.cpp
test/unit/diskdriverwritetest.cpp
test/unit/eventmanagertest.cpp
test/unit/ethernetpacketizertest.cpp
test/unit/i2cencoderdecodertest.cpp
test/unit/linencoderdecodertest.cpp
test/unit/a2bencoderdecodertest.cpp
test/unit/mdioencoderdecodertest.cpp
test/unit/livedataencoderdecodertest.cpp
test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp
)
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
target_link_libraries(libicsneo-unit-tests icsneocpp)
target_include_directories(libicsneo-unit-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
add_executable(runTests test/main.cpp test/eventmanagertest.cpp)
target_link_libraries(runTests gtest gtest_main)
target_link_libraries(runTests icsneocpp)
target_include_directories(runTests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
enable_testing()
add_test(NAME libicsneo-unit-test-suite COMMAND libicsneo-unit-tests)
endif()
if(LIBICSNEO_BUILD_SYSTEM_TESTS)
if(DEFINED ENV{LIBICSNEO_SYSTEM_TESTS})
include(FetchContent)
file(MAKE_DIRECTORY test/system)
FetchContent_Declare(
SystemTests
GIT_REPOSITORY $ENV{LIBICSNEO_SYSTEM_TESTS}
GIT_TAG main
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test/system
)
FetchContent_MakeAvailable(SystemTests)
else()
message("System test repo not defined!")
endif()
add_test(NAME testSuite COMMAND runTests)
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
+39
View File
@@ -0,0 +1,39 @@
# Hardware Support
- Connecting over Ethernet
- neoVI FIRE 2
- CAN works
- CAN FD works
- ValueCAN 4-2EL
- CAN works
- CAN FD works
- Ethernet works
- RADGalaxy
- CAN works
- Ethernet works
- RADStar 2
- CAN works
- Ethernet works
- Connecting over USB
- ValueCAN 4 series
- CAN works
- CAN FD works
- Ethernet works (on 4-2EL)
- neoOBD2 PRO
- CAN works
- neoVI FIRE
- CAN works
- neoVI FIRE 2
- CAN works
- CAN FD works
- Ethernet works
- ValueCAN 3
- CAN works
- RADStar 2
- CAN works
- Ethernet works
- neoVI PLASMA
- CAN works
- neoVI ION
- CAN works
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2018-2024 Intrepid Control Systems, Inc.
Copyright 2019-2020 Intrepid Control Systems, Inc.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+122 -34
View File
@@ -1,42 +1,130 @@
# libicsneo
### The Intrepid Control Systems Open Source Cross-Platform Device Communication API
libicsneo is the [Intrepid Control Systems](https://intrepidcs.com/) device
communication library. Installation and usage documentation can be found within
each of the respective APIs.
An open source solution to integrate Intrepid Control Systems vehicle networking hardware with your application.
## Documentation
[Read the Full Documentation](https://libicsneo.readthedocs.io/)
- [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/)
- [Python](https://libicsneo.readthedocs.io/en/latest/icsneopy/)
- [C](https://libicsneo.readthedocs.io/en/latest/icsneoc/)
## Getting Started
There are two major ways to write a new application using libicsneo. You can use the C++ interface, which will be compiled with your project and statically linked, or you can use the C interface, which can be either statically or dynamically linked.
### Integration with CMake (Static Linking)
Integrating the library with your current CMake project is extremely easy.
1. Checkout the library (or add as a submodule) into a subdirectory of your project.
2. Within your `CMakeLists.txt` you can add the line `add_subdirectory("third-party/libicsneo")` to bring in the libicsneo targets. Replace `third-party` with any subdirectory you choose.
3. The libicsneo library include paths should automatically be added to your include path.
4. Link the library with your target by adding `target_link_libraries(libicsneocpp-example icsneocpp)` after your target, substituting `libicsneocpp-example` with your target application.
## Hardware Support
You can now include either the C++ API with `#include <icsneo/icsneocpp.h>` or the C API with `#include <icsneo/icsneoc.h>`
- EtherBADGE
- neoVI Connect
- neoVI FIRE
- neoVI FIRE 2
- neoVI FIRE 3
- neoVI ION
- neoVI PLASMA
- neoVI RED 2
- RAD-A2B
- RAD-Comet 2
- RAD-Comet 3
- RAD-Galaxy
- RAD-Gigastar
- RAD-Gigastar 2
- RAD-Moon 2
- RAD-Moon 3
- RAD-Moon T1S
- RAD-Pluto
- RAD-Star 2
- RAD-SuperMoon
- RADComet
- ValueCAN 3
- ValueCAN 4
### DLL / SO / DYLIB Releases (Dynamic Linking)
It is also possible to use the precompiled binaries with runtime linking. It is not recommended or supported to attempt to use the C++ interface with dynamic linking due to the complexities of C++ compilers.
1. Add this repository's `/include` to your include path
2. Add `#define ICSNEOC_DYNAMICLOAD` to the top of your source file
2. Add `#import <icsneo/icsneoc.h>` below that line
3. Call `icsneo_init();` to import the library before using any other libicsneo functions.
4. Use the library as normal.
5. Call `icsneo_close();` to unload the library.
## License
## Usage
### Using the C++ API
The C++ API is designed to be modern and easy to use. All library functions and classes are in the namespace `icsneo`. Most applications will start by calling `icsneo::FindAllDevices()`. This will return an `std::vector` of `std::shared_ptr<icsneo::Device>` objects. You will want to keep a copy of the `shared_ptr` to any devices you want to use, as allowing it to go out of scope will automatically close the device and free all memory associated with it.
libicsneo is licensed as BSD-3 with an extra clause, see [LICENSE](LICENSE)
for more details.
Any time you get bus traffic from the API, you will receive it as an `std::shared_ptr<icsneo::Message>`. The message will be valid as long as the `shared_ptr` stays in scope. Checking the type of the message allows you to cast it accordingly and access extra data for certain protocols. For instance, casting an `icsneo::Message` to an `icsneo::CANMessage` allows you to access the arbitration ID.
A barebones example is provided. For a more complete example, check [intrepidcs/libicsneo-examples](https://github.com/intrepidcs/libicsneo-examples).
``` c++
std::vector<std::shared_ptr<icsneo::Device>> devices = icsneo::FindAllDevices();
std::cout << devices.size() << " found!" << std::endl;
for(auto& device : devices)
std::cout << "Found " << device->describe() << std::endl; // "Found neoVI FIRE 2 CY2345"
std::shared_ptr<icsneo::Device> myDevice = devices[0];
if(!myDevice->open()) // Device tried and failed to open, print the last error
std::cout << icsneo::GetLastError() << std::endl;
myDevice->goOnline(); // Start receiving messages
myDevice->enableMessagePolling(); // Allow the use of myDevice->getMessages() later
// Alternatively, assign a callback for new messages
std::this_thread::wait_for(std::chrono::seconds(5));
std::vector<std::shared_ptr<icsneo::Message>> messages = myDevice->getMessages();
std::cout << "We got " << messages.size() << " messages!" << std::endl;
for(auto& msg : messages) {
switch(msg->network.getType()) {
case icsneo::Network::Type::CAN:
case icsneo::Network::Type::SWCAN:
case icsneo::Network::Type::LSFTCAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canmsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
// canmsg->arbid is valid here
// canmsg->data is an std::vector<uint8_t>, you can check .size() for the DLC of the message
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
default:
// Handle others
}
}
myDevice->close();
```
### Using the C API
The C API is designed to be a robust and fault tolerant interface which allows easy integration with other languages as well as existing C applications. When calling `icsneo_findAllDevices()` you will provide a buffer of `neodevice_t` structures, which will be written with the found devices. These `neodevice_t` structures can be uses to interface with the API from then on. Once you call `icsneo_close()` with a device, that device and all associated memory will be freed. You will need to run `icsneo_findAllDevices()` again to reconnect.
Messages are passed in the form of `neomessage_t` structures when calling `icsneo_getMessages()`. These structures contain a `uint8_t*` to the payload data, and this pointer will be valid until the next call to `icsneo_getMessages()` or the device is closed.
A barebones example is provided. For a more complete example, check [intrepidcs/libicsneo-examples](https://github.com/intrepidcs/libicsneo-examples).
``` c
size_t deviceCount = 10; // Pre-set to the size of your buffer before the icsneo_findAllDevices() call
neodevice_t devices[10];
icsneo_findAllDevices(devices, &deviceCount);
printf("We found %ull devices\n", deviceCount);
for(size_t i = 0; i < deviceCount; i++) {
neodevice_t* myDevice = &devices[i];
char desc[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION];
size_t sz = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
icsneo_describeDevice(myDevice, desc, &sz);
printf("Found %s\n", desc); // "Found neoVI FIRE 2 CY2345"
}
neodevice_t* myDevice = &devices[0];
if(!icsneo_openDevice(myDevice)) {
neoevent_t error;
if(icsneo_getLastError(&error))
printf("Error! %s\n", error.description);
}
icsneo_goOnline(myDevice); // Start receiving messages
icsneo_enableMessagePolling(myDevice); // Allow the use of icsneo_getMessages() later
sleep(5);
neomessage_t messages[50];
size_t messageCount = 50;
icsneo_getMessages(myDevice, messages, &messageCount, 0 /* non-blocking */);
printf("We got %ull messages!\n", messageCount);
for(size_t i = 0; i < messageCount; i++) {
if(messages[i].type == ICSNEO_NETWORK_TYPE_CAN) {
// A message of type CAN should be interperated a neomessage_can_t, so we can cast safely
neomessage_can_t* canmsg = (neomessage_can_t*)&messages[i];
// canmsg->arbid is valid here
// canmsg->data is an uint8_t*, you can check canmsg->length for the length of the payload
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
}
icsneo_closeDevice(myDevice);
```
## Building from Source
### Windows
Building will require Microsoft Visual Studio 2017+ and CMake to be installed.
### macOS
Getting the dependencies is easiest with the Homebrew package manager. You will also need XCode installed. You can then install CMake, an up-to-date version of GCC or Clang, and `libusb-1.0`.
### Linux
The dependencies are as follows
- CMake 3.2 or above
- GCC 4.7 or above, 4.8+ recommended
- `libusb-1.0-0-dev`
- `libpcap0.8-dev`
- `build-essential` is recommended
If you'd like to be able to run programs that use this library without being root, consider using the included udev rules
```
$ sudo cp 99-intrepidcs.rules /etc/udev/rules.d/
```
+622 -759
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -29,7 +29,7 @@ BEGIN
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneoc.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2019"
VALUE "OriginalFilename", "icsneoc.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+4 -230
View File
@@ -69,18 +69,10 @@ static constexpr const char* DEVICE_CURRENTLY_POLLING = "The device is currently
static constexpr const char* DEVICE_NOT_CURRENTLY_POLLING = "The device is not currently polling for messages.";
static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network.";
static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long.";
static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present.";
static constexpr const char* TIMEOUT = "The timeout was reached.";
static constexpr const char* WIVI_NOT_SUPPORTED = "Wireless neoVI functions are not supported on this device.";
static constexpr const char* RESTRICTED_ENTRY_FLAG = "Attempted to set a restricted flag in a Root Directory entry.";
static constexpr const char* NOT_SUPPORTED = "The requested feature is not supported.";
// Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
static constexpr const char* NO_SERIAL_NUMBER_FW_12V = "Communication could not be established with the device. Perhaps it is not powered with 12 volts?";
static constexpr const char* NO_SERIAL_NUMBER_FW = "Communication could not be established with the device. Perhaps it is not powered?";
static constexpr const char* NO_SERIAL_NUMBER_12V = "Communication could not be established with the device. Perhaps it is not powered with 12 volts or requires a firmware update using Vehicle Spy.";
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy.";
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered with 12 volts?";
static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer.";
@@ -101,25 +93,6 @@ static constexpr const char* NO_DEVICE_RESPONSE = "Expected a response from the
static constexpr const char* MESSAGE_FORMATTING = "The message was not properly formed.";
static constexpr const char* CANFD_NOT_SUPPORTED = "This device does not support CANFD.";
static constexpr const char* RTR_NOT_SUPPORTED = "RTR is not supported with CANFD.";
static constexpr const char* DEVICE_DISCONNECTED = "The device was disconnected.";
static constexpr const char* ONLINE_NOT_SUPPORTED = "This device does not support going online.";
static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination.";
static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device.";
static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled.";
static constexpr const char* ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE = "Ethernet PHY register control is not available for this device.";
static constexpr const char* DISK_NOT_SUPPORTED = "This device does not support accessing the specified disk.";
static constexpr const char* EOF_REACHED = "The requested length exceeds the available data from this disk.";
static constexpr const char* SETTINGS_DEFAULTS_USED = "The device settings could not be loaded, the default settings have been applied.";
static constexpr const char* ATOMIC_OPERATION_RETRIED = "An operation failed to be atomically completed, but will be retried.";
static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An ideally-atomic operation was completed nonatomically.";
static constexpr const char* WIVI_STACK_REFRESH_FAILED = "The Wireless neoVI stack encountered a communication error.";
static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI upload stack has encountered an overflow condition.";
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device.";
static constexpr const char* MODE_NOT_FOUND = "The mode was not found.";
// Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
@@ -128,59 +101,9 @@ static constexpr const char* DRIVER_FAILED_TO_OPEN = "The device driver encounte
static constexpr const char* DRIVER_FAILED_TO_CLOSE = "The device driver encountered a low-level error while closing the device.";
static constexpr const char* PACKET_CHECKSUM_ERROR = "There was a checksum error while decoding a packet. The packet was dropped.";
static constexpr const char* TRANSMIT_BUFFER_FULL = "The transmit buffer is full and the device is set to non-blocking.";
static constexpr const char* DEVICE_IN_USE = "The device is currently in use by another program.";
static constexpr const char* PCAP_COULD_NOT_START = "The PCAP driver could not be started. Ethernet devices will not be found.";
static constexpr const char* PCAP_COULD_NOT_FIND_DEVICES = "The PCAP driver failed to find devices. Ethernet devices will not be found.";
static constexpr const char* PACKET_DECODING = "There was an error decoding a packet from the device.";
static constexpr const char* SOCKET_FAILED_TO_OPEN = "Unable to open new socket.";
static constexpr const char* FAILED_TO_BIND = "Unable to bind socket.";
static constexpr const char* ERROR_SETTING_SOCKET_OPTION = "A call to setsockopt() failed.";
static constexpr const char* GETIFADDRS_ERROR = "A call to getifaddrs() failed.";
static constexpr const char* SEND_TO_ERROR = "A call to sendto() failed.";
// FTD3XX
static constexpr const char* FT_OK = "FTD3XX success.";
static constexpr const char* FT_INVALID_HANDLE = "Invalid FTD3XX handle.";
static constexpr const char* FT_DEVICE_NOT_FOUND = "FTD3XX device not found.";
static constexpr const char* FT_DEVICE_NOT_OPENED = "FTD3XX device not opened.";
static constexpr const char* FT_IO_ERROR = "FTD3XX IO error.";
static constexpr const char* FT_INSUFFICIENT_RESOURCES = "Insufficient resources for FTD3XX.";
static constexpr const char* FT_INVALID_PARAMETER = "Invalid FTD3XX parameter.";
static constexpr const char* FT_INVALID_BAUD_RATE = "Invalid FTD3XX baud rate.";
static constexpr const char* FT_DEVICE_NOT_OPENED_FOR_ERASE = "FTD3XX device not opened for erase.";
static constexpr const char* FT_DEVICE_NOT_OPENED_FOR_WRITE = "FTD3XX not opened for write.";
static constexpr const char* FT_FAILED_TO_WRITE_DEVICE = "FTD3XX failed to write device.";
static constexpr const char* FT_EEPROM_READ_FAILED = "FTD3XX EEPROM read failed.";
static constexpr const char* FT_EEPROM_WRITE_FAILED = "FTD3XX EEPROM write failed.";
static constexpr const char* FT_EEPROM_ERASE_FAILED = "FTD3XX EEPROM erase failed.";
static constexpr const char* FT_EEPROM_NOT_PRESENT = "FTD3XX EEPROM not present.";
static constexpr const char* FT_EEPROM_NOT_PROGRAMMED = "FTD3XX EEPROM not programmed.";
static constexpr const char* FT_INVALID_ARGS = "Invalid FTD3XX arguments.";
static constexpr const char* FT_NOT_SUPPORTED = "FTD3XX not supported.";
static constexpr const char* FT_NO_MORE_ITEMS = "No more FTD3XX items.";
static constexpr const char* FT_TIMEOUT = "FTD3XX timeout.";
static constexpr const char* FT_OPERATION_ABORTED = "FTD3XX operation aborted.";
static constexpr const char* FT_RESERVED_PIPE = "Reserved FTD3XX pipe.";
static constexpr const char* FT_INVALID_CONTROL_REQUEST_DIRECTION = "Invalid FTD3XX control request direction.";
static constexpr const char* FT_INVALID_CONTROL_REQUEST_TYPE = "Invalid FTD3XX control request type.";
static constexpr const char* FT_IO_PENDING = "FTD3XX IO pending.";
static constexpr const char* FT_IO_INCOMPLETE = "FTD3XX IO incomplete.";
static constexpr const char* FT_HANDLE_EOF = "Handle FTD3XX EOF.";
static constexpr const char* FT_BUSY = "FTD3XX busy.";
static constexpr const char* FT_NO_SYSTEM_RESOURCES = "No FTD3XX system resources.";
static constexpr const char* FT_DEVICE_LIST_NOT_READY = "FTD3XX device list not ready.";
static constexpr const char* FT_DEVICE_NOT_CONNECTED = "FTD3XX device not connected.";
static constexpr const char* FT_INCORRECT_DEVICE_PATH = "Incorrect FTD3XX device path.";
static constexpr const char* FT_OTHER_ERROR = "Other FTD3XX error.";
// VSA
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted.";
static constexpr const char* VSA_TIMESTAMP_NOT_FOUND = "Unable to find a VSA record with a valid timestamp.";
static constexpr const char* VSA_BUFFER_FORMAT_ERROR = "VSA record buffer is formatted incorrectly.";
static constexpr const char* VSA_MAX_READ_ATTEMPTS_REACHED = "Reached max attempts to read VSA records before exit.";
static constexpr const char* VSA_BYTE_PARSE_FAILURE = "Failure to parse record bytes from VSA buffer.";
static constexpr const char* VSA_EXTENDED_MESSAGE_ERROR = "Failure to parse extended message record sequence";
static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API.";
static constexpr const char* PACKET_DECODING = "The packet could not be decoded.";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
@@ -214,16 +137,6 @@ const char* APIEvent::DescriptionForType(Type type) {
return UNSUPPORTED_TX_NETWORK;
case Type::MessageMaxLengthExceeded:
return MESSAGE_MAX_LENGTH_EXCEEDED;
case Type::ValueNotYetPresent:
return VALUE_NOT_YET_PRESENT;
case Type::Timeout:
return TIMEOUT;
case Type::WiVINotSupported:
return WIVI_NOT_SUPPORTED;
case Type::RestrictedEntryFlag:
return RESTRICTED_ENTRY_FLAG;
case Type::NotSupported:
return NOT_SUPPORTED;
// Device Errors
case Type::PollingMessageOverflow:
@@ -270,50 +183,7 @@ const char* APIEvent::DescriptionForType(Type type) {
return CANFD_NOT_SUPPORTED;
case Type::RTRNotSupported:
return RTR_NOT_SUPPORTED;
case Type::DeviceDisconnected:
return DEVICE_DISCONNECTED;
case Type::OnlineNotSupported:
return ONLINE_NOT_SUPPORTED;
case Type::TerminationNotSupportedDevice:
return TERMINATION_NOT_SUPPORTED_DEVICE;
case Type::TerminationNotSupportedNetwork:
return TERMINATION_NOT_SUPPORTED_NETWORK;
case Type::AnotherInTerminationGroupEnabled:
return ANOTHER_IN_TERMINATION_GROUP_ENABLED;
case Type::NoSerialNumberFW:
return NO_SERIAL_NUMBER_FW;
case Type::NoSerialNumber12V:
return NO_SERIAL_NUMBER_12V;
case Type::NoSerialNumberFW12V:
return NO_SERIAL_NUMBER_FW_12V;
case Type::EthPhyRegisterControlNotAvailable:
return ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE;
case Type::DiskNotSupported:
return DISK_NOT_SUPPORTED;
case Type::EOFReached:
return EOF_REACHED;
case Type::SettingsDefaultsUsed:
return SETTINGS_DEFAULTS_USED;
case Type::AtomicOperationRetried:
return ATOMIC_OPERATION_RETRIED;
case Type::AtomicOperationCompletedNonatomically:
return ATOMIC_OPERATION_COMPLETED_NONATOMICALLY;
case Type::WiVIStackRefreshFailed:
return WIVI_STACK_REFRESH_FAILED;
case Type::WiVIUploadStackOverflow:
return WIVI_UPLOAD_STACK_OVERFLOW;
case Type::A2BMessageIncompleteFrame:
return A2B_MESSAGE_INCOMPLETE_FRAME;
case Type::CoreminiUploadVersionMismatch:
return COREMINI_UPLOAD_VERSION_MISMATCH;
case Type::DiskNotConnected:
return DISK_NOT_CONNECTED;
case Type::UnexpectedResponse:
return UNEXPECTED_RESPONSE;
case Type::LINSettingsNotAvailable:
return LIN_SETTINGS_NOT_AVAILABLE;
case Type::ModeNotFound:
return MODE_NOT_FOUND;
// Transport Errors
case Type::FailedToRead:
return FAILED_TO_READ;
@@ -327,109 +197,13 @@ const char* APIEvent::DescriptionForType(Type type) {
return PACKET_CHECKSUM_ERROR;
case Type::TransmitBufferFull:
return TRANSMIT_BUFFER_FULL;
case Type::DeviceInUse:
return DEVICE_IN_USE;
case Type::PCAPCouldNotStart:
return PCAP_COULD_NOT_START;
case Type::PCAPCouldNotFindDevices:
return PCAP_COULD_NOT_FIND_DEVICES;
case Type::PacketDecodingError:
return PACKET_DECODING;
case Type::SocketFailedToOpen:
return SOCKET_FAILED_TO_OPEN;
case Type::FailedToBind:
return FAILED_TO_BIND;
case Type::ErrorSettingSocketOption:
return ERROR_SETTING_SOCKET_OPTION;
case Type::GetIfAddrsError:
return GETIFADDRS_ERROR;
case Type::SendToError:
return SEND_TO_ERROR;
// FTD3XX
case Type::FTOK:
return FT_OK;
case Type::FTInvalidHandle:
return FT_INVALID_HANDLE;
case Type::FTDeviceNotFound:
return FT_DEVICE_NOT_FOUND;
case Type::FTDeviceNotOpened:
return FT_DEVICE_NOT_OPENED;
case Type::FTIOError:
return FT_IO_ERROR;
case Type::FTInsufficientResources:
return FT_INSUFFICIENT_RESOURCES;
case Type::FTInvalidParameter:
return FT_INVALID_PARAMETER;
case Type::FTInvalidBaudRate:
return FT_INVALID_BAUD_RATE;
case Type::FTDeviceNotOpenedForErase:
return FT_DEVICE_NOT_OPENED_FOR_ERASE;
case Type::FTDeviceNotOpenedForWrite:
return FT_DEVICE_NOT_OPENED_FOR_WRITE;
case Type::FTFailedToWriteDevice:
return FT_FAILED_TO_WRITE_DEVICE;
case Type::FTEEPROMReadFailed:
return FT_EEPROM_READ_FAILED;
case Type::FTEEPROMWriteFailed:
return FT_EEPROM_WRITE_FAILED;
case Type::FTEEPROMEraseFailed:
return FT_EEPROM_ERASE_FAILED;
case Type::FTEEPROMNotPresent:
return FT_EEPROM_NOT_PRESENT;
case Type::FTEEPROMNotProgrammed:
return FT_EEPROM_NOT_PROGRAMMED;
case Type::FTInvalidArgs:
return FT_INVALID_ARGS;
case Type::FTNotSupported:
return FT_NOT_SUPPORTED;
case Type::FTNoMoreItems:
return FT_NO_MORE_ITEMS;
case Type::FTTimeout:
return FT_TIMEOUT;
case Type::FTOperationAborted:
return FT_OPERATION_ABORTED;
case Type::FTReservedPipe:
return FT_RESERVED_PIPE;
case Type::FTInvalidControlRequestDirection:
return FT_INVALID_CONTROL_REQUEST_DIRECTION;
case Type::FTInvalidControlRequestType:
return FT_INVALID_CONTROL_REQUEST_TYPE;
case Type::FTIOPending:
return FT_IO_PENDING;
case Type::FTIOIncomplete:
return FT_IO_INCOMPLETE;
case Type::FTHandleEOF:
return FT_HANDLE_EOF;
case Type::FTBusy:
return FT_BUSY;
case Type::FTNoSystemResources:
return FT_NO_SYSTEM_RESOURCES;
case Type::FTDeviceListNotReady:
return FT_DEVICE_LIST_NOT_READY;
case Type::FTDeviceNotConnected:
return FT_DEVICE_NOT_CONNECTED;
case Type::FTIncorrectDevicePath:
return FT_INCORRECT_DEVICE_PATH;
case Type::FTOtherError:
return FT_OTHER_ERROR;
// VSA
case Type::VSABufferCorrupted:
return VSA_BUFFER_CORRUPTED;
case Type::VSATimestampNotFound:
return VSA_TIMESTAMP_NOT_FOUND;
case Type::VSABufferFormatError:
return VSA_BUFFER_FORMAT_ERROR;
case Type::VSAMaxReadAttemptsReached:
return VSA_MAX_READ_ATTEMPTS_REACHED;
case Type::VSAByteParseFailure:
return VSA_BYTE_PARSE_FAILURE;
case Type::VSAExtendedMessageError:
return VSA_EXTENDED_MESSAGE_ERROR;
case Type::VSAOtherError:
return VSA_OTHER_ERROR;
// Other Errors
case Type::TooManyEvents:
return TOO_MANY_EVENTS;
+5 -120
View File
@@ -1,8 +1,5 @@
#include "icsneo/api/eventmanager.h"
#include <memory>
#include <optional>
#include <iostream>
#include <cstdlib>
using namespace icsneo;
@@ -11,118 +8,6 @@ EventManager& EventManager::GetInstance() {
return inst;
}
void EventManager::downgradeErrorsOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = true;
} else {
downgradedThreads.insert({std::this_thread::get_id(), true});
}
}
void EventManager::cancelErrorDowngradingOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = false;
}
}
void EventManager::add(APIEvent event) {
if(destructing)
return;
static const auto printLevel = []() -> std::optional<uint8_t> {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const auto level = std::getenv("LIBICSNEO_PRINT_EVENTS");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
if(!level)
return std::nullopt;
try {
return (uint8_t)std::stoi(level);
} catch (std::invalid_argument const&) {
return std::nullopt;
}
}();
if(printLevel && (uint8_t)event.getSeverity() >= *printLevel)
std::cerr << event.describe() << std::endl;
if(event.getSeverity() == APIEvent::Severity::Error) {
// if the error was added on a thread that downgrades errors (non-user thread)
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end() && i->second) {
event.downgradeFromError();
{
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
} else {
std::lock_guard<std::mutex> errorsLock(errorsMutex);
lastUserErrors[std::this_thread::get_id()] = event;
}
} else {
{
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
}
}
void EventManager::addEventInternal(APIEvent event) {
// Ensure the event list is at most exactly full (size of eventLimit - 1, leaving room for a potential APIEvent::TooManyEvents)
// Removes any events of type TooManyEvents from the end before checking to avoid duplicates.
enforceLimit();
// We are exactly full, either because the list was truncated or because we were simply full before
if(events.size() == eventLimit - 1) {
// If the event is worth adding
if(event.getType() != APIEvent::Type::TooManyEvents) {
discardOldest(1);
events.push_back(event);
}
events.push_back(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
} else {
if (event.getType() != APIEvent::Type::TooManyEvents)
events.push_back(event);
}
}
void EventManager::runCallbacks(APIEvent event) {
std::lock_guard<std::mutex> lk(callbacksMutex);
for(auto& i : callbacks)
i.second.callIfMatch(std::make_shared<APIEvent>(event));
}
void EventManager::setEventLimit(size_t newLimit) {
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
if(newLimit == eventLimit)
return;
if(newLimit < 10) {
add(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return;
}
eventLimit = newLimit;
std::lock_guard<std::mutex> eventsLock(eventsMutex);
if(enforceLimit())
addEventInternal(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
}
void EventManager::ResetInstance() {
std::lock_guard<std::mutex> eventsLock(eventsMutex);
std::lock_guard<std::mutex> errorsLock(errorsMutex);
@@ -136,7 +21,7 @@ void EventManager::ResetInstance() {
lastUserErrors.clear();
downgradedThreads.clear();
callbacks.clear();
callbackID = 0;
eventLimit = 10000;
}
@@ -170,7 +55,7 @@ bool EventManager::isDowngradingErrorsOnCurrentThread() const {
void EventManager::get(std::vector<APIEvent>& eventOutput, size_t max, EventFilter filter) {
std::lock_guard<std::mutex> lk(eventsMutex);
if(max == 0) // A limit of 0 indicates no limit
max = (size_t)-1;
@@ -213,7 +98,7 @@ void EventManager::discard(EventFilter filter) {
});
}
size_t EventManager::countInternal(EventFilter filter) const {
size_t EventManager::count_internal(EventFilter filter) const {
size_t ret = 0;
for(auto& event : events)
if(filter.match(event))
@@ -232,7 +117,7 @@ bool EventManager::enforceLimit() {
while(it != events.rend() && filter.match(*it)) {
it = decltype(it){events.erase( std::next(it).base() )};
}
// We are not overflowing
if(events.size() < eventLimit)
return false;
@@ -252,6 +137,6 @@ void EventManager::discardOldest(size_t count) {
while(it != events.end()) {
it = events.erase(it);
if(--count == 0)
break;
break;
}
}
+47 -47
View File
@@ -1,48 +1,48 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h"
using namespace icsneo;
std::vector<std::shared_ptr<Device>> icsneo::FindAllDevices() {
return DeviceFinder::FindAll();
}
std::vector<DeviceType> icsneo::GetSupportedDevices() {
return DeviceFinder::GetSupportedDevices();
}
size_t icsneo::EventCount(EventFilter filter) {
return EventManager::GetInstance().eventCount(filter);
}
std::vector<APIEvent> icsneo::GetEvents(EventFilter filter, size_t max) {
return EventManager::GetInstance().get(filter, max);
}
std::vector<APIEvent> icsneo::GetEvents(size_t max, EventFilter filter) {
return EventManager::GetInstance().get(max, filter);
}
void icsneo::GetEvents(std::vector<APIEvent>& events, EventFilter filter, size_t max) {
EventManager::GetInstance().get(events, filter, max);
}
void icsneo::GetEvents(std::vector<APIEvent>& events, size_t max, EventFilter filter) {
EventManager::GetInstance().get(events, max, filter);
}
APIEvent icsneo::GetLastError() {
return EventManager::GetInstance().getLastError();
}
void icsneo::DiscardEvents(EventFilter filter) {
EventManager::GetInstance().discard(filter);
}
void icsneo::SetEventLimit(size_t newLimit) {
EventManager::GetInstance().setEventLimit(newLimit);
}
size_t icsneo::GetEventLimit() {
return EventManager::GetInstance().getEventLimit();
#include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h"
using namespace icsneo;
std::vector<std::shared_ptr<Device>> icsneo::FindAllDevices() {
return DeviceFinder::FindAll();
}
std::vector<DeviceType> icsneo::GetSupportedDevices() {
return DeviceFinder::GetSupportedDevices();
}
size_t icsneo::EventCount(EventFilter filter) {
return EventManager::GetInstance().eventCount(filter);
}
std::vector<APIEvent> icsneo::GetEvents(EventFilter filter, size_t max) {
return EventManager::GetInstance().get(filter, max);
}
std::vector<APIEvent> icsneo::GetEvents(size_t max, EventFilter filter) {
return EventManager::GetInstance().get(max, filter);
}
void icsneo::GetEvents(std::vector<APIEvent>& events, EventFilter filter, size_t max) {
EventManager::GetInstance().get(events, filter, max);
}
void icsneo::GetEvents(std::vector<APIEvent>& events, size_t max, EventFilter filter) {
EventManager::GetInstance().get(events, max, filter);
}
APIEvent icsneo::GetLastError() {
return EventManager::GetInstance().getLastError();
}
void icsneo::DiscardEvents(EventFilter filter) {
EventManager::GetInstance().discard(filter);
}
void icsneo::SetEventLimit(size_t newLimit) {
EventManager::GetInstance().setEventLimit(newLimit);
}
size_t icsneo::GetEventLimit() {
return EventManager::GetInstance().getEventLimit();
}
+22 -19
View File
@@ -3,7 +3,8 @@
#include <Tchar.h>
//Basic Functions
OPENDEVICE icsneoOpenDevice;
FINDNEODEVICES icsneoFindNeoDevices;
OPENNEODEVICE icsneoOpenNeoDevice;
CLOSEPORT icsneoClosePort;
FREEOBJECT icsneoFreeObject;
////OPENPORTEX icsneoOpenPortEx;
@@ -44,7 +45,6 @@ SETVCAN412SETTINGS icsneoSetVCAN412Settings;
SETBITRATE icsneoSetBitRate;
GETDEVICEPARMS icsneoGetDeviceParameters;
SETDEVICEPARMS icsneoSetDeviceParameters;
ENABLEDOIPACTIVATIONLINE icsneoEnableDOIPLine;
//Error Functions
GETLASTAPIERROR icsneoGetLastAPIError;
@@ -81,17 +81,17 @@ SCRIPTWRITEAPPSIGNAL icsneoScriptWriteAppSignal;
//SCRIPTWRITETXMESSAGE icsneoScriptWriteTxMessage;
//The following are valid strings for setting parameters on devices
//The following are valid strings for setting parameters on devices
//using the icsneoGetDeviceParameters() and icsneoSetDeviceParameters() functions
char *FireParameters[] =
{
"can1", "can2", "can3", "can4", "swcan", "lsftcan", "lin1", "lin2",
"lin3", "lin4", "cgi_baud", "cgi_tx_ifs_bit_times",
"cgi_rx_ifs_bit_times", "cgi_chksum_enable", "network_enables",
"network_enabled_on_boot", "pwm_man_timeout", "pwr_man_enable",
"misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_analog_enable",
"misc_io_report_period", "misc_io_on_report_events", "ain_sample_period",
"ain_threshold", "iso15765_separation_time_offset", "iso9141_kwp_settings",
"cgi_rx_ifs_bit_times", "cgi_chksum_enable", "network_enables",
"network_enabled_on_boot", "pwm_man_timeout", "pwr_man_enable",
"misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_analog_enable",
"misc_io_report_period", "misc_io_on_report_events", "ain_sample_period",
"ain_threshold", "iso15765_separation_time_offset", "iso9141_kwp_settings",
"perf_en", "iso_parity", "iso_msg_termination", "network_enables_2"
};
@@ -99,30 +99,30 @@ char *FireParameters[] =
char *VCAN3Parameters[] =
{
"can1", "can2", "network_enables", "network_enabled_on_boot", "iso15765_separation_time_offset",
"perf_en", "misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_report_period",
"perf_en", "misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_report_period",
"misc_io_on_report_events"
};
char *CANParameters[] =
char *CANParameters[] =
{
"Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1",
"TqSeg2", "TqProp", "TqSync", "BRP", "auto_baud"
};
char *SWCANParameters[] =
char *SWCANParameters[] =
{
"Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1", "TqSeg2",
"Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1", "TqSeg2",
"TqProp", "TqSync", "BRP", "high_speed_auto_switch", "auto_baud"
};
char *LINParameters[] =
char *LINParameters[] =
{
"Baudrate", "spbrg", "brgh", "MasterResistor", "Mode"
};
char *ISOKWPParms[] =
{
"Baudrate", "spbrg", "brgh", "init_steps", "init_step_count",
"Baudrate", "spbrg", "brgh", "init_steps", "init_step_count",
"p2_500us", "p3_500us", "p4_500us", "chksum_enabled"
};
@@ -132,7 +132,10 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
if((hAPIDLL = LoadLibrary(_T("icsneo40.dll"))) == NULL)
return false;
icsneoOpenDevice = (OPENDEVICE) GetProcAddress(hAPIDLL, "icsneoOpenDevice");
icsneoFindNeoDevices = (FINDNEODEVICES) GetProcAddress(hAPIDLL, "icsneoFindNeoDevices");
icsneoOpenNeoDevice = (OPENNEODEVICE) GetProcAddress(hAPIDLL, "icsneoOpenNeoDevice");
icsneoClosePort = (CLOSEPORT) GetProcAddress(hAPIDLL, "icsneoClosePort");
icsneoFreeObject = (FREEOBJECT) GetProcAddress(hAPIDLL, "icsneoFreeObject");
//// icsneoOpenPortEx = (OPENPORTEX) GetProcAddress(hAPIDLL, "icsneoOpenPortEx");
@@ -198,22 +201,22 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
icsneoScriptReadAppSignal = (SCRIPTREADAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptReadAppSignal");
icsneoScriptWriteAppSignal = (SCRIPTWRITEAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptWriteAppSignal");
icsneoEnableDOIPLine = (ENABLEDOIPACTIVATIONLINE)GetProcAddress(hAPIDLL, "icsneoEnableDOIPLine");
if(!icsneoOpenDevice || !icsneoClosePort || !icsneoFreeObject ||
if(!icsneoFindNeoDevices || !icsneoOpenNeoDevice || !icsneoClosePort || !icsneoFreeObject ||
!icsneoTxMessages || !icsneoGetMessages || !icsneoWaitForRxMessagesWithTimeOut ||
!icsneoGetTimeStampForMsg || !icsneoEnableNetworkRXQueue || !icsneoGetISO15765Status || !icsneoTxMessagesEx ||
!icsneoSetISO15765RxParameters || !icsneoGetConfiguration || !icsneoSendConfiguration ||
!icsneoGetFireSettings || !icsneoSetFireSettings || !icsneoGetVCAN3Settings ||
!icsneoSetVCAN3Settings || !icsneoGetVCANRFSettings || !icsneoSetVCANRFSettings || !icsneoGetFire2Settings ||
!icsneoGetVCAN412Settings || !icsneoSetVCAN412Settings ||
!icsneoSetFire2Settings || !icsneoGetRADGalaxySettings || !icsneoSetRADGalaxySettings ||
!icsneoSetFire2Settings || !icsneoGetRADGalaxySettings || !icsneoSetRADGalaxySettings ||
!icsneoSetBitRate || !icsneoGetDeviceParameters || !icsneoSerialNumberToString ||
!icsneoSetDeviceParameters || !icsneoGetLastAPIError || !icsneoGetErrorMessages ||
!icsneoGetErrorInfo || !icsneoScriptLoad || !icsneoScriptStart || !icsneoScriptStop ||
!icsneoScriptClear || !icsneoScriptStartFBlock || !icsneoScriptStopFBlock ||
!icsneoScriptGetFBlockStatus || !icsneoScriptGetScriptStatus || !icsneoScriptReadAppSignal ||
!icsneoScriptWriteAppSignal || !icsneoGetDLLVersion || !icsneoEnableDOIPLine)
!icsneoScriptWriteAppSignal || !icsneoGetDLLVersion)
{
FreeLibrary(hAPIDLL);
return false;
+17 -19
View File
@@ -11,24 +11,23 @@ void UnloadDLLAPI(HINSTANCE &hAPIDLL);
//Basic Functions
typedef int (__stdcall *FINDNEODEVICES)(unsigned long DeviceTypes, NeoDevice *pNeoDevice, int *pNumDevices);
typedef int (__stdcall *OPENNEODEVICE)(NeoDevice *pNeoDevice, void * hObject, unsigned char *bNetworkIDs, int bConfigRead, int bSyncToPC);
typedef int (__stdcall *OPENDEVICE)(NeoDeviceEx* pNeoDeviceEx, void** hObject, unsigned char* bNetworkIDs, int bConfigRead, int iOptions, OptionsOpenNeoEx* stOptionsOpenNeoEx, unsigned long reserved);
typedef int (__stdcall *CLOSEPORT)(void * hObject, int *pNumberOfErrors);
typedef int (__stdcall *CLOSEPORT)(void * hObject, int *pNumberOfErrors);
typedef void (__stdcall *FREEOBJECT)(void * hObject);
typedef int (__stdcall *OPENPORTEX)(void * lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB, int lIPAddressLSBOrBaudRate,
typedef int (__stdcall *OPENPORTEX)(void * lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB, int lIPAddressLSBOrBaudRate,
int bConfigRead, unsigned char *bNetworkID, int * hObject);
typedef int (__stdcall *SERIALNUMBERTOSTRING) (unsigned long serial, char *data,unsigned long data_size);
//Message Functions
typedef int (__stdcall *GETMESSAGES)(void * hObject, icsSpyMessage *pMsg, int * pNumberOfMessages, int * pNumberOfErrors);
typedef int (__stdcall *TXMESSAGES)(void * hObject, icsSpyMessage *pMsg, int lNetworkID, int lNumMessages);
typedef int (__stdcall *GETMESSAGES)(void * hObject, icsSpyMessage *pMsg, int * pNumberOfMessages, int * pNumberOfErrors);
typedef int (__stdcall *TXMESSAGES)(void * hObject, icsSpyMessage *pMsg, int lNetworkID, int lNumMessages);
typedef int (__stdcall *TXMESSAGESEX)(void * hObject,icsSpyMessage *pMsg, unsigned int lNetworkID,unsigned int lNumMessages,unsigned int *NumTxed, unsigned int zero2);
typedef int (__stdcall *WAITFORRXMSGS)(void * hObject, unsigned int iTimeOut);
typedef int (__stdcall *ENABLERXQUEUE)(void * hObject, int iEnable);
typedef int (__stdcall *GETTSFORMSG)(void * hObject, icsSpyMessage *pMsg, double *pTimeStamp);
typedef void (__stdcall *GETISO15765STATUS)(void * hObject, int lNetwork, int lClearTxStatus,
typedef void (__stdcall *GETISO15765STATUS)(void * hObject, int lNetwork, int lClearTxStatus,
int lClearRxStatus, int *lTxStatus, int *lRxStatus);
typedef void (__stdcall *SETISO15765RXPARMS)(void * hObject, int lNetwork, int lEnable,
spyFilterLong *pFF_CFMsgFilter, icsSpyMessage *pTxMsg,
typedef void (__stdcall *SETISO15765RXPARMS)(void * hObject, int lNetwork, int lEnable,
spyFilterLong *pFF_CFMsgFilter, icsSpyMessage *pTxMsg,
int lCFTimeOutMs, int lFlowCBlockSize,
int lUsesExtendedAddressing, int lUseHardwareIfPresent);
typedef int (__stdcall *DOWNLOADISO15765_2_TXSCRIPT)(void * hObject, unsigned int NetworkID);
@@ -37,7 +36,7 @@ typedef int (__stdcall *TXISO15765_2_MESSAGE)(void * hObject, stCM_ISO157652_TxM
//Device Functions
typedef int (__stdcall *GETCONFIG)(void * hObject, unsigned char * pData, int * lNumBytes);
typedef int (__stdcall *SENDCONFIG)(void * hObject, unsigned char * pData, int lNumBytes);
typedef int (__stdcall *SENDCONFIG)(void * hObject, unsigned char * pData, int lNumBytes);
typedef int (__stdcall *GETFIRESETTINGS)(void * hObject, SFireSettings *pSettings, int iNumBytes);
typedef int (__stdcall *SETFIRESETTINGS)(void * hObject, SFireSettings *pSettings, int iNumBytes, int bSaveToEEPROM);
@@ -63,12 +62,11 @@ typedef int (__stdcall *SETRADSTAR2SETTINGS)(void * hObject, SRADStar2Settings *
typedef int (__stdcall *SETBITRATE)(void * hObject, int BitRate, int NetworkID);
typedef int (__stdcall *GETDEVICEPARMS)(void * hObject, char *pParameter, char *pValues, short ValuesLength);
typedef int (__stdcall *SETDEVICEPARMS)(void * hObject, char *pParmValue, int *pErrorIndex, int bSaveToEEPROM);
typedef int(__stdcall *ENABLEDOIPACTIVATIONLINE)(void * hObject, bool Val);
//Error Functions
typedef int (__stdcall *GETLASTAPIERROR)(void * hObject, unsigned long *pErrorNumber);
typedef int (__stdcall *GETERRMSGS)(void * hObject, int * pErrorMsgs, int * pNumberOfErrors);
typedef int (__stdcall *GETERRORINFO)(int lErrorNumber, TCHAR *szErrorDescriptionShort,
typedef int (__stdcall *GETERRORINFO)(int lErrorNumber, TCHAR *szErrorDescriptionShort,
TCHAR *szErrorDescriptionLong, int * lMaxLengthShort,
int * lMaxLengthLong,int * lErrorSeverity,int * lRestartNeeded);
@@ -86,8 +84,8 @@ typedef int (__stdcall *STARTSOCKSERVER)(void * hObject, int iPort);
typedef int (__stdcall *STOPSOCKSERVER)(void * hObject);
//CoreMini Script functions
typedef int (__stdcall *SCRIPTSTART)(void * hObject, int iLocation);
typedef int (__stdcall *SCRIPTSTOP)(void * hObject);
typedef int (__stdcall *SCRIPTSTART)(void * hObject, int iLocation);
typedef int (__stdcall *SCRIPTSTOP)(void * hObject);
typedef int (__stdcall *SCRIPTLOAD)(void * hObject, const unsigned char * bin, unsigned long len_bytes, int iLocation);
typedef int (__stdcall *SCRIPTCLEAR)(void * hObject, int iLocation);
typedef int (__stdcall *SCRIPTSTARTFBLOCK)(void * hObject,unsigned int fb_index);
@@ -101,20 +99,21 @@ typedef int (__stdcall *SCRIPTWRITEISO15765TXMESSAGE)(void * hObject, unsigned
//Deprecated (but still suppored in the DLL)
//////typedef int (__stdcall *OPENPORTEX)(int lPortSerialNumber, int lPortType, int lDriverType,
////// int lIPAddressMSB, int lIPAddressLSBOrBaudRate,int bConfigRead,
//////typedef int (__stdcall *OPENPORTEX)(int lPortSerialNumber, int lPortType, int lDriverType,
////// int lIPAddressMSB, int lIPAddressLSBOrBaudRate,int bConfigRead,
////// unsigned char * bNetworkID, int * hObject);
//////
//////typedef int (__stdcall *OPENPORT)(int lPortNumber, int lPortType, int lDriverType,
//////typedef int (__stdcall *OPENPORT)(int lPortNumber, int lPortType, int lDriverType,
////// unsigned char *bNetworkID, unsigned char *bSCPIDs, int * hObject);
//////typedef int (__stdcall *ENABLENETWORKCOM)(void * hObject, int Enable);
//////typedef int (__stdcall *FINDCOMDEVICES)(int lDriverType, int lGetSerialNumbers, int lStopAtFirst, int lUSBCommOnly,
////// int *p_lDeviceTypes, int *p_lComPorts, int *p_lSerialNumbers, int *lNumDevices);
////// int *p_lDeviceTypes, int *p_lComPorts, int *p_lSerialNumbers, int *lNumDevices);
//Basic Functions
extern OPENDEVICE icsneoOpenDevice;
extern FINDNEODEVICES icsneoFindNeoDevices;
extern OPENNEODEVICE icsneoOpenNeoDevice;
extern CLOSEPORT icsneoClosePort;
extern FREEOBJECT icsneoFreeObject;
extern SERIALNUMBERTOSTRING icsneoSerialNumberToString;
@@ -158,7 +157,6 @@ extern SETVCAN412SETTINGS icsneoSetVCAN412Settings;
extern SETBITRATE icsneoSetBitRate;
extern GETDEVICEPARMS icsneoGetDeviceParameters;
extern SETDEVICEPARMS icsneoSetDeviceParameters;
extern ENABLEDOIPACTIVATIONLINE icsneoEnableDOIPLine;
//Error Functions
extern GETLASTAPIERROR icsneoGetLastAPIError;
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -14,15 +14,15 @@
using namespace icsneo;
extern "C" {
extern int LegacyDLLExport icsneoValidateHObject(void* hObject);
extern int LegacyDLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut);
extern int DLLExport icsneoValidateHObject(void* hObject);
extern int DLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut);
}
int LegacyDLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut) {
int icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut) {
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
if(device->device->getCurrentMessageCount() != 0)
return true;
return bool(device->device->com->waitForMessageSync({}, std::chrono::milliseconds(iTimeOut)));
return bool(device->device->com->waitForMessageSync(MessageFilter(), std::chrono::milliseconds(iTimeOut)));
}
-3
View File
@@ -1,3 +0,0 @@
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
add_subdirectory(python)
endif()
-24
View File
@@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.20)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(icsneopy
icsneopy/api/event.cpp
icsneopy/api/eventcallback.cpp
icsneopy/api/eventmanager.cpp
icsneopy/api/version.cpp
icsneopy/device/devicetype.cpp
icsneopy/communication/network.cpp
icsneopy/communication/message/message.cpp
icsneopy/communication/message/canmessage.cpp
icsneopy/communication/message/ethernetmessage.cpp
icsneopy/communication/message/tc10statusmessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/device/device.cpp
icsneopy/icsneocpp.cpp
)
target_link_libraries(icsneopy PRIVATE icsneocpp)
install(TARGETS icsneopy LIBRARY DESTINATION .)
-170
View File
@@ -1,170 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/event.h"
namespace icsneo {
void init_event(pybind11::module_& m) {
pybind11::class_<APIEvent, std::shared_ptr<APIEvent>> apiEvent(m, "APIEvent");
pybind11::enum_<APIEvent::Type>(apiEvent, "Type")
.value("Any", APIEvent::Type::Any)
.value("InvalidNeoDevice", APIEvent::Type::InvalidNeoDevice)
.value("RequiredParameterNull", APIEvent::Type::RequiredParameterNull)
.value("BufferInsufficient", APIEvent::Type::BufferInsufficient)
.value("OutputTruncated", APIEvent::Type::OutputTruncated)
.value("ParameterOutOfRange", APIEvent::Type::ParameterOutOfRange)
.value("DeviceCurrentlyOpen", APIEvent::Type::DeviceCurrentlyOpen)
.value("DeviceCurrentlyClosed", APIEvent::Type::DeviceCurrentlyClosed)
.value("DeviceCurrentlyOnline", APIEvent::Type::DeviceCurrentlyOnline)
.value("DeviceCurrentlyOffline", APIEvent::Type::DeviceCurrentlyOffline)
.value("DeviceCurrentlyPolling", APIEvent::Type::DeviceCurrentlyPolling)
.value("DeviceNotCurrentlyPolling", APIEvent::Type::DeviceNotCurrentlyPolling)
.value("UnsupportedTXNetwork", APIEvent::Type::UnsupportedTXNetwork)
.value("MessageMaxLengthExceeded", APIEvent::Type::MessageMaxLengthExceeded)
.value("ValueNotYetPresent", APIEvent::Type::ValueNotYetPresent)
.value("Timeout", APIEvent::Type::Timeout)
.value("WiVINotSupported", APIEvent::Type::WiVINotSupported)
.value("RestrictedEntryFlag", APIEvent::Type::RestrictedEntryFlag)
.value("NotSupported", APIEvent::Type::NotSupported)
.value("PollingMessageOverflow", APIEvent::Type::PollingMessageOverflow)
.value("NoSerialNumber", APIEvent::Type::NoSerialNumber)
.value("IncorrectSerialNumber", APIEvent::Type::IncorrectSerialNumber)
.value("SettingsReadError", APIEvent::Type::SettingsReadError)
.value("SettingsVersionError", APIEvent::Type::SettingsVersionError)
.value("SettingsLengthError", APIEvent::Type::SettingsLengthError)
.value("SettingsChecksumError", APIEvent::Type::SettingsChecksumError)
.value("SettingsNotAvailable", APIEvent::Type::SettingsNotAvailable)
.value("SettingsReadOnly", APIEvent::Type::SettingsReadOnly)
.value("CANSettingsNotAvailable", APIEvent::Type::CANSettingsNotAvailable)
.value("CANFDSettingsNotAvailable", APIEvent::Type::CANFDSettingsNotAvailable)
.value("LSFTCANSettingsNotAvailable", APIEvent::Type::LSFTCANSettingsNotAvailable)
.value("SWCANSettingsNotAvailable", APIEvent::Type::SWCANSettingsNotAvailable)
.value("BaudrateNotFound", APIEvent::Type::BaudrateNotFound)
.value("UnexpectedNetworkType", APIEvent::Type::UnexpectedNetworkType)
.value("DeviceFirmwareOutOfDate", APIEvent::Type::DeviceFirmwareOutOfDate)
.value("SettingsStructureMismatch", APIEvent::Type::SettingsStructureMismatch)
.value("SettingsStructureTruncated", APIEvent::Type::SettingsStructureTruncated)
.value("NoDeviceResponse", APIEvent::Type::NoDeviceResponse)
.value("MessageFormattingError", APIEvent::Type::MessageFormattingError)
.value("CANFDNotSupported", APIEvent::Type::CANFDNotSupported)
.value("RTRNotSupported", APIEvent::Type::RTRNotSupported)
.value("DeviceDisconnected", APIEvent::Type::DeviceDisconnected)
.value("OnlineNotSupported", APIEvent::Type::OnlineNotSupported)
.value("TerminationNotSupportedDevice", APIEvent::Type::TerminationNotSupportedDevice)
.value("TerminationNotSupportedNetwork", APIEvent::Type::TerminationNotSupportedNetwork)
.value("AnotherInTerminationGroupEnabled", APIEvent::Type::AnotherInTerminationGroupEnabled)
.value("NoSerialNumberFW", APIEvent::Type::NoSerialNumberFW)
.value("NoSerialNumber12V", APIEvent::Type::NoSerialNumber12V)
.value("NoSerialNumberFW12V", APIEvent::Type::NoSerialNumberFW12V)
.value("EthPhyRegisterControlNotAvailable", APIEvent::Type::EthPhyRegisterControlNotAvailable)
.value("DiskNotSupported", APIEvent::Type::DiskNotSupported)
.value("EOFReached", APIEvent::Type::EOFReached)
.value("SettingsDefaultsUsed", APIEvent::Type::SettingsDefaultsUsed)
.value("AtomicOperationRetried", APIEvent::Type::AtomicOperationRetried)
.value("AtomicOperationCompletedNonatomically", APIEvent::Type::AtomicOperationCompletedNonatomically)
.value("WiVIStackRefreshFailed", APIEvent::Type::WiVIStackRefreshFailed)
.value("WiVIUploadStackOverflow", APIEvent::Type::WiVIUploadStackOverflow)
.value("I2CMessageExceedsMaxLength", APIEvent::Type::I2CMessageExceedsMaxLength)
.value("A2BMessageIncompleteFrame", APIEvent::Type::A2BMessageIncompleteFrame)
.value("CoreminiUploadVersionMismatch", APIEvent::Type::CoreminiUploadVersionMismatch)
.value("DiskNotConnected", APIEvent::Type::DiskNotConnected)
.value("UnexpectedResponse", APIEvent::Type::UnexpectedResponse)
.value("LiveDataInvalidHandle", APIEvent::Type::LiveDataInvalidHandle)
.value("LiveDataInvalidCommand", APIEvent::Type::LiveDataInvalidCommand)
.value("LiveDataInvalidArgument", APIEvent::Type::LiveDataInvalidArgument)
.value("LiveDataVersionMismatch", APIEvent::Type::LiveDataVersionMismatch)
.value("LiveDataNoDeviceResponse", APIEvent::Type::LiveDataNoDeviceResponse)
.value("LiveDataMaxSignalsReached", APIEvent::Type::LiveDataMaxSignalsReached)
.value("LiveDataCommandFailed", APIEvent::Type::LiveDataCommandFailed)
.value("LiveDataEncoderError", APIEvent::Type::LiveDataEncoderError)
.value("LiveDataDecoderError", APIEvent::Type::LiveDataDecoderError)
.value("LiveDataNotSupported", APIEvent::Type::LiveDataNotSupported)
.value("LINSettingsNotAvailable", APIEvent::Type::LINSettingsNotAvailable)
.value("ModeNotFound", APIEvent::Type::ModeNotFound)
.value("AppErrorParsingFailed", APIEvent::Type::AppErrorParsingFailed)
.value("FailedToRead", APIEvent::Type::FailedToRead)
.value("FailedToWrite", APIEvent::Type::FailedToWrite)
.value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen)
.value("DriverFailedToClose", APIEvent::Type::DriverFailedToClose)
.value("PacketChecksumError", APIEvent::Type::PacketChecksumError)
.value("TransmitBufferFull", APIEvent::Type::TransmitBufferFull)
.value("DeviceInUse", APIEvent::Type::DeviceInUse)
.value("PCAPCouldNotStart", APIEvent::Type::PCAPCouldNotStart)
.value("PCAPCouldNotFindDevices", APIEvent::Type::PCAPCouldNotFindDevices)
.value("PacketDecodingError", APIEvent::Type::PacketDecodingError)
.value("SocketFailedToOpen", APIEvent::Type::SocketFailedToOpen)
.value("FailedToBind", APIEvent::Type::FailedToBind)
.value("ErrorSettingSocketOption", APIEvent::Type::ErrorSettingSocketOption)
.value("GetIfAddrsError", APIEvent::Type::GetIfAddrsError)
.value("SendToError", APIEvent::Type::SendToError)
.value("MDIOMessageExceedsMaxLength", APIEvent::Type::MDIOMessageExceedsMaxLength)
.value("FTOK", APIEvent::Type::FTOK)
.value("FTInvalidHandle", APIEvent::Type::FTInvalidHandle)
.value("FTDeviceNotFound", APIEvent::Type::FTDeviceNotFound)
.value("FTDeviceNotOpened", APIEvent::Type::FTDeviceNotOpened)
.value("FTIOError", APIEvent::Type::FTIOError)
.value("FTInsufficientResources", APIEvent::Type::FTInsufficientResources)
.value("FTInvalidParameter", APIEvent::Type::FTInvalidParameter)
.value("FTInvalidBaudRate", APIEvent::Type::FTInvalidBaudRate)
.value("FTDeviceNotOpenedForErase", APIEvent::Type::FTDeviceNotOpenedForErase)
.value("FTDeviceNotOpenedForWrite", APIEvent::Type::FTDeviceNotOpenedForWrite)
.value("FTFailedToWriteDevice", APIEvent::Type::FTFailedToWriteDevice)
.value("FTEEPROMReadFailed", APIEvent::Type::FTEEPROMReadFailed)
.value("FTEEPROMWriteFailed", APIEvent::Type::FTEEPROMWriteFailed)
.value("FTEEPROMEraseFailed", APIEvent::Type::FTEEPROMEraseFailed)
.value("FTEEPROMNotPresent", APIEvent::Type::FTEEPROMNotPresent)
.value("FTEEPROMNotProgrammed", APIEvent::Type::FTEEPROMNotProgrammed)
.value("FTInvalidArgs", APIEvent::Type::FTInvalidArgs)
.value("FTNotSupported", APIEvent::Type::FTNotSupported)
.value("FTNoMoreItems", APIEvent::Type::FTNoMoreItems)
.value("FTTimeout", APIEvent::Type::FTTimeout)
.value("FTOperationAborted", APIEvent::Type::FTOperationAborted)
.value("FTReservedPipe", APIEvent::Type::FTReservedPipe)
.value("FTInvalidControlRequestDirection", APIEvent::Type::FTInvalidControlRequestDirection)
.value("FTInvalidControlRequestType", APIEvent::Type::FTInvalidControlRequestType)
.value("FTIOPending", APIEvent::Type::FTIOPending)
.value("FTIOIncomplete", APIEvent::Type::FTIOIncomplete)
.value("FTHandleEOF", APIEvent::Type::FTHandleEOF)
.value("FTBusy", APIEvent::Type::FTBusy)
.value("FTNoSystemResources", APIEvent::Type::FTNoSystemResources)
.value("FTDeviceListNotReady", APIEvent::Type::FTDeviceListNotReady)
.value("FTDeviceNotConnected", APIEvent::Type::FTDeviceNotConnected)
.value("FTIncorrectDevicePath", APIEvent::Type::FTIncorrectDevicePath)
.value("FTOtherError", APIEvent::Type::FTOtherError)
.value("VSABufferCorrupted", APIEvent::Type::VSABufferCorrupted)
.value("VSATimestampNotFound", APIEvent::Type::VSATimestampNotFound)
.value("VSABufferFormatError", APIEvent::Type::VSABufferFormatError)
.value("VSAMaxReadAttemptsReached", APIEvent::Type::VSAMaxReadAttemptsReached)
.value("VSAByteParseFailure", APIEvent::Type::VSAByteParseFailure)
.value("VSAExtendedMessageError", APIEvent::Type::VSAExtendedMessageError)
.value("VSAOtherError", APIEvent::Type::VSAOtherError)
.value("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown);
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
.value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning)
.value("Error", APIEvent::Severity::Error);
apiEvent
.def("get_type", &APIEvent::getType)
.def("get_severity", &APIEvent::getSeverity)
.def("get_description", &APIEvent::getDescription)
.def("describe", &APIEvent::describe)
.def("__repr__", &APIEvent::describe);
pybind11::class_<EventFilter, std::shared_ptr<EventFilter>>(m, "EventFilter")
.def(pybind11::init())
.def(pybind11::init<APIEvent::Type>())
.def(pybind11::init<APIEvent::Severity>())
.def_readwrite("type", &EventFilter::type)
.def_readwrite("severity", &EventFilter::severity)
.def_readwrite("serial", &EventFilter::serial);
}
} // namespace icsneo
@@ -1,16 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/eventcallback.h"
namespace icsneo {
void init_eventcallback(pybind11::module_& m) {
pybind11::class_<EventCallback>(m, "EventCallback")
.def(pybind11::init<EventCallback::fn_eventCallback, EventFilter>())
.def(pybind11::init<EventCallback::fn_eventCallback>());
}
} // namespace icsneo
@@ -1,18 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/eventmanager.h"
namespace icsneo {
void init_eventmanager(pybind11::module_& m) {
pybind11::class_<EventManager>(m, "EventManager")
.def_static("get_instance", &EventManager::GetInstance, pybind11::return_value_policy::reference)
.def("add_event_callback", &EventManager::addEventCallback)
.def("remove_event_callback", &EventManager::removeEventCallback)
.def("get_last_error", &EventManager::getLastError);
}
} // namespace icsneo
-28
View File
@@ -1,28 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/version.h"
#include <sstream>
namespace icsneo {
void init_version(pybind11::module_& m) {
pybind11::class_<neoversion_t>(m, "NeoVersion")
.def_readonly("major", &neoversion_t::major)
.def_readonly("minor", &neoversion_t::minor)
.def_readonly("patch", &neoversion_t::patch)
.def_readonly("metadata", &neoversion_t::metadata)
.def_readonly("buildBranch", &neoversion_t::buildBranch)
.def_readonly("buildTag", &neoversion_t::buildTag)
.def("__repr__", [](const neoversion_t& self) -> std::string {
std::stringstream ss;
ss << self;
return ss.str();
});
m.def("get_version", &GetVersion);
}
} // namespace icsneo
@@ -1,15 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/callback/messagecallback.h"
namespace icsneo {
void init_messagecallback(pybind11::module_& m) {
pybind11::class_<MessageCallback, std::shared_ptr<MessageCallback>>(m, "MessageCallback")
.def(pybind11::init<MessageCallback::fn_messageCallback, std::shared_ptr<MessageFilter>>());
}
} // namespace icsneo
@@ -1,22 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/canmessage.h"
namespace icsneo {
void init_canmessage(pybind11::module_& m) {
pybind11::class_<CANMessage, std::shared_ptr<CANMessage>, Frame>(m, "CANMessage")
.def(pybind11::init())
.def_readwrite("arbid", &CANMessage::arbid)
.def_readwrite("dlcOnWire", &CANMessage::dlcOnWire)
.def_readwrite("isRemote", &CANMessage::isRemote)
.def_readwrite("isExtended", &CANMessage::isExtended)
.def_readwrite("isCANFD", &CANMessage::isCANFD)
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator);
}
} // namespace icsneo
@@ -1,27 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethernetmessage.h"
namespace icsneo {
void init_ethernetmessage(pybind11::module_& m) {
pybind11::class_<MACAddress>(m, "MACAddress")
.def("to_string", &MACAddress::toString)
.def("__repr__", &MACAddress::toString);
pybind11::class_<EthernetMessage, std::shared_ptr<EthernetMessage>, Frame>(m, "EthernetMessage")
.def(pybind11::init())
.def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def_readwrite("fcsAvailable", &EthernetMessage::fcsAvailable)
.def_readwrite("frameTooShort", &EthernetMessage::frameTooShort)
.def_readwrite("noPadding", &EthernetMessage::noPadding)
.def("get_destination_mac", &EthernetMessage::getDestinationMAC, pybind11::return_value_policy::reference)
.def("get_source_mac", &EthernetMessage::getSourceMAC, pybind11::return_value_policy::reference)
.def("get_ether_type", &EthernetMessage::getEtherType);
}
} // namespace icsneo
@@ -1,15 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/filter/messagefilter.h"
namespace icsneo {
void init_messagefilter(pybind11::module_& m) {
pybind11::class_<MessageFilter, std::shared_ptr<MessageFilter>>(m, "MessageFilter")
.def(pybind11::init<Network::NetID>());
}
} // namespace icsneo
@@ -1,51 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/message.h"
namespace icsneo {
void init_message(pybind11::module_& m) {
pybind11::class_<Message, std::shared_ptr<Message>> message(m, "Message");
pybind11::enum_<Message::Type>(message, "Type")
.value("Frame", Message::Type::Frame)
.value("CANErrorCount", Message::Type::CANErrorCount)
.value("LINHeaderOnly", Message::Type::LINHeaderOnly)
.value("LINBreak", Message::Type::LINBreak)
.value("Invalid", Message::Type::Invalid)
.value("RawMessage", Message::Type::RawMessage)
.value("ReadSettings", Message::Type::ReadSettings)
.value("ResetStatus", Message::Type::ResetStatus)
.value("DeviceVersion", Message::Type::DeviceVersion)
.value("Main51", Message::Type::Main51)
.value("FlexRayControl", Message::Type::FlexRayControl)
.value("EthernetPhyRegister", Message::Type::EthernetPhyRegister)
.value("LogicalDiskInfo", Message::Type::LogicalDiskInfo)
.value("ExtendedResponse", Message::Type::ExtendedResponse)
.value("WiVICommandResponse", Message::Type::WiVICommandResponse)
.value("ScriptStatus", Message::Type::ScriptStatus)
.value("ComponentVersions", Message::Type::ComponentVersions)
.value("SupportedFeatures", Message::Type::SupportedFeatures)
.value("GenericBinaryStatus", Message::Type::GenericBinaryStatus)
.value("LiveData", Message::Type::LiveData)
.value("HardwareInfo", Message::Type::HardwareInfo)
.value("TC10Status", Message::Type::TC10Status)
.value("AppError", Message::Type::AppError);
message.def(pybind11::init<Message::Type>());
message.def_readonly("type", &Message::type);
message.def_readwrite("timestamp", &Message::timestamp);
pybind11::class_<RawMessage, std::shared_ptr<RawMessage>, Message>(m, "RawMessage")
.def_readwrite("network", &RawMessage::network)
.def_readwrite("data", &RawMessage::data);
pybind11::class_<Frame, std::shared_ptr<Frame>, RawMessage>(m, "Frame")
.def_readwrite("description", &Frame::description)
.def_readwrite("transmitted", &Frame::transmitted)
.def_readwrite("error", &Frame::error);
}
} // namespace icsneo
@@ -1,25 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/tc10statusmessage.h"
namespace icsneo {
void init_tc10statusmessage(pybind11::module_& m) {
pybind11::enum_<TC10WakeStatus>(m, "TC10WakeStatus")
.value("NoWakeReceived", TC10WakeStatus::NoWakeReceived)
.value("WakeReceived", TC10WakeStatus::WakeReceived);
pybind11::enum_<TC10SleepStatus>(m, "TC10SleepStatus")
.value("NoSleepReceived", TC10SleepStatus::NoSleepReceived)
.value("SleepReceived", TC10SleepStatus::SleepReceived)
.value("SleepFailed", TC10SleepStatus::SleepFailed)
.value("SleepAborted", TC10SleepStatus::SleepAborted);
pybind11::class_<TC10StatusMessage, std::shared_ptr<TC10StatusMessage>, Message>(m, "TC10StatusMessage")
.def_readonly("wakeStatus", &TC10StatusMessage::wakeStatus)
.def_readonly("sleepStatus", &TC10StatusMessage::sleepStatus);
}
} // namespace icsneo
@@ -1,174 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/network.h"
namespace icsneo {
void init_network(pybind11::module_& m) {
pybind11::class_<Network> network(m, "Network");
pybind11::enum_<Network::NetID>(network, "NetID")
.value("Device", Network::NetID::Device)
.value("HSCAN", Network::NetID::HSCAN)
.value("MSCAN", Network::NetID::MSCAN)
.value("SWCAN", Network::NetID::SWCAN)
.value("LSFTCAN", Network::NetID::LSFTCAN)
.value("FordSCP", Network::NetID::FordSCP)
.value("J1708", Network::NetID::J1708)
.value("Aux", Network::NetID::Aux)
.value("J1850VPW", Network::NetID::J1850VPW)
.value("ISO9141", Network::NetID::ISO9141)
.value("DiskData", Network::NetID::DiskData)
.value("Main51", Network::NetID::Main51)
.value("RED", Network::NetID::RED)
.value("SCI", Network::NetID::SCI)
.value("ISO9141_2", Network::NetID::ISO9141_2)
.value("ISO14230", Network::NetID::ISO14230)
.value("LIN", Network::NetID::LIN)
.value("OP_Ethernet1", Network::NetID::OP_Ethernet1)
.value("OP_Ethernet2", Network::NetID::OP_Ethernet2)
.value("OP_Ethernet3", Network::NetID::OP_Ethernet3)
.value("RED_EXT_MEMORYREAD", Network::NetID::RED_EXT_MEMORYREAD)
.value("RED_INT_MEMORYREAD", Network::NetID::RED_INT_MEMORYREAD)
.value("RED_DFLASH_READ", Network::NetID::RED_DFLASH_READ)
.value("NeoMemorySDRead", Network::NetID::NeoMemorySDRead)
.value("CAN_ERRBITS", Network::NetID::CAN_ERRBITS)
.value("NeoMemoryWriteDone", Network::NetID::NeoMemoryWriteDone)
.value("RED_WAVE_CAN1_LOGICAL", Network::NetID::RED_WAVE_CAN1_LOGICAL)
.value("RED_WAVE_CAN2_LOGICAL", Network::NetID::RED_WAVE_CAN2_LOGICAL)
.value("RED_WAVE_LIN1_LOGICAL", Network::NetID::RED_WAVE_LIN1_LOGICAL)
.value("RED_WAVE_LIN2_LOGICAL", Network::NetID::RED_WAVE_LIN2_LOGICAL)
.value("RED_WAVE_LIN1_ANALOG", Network::NetID::RED_WAVE_LIN1_ANALOG)
.value("RED_WAVE_LIN2_ANALOG", Network::NetID::RED_WAVE_LIN2_ANALOG)
.value("RED_WAVE_MISC_ANALOG", Network::NetID::RED_WAVE_MISC_ANALOG)
.value("RED_WAVE_MISCDIO2_LOGICAL", Network::NetID::RED_WAVE_MISCDIO2_LOGICAL)
.value("RED_NETWORK_COM_ENABLE_EX", Network::NetID::RED_NETWORK_COM_ENABLE_EX)
.value("RED_NEOVI_NETWORK", Network::NetID::RED_NEOVI_NETWORK)
.value("RED_READ_BAUD_SETTINGS", Network::NetID::RED_READ_BAUD_SETTINGS)
.value("RED_OLDFORMAT", Network::NetID::RED_OLDFORMAT)
.value("RED_SCOPE_CAPTURE", Network::NetID::RED_SCOPE_CAPTURE)
.value("RED_HARDWARE_EXCEP", Network::NetID::RED_HARDWARE_EXCEP)
.value("RED_GET_RTC", Network::NetID::RED_GET_RTC)
.value("ISO9141_3", Network::NetID::ISO9141_3)
.value("HSCAN2", Network::NetID::HSCAN2)
.value("HSCAN3", Network::NetID::HSCAN3)
.value("OP_Ethernet4", Network::NetID::OP_Ethernet4)
.value("OP_Ethernet5", Network::NetID::OP_Ethernet5)
.value("ISO9141_4", Network::NetID::ISO9141_4)
.value("LIN2", Network::NetID::LIN2)
.value("LIN3", Network::NetID::LIN3)
.value("LIN4", Network::NetID::LIN4)
.value("RED_App_Error", Network::NetID::RED_App_Error)
.value("CGI", Network::NetID::CGI)
.value("Reset_Status", Network::NetID::Reset_Status)
.value("FB_Status", Network::NetID::FB_Status)
.value("App_Signal_Status", Network::NetID::App_Signal_Status)
.value("Read_Datalink_Cm_Tx_Msg", Network::NetID::Read_Datalink_Cm_Tx_Msg)
.value("Read_Datalink_Cm_Rx_Msg", Network::NetID::Read_Datalink_Cm_Rx_Msg)
.value("Logging_Overflow", Network::NetID::Logging_Overflow)
.value("ReadSettings", Network::NetID::ReadSettings)
.value("HSCAN4", Network::NetID::HSCAN4)
.value("HSCAN5", Network::NetID::HSCAN5)
.value("RS232", Network::NetID::RS232)
.value("UART", Network::NetID::UART)
.value("UART2", Network::NetID::UART2)
.value("UART3", Network::NetID::UART3)
.value("UART4", Network::NetID::UART4)
.value("SWCAN2", Network::NetID::SWCAN2)
.value("Ethernet_DAQ", Network::NetID::Ethernet_DAQ)
.value("Data_To_Host", Network::NetID::Data_To_Host)
.value("TextAPI_To_Host", Network::NetID::TextAPI_To_Host)
.value("SPI1", Network::NetID::SPI1)
.value("OP_Ethernet6", Network::NetID::OP_Ethernet6)
.value("Red_VBat", Network::NetID::Red_VBat)
.value("OP_Ethernet7", Network::NetID::OP_Ethernet7)
.value("OP_Ethernet8", Network::NetID::OP_Ethernet8)
.value("OP_Ethernet9", Network::NetID::OP_Ethernet9)
.value("OP_Ethernet10", Network::NetID::OP_Ethernet10)
.value("OP_Ethernet11", Network::NetID::OP_Ethernet11)
.value("FlexRay1a", Network::NetID::FlexRay1a)
.value("FlexRay1b", Network::NetID::FlexRay1b)
.value("FlexRay2a", Network::NetID::FlexRay2a)
.value("FlexRay2b", Network::NetID::FlexRay2b)
.value("LIN5", Network::NetID::LIN5)
.value("FlexRay", Network::NetID::FlexRay)
.value("FlexRay2", Network::NetID::FlexRay2)
.value("OP_Ethernet12", Network::NetID::OP_Ethernet12)
.value("I2C", Network::NetID::I2C)
.value("MOST25", Network::NetID::MOST25)
.value("MOST50", Network::NetID::MOST50)
.value("MOST150", Network::NetID::MOST150)
.value("Ethernet", Network::NetID::Ethernet)
.value("GMFSA", Network::NetID::GMFSA)
.value("TCP", Network::NetID::TCP)
.value("HSCAN6", Network::NetID::HSCAN6)
.value("HSCAN7", Network::NetID::HSCAN7)
.value("LIN6", Network::NetID::LIN6)
.value("LSFTCAN2", Network::NetID::LSFTCAN2)
.value("LogicalDiskInfo", Network::NetID::LogicalDiskInfo)
.value("WiVICommand", Network::NetID::WiVICommand)
.value("ScriptStatus", Network::NetID::ScriptStatus)
.value("EthPHYControl", Network::NetID::EthPHYControl)
.value("ExtendedCommand", Network::NetID::ExtendedCommand)
.value("ExtendedData", Network::NetID::ExtendedData)
.value("FlexRayControl", Network::NetID::FlexRayControl)
.value("CoreMiniPreLoad", Network::NetID::CoreMiniPreLoad)
.value("HW_COM_Latency_Test", Network::NetID::HW_COM_Latency_Test)
.value("DeviceStatus", Network::NetID::DeviceStatus)
.value("UDP", Network::NetID::UDP)
.value("ForwardedMessage", Network::NetID::ForwardedMessage)
.value("I2C2", Network::NetID::I2C2)
.value("I2C3", Network::NetID::I2C3)
.value("I2C4", Network::NetID::I2C4)
.value("Ethernet2", Network::NetID::Ethernet2)
.value("A2B1", Network::NetID::A2B1)
.value("A2B2", Network::NetID::A2B2)
.value("Ethernet3", Network::NetID::Ethernet3)
.value("WBMS", Network::NetID::WBMS)
.value("DWCAN9", Network::NetID::DWCAN9)
.value("DWCAN10", Network::NetID::DWCAN10)
.value("DWCAN11", Network::NetID::DWCAN11)
.value("DWCAN12", Network::NetID::DWCAN12)
.value("DWCAN13", Network::NetID::DWCAN13)
.value("DWCAN14", Network::NetID::DWCAN14)
.value("DWCAN15", Network::NetID::DWCAN15)
.value("DWCAN16", Network::NetID::DWCAN16)
.value("LIN7", Network::NetID::LIN7)
.value("LIN8", Network::NetID::LIN8)
.value("SPI2", Network::NetID::SPI2)
.value("MDIO1", Network::NetID::MDIO1)
.value("MDIO2", Network::NetID::MDIO2)
.value("MDIO3", Network::NetID::MDIO3)
.value("MDIO4", Network::NetID::MDIO4)
.value("MDIO5", Network::NetID::MDIO5)
.value("MDIO6", Network::NetID::MDIO6)
.value("MDIO7", Network::NetID::MDIO7)
.value("MDIO8", Network::NetID::MDIO8)
.value("OP_Ethernet13", Network::NetID::OP_Ethernet13)
.value("OP_Ethernet14", Network::NetID::OP_Ethernet14)
.value("OP_Ethernet15", Network::NetID::OP_Ethernet15)
.value("OP_Ethernet16", Network::NetID::OP_Ethernet16)
.value("SPI3", Network::NetID::SPI3)
.value("SPI4", Network::NetID::SPI4)
.value("SPI5", Network::NetID::SPI5)
.value("SPI6", Network::NetID::SPI6)
.value("SPI7", Network::NetID::SPI7)
.value("SPI8", Network::NetID::SPI8)
.value("LIN9", Network::NetID::LIN9)
.value("LIN10", Network::NetID::LIN10)
.value("LIN11", Network::NetID::LIN11)
.value("LIN12", Network::NetID::LIN12)
.value("LIN13", Network::NetID::LIN13)
.value("LIN14", Network::NetID::LIN14)
.value("LIN15", Network::NetID::LIN15)
.value("LIN16", Network::NetID::LIN16)
.value("Any", Network::NetID::Any)
.value("Invalid", Network::NetID::Invalid);
network.def(pybind11::init<Network::NetID>());
}
} // namespace icsneo
@@ -1,43 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/device/device.h"
namespace icsneo {
void init_device(pybind11::module_& m) {
pybind11::class_<Device, std::shared_ptr<Device>>(m, "Device")
.def("get_type", &Device::getType)
.def("get_serial", &Device::getSerial)
.def("get_serial_number", &Device::getSerialNumber)
.def("get_product_name", &Device::getProductName)
.def("open", [](Device& device) { return device.open(); })
.def("close", &Device::close)
.def("is_open", &Device::isOpen)
.def("go_online", &Device::goOnline)
.def("go_offline", &Device::goOffline)
.def("is_online", &Device::isOnline).def("enable_message_polling", &Device::enableMessagePolling)
.def("disable_message_polling", &Device::disableMessagePolling)
.def("is_message_polling_enabled", &Device::isMessagePollingEnabled)
.def("get_messages", [](Device& device) { return device.getMessages(); })
.def("get_current_message_count", &Device::getCurrentMessageCount)
.def("get_polling_message_limit", &Device::getPollingMessageLimit)
.def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("add_message_callback", &Device::addMessageCallback)
.def("remove_message_callback", &Device::removeMessageCallback)
.def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit))
.def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference)
.def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference)
.def("get_rtc", &Device::getRTC)
.def("set_rtc", &Device::setRTC)
.def("describe", &Device::describe)
.def("is_online_supported", &Device::isOnlineSupported)
.def("supports_tc10", &Device::supportsTC10)
.def("request_tc10_wake", &Device::requestTC10Wake)
.def("request_tc10_sleep", &Device::requestTC10Sleep)
.def("__repr__", &Device::describe);
}
} // namespace icsneo
@@ -1,75 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/device/devicetype.h"
namespace icsneo {
void init_devicetype(pybind11::module_& m) {
pybind11::class_<DeviceType> deviceType(m, "DeviceType");
pybind11::enum_<DeviceType::Enum>(deviceType, "Enum")
.value("Unknown", DeviceType::Enum::Unknown)
.value("BLUE", DeviceType::Enum::BLUE)
.value("ECU_AVB", DeviceType::Enum::ECU_AVB)
.value("RADSupermoon", DeviceType::Enum::RADSupermoon)
.value("DW_VCAN", DeviceType::Enum::DW_VCAN)
.value("RADMoon2", DeviceType::Enum::RADMoon2)
.value("RADMars", DeviceType::Enum::RADMars)
.value("VCAN4_1", DeviceType::Enum::VCAN4_1)
.value("FIRE", DeviceType::Enum::FIRE)
.value("RADPluto", DeviceType::Enum::RADPluto)
.value("VCAN4_2EL", DeviceType::Enum::VCAN4_2EL)
.value("RADIO_CANHUB", DeviceType::Enum::RADIO_CANHUB)
.value("NEOECU12", DeviceType::Enum::NEOECU12)
.value("OBD2_LCBADGE", DeviceType::Enum::OBD2_LCBADGE)
.value("RADMoonDuo", DeviceType::Enum::RADMoonDuo)
.value("FIRE3", DeviceType::Enum::FIRE3)
.value("VCAN3", DeviceType::Enum::VCAN3)
.value("RADJupiter", DeviceType::Enum::RADJupiter)
.value("VCAN4_IND", DeviceType::Enum::VCAN4_IND)
.value("RADGigastar", DeviceType::Enum::RADGigastar)
.value("RED2", DeviceType::Enum::RED2)
.value("EtherBADGE", DeviceType::Enum::EtherBADGE)
.value("RAD_A2B", DeviceType::Enum::RAD_A2B)
.value("RADEpsilon", DeviceType::Enum::RADEpsilon)
.value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADComet", DeviceType::Enum::RADComet)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("Connect", DeviceType::Enum::Connect)
.value("RADComet3", DeviceType::Enum::RADComet3)
.value("RADMoonT1S", DeviceType::Enum::RADMoonT1S)
.value("RADGigastar2", DeviceType::Enum::RADGigastar2)
.value("RED", DeviceType::Enum::RED)
.value("ECU", DeviceType::Enum::ECU)
.value("IEVB", DeviceType::Enum::IEVB)
.value("Pendant", DeviceType::Enum::Pendant)
.value("OBD2_PRO", DeviceType::Enum::OBD2_PRO)
.value("ECUChip_UART", DeviceType::Enum::ECUChip_UART)
.value("PLASMA", DeviceType::Enum::PLASMA)
.value("DONT_REUSE0", DeviceType::Enum::DONT_REUSE0)
.value("NEOAnalog", DeviceType::Enum::NEOAnalog)
.value("CT_OBD", DeviceType::Enum::CT_OBD)
.value("DONT_REUSE1", DeviceType::Enum::DONT_REUSE1)
.value("DONT_REUSE2", DeviceType::Enum::DONT_REUSE2)
.value("ION", DeviceType::Enum::ION)
.value("RADStar", DeviceType::Enum::RADStar)
.value("DONT_REUSE3", DeviceType::Enum::DONT_REUSE3)
.value("VCAN4_4", DeviceType::Enum::VCAN4_4)
.value("VCAN4_2", DeviceType::Enum::VCAN4_2)
.value("CMProbe", DeviceType::Enum::CMProbe)
.value("EEVB", DeviceType::Enum::EEVB)
.value("VCANrf", DeviceType::Enum::VCANrf)
.value("FIRE2", DeviceType::Enum::FIRE2)
.value("Flex", DeviceType::Enum::Flex)
.value("RADGalaxy", DeviceType::Enum::RADGalaxy)
.value("RADStar2", DeviceType::Enum::RADStar2)
.value("VividCAN", DeviceType::Enum::VividCAN)
.value("OBD2_SIM", DeviceType::Enum::OBD2_SIM);
deviceType.def(pybind11::init<DeviceType::Enum>());
deviceType.def("get_device_type", &DeviceType::getDeviceType);
deviceType.def("get_generic_product_name", &DeviceType::getGenericProductName);
}
} // namespace icsneo
-45
View File
@@ -1,45 +0,0 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/icsneocpp.h"
namespace icsneo {
void init_event(pybind11::module_&);
void init_eventcallback(pybind11::module_&);
void init_eventmanager(pybind11::module_&);
void init_network(pybind11::module_&);
void init_devicetype(pybind11::module_&);
void init_message(pybind11::module_&);
void init_canmessage(pybind11::module_&);
void init_ethernetmessage(pybind11::module_&);
void init_tc10statusmessage(pybind11::module_&);
void init_device(pybind11::module_&);
void init_messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&);
PYBIND11_MODULE(icsneopy, m) {
m.doc() = "libicsneo Python module";
init_event(m);
init_eventcallback(m);
init_eventmanager(m);
init_version(m);
init_devicetype(m);
init_network(m);
init_message(m);
init_canmessage(m);
init_ethernetmessage(m);
init_tc10statusmessage(m);
init_messagefilter(m);
init_messagecallback(m);
init_device(m);
m.def("find_all_devices", &FindAllDevices);
m.def("get_supported_devices", &GetSupportedDevices);
m.def("get_last_error", &GetLastError);
}
} // namespace icsneo
-18
View File
@@ -1,18 +0,0 @@
#!/bin/sh
VERSION="1.10.5"
ROOT="$PWD/libpcap"
SOURCE="$ROOT/source"
BUILD="$ROOT/build"
INSTALL="$ROOT/install"
mkdir -p "$ROOT"
cd "$ROOT" || exit 1
curl -LO "https://www.tcpdump.org/release/libpcap-$VERSION.tar.xz" || exit 1
tar -xf "libpcap-$VERSION.tar.xz" || exit 1
mv "libpcap-$VERSION" "$SOURCE" || exit 1
cmake -D CMAKE_POSITION_INDEPENDENT_CODE=ON -D CMAKE_INSTALL_PREFIX="$INSTALL" -D BUILD_SHARED_LIBS=OFF -D BUILD_WITH_LIBNL=OFF -D DISABLE_DBUS=ON -D DISABLE_LINUX_USBMON=ON -D DISABLE_BLUETOOTH=ON -D DISABLE_NETMAP=ON -D DISABLE_DPDK=ON -D DISABLE_RDMA=ON -D DISABLE_DAG=ON -D DISABLE_SEPTEL=ON -D DISABLE_SNF=ON -D DISABLE_TC=ON -B "$BUILD" -S "$SOURCE" || exit 1
cmake --build "$BUILD" || exit 1
cmake --install "$BUILD" || exit 1
-21
View File
@@ -1,21 +0,0 @@
#!/bin/sh
VERSION="1.0.27"
ROOT="$PWD/libusb"
SOURCE="$ROOT/source"
BUILD="$ROOT/build"
INSTALL="$ROOT/install"
mkdir -p "$ROOT"
cd "$ROOT" || exit 1
curl -LO "https://github.com/libusb/libusb/releases/download/v$VERSION/libusb-$VERSION.tar.bz2" || exit 1
tar -xf "libusb-$VERSION.tar.bz2" || exit 1
mv "libusb-$VERSION" "$SOURCE" || exit 1
mkdir "$BUILD" || exit 1
cd "$BUILD" || exit 1
"$SOURCE/configure" --prefix="$INSTALL" --disable-shared --disable-udev --disable-eventfd --disable-timerfd --with-pic || exit 1
make || exit 1
make install || exit 1
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON \
-DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_BUILD_SYSTEM_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
cmake --build build || exit 1
exit 0
-7
View File
@@ -1,7 +0,0 @@
#!/bin/sh
python3 -m venv env || exit 1
. env/bin/activate || exit 1
python3 -m pip install cibuildwheel || exit 1
python3 -m cibuildwheel --output-dir wheelhouse || exit 1
-9
View File
@@ -1,9 +0,0 @@
@setlocal
@echo off
call "%VCVARS64_2022%"
python.exe -m venv env || exit /b 1
call env\Scripts\Activate.bat || exit /b 1
python.exe -m pip install cibuildwheel || exit /b 1
python.exe -m cibuildwheel --output-dir wheelhouse --platform windows || exit /b 1
-12
View File
@@ -1,12 +0,0 @@
REM clean intermediate directories
rmdir /s /q build
mkdir build
REM build
cd build
set CFLAGS=/WX
set CXXFLAGS=/WX
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_BUILD_SYSTEM_TESTS=ON -DLIBICSNEO_ENABLE_TCP=ON ..
if %errorlevel% neq 0 exit /b %errorlevel%
cmake --build .
if %errorlevel% neq 0 exit /b %errorlevel%
-2
View File
@@ -1,2 +0,0 @@
call "%VCVARS32%"
call "ci\build-windows.bat"
-2
View File
@@ -1,2 +0,0 @@
call "%VCVARS64%"
call "ci\build-windows.bat"
-22
View File
@@ -1,22 +0,0 @@
find_path(FTD3XX_INCLUDE_DIR
NAMES ftd3xx.h FTD3XX.h
)
find_library(FTD3XX_LIBRARY
NAMES libftd3xx.a libftd3xx-static.a FTD3XX.lib
PATH_SUFFIXES x64/Static
)
mark_as_advanced(FTD3XX_FOUND FTD3XX_INCLUDE_DIR FTD3XX_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FTD3XX
REQUIRED_VARS FTD3XX_INCLUDE_DIR FTD3XX_LIBRARY
)
if(FTD3XX_FOUND AND NOT TARGET D3XX::D3XX)
add_library(FTD3XX::FTD3XX INTERFACE IMPORTED)
set_target_properties(FTD3XX::FTD3XX PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FTD3XX_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${FTD3XX_LIBRARY}"
)
endif()
+40 -177
View File
@@ -12,28 +12,19 @@
#include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/filter/main51messagefilter.h"
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/versionmessage.h"
#include "icsneo/communication/message/componentversionsmessage.h"
using namespace icsneo;
int Communication::messageCallbackIDCounter = 1;
Communication::~Communication() {
if(isOpen())
close();
}
bool Communication::open() {
if(isOpen()) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
return false;
}
if(!driver->open())
return false;
spawnThreads();
return true;
return impl->open();
}
void Communication::spawnThreads() {
@@ -42,33 +33,24 @@ void Communication::spawnThreads() {
void Communication::joinThreads() {
closing = true;
if(pauseReadTask) {
resumeReads();
}
if(readTaskThread.joinable())
readTaskThread.join();
closing = false;
}
bool Communication::close() {
joinThreads();
if(!isOpen() && !isDisconnected()) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
return driver->close();
joinThreads();
return impl->close();
}
bool Communication::isOpen() {
return driver->isOpen();
}
bool Communication::isDisconnected() {
return driver->isDisconnected();
return impl->isOpen();
}
bool Communication::sendPacket(std::vector<uint8_t>& bytes) {
@@ -78,32 +60,15 @@ bool Communication::sendPacket(std::vector<uint8_t>& bytes) {
bool Communication::sendCommand(Command cmd, std::vector<uint8_t> arguments) {
std::vector<uint8_t> packet;
if(!encoder->encode(*packetizer, packet, cmd, arguments))
if(!encoder->encode(packet, cmd, arguments))
return false;
return sendPacket(packet);
}
bool Communication::sendCommand(ExtendedCommand cmd, std::vector<uint8_t> arguments) {
const auto size = arguments.size();
if (size > std::numeric_limits<uint16_t>::max())
return false;
arguments.insert(arguments.begin(), {
uint8_t(uint16_t(cmd) & 0xff),
uint8_t((uint16_t(cmd) >> 8) & 0xff),
uint8_t(size & 0xff),
uint8_t((size >> 8) & 0xff)
});
return sendCommand(Command::Extended, arguments);
}
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ });
}, filter, timeout);
sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ });
std::shared_ptr<Message> msg = waitForMessageSync(MessageFilter(Network::NetID::ReadSettings), timeout);
if(!msg)
return false;
@@ -113,75 +78,29 @@ bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::mil
return false;
}
if(gsmsg->response == ReadSettingsMessage::Response::OKDefaultsUsed) {
report(APIEvent::Type::SettingsDefaultsUsed, APIEvent::Severity::EventInfo);
} else if(gsmsg->response != ReadSettingsMessage::Response::OK) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
if(gsmsg->response != ReadSettingsMessage::Response::OK) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false;
}
data = std::move(gsmsg->data);
data = std::move(msg->data);
return true;
}
std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<Main51MessageFilter>(Command::RequestSerialNumber);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::RequestSerialNumber);
}, filter, timeout);
sendCommand(Command::RequestSerialNumber);
std::shared_ptr<Message> msg = waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::RequestSerialNumber), timeout);
if(!msg) // Did not receive a message
return std::shared_ptr<SerialNumberMessage>();
auto m51 = std::dynamic_pointer_cast<Main51Message>(msg);
if(!m51) // Could not upcast for some reason
return std::shared_ptr<SerialNumberMessage>();
return std::dynamic_pointer_cast<SerialNumberMessage>(m51);
}
std::optional< std::vector< std::optional<DeviceAppVersion> > > Communication::getVersionsSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::DeviceVersion);
std::vector< std::optional<DeviceAppVersion> > ret;
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::GetMainVersion);
}, filter, timeout);
if(!msg) // Did not receive a message
return std::nullopt;
auto ver = std::dynamic_pointer_cast<VersionMessage>(msg);
if(!ver) // Could not upcast for some reason
return std::nullopt;
if(ver->ForChip != VersionMessage::MainChip || ver->Versions.size() != 1)
return std::nullopt;
ret.push_back(ver->Versions.front());
msg = waitForMessageSync([this]() {
return sendCommand(Command::GetSecondaryVersions);
}, filter, timeout);
if(msg) { // This one is allowed to fail
ver = std::dynamic_pointer_cast<VersionMessage>(msg);
if(ver && ver->ForChip != VersionMessage::MainChip)
ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end());
}
return ret;
}
std::shared_ptr<LogicalDiskInfoMessage> Communication::getLogicalDiskInfoSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::LogicalDiskInfo);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::GetLogicalDiskInfo);
}, filter, timeout);
if(!msg) // Did not receive a message
return {};
return std::dynamic_pointer_cast<LogicalDiskInfoMessage>(msg);
}
int Communication::addMessageCallback(const std::shared_ptr<MessageCallback>& cb) {
int Communication::addMessageCallback(const MessageCallback& cb) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb));
return messageCallbackIDCounter++;
@@ -198,34 +117,25 @@ bool Communication::removeMessageCallback(int id) {
}
}
std::shared_ptr<Message> Communication::waitForMessageSync(std::function<bool(void)> onceWaitingDo,
const std::shared_ptr<MessageFilter>& f, std::chrono::milliseconds timeout) {
std::mutex cvMutex;
std::shared_ptr<Message> Communication::waitForMessageSync(std::shared_ptr<MessageFilter> f, std::chrono::milliseconds timeout) {
std::mutex m;
std::condition_variable cv;
std::shared_ptr<Message> returnedMessage;
std::unique_lock<std::mutex> fnLk(syncMessageMutex); // Only allow for one sync message at a time
std::unique_lock<std::mutex> cvLk(cvMutex); // Don't let the callback fire until we're waiting for it
int cb = addMessageCallback(std::make_shared<MessageCallback>([&cvMutex, &returnedMessage, &cv](std::shared_ptr<Message> message) {
int cb = addMessageCallback(MessageCallback([&m, &returnedMessage, &cv](std::shared_ptr<Message> message) {
{
std::lock_guard<std::mutex> lk(cvMutex);
std::lock_guard<std::mutex> lk(m);
returnedMessage = message;
}
cv.notify_all();
cv.notify_one();
}, f));
// We have now added the callback, do whatever the caller wanted to do
bool fail = !onceWaitingDo();
if(!fail)
cv.wait_for(cvLk, timeout, [&returnedMessage] { return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value
cvLk.unlock(); // Ensure callbacks can complete even if we didn't wait for them
// We have now added the callback, wait for it to return from the other thread
std::unique_lock<std::mutex> lk(m);
cv.wait_for(lk, timeout, [&returnedMessage] { return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value
lk.unlock();
// We don't actually check that we got a message, because either way we want to remove the callback (since it should only happen once)
removeMessageCallback(cb);
// We are now guaranteed that no more callbacks will happen
if(fail) // The caller's function failed, so don't return a message
returnedMessage.reset();
// Then we either will return the message we got or we will return the empty shared_ptr, caller responsible for checking
return returnedMessage;
@@ -240,77 +150,30 @@ void Communication::dispatchMessage(const std::shared_ptr<Message>& msg) {
EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread();
for(auto& cb : messageCallbacks) {
if(!closing) { // We might have closed while reading or processing
cb.second->callIfMatch(msg);
cb.second.callIfMatch(msg);
}
}
if(downgrade)
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
}
void Communication::pauseReads() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
pauseReadTask = true;
}
void Communication::resumeReads() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
if(!pauseReadTask) {
return;
}
pauseReadTask = false;
lk.unlock();
pauseReadTaskCv.notify_one();
}
bool Communication::readsArePaused() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
return pauseReadTask;
}
void Communication::readTask() {
std::vector<uint8_t> readBytes;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
if(pauseReadTask) {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
pauseReadTaskCv.wait(lk, [this]() { return !pauseReadTask; });
}
if(driver->waitForRx(readTaskWakeLimit, readTaskWakeTimeout)) {
if(pauseReadTask) {
/**
* Reads could have paused while the driver was not available
*/
continue;
readBytes.clear();
if(impl->readWait(readBytes)) {
if(packetizer->input(readBytes)) {
for(auto& packet : packetizer->output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue;
dispatchMessage(msg);
}
}
handleInput(*packetizer);
}
}
}
void Communication::handleInput(Packetizer& p) {
if(p.input(driver->getReadBuffer())) {
for(const auto& packet : p.output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue;
dispatchMessage(msg);
}
}
}
std::optional< std::vector<ComponentVersion> > Communication::getComponentVersionsSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::ComponentVersions);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(ExtendedCommand::GetComponentVersions, {});
}, filter, timeout);
if(!msg) // Did not receive a message
return std::nullopt;
auto ver = std::dynamic_pointer_cast<ComponentVersionsMessage>(msg);
if(!ver) // Could not upcast for some reason
return std::nullopt;
return std::make_optional< std::vector<ComponentVersion> >(std::move(ver->versions));
}
+28 -327
View File
@@ -3,59 +3,27 @@
#include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flashmemorymessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/message/wiviresponsemessage.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
#include "icsneo/communication/message/a2bmessage.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/message/i2cmessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/mdiomessage.h"
#include "icsneo/communication/message/extendeddatamessage.h"
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/diskdatamessage.h"
#include "icsneo/communication/message/hardwareinfo.h"
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/a2bpacket.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/flexraypacket.h"
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/versionpacket.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
#include "icsneo/communication/packet/wivicommandpacket.h"
#include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/packet/scriptstatuspacket.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/packet/componentversionpacket.h"
#include "icsneo/communication/packet/supportedfeaturespacket.h"
#include "icsneo/communication/packet/mdiopacket.h"
#include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include <iostream>
using namespace icsneo;
uint64_t Decoder::GetUInt64FromLEBytes(const uint8_t* bytes) {
uint64_t Decoder::GetUInt64FromLEBytes(uint8_t* bytes) {
uint64_t ret = 0;
for(int i = 0; i < 8; i++)
ret |= (uint64_t(bytes[i]) << (i * 8));
ret |= (bytes[i] << (i * 8));
return ret;
}
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
switch(packet->network.getType()) {
case Network::Type::Ethernet: {
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
case Network::Type::Ethernet:
result = HardwareEthernetPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
@@ -63,11 +31,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
EthernetMessage& eth = *static_cast<EthernetMessage*>(result.get());
eth.timestamp *= timestampResolution;
eth.network = packet->network;
result->timestamp *= timestampResolution;
result->network = packet->network;
return true;
}
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
@@ -81,28 +47,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
result->timestamp *= timestampResolution;
switch(result->type) {
case Message::Type::Frame: {
CANMessage& can = *static_cast<CANMessage*>(result.get());
can.network = packet->network;
break;
}
case Message::Type::CANErrorCount: {
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get());
can.network = packet->network;
break;
}
default: {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // An unknown type was returned, the packet was malformed
}
}
result->network = packet->network;
return true;
}
case Network::Type::FlexRay: {
@@ -116,95 +64,27 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
FlexRayMessage& fr = *static_cast<FlexRayMessage*>(result.get());
fr.timestamp *= timestampResolution;
fr.network = packet->network;
return true;
}
case Network::Type::ISO9141: {
if(packet->data.size() < sizeof(HardwareISO9141Packet)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = iso9141decoder.decodeToMessage(packet->data);
if(!result)
return false; // A nullptr was returned, more data is required to decode this packet
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
ISO9141Message& iso = *static_cast<ISO9141Message*>(result.get());
iso.timestamp *= timestampResolution;
iso.network = packet->network;
return true;
}
case Network::Type::I2C: {
if(packet->data.size() < sizeof(HardwareI2CPacket)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = HardwareI2CPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; //malformed packet indicated by a nullptr return
}
return true;
}
case Network::Type::A2B: {
result = HardwareA2BPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
A2BMessage& msg = *static_cast<A2BMessage*>(result.get());
msg.network = packet->network;
msg.timestamp *= timestampResolution;
return true;
}
case Network::Type::LIN: {
result = HardwareLINPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
LINMessage& msg = *static_cast<LINMessage*>(result.get());
msg.network = packet->network;
return true;
}
case Network::Type::MDIO: {
result = HardwareMDIOPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
MDIOMessage& msg = *static_cast<MDIOMessage*>(result.get());
msg.network = packet->network;
result->timestamp *= timestampResolution;
result->network = packet->network;
return true;
}
case Network::Type::Internal: {
switch(packet->network.getNetID()) {
case Network::NetID::Reset_Status: {
// We can deal with not having the last two fields (voltage and temperature)
if(packet->data.size() < (sizeof(HardwareResetStatusPacket) - (sizeof(uint16_t) * 2))) {
if(packet->data.size() < sizeof(HardwareResetStatusPacket)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
auto msg = std::make_shared<ResetStatusMessage>();
msg->network = packet->network;
msg->mainLoopTime = data->main_loop_time_25ns * 25;
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
msg->busVoltage = data->busVoltage;
msg->deviceTemperature = data->deviceTemperature;
msg->justReset = data->status.just_reset;
msg->comEnabled = data->status.com_enabled;
msg->cmRunning = data->status.cm_is_running;
@@ -218,124 +98,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
msg->cmTooBig = data->status.cm_too_big;
msg->hidUsbState = data->status.hidUsbState;
msg->fpgaUsbState = data->status.fpgaUsbState;
if(packet->data.size() >= sizeof(HardwareResetStatusPacket)) {
msg->busVoltage = data->busVoltage;
msg->deviceTemperature = data->deviceTemperature;
}
result = msg;
return true;
}
case Network::NetID::Device: {
// These are neoVI network messages
// They come in as CAN but we will handle them in the device rather than
// passing them onto the user.
if(packet->data.size() < 24) {
auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device);
result = rawmsg;
rawmsg->data = packet->data;
return true;
}
result = HardwareCANPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
auto* raw = dynamic_cast<RawMessage*>(result.get());
if(raw == nullptr) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
raw->timestamp *= timestampResolution;
raw->network = packet->network;
return true;
}
case Network::NetID::DeviceStatus: {
// Just pass along the data, the device needs to handle this itself
result = std::make_shared<RawMessage>(packet->network, packet->data);
return true;
}
case Network::NetID::RED_INT_MEMORYREAD: {
if(packet->data.size() != 512 + sizeof(uint16_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<FlashMemoryMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint16_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 2, packet->data.end());
return true;
}
case Network::NetID::NeoMemorySDRead: {
if(packet->data.size() != 512 + sizeof(uint32_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<NeoReadMemorySDMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint32_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 4, packet->data.end());
return true;
}
case Network::NetID::ExtendedCommand: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse))
break; // Handle as a raw message, might not be a generic response
const auto& resp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
switch(resp.header.command) {
case ExtendedCommand::GetComponentVersions:
result = ComponentVersionPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetSupportedFeatures:
result = SupportedFeaturesPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GenericBinaryInfo:
result = GenericBinaryStatusPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GenericReturn:
result = std::make_shared<ExtendedResponseMessage>(resp.command, resp.returnCode);
return true;
case ExtendedCommand::LiveData:
result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report);
return true;
case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data);
return true;
default:
// No defined handler, treat this as a RawMessage
break;
}
break;
}
case Network::NetID::ExtendedData: {
if(packet->data.size() < sizeof(ExtendedDataMessage::ExtendedDataHeader))
break;
const auto& header = *reinterpret_cast<ExtendedDataMessage::ExtendedDataHeader*>(packet->data.data());
switch(header.subCommand) {
case ExtendedDataSubCommand::GenericBinaryRead: {
result = std::make_shared<ExtendedDataMessage>(header);
auto extDataMsg = std::static_pointer_cast<ExtendedDataMessage>(result);
size_t numRead = std::min(ExtendedDataMessage::MaxExtendedDataBufferSize, (size_t)header.length);
extDataMsg->data.resize(numRead);
std::copy(packet->data.begin() + sizeof(header), packet->data.begin() + sizeof(header) + numRead, extDataMsg->data.begin());
extDataMsg->network = Network(static_cast<uint16_t>(Network::NetID::ExtendedData), false);
return true;
}
default:
break;
}
break;
}
case Network::NetID::FlexRayControl: {
auto frResult = std::make_shared<FlexRayControlMessage>(*packet);
if(!frResult->decoded) {
@@ -345,10 +110,17 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = frResult;
return true;
}
default:
break;//return false;
}
}
default:
switch(packet->network.getNetID()) {
case Network::NetID::Main51: {
switch((Command)packet->data[0]) {
case Command::RequestSerialNumber: {
auto msg = std::make_shared<SerialNumberMessage>();
msg->network = packet->network;
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
// The device sends 64-bits of serial number, but we never use more than 32-bits.
msg->deviceSerial = Device::SerialNumToString((uint32_t)serial);
@@ -361,36 +133,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg;
return true;
}
case Command::GetMainVersion: {
result = HardwareVersionPacket::DecodeMainToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
case Command::GetSecondaryVersions: {
result = HardwareVersionPacket::DecodeSecondaryToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
case Command::GetHardwareInfo: {
result = HardwareInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
default:
auto msg = std::make_shared<Main51Message>();
msg->network = packet->network;
msg->command = Command(packet->data[0]);
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
result = msg;
@@ -412,18 +157,11 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
packet->data.resize(length);
return decode(result, packet);
}
case Network::NetID::RED_App_Error: {
result = AppErrorMessage::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::ReadSettings: {
auto msg = std::make_shared<ReadSettingsMessage>();
msg->network = packet->network;
msg->response = ReadSettingsMessage::Response(packet->data[0]);
if(msg->response == ReadSettingsMessage::Response::OK) {
// The global settings structure is the payload of the message in this case
msg->data.insert(msg->data.begin(), packet->data.begin() + 10, packet->data.end());
@@ -439,50 +177,13 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg;
return true;
}
case Network::NetID::LogicalDiskInfo: {
result = LogicalDiskInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::WiVICommand: {
result = WiVI::CommandPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::EthPHYControl: {
result = HardwareEthernetPhyRegisterPacket::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::ScriptStatus: {
result = ScriptStatus::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::DiskData: {
result = std::make_shared<DiskDataMessage>(std::move(packet->data));
return true;
}
default:
break;
}
break;
}
}
// For the moment other types of messages will automatically be decoded as raw messages
result = std::make_shared<RawMessage>(packet->network, packet->data);
auto msg = std::make_shared<Message>();
msg->network = packet->network;
msg->data = packet->data;
result = msg;
return true;
}
}
-97
View File
@@ -1,97 +0,0 @@
#include "icsneo/communication/driver.h"
//#define ICSNEO_DRIVER_DEBUG_PRINTS
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
#include <iostream>
#include <iomanip>
#endif
using namespace icsneo;
bool Driver::pushRx(const uint8_t* buf, size_t numReceived) {
bool ret = readBuffer.write(buf, numReceived);
rxWaitCv.notify_all();
return ret;
}
void Driver::clearBuffers()
{
WriteOperation flushop;
readBuffer.clear();
rxWaitCv.notify_all();
while (writeQueue.try_dequeue(flushop)) {}
}
bool Driver::waitForRx(size_t limit, std::chrono::milliseconds timeout) {
return waitForRx([limit, this]() {
return readBuffer.size() >= limit;
}, timeout);
}
bool Driver::waitForRx(std::function<bool()> predicate, std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> lk(rxWaitMutex);
return rxWaitCv.wait_for(lk, timeout, predicate);
}
bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
if(limit > (readBuffer.size() + 4))
limit = (readBuffer.size() + 4);
// wait until we have enough data, or the timout occurs
waitForRx(limit, timeout);
size_t actuallyRead = std::min(readBuffer.size(), limit);
bytes.resize(actuallyRead);
readBuffer.read(bytes.data(), 0, actuallyRead);
readBuffer.pop(actuallyRead);
bytes.resize(actuallyRead);
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
if(actuallyRead > 0) {
std::cout << "Read data: (" << actuallyRead << ')' << std::hex << std::endl;
for(int i = 0; i < actuallyRead; i += 16) {
for(int j = 0; j < std::min<int>(actuallyRead - i, 16); j++)
std::cout << std::setw(2) << std::setfill('0') << uint32_t(bytes[i+j]) << ' ';
std::cout << std::endl;
}
std::cout << std::dec << std::endl;
}
#endif
return actuallyRead > 0;
}
bool Driver::write(const std::vector<uint8_t>& bytes) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
if(writeBlocks) {
if(writeQueueFull()) {
while(writeQueueAlmostFull()) // Wait until we have some decent amount of space
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
} else {
if(writeQueueFull()) {
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
return false;
}
}
const bool ret = writeInternal(bytes);
if(!ret)
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return ret;
}
+78 -227
View File
@@ -1,278 +1,129 @@
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/main51message.h"
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/message/i2cmessage.h"
#include "icsneo/communication/packet/a2bpacket.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/packet/mdiopacket.h"
using namespace icsneo;
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
bool shortFormat = false;
std::vector<uint8_t>* buffer = &result;
uint16_t netid = 0;
bool useResultAsBuffer = false; // Otherwise it's expected that we use message->data
result.clear();
switch(message->type) {
case Message::Type::Frame: {
auto frame = std::dynamic_pointer_cast<Frame>(message);
// Frame uses frame->data as the buffer unless directed otherwise
buffer = &frame->data;
netid = uint16_t(frame->network.getNetID());
switch(frame->network.getType()) {
case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed EthernetMessage
}
buffer = &result;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
return false;
break;
} // End of Network::Type::Ethernet
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed CANMessage
}
if(!supportCANFD && canmsg->isCANFD) {
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
return false; // This device does not support CAN FD
}
buffer = &result;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
return false; // The CANMessage was malformed
break;
} // End of Network::Type::CAN
case Network::Type::ISO9141: {
auto isomsg = std::dynamic_pointer_cast<ISO9141Message>(message);
if(!isomsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed ISO9141Message
}
// Skip the normal message wrapping at the bottom since we need to send multiple
// packets to the device. This function just encodes them back to back into `result`
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
} // End of Network::Type::ISO9141
case Network::Type::A2B: {
auto a2bmsg = std::dynamic_pointer_cast<A2BMessage>(message);
if(!a2bmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareA2BPacket::EncodeFromMessage(*a2bmsg, result, report)) {
return false;
}
break;
} // End of Network::Type::A2B
case Network::Type::I2C: {
auto i2cmsg = std::dynamic_pointer_cast<I2CMessage>(message);
if(!i2cmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareI2CPacket::EncodeFromMessage(*i2cmsg, result, report)) {
return false;
}
break;
} // End of Network::Type::I2C
case Network::Type::LIN: {
auto linmsg = std::dynamic_pointer_cast<LINMessage>(message);
if(!linmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareLINPacket::EncodeFromMessage(*linmsg, result, report)) {
return false;
}
break;
} // End of Network::Type::LIN
case Network::Type::MDIO: {
auto mdiomsg = std::dynamic_pointer_cast<MDIOMessage>(message);
if(!mdiomsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareMDIOPacket::EncodeFromMessage(*mdiomsg, result, report)) {
return false;
}
break;
} // End of Network::Type::MDIO
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
switch(message->network.getType()) {
case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed EthernetMessage
}
useResultAsBuffer = true;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
return false;
break;
}
case Message::Type::RawMessage: {
auto raw = std::dynamic_pointer_cast<RawMessage>(message);
} // End of Network::Type::Ethernet
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed CANMessage
}
// Raw message uses raw->data as the buffer unless directed otherwise
buffer = &raw->data;
netid = uint16_t(raw->network.getNetID());
if(!supportCANFD && canmsg->isCANFD) {
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
return false; // This device does not support CAN FD
}
useResultAsBuffer = true;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
return false; // The CANMessage was malformed
switch(raw->network.getNetID()) {
break;
} // End of Network::Type::CAN
default:
switch(message->network.getNetID()) {
case Network::NetID::Device:
shortFormat = true;
break;
case Network::NetID::Main51:
if(message->data.size() > 0xF) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(message->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
message->data.insert(message->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8)
});
result = packetizer->packetWrap(message->data, shortFormat);
return true;
} else {
shortFormat = true;
}
break;
case Network::NetID::RED_OLDFORMAT: {
// See the decoder for an explanation
// We expect the network byte to be populated already in data, but not the length
uint16_t length = uint16_t(raw->data.size()) - 1;
raw->data.insert(raw->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
uint16_t length = uint16_t(message->data.size()) - 1;
message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
break;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
break;
}
case Message::Type::Main51: {
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
if(!m51msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Main51Message
}
buffer = &m51msg->data;
netid = uint16_t(Network::NetID::Main51);
if(!m51msg->forceShortFormat) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(m51msg->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
size += 1; // Main51 Command
m51msg->data.insert(m51msg->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)m51msg->command
});
result = packetizer.packetWrap(m51msg->data, shortFormat);
return true;
} else {
m51msg->data.insert(m51msg->data.begin(), { uint8_t(m51msg->command) });
shortFormat = true;
}
break;
}
case Message::Type::EthernetPhyRegister: {
if(!supportEthPhy) {
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
return false;
}
auto ethPhyMessage = std::dynamic_pointer_cast<EthPhyMessage>(message);
if(!ethPhyMessage) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
if(!HardwareEthernetPhyRegisterPacket::EncodeFromMessage(*ethPhyMessage, result, report))
return false;
break;
}
case Message::Type::LiveData: {
auto liveDataMsg = std::dynamic_pointer_cast<LiveDataMessage>(message);
if(!liveDataMsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed LiveDataMessage
}
if(!HardwareLiveDataPacket::EncodeFromMessage(*liveDataMsg, result, report))
return false;
result = packetizer.packetWrap(result, false);
return true;
}
break;
}
// Early returns may mean we don't reach this far, check the type you're concerned with
if(shortFormat) {
buffer->insert(buffer->begin(), (uint8_t(buffer->size()) << 4) | uint8_t(netid));
} else {
// Size for the host-to-device long format is the size of the entire packet + 1
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
// Then an extra +1, due to a firmware idiosyncrasy
uint16_t size = static_cast<uint16_t>(buffer->size()) + 1 + 1 + 2 + 2 + 1;
auto& buffer = useResultAsBuffer ? result : message->data;
buffer->insert(buffer->begin(), {
if(shortFormat) {
buffer.insert(buffer.begin(), (uint8_t(buffer.size()) << 4) | uint8_t(message->network.getNetID()));
} else {
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
uint16_t size = uint16_t(buffer.size()) + 1 + 1 + 2 + 2;
buffer.insert(buffer.begin(), {
(uint8_t)Network::NetID::RED, // 0x0C for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)netid, // NetID, little endian 16-bit
(uint8_t)(netid >> 8)
(uint8_t)message->network.getNetID(), // NetID, little endian 16-bit
(uint8_t)(uint16_t(message->network.getNetID()) >> 8)
});
}
result = packetizer.packetWrap(*buffer, shortFormat);
result = packetizer->packetWrap(buffer, shortFormat);
return true;
}
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments) {
std::shared_ptr<Message> msg;
bool Encoder::encode(std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments) {
auto msg = std::make_shared<Message>();
if(cmd == Command::UpdateLEDState) {
/* NetID::Device is a super old command type.
* It has a leading 0x00 byte, a byte for command, and a byte for an argument.
* In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else.
*/
auto canmsg = std::make_shared<RawMessage>(Network::NetID::Device);
msg = canmsg;
if(arguments.empty()) {
if (arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
canmsg->data.reserve(3);
canmsg->data.push_back(0x00);
canmsg->data.push_back(0x06); // SetLEDState
canmsg->data.push_back(arguments.at(0)); // See Device::LEDState
msg->network = Network::NetID::Device;
msg->data.reserve(3);
msg->data.push_back(0x00);
msg->data.push_back(0x06); // SetLEDState
msg->data.push_back(arguments.at(0)); // See Device::LEDState
} else {
auto m51msg = std::make_shared<Main51Message>();
msg = m51msg;
m51msg->command = cmd;
switch(cmd) {
case Command::ReadSettings:
case Command::RequestSerialNumber:
case Command::EnableNetworkCommunication:
case Command::EnableNetworkCommunicationEx:
case Command::GetMainVersion:
case Command::GetSecondaryVersions:
case Command::NeoReadMemory:
// There is a firmware handling idiosyncrasy with these commands
// They must be encoded in the short format
m51msg->forceShortFormat = true;
default:
break;
}
m51msg->data.insert(m51msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
msg->network = Network::NetID::Main51;
msg->data.reserve(arguments.size() + 1);
msg->data.push_back((uint8_t)cmd);
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
}
return encode(packetizer, result, msg);
return encode(result, msg);
}
-188
View File
@@ -1,188 +0,0 @@
#include "icsneo/communication/ethernetpacketizer.h"
#include <algorithm>
#include <iterator>
#include <cstring>
#include <cassert>
using namespace icsneo;
const size_t EthernetPacketizer::MaxPacketLength = 1490; // MTU - overhead
static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EthernetPacketizer::EthernetPacket& EthernetPacketizer::newSendPacket(bool first) {
processedDownPackets.emplace_back();
EthernetPacket& ret = processedDownPackets.back();
if(first) {
ret.packetNumber = sequenceDown++;
} else {
ret.firstPiece = false;
if(processedDownPackets.size() > 1)
ret.packetNumber = (processedDownPackets.rbegin() + 1)->packetNumber;
else
assert(false); // This should never be called with !first if there are no packets in the queue
}
std::copy(std::begin(hostMAC), std::end(hostMAC), std::begin(ret.srcMAC));
std::copy(std::begin(deviceMAC), std::end(deviceMAC), std::begin(ret.destMAC));
return ret;
}
void EthernetPacketizer::inputDown(std::vector<uint8_t> bytes, bool first) {
EthernetPacket* sendPacket = nullptr;
if(first && !processedDownPackets.empty()) {
// We have some packets already, let's see if we can add this to the last one
if(processedDownPackets.back().payload.size() + bytes.size() <= MaxPacketLength)
sendPacket = &processedDownPackets.back();
}
if(sendPacket == nullptr)
sendPacket = &newSendPacket(first);
if(sendPacket->payload.empty())
sendPacket->payload = std::move(bytes);
else
sendPacket->payload.insert(sendPacket->payload.end(), bytes.begin(), bytes.end());
// Split packets larger than MTU
std::vector<uint8_t> extraData;
if(sendPacket->payload.size() > MaxPacketLength) {
extraData.insert(extraData.end(), sendPacket->payload.begin() + MaxPacketLength, sendPacket->payload.end());
sendPacket->payload.resize(MaxPacketLength);
sendPacket->lastPiece = false;
inputDown(std::move(extraData), false);
}
}
std::vector< std::vector<uint8_t> > EthernetPacketizer::outputDown() {
std::vector< std::vector<uint8_t> > ret;
ret.reserve(processedDownPackets.size());
for(auto&& packet : std::move(processedDownPackets))
ret.push_back(packet.getBytestream());
processedDownPackets.clear();
return ret;
}
bool EthernetPacketizer::inputUp(std::vector<uint8_t> bytes) {
EthernetPacket packet(bytes);
if(packet.errorWhileDecodingFromBytestream)
return false; // Bad packet
if(packet.etherType != 0xCAB2)
return false; // Not a packet to host
if(memcmp(packet.destMAC, hostMAC, sizeof(packet.destMAC)) != 0 &&
memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0)
return false; // Packet is not addressed to us or broadcast
if(!allowInPacketsFromAnyMAC && memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0)
return false; // Not a packet from the device we're concerned with
// Handle single packets
if(packet.firstPiece && packet.lastPiece) {
// Could ensure no out-of-order reassembly by checking reassembing here,
// not doing that here because it should be harmless if it ever happened.
processedUpBytes.insert(processedUpBytes.end(), std::make_move_iterator(packet.payload.begin()), std::make_move_iterator(packet.payload.end()));
return true;
}
if(packet.firstPiece) {
if(reassembling) {
//report(APIEvent::Type::FailedToRead, APIEvent::Severity::EventWarning);
reassemblingData.clear();
}
reassembling = true;
reassemblingId = packet.packetNumber;
reassemblingData = std::move(packet.payload);
return !processedUpBytes.empty(); // If there are other packets in the pipe
}
if(!reassembling || reassemblingId != packet.packetNumber) {
//report(APIEvent::Type::FailedToRead, APIEvent::Severity::EventWarning);
reassembling = false;
reassemblingData.clear();
return !processedUpBytes.empty(); // If there are other packets in the pipe
}
if(packet.lastPiece) {
processedUpBytes.insert(processedUpBytes.end(), std::make_move_iterator(reassemblingData.begin()), std::make_move_iterator(reassemblingData.end()));
reassemblingData.clear();
reassembling = false;
processedUpBytes.insert(processedUpBytes.end(), std::make_move_iterator(packet.payload.begin()), std::make_move_iterator(packet.payload.end()));
return true;
}
reassemblingData.insert(reassemblingData.end(), std::make_move_iterator(packet.payload.begin()), std::make_move_iterator(packet.payload.end()));
return !processedUpBytes.empty(); // If there are other packets in the pipe
}
std::vector<uint8_t> EthernetPacketizer::outputUp() {
std::vector<uint8_t> ret = std::move(processedUpBytes);
processedUpBytes.clear();
return ret;
}
EthernetPacketizer::EthernetPacket::EthernetPacket(const std::vector<uint8_t>& bytestream) {
loadBytestream(bytestream);
}
EthernetPacketizer::EthernetPacket::EthernetPacket(const uint8_t* data, size_t size) {
std::vector<uint8_t> bs(data, data + size);
loadBytestream(bs);
}
int EthernetPacketizer::EthernetPacket::loadBytestream(const std::vector<uint8_t>& bytestream) {
errorWhileDecodingFromBytestream = 0;
for(size_t i = 0; i < 6; i++)
destMAC[i] = bytestream[i];
for(size_t i = 0; i < 6; i++)
srcMAC[i] = bytestream[i + 6];
etherType = (bytestream[12] << 8) | bytestream[13];
icsEthernetHeader = (bytestream[14] << 24) | (bytestream[15] << 16) | (bytestream[16] << 8) | bytestream[17];
payloadSize = bytestream[18] | (bytestream[19] << 8);
packetNumber = bytestream[20] | (bytestream[21] << 8);
uint16_t packetInfo = bytestream[22] | (bytestream[23] << 8);
firstPiece = packetInfo & 1;
lastPiece = (packetInfo >> 1) & 1;
bufferHalfFull = (packetInfo >> 2) & 2;
payload = std::vector<uint8_t>(bytestream.begin() + 24, bytestream.end());
size_t payloadActualSize = payload.size();
if(payloadActualSize > payloadSize)
payload.resize(payloadSize);
return errorWhileDecodingFromBytestream;
}
std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
uint16_t actualPayloadSize = uint16_t(payload.size());
std::vector<uint8_t> bytestream;
bytestream.reserve(6 + 6 + 2 + 4 + 2 + 2 + 2 + actualPayloadSize);
for(size_t i = 0; i < 6; i++)
bytestream.push_back(destMAC[i]);
for(size_t i = 0; i < 6; i++)
bytestream.push_back(srcMAC[i]);
// EtherType should be put into the bytestream as big endian
bytestream.push_back((uint8_t)(etherType >> 8));
bytestream.push_back((uint8_t)(etherType));
// Our Ethernet header should be put into the bytestream as big endian
bytestream.push_back((uint8_t)(icsEthernetHeader >> 24));
bytestream.push_back((uint8_t)(icsEthernetHeader >> 16));
bytestream.push_back((uint8_t)(icsEthernetHeader >> 8));
bytestream.push_back((uint8_t)(icsEthernetHeader));
uint16_t declaredPayloadSize = payloadSize ? payloadSize : actualPayloadSize;
// The payload size comes next, it's little endian
bytestream.push_back((uint8_t)(declaredPayloadSize));
bytestream.push_back((uint8_t)(declaredPayloadSize >> 8));
// Packet number is little endian
bytestream.push_back((uint8_t)(packetNumber));
bytestream.push_back((uint8_t)(packetNumber >> 8));
// Packet info gets assembled into a bitfield
uint16_t packetInfo = 0;
packetInfo |= firstPiece & 1;
packetInfo |= (lastPiece & 1) << 1;
packetInfo |= (bufferHalfFull & 1) << 2;
packetInfo |= 1 << 8; // Protocol version 1
bytestream.push_back((uint8_t)(packetInfo));
bytestream.push_back((uint8_t)(packetInfo >> 8));
bytestream.insert(bytestream.end(), payload.begin(), payload.end());
return bytestream;
}
+63
View File
@@ -0,0 +1,63 @@
#include "icsneo/communication/icommunication.h"
using namespace icsneo;
bool ICommunication::read(std::vector<uint8_t>& bytes, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
if(limit > (readQueue.size_approx() + 4))
limit = (readQueue.size_approx() + 4);
if(bytes.capacity() < limit)
bytes.resize(limit);
size_t actuallyRead = readQueue.try_dequeue_bulk(bytes.data(), limit);
if(bytes.size() > actuallyRead)
bytes.resize(actuallyRead);
return true;
}
bool ICommunication::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
if(limit > (readQueue.size_approx() + 4))
limit = (readQueue.size_approx() + 4);
bytes.resize(limit);
size_t actuallyRead = readQueue.wait_dequeue_bulk_timed(bytes.data(), limit, timeout);
bytes.resize(actuallyRead);
return actuallyRead > 0;
}
bool ICommunication::write(const std::vector<uint8_t>& bytes) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
if(writeBlocks) {
std::unique_lock<std::mutex> lk(writeMutex);
if(writeQueue.size_approx() > writeQueueSize)
writeCV.wait(lk);
} else {
if(writeQueue.size_approx() > writeQueueSize) {
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
return false;
}
}
bool ret = writeQueue.enqueue(WriteOperation(bytes));
if(!ret)
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return ret;
}
-22
View File
@@ -1,22 +0,0 @@
#include "icsneo/communication/livedata.h"
namespace icsneo {
namespace LiveDataUtil {
LiveDataHandle getNewHandle() {
static LiveDataHandle currentHandle = 0;
++currentHandle;
if(currentHandle == std::numeric_limits<LiveDataHandle>::max()) {
EventManager::GetInstance().add(APIEvent::Type::LiveDataInvalidHandle, APIEvent::Severity::Error);
currentHandle = 1;
}
return currentHandle;
}
double liveDataValueToDouble(const LiveDataValue& val) {
constexpr double liveDataFixedPointToDouble = 0.00000000023283064365386962890625;
return val.value * liveDataFixedPointToDouble;
}
} // namespace LiveDataUtil
} // namespace icsneo
-257
View File
@@ -1,257 +0,0 @@
#include "icsneo/communication/message/a2bmessage.h"
#include "icsneo/communication/message/callback/streamoutput/streamoutput.h"
using namespace icsneo;
// Read a 16 bit sample from the audio buffer, which is stored as little endian
#define SAMPLE_FROM_BYTES_16(audioData) (((audioData)[0]) | ((audioData)[1] << 8))
// Read a 32 bit sample from the audio buffer
#define SAMPLE_FROM_BYTES_32(audioData) (((audioData)[0]) | ((audioData)[1] << 8) | ((audioData)[2] << 16) | ((audioData)[3] << 24))
// Read the most significant bytes of a sample stored in a 32 bit unsigned integer into audioData
#define SAMPLE_TO_BYTES_16(audioData, offset, sample) {\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x00FF0000u) >> 16);\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0xFF000000u) >> 24);\
}
// Read little endian a 32 bit unsigned integer into audioData
#define SAMPLE_TO_BYTES_32(audioData, offset, sample) {\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x000000FFu));\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x0000FF00u) >> 8);\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x00FF0000u) >> 16);\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0xFF000000u) >> 24);\
}
uint8_t A2BMessage::tdmToChannelNum(TDMMode tdm) {
switch(tdm) {
case TDMMode::TDM2:
return 4;
case TDMMode::TDM4:
return 8;
case TDMMode::TDM8:
return 16;
case TDMMode::TDM12:
return 24;
case TDMMode::TDM16:
return 32;
case TDMMode::TDM20:
return 40;
case TDMMode::TDM24:
return 48;
case TDMMode::TDM32:
return 64;
}
return 0;
}
uint8_t A2BMessage::getBytesPerChannel() const {
return channelSize16 ? 2u : 4u;
}
size_t A2BMessage::getFrameSize() const {
return static_cast<size_t>(2 * numChannels * getBytesPerChannel());
}
size_t A2BMessage::getSampleOffset(Direction dir, uint8_t channel, size_t frame) const {
size_t frameSize = getFrameSize();
size_t sampleOffset = static_cast<size_t>(frameSize * frame + 2 * channel * getBytesPerChannel());
if(dir == Direction::Upstream) {
sampleOffset += getBytesPerChannel();
}
return sampleOffset;
}
size_t A2BMessage::getNumFrames() const {
size_t frameSize = getFrameSize();
if(frameSize == 0) {
return 0;
}
return data.size() / frameSize;
}
A2BMessage::A2BMessage(size_t numFrames, TDMMode tdm, bool chSize16) : channelSize16(chSize16) {
numChannels = static_cast<uint8_t>(tdmToChannelNum(tdm) / 2);
size_t frameSize = static_cast<size_t>(2 * numChannels * (chSize16 ? 2u : 4u));
size_t audioBufferSize = frameSize * numFrames;
if(audioBufferSize > maxAudioBufferSize) {
size_t maxNumFrames = maxAudioBufferSize / frameSize;
audioBufferSize = maxNumFrames * frameSize;
}
data.resize(std::min<size_t>(maxAudioBufferSize, audioBufferSize), 0);
}
A2BMessage::A2BMessage(TDMMode tdm, bool chSize16) : channelSize16(chSize16) {
numChannels = static_cast<uint8_t>(tdmToChannelNum(tdm) / 2);
size_t frameSize = static_cast<size_t>(2 * numChannels * (chSize16 ? 2u : 4u));
size_t maxNumFrames = maxAudioBufferSize / frameSize;
size_t audioBufferSize = maxNumFrames * frameSize;
data.resize(audioBufferSize, 0);
}
PCMSample A2BMessage::getChannelSample(Direction dir, uint8_t channel, size_t frame, PCMType pcmType) const {
size_t sampleOffset = getSampleOffset(dir, channel, frame);
const uint8_t* audioData = &data[sampleOffset];
PCMSample result = 0;
// Samples coming from the device will either come from a 16 bit channel or 32 bit channel
if(channelSize16) {
int16_t sample16 = 0;
uint16_t& uSample16 = *reinterpret_cast<uint16_t*>(&sample16);
// Read little endian from the audio buffer
uSample16 = SAMPLE_FROM_BYTES_16(audioData);
// Scale the sample up according to the desired PCM size by
// multiplying using logical shifting
switch(pcmType) {
case PCMType::L16:
result = static_cast<PCMSample>(sample16);
break;
case PCMType::L24:
result = static_cast<PCMSample>(sample16) << 8;
break;
case PCMType::L32:
result = static_cast<PCMSample>(sample16) << 16;
break;
}
} else {
PCMSample sample32 = 0;
uint32_t& uSample32 = *reinterpret_cast<uint32_t*>(&sample32);
// Read little endian
uSample32 = SAMPLE_FROM_BYTES_32(audioData);
// Scale the sample down according to the desired PCM size by dividing using
// logical shifting, if the A2B network was set up with the desired pcmType
// there should be a clean division and no loss in PCM resolution.
switch(pcmType) {
case PCMType::L16:
result = sample32 >> 16;
break;
case PCMType::L24:
result = sample32 >> 8;
break;
case PCMType::L32:
result = sample32;
break;
}
}
return result;
}
void A2BMessage::setChannelSample(Direction dir, uint8_t channel, size_t frame, PCMSample sampleToSet, PCMType pcmType) {
size_t sampleOffset = getSampleOffset(dir, channel, frame);
uint32_t& uSample = *reinterpret_cast<uint32_t*>(&sampleToSet);
// Align the bytes towards the most significant bit by multiplying using
// left shifts
switch(pcmType) {
case PCMType::L16:
sampleToSet = sampleToSet << 16;
break;
case PCMType::L24:
sampleToSet = sampleToSet << 8;
break;
}
if(channelSize16) {
// Read the 2 most significant bytes of the sample
SAMPLE_TO_BYTES_16(data, sampleOffset, uSample)
} else {
// Read the entire sample
SAMPLE_TO_BYTES_32(data, sampleOffset, uSample);
}
}
bool A2BMessage::loadAudioBuffer(IWAVStream& wavStream, const ChannelMap& channelMap) {
if(!wavStream) {
return false;
}
size_t totalMessageChannels = numChannels * 2; // Multiply by two inorder to include both down and upstream channels
size_t bytesPerChannel = static_cast<size_t>(getBytesPerChannel()); // Number of bytes per message channel
size_t frameSize = getFrameSize();
size_t numFrames = getNumFrames();
size_t bytesPerSampleWAV = static_cast<size_t>(wavStream.header.bitsPerSample / 8); // Number of bytes per sample in the WAV data-stream
size_t numWAVChannels = static_cast<size_t>(wavStream.header.numChannels);
size_t wavFrameSize = numWAVChannels * bytesPerSampleWAV;
if(bytesPerSampleWAV != 2 && bytesPerSampleWAV != 3 && bytesPerSampleWAV != 4) {
return false;
}
if(numFrames == 0) {
return false;
}
uint8_t* audioBuffer = data.data();
std::vector<uint8_t> wavFrame(wavFrameSize, 0);
for(size_t frame = 0; frame < numFrames; frame++) {
// Read one frame of data from the input stream
if(!wavStream.read(reinterpret_cast<char*>(wavFrame.data()), wavFrame.size())) {
break;
}
// Iterate through each mapping and set a message channel to a channel in the WAV frame above
for(const auto& [messageChannel, wavChannel] : channelMap) {
if(messageChannel >= totalMessageChannels || wavChannel >= numWAVChannels) {
return false;
}
size_t frameOffset = wavChannel * bytesPerSampleWAV; // Offset in the read WAV frame
size_t audioBufferOffset = frame * frameSize + messageChannel * bytesPerChannel; // Offset in the message audio buffer
if(bytesPerChannel < bytesPerSampleWAV) {
// In this case, the message channels are smaller than the samples in the input WAV
// samples in both the message channel and WAV are little endian, so we write only the
// most significant bytes of the WAV
// Align to most significant bytes of wav frame
size_t align = bytesPerSampleWAV - bytesPerChannel;
for(
size_t frameByte = frameOffset + align;
frameByte < frameOffset + bytesPerSampleWAV;
frameByte++,
audioBufferOffset++
) {
audioBuffer[audioBufferOffset] = wavFrame[frameByte];
}
} else {
// The message channel is greater than or equal to the sample in the WAV
// I2S specifies that the sample in this case is right aligned to the most significant
// byte of the message channel
// Align to most significant byte of audio buffer channel
size_t align = bytesPerChannel - bytesPerSampleWAV;
for(
size_t audioByte = audioBufferOffset + align;
audioByte < audioBufferOffset + bytesPerChannel;
audioByte++,
frameOffset++
) {
audioBuffer[audioByte] = wavFrame[frameOffset];
}
}
}
}
return true;
}
-148
View File
@@ -1,148 +0,0 @@
#include <icsneo/communication/message/apperrormessage.h>
namespace icsneo {
#pragma pack(push, 2)
typedef struct {
uint16_t error_type;
uint16_t network_id;
uint32_t uiTimeStamp10uS;
uint32_t uiTimeStamp10uSMSB;
} AppErrorData;
#pragma pack(pop)
std::shared_ptr<Message> AppErrorMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
const AppErrorData* data = reinterpret_cast<const AppErrorData*>(bytestream.data());
if(!data) {
report(APIEvent::Type::AppErrorParsingFailed, APIEvent::Severity::Error);
return nullptr;
}
auto appErr = std::make_shared<AppErrorMessage>();
appErr->errorType = data->error_type;
appErr->errorNetID = static_cast<Network::NetID>(data->network_id);
appErr->timestamp10us = data->uiTimeStamp10uS;
appErr->timestamp10usMSB = data->uiTimeStamp10uSMSB;
appErr->network = Network::NetID::RED_App_Error;
return appErr;
}
AppErrorType AppErrorMessage::getAppErrorType() {
AppErrorType errType = static_cast<AppErrorType>(errorType);
if(errType > AppErrorType::AppNoError) {
return AppErrorType::AppNoError;
}
return errType;
}
std::string AppErrorMessage::getAppErrorString() {
auto netIDString = Network::GetNetIDString(errorNetID);
AppErrorType errType = static_cast<AppErrorType>(errorType);
switch (errType) {
case AppErrorType::AppErrorRxMessagesFull:
return std::string(netIDString) + ": RX message buffer full";
case AppErrorType::AppErrorTxMessagesFull:
return std::string(netIDString) + ": TX message buffer full";
case AppErrorType::AppErrorTxReportMessagesFull:
return std::string(netIDString) + ": TX report buffer full";
case AppErrorType::AppErrorBadCommWithDspIC:
return "Received bad packet from DSP IC";
case AppErrorType::AppErrorDriverOverflow:
return std::string(netIDString) + ": Driver overflow";
case AppErrorType::AppErrorPCBuffOverflow:
return "PC buffer overflow";
case AppErrorType::AppErrorPCChksumError:
return "PC checksum error";
case AppErrorType::AppErrorPCMissedByte:
return "PC missed byte";
case AppErrorType::AppErrorPCOverrunError:
return "PC overrun error";
case AppErrorType::AppErrorSettingFailure:
return std::string(netIDString) + ": Settings incorrectly set";
case AppErrorType::AppErrorTooManySelectedNetworks:
return "Too many selected networks";
case AppErrorType::AppErrorNetworkNotEnabled:
return std::string(netIDString) + ": Network not enabled";
case AppErrorType::AppErrorRtcNotCorrect:
return "RTC not correct";
case AppErrorType::AppErrorLoadedDefaultSettings:
return "Loaded default settings";
case AppErrorType::AppErrorFeatureNotUnlocked:
return "Feature not unlocked";
case AppErrorType::AppErrorFeatureRtcCmdDropped:
return "RTC command dropped";
case AppErrorType::AppErrorTxMessagesFlushed:
return "TX message buffer flushed";
case AppErrorType::AppErrorTxMessagesHalfFull:
return "TX message buffer half full";
case AppErrorType::AppErrorNetworkNotValid:
return "Network is not valid";
case AppErrorType::AppErrorTxInterfaceNotImplemented:
return "TX interface is not implemented";
case AppErrorType::AppErrorTxMessagesCommEnableIsOff:
return "TX message communication is disabled";
case AppErrorType::AppErrorRxFilterMatchCountExceeded:
return "RX filter match count exceeded";
case AppErrorType::AppErrorEthPreemptionNotEnabled:
return std::string(netIDString) + ": Ethernet preemption not enabled";
case AppErrorType::AppErrorTxNotSupportedInMode:
return std::string(netIDString) + ": Transmit is not supported in this mode";
case AppErrorType::AppErrorJumboFramesNotSupported:
return std::string(netIDString) + ": Jumbo frames not supported";
case AppErrorType::AppErrorEthernetIpFragment:
return "Ethernet IP fragment received";
case AppErrorType::AppErrorTxMessagesUnderrun:
return std::string(netIDString) + ": Transmit buffer underrun";
case AppErrorType::AppErrorDeviceFanFailure:
return "Device fan failure";
case AppErrorType::AppErrorDeviceOvertemperature:
return "Device overtemperature";
case AppErrorType::AppErrorTxMessageIndexOutOfRange:
return "Transmit message index out of range";
case AppErrorType::AppErrorUndersizedFrameDropped:
return std::string(netIDString) + ": Undersized frame dropped";
case AppErrorType::AppErrorOversizedFrameDropped:
return std::string(netIDString) + ": Oversized frame dropped";
case AppErrorType::AppErrorWatchdogEvent:
return "Watchdog event occured";
case AppErrorType::AppErrorSystemClockFailure:
return "Device clock failed";
case AppErrorType::AppErrorSystemClockRecovered:
return "Device clock recovered";
case AppErrorType::AppErrorSystemPeripheralReset:
return "Device peripheral reset";
case AppErrorType::AppErrorSystemCommunicationFailure:
return "Device communication failure";
case AppErrorType::AppErrorTxMessagesUnsupportedSourceOrPacketId:
return std::string(netIDString) + ": Transmit unsupported source or packet ID";
case AppErrorType::AppErrorWbmsManagerConnectFailed:
return std::string(netIDString) + ": Failed to connect to managers with settings";
case AppErrorType::AppErrorWbmsManagerConnectBadState:
return std::string(netIDString) + ": Connected to managers in a invalid state";
case AppErrorType::AppErrorWbmsManagerConnectTimeout:
return std::string(netIDString) + ": Timeout while attempting to connect to managers";
case AppErrorType::AppErrorFailedToInitializeLoggerDisk:
return "Device failed to initialize storage disk";
case AppErrorType::AppErrorInvalidSetting:
return std::string(netIDString) + ": Invalid settings";
case AppErrorType::AppErrorSystemFailureRequestedReset:
return "Device rebooted to recover from an unexpected error condition";
case AppErrorType::AppErrorPortKeyMistmatch:
return std::string(netIDString) + ": Mismatch between key in manager and stored key";
case AppErrorType::AppErrorBusFailure:
return std::string(netIDString) + ": Bus failure";
case AppErrorType::AppErrorTapOverflow:
return std::string(netIDString) + ": Tap overflow";
case AppErrorType::AppErrorEthTxNoLink:
return std::string(netIDString) + ": Attempted Ethernet transmit without link";
case AppErrorType::AppErrorErrorBufferOverflow:
return "Device error buffer overflow";
case AppErrorType::AppNoError:
return "No error";
default:
return "Unknown error";
}
}
} // namespace icsneo
@@ -1,234 +0,0 @@
#include "icsneo/communication/message/callback/streamoutput/a2bwavoutput.h"
#include "icsneo/device/tree/rada2b/rada2b.h"
#include "icsneo/icsneocpp.h"
namespace icsneo {
A2BWAVOutput::A2BWAVOutput(
const char* filename,
const ChannelMap& channelMap,
PCMType bitDepth,
size_t numWAVChannels,
uint32_t sampleRate
)
: StreamOutput(filename), wavSampleRate(sampleRate), numChannelsWAV(numWAVChannels), chMap(channelMap) {
switch(bitDepth) {
case PCMType::L16:
bytesPerSampleWAV = 2;
break;
case PCMType::L24:
bytesPerSampleWAV = 3;
break;
case PCMType::L32:
bytesPerSampleWAV = 4;
break;
}
if(initialize()) {
initialized = true;
}
}
A2BWAVOutput::A2BWAVOutput(
std::ostream& os,
const ChannelMap& channelMap,
PCMType bitDepth,
size_t numWAVChannels,
uint32_t sampleRate
)
: StreamOutput(os), wavSampleRate(sampleRate), numChannelsWAV(numWAVChannels), chMap(channelMap) {
switch(bitDepth) {
case PCMType::L16:
bytesPerSampleWAV = 2;
break;
case PCMType::L24:
bytesPerSampleWAV = 3;
break;
case PCMType::L32:
bytesPerSampleWAV = 4;
break;
}
if(initialize()) {
initialized = true;
}
}
A2BWAVOutput::~A2BWAVOutput() {
if(!closed) {
close();
}
}
bool A2BWAVOutput::initialize() {
static constexpr size_t maxWAVChannels = 256;
if(numChannelsWAV > maxWAVChannels) {
return false;
}
maxMessageChannel = 0;
// Check if the inputted channel map has invalid mappings and compute maxMessageChannel
for(auto [wavChannel, messageChannel] : chMap) {
maxMessageChannel = std::max<size_t>(maxMessageChannel, messageChannel);
if(wavChannel >= numChannelsWAV) {
return false;
}
}
WAVHeader header = WAVHeader(
static_cast<uint16_t>(chMap.size()),
wavSampleRate,
static_cast<uint16_t>(bytesPerSampleWAV * 8)
);
if(!stream->write(reinterpret_cast<const char*>(&header), sizeof(WAVHeader))) {
return false;
}
streamStartPos = static_cast<uint32_t>(stream->tellp());
wavBuffer = std::vector<uint8_t>(wavBufferSize, 0);
wavBufferOffset = 0;
return true;
}
bool A2BWAVOutput::callIfMatch(const std::shared_ptr<Message>& message) const {
if(!initialized) {
return false;
}
if(closed) {
return false;
}
if(message->type != Message::Type::Frame) {
return false;
}
const auto& frameMsg = std::dynamic_pointer_cast<Frame>(message);
if(!frameMsg) {
return false;
}
if(frameMsg->network.getType() != Network::Type::A2B)
return false;
const auto& a2bMsg = std::dynamic_pointer_cast<A2BMessage>(frameMsg);
if(!a2bMsg) {
return false;
}
size_t frameSize = a2bMsg->getFrameSize();
size_t wavFrameSize = numChannelsWAV * bytesPerSampleWAV;
size_t bytesPerChannel = static_cast<size_t>(a2bMsg->getBytesPerChannel());
size_t numMessageChannels = 2 * a2bMsg->numChannels;
size_t numFrames = a2bMsg->getNumFrames();
const uint8_t* audioBuffer = a2bMsg->data.data();
if(maxMessageChannel >= numMessageChannels) {
// The max message channel in our channel map is larger than the number of channels in this message
// this is likely due to the user inputting incorrect settings
return false;
}
for(size_t frame = 0; frame < numFrames; frame++) {
// Check to see if we can read another frame in wavBuffer, otherwise write and clear the buffer
if(wavBufferOffset + wavFrameSize >= wavBufferSize) {
if(!writeCurrentBuffer()) {
return false;
}
}
for(size_t wavChannel = 0; wavChannel < numChannelsWAV; wavChannel++) {
if(auto iter = chMap.find(static_cast<uint8_t>(wavChannel)); iter != chMap.end()) {
auto messageChannel = iter->second;
size_t messageChannelOffset = messageChannel * bytesPerChannel + frameSize* frame;
// Samples in the WAV are little endian signed integers
// Samples in the message channels are little endian signed integers that are
// most significant bit aligned
if(a2bMsg->channelSize16) {
// In this case, the channel size will be less than or equal to the sample we are writing
// so we zero out any of the least significant bytes which won't be occupied by a sample byte
for(size_t zeroByte = 0; zeroByte < bytesPerSampleWAV - bytesPerChannel; zeroByte++) {
wavBuffer[wavBufferOffset++] = 0;
}
// Write the channel data in the most signifant bytes of the wav sample, this effectively
// writes a sample which is scaled up.
for(size_t channelByte = 0; channelByte < bytesPerChannel; channelByte++) {
wavBuffer[wavBufferOffset++] = audioBuffer[messageChannelOffset + channelByte];
}
} else {
// In this case, the channel size will be greater than or equal to the sample we are reading
// Align the wav sample with the most significant bytes of the channel
size_t channelByte = messageChannelOffset + (bytesPerChannel - bytesPerSampleWAV);
// Read the most significant bytes of the channel into the wavBuffer
for(size_t sampleByte = 0; sampleByte < bytesPerSampleWAV; sampleByte++, channelByte++) {
wavBuffer[wavBufferOffset++] = audioBuffer[channelByte];
}
}
} else {
// If this channel wasn't specified in the channel map, set a zero sample
for(
size_t sampleByte = 0;
sampleByte < bytesPerSampleWAV;
sampleByte++
) {
wavBuffer[wavBufferOffset++] = 0;
}
}
}
}
return true;
}
void A2BWAVOutput::close() const {
if(closed) {
return;
}
if(!initialized) {
return;
}
// Write any left over data in the buffer
if(wavBufferOffset > 0) {
writeCurrentBuffer();
}
// Seek back in the output stream and write the WAV chunk sizes
uint32_t streamEndPos = static_cast<uint32_t>(stream->tellp());
uint32_t subChunk2Size = streamEndPos - streamStartPos;
uint32_t chunkSize = streamEndPos - 8;
stream->seekp(streamStartPos - 4);
stream->write(reinterpret_cast<const char*>(&subChunk2Size), 4);
stream->seekp(4, std::ios::beg);
stream->write(reinterpret_cast<const char*>(&chunkSize), 4);
closed = true;
}
bool A2BWAVOutput::writeCurrentBuffer() const {
if(!stream->write(reinterpret_cast<const char*>(wavBuffer.data()), wavBufferOffset)) {
return false;
}
wavBufferOffset = 0;
return true;
}
}
-50
View File
@@ -1,50 +0,0 @@
#include "icsneo/communication/message/ethphymessage.h"
namespace icsneo
{
bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t phyAddrOrPort, uint8_t pageOrDevice, uint16_t regAddr, uint16_t regVal, bool enabled)
{
auto msg = std::make_shared<PhyMessage>();
msg->Clause45Enable = clause45;
msg->Enabled = enabled;
msg->WriteEnable = writeEnable;
msg->version = 1u;
if( (FiveBits < phyAddrOrPort) ||
(clause45 && (FiveBits < pageOrDevice)) ||
(!clause45 && (FiveBits < regAddr)) )
{
return false;
}
if(clause45)
{
msg->clause45.port = phyAddrOrPort;
msg->clause45.device = pageOrDevice;
msg->clause45.regAddr = regAddr;
msg->clause45.regVal = regVal;
}
else
{
msg->clause22.phyAddr = phyAddrOrPort;
msg->clause22.page = pageOrDevice;
msg->clause22.regAddr = regAddr;
msg->clause22.regVal = regVal;
}
return appendPhyMessage(msg);
}
bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message)
{
if(message != nullptr)
{
messages.push_back(message);
return true;
}
return false;
}
size_t EthPhyMessage::getMessageCount() const
{
return messages.size();
}
}
@@ -2,11 +2,10 @@
#include <cstring> // memcpy
#include <limits>
#include <algorithm>
#include <iostream>
using namespace icsneo;
std::vector<uint8_t> FlexRayControlMessage::BuildBaseControlArgs(uint8_t controller, FlexRay::Opcode op, const std::vector<uint8_t>& args) {
std::vector<uint8_t> FlexRayControlMessage::BuildBaseControlArgs(uint8_t controller, FlexRay::Opcode op, std::initializer_list<uint8_t> args) {
std::vector<uint8_t> ret;
ret.reserve(args.size() + 4);
ret.push_back(controller);
@@ -29,7 +28,7 @@ std::vector<uint8_t> FlexRayControlMessage::BuildReadCCRegsArgs(uint8_t controll
std::vector<uint8_t> FlexRayControlMessage::BuildWriteCCRegArgs(uint8_t controller, uint16_t address, uint32_t value) {
address /= 4;
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteCCReg, {
return BuildBaseControlArgs(controller, FlexRay::Opcode::ReadCCRegs, {
uint8_t(address),
uint8_t(address >> 8),
uint8_t(value),
@@ -39,43 +38,18 @@ std::vector<uint8_t> FlexRayControlMessage::BuildWriteCCRegArgs(uint8_t controll
});
}
std::vector<uint8_t> FlexRayControlMessage::BuildAddConfiguredTxMessageArgs(
uint8_t controller, uint16_t descriptionId, uint16_t slotId, uint8_t baseCycle, uint8_t cycleReps, FlexRay::Channel channel) {
return BuildBaseControlArgs(controller, FlexRay::Opcode::AddConfiguredTxMessage, {
uint8_t(descriptionId),
uint8_t(descriptionId >> 8),
uint8_t(slotId),
uint8_t(slotId >> 8),
uint8_t(baseCycle + cycleReps),
uint8_t(channel)
});
}
std::vector<uint8_t> FlexRayControlMessage::BuildWriteMessageBufferArgs(
uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize) {
desiredSize += desiredSize % 4; // Must be a multiple of 4
std::vector<uint8_t> args = {
uint8_t(bufferId),
uint8_t(desiredSize / 4)
};
args.insert(args.end(), data.begin(), data.end());
if((int)args.size() != desiredSize + 2)
args.resize(desiredSize + 2);
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
}
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message(Message::Type::FlexRayControl) {
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() {
if(packet.data.size() < 2)
return; // huh?
controller = packet.data[0];
if(controller >= 2)
if(controller < 2)
return; // Invalid controller
// Opcode is only ReadCCStatus or ReadCCRegs for the moment
opcode = FlexRay::Opcode(packet.data[1]);
if(opcode != FlexRay::Opcode::ReadCCRegs && opcode != FlexRay::Opcode::ReadCCStatus)
return;
// Read out registers
size_t bytes = packet.data.size() - 2;
const size_t count = bytes / sizeof(uint32_t);
-30
View File
@@ -1,30 +0,0 @@
#include "icsneo/communication/message/linmessage.h"
#include <numeric>
namespace icsneo {
void LINMessage::calcChecksum(LINMessage& message) {
uint16_t sum = 0;
auto limitFunc = [](uint16_t x, uint16_t y) -> uint16_t {
if ((x + y) > 0xFFu)
return ((x + y) - 0xFFu);
else
return (x + y);
};
message.checksum = static_cast<uint8_t>(std::accumulate(message.data.begin(), message.data.end(), sum, limitFunc));
if(message.isEnhancedChecksum)
message.checksum = static_cast<uint8_t>(limitFunc(message.checksum, message.protectedID));
message.checksum ^= 0xFFu;
}
uint8_t LINMessage::calcProtectedID(uint8_t& id) {
uint8_t protID = id;
auto bit = [&](uint8_t pos)->uint8_t { return ((protID >> pos) & 0x1u); };
protID |= (~(bit(1) ^ bit(3) ^ bit(4) ^ bit(5)) << 7);
protID |= ((bit(0) ^ bit(1) ^ bit(2) ^ bit(4)) << 6);
return protID;
}
} //namespace icsneo
-15
View File
@@ -1,15 +0,0 @@
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/livedata.h"
namespace icsneo
{
void LiveDataCommandMessage::appendSignalArg(LiveDataValueType valueType) {
auto& arg = args.emplace_back(std::make_shared<LiveDataArgument>());
arg->objectType = LiveDataObjectType::MISC;
arg->objectIndex = 0u;
arg->signalIndex = 0u;
arg->valueType = valueType;
}
} // namespace icsneo
+56 -185
View File
@@ -1,206 +1,77 @@
#include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/linmessage.h"
using namespace icsneo;
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// This function is not responsible for storing the message!
// Keep the shared_ptr around for the lifetime of the data access
const auto type = message->network.getType();
neomessage_t neomsg = {}; // Clear out the memory
neomsg.messageType = (neomessagetype_t)message->type;
neomsg.netid = (uint32_t)message->network.getNetID();
neomsg.type = (uint8_t)type;
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp;
switch (message->type)
{
case Message::Type::Frame: {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<Frame>(message);
const auto netType = framemsg->network.getType();
neomsg.status.globalError = message->error;
neomsg.status.transmitMessage = message->transmitted;
frame.netid = (neonetid_t)framemsg->network.getNetID();
frame.type = (neonettype_t)netType;
frame.description = framemsg->description;
frame.length = framemsg->data.size();
frame.data = framemsg->data.data();
frame.timestamp = framemsg->timestamp;
frame.status.globalError = framemsg->error;
frame.status.transmitMessage = framemsg->transmitted;
switch(netType) {
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
auto canmsg = std::static_pointer_cast<CANMessage>(message);
can.arbid = canmsg->arbid;
can.dlcOnWire = canmsg->dlcOnWire;
can.status.extendedFrame = canmsg->isExtended;
can.status.remoteFrame = canmsg->isRemote;
can.status.canfdRTR = canmsg->isRemote;
can.status.canfdFDF = canmsg->isCANFD;
can.status.canfdBRS = canmsg->baudrateSwitch;
can.status.canfdESI = canmsg->errorStateIndicator;
break;
}
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags;
eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcsAvailable;
//eth.status.xyz = ethmsg->noPadding;
break;
}
case Network::Type::LIN: {
neomessage_lin_t& lin = *(neomessage_lin_t*)&neomsg;
auto linmsg = std::static_pointer_cast<LINMessage>(message);
if(!linmsg) { break; }
const auto linHdrBytes = std::min(linmsg->data.size(), static_cast<size_t>(2));
lin.header[0] = linmsg->protectedID;
std::copy(linmsg->data.begin(), linmsg->data.begin() + linHdrBytes, lin.header + 1);
linmsg->calcChecksum(*linmsg);
lin.checksum = linmsg->checksum;
lin.data = linmsg->data.data() + linHdrBytes;
if(linmsg->isEnhancedChecksum != linmsg->statusFlags.TxChecksumEnhanced) {
linmsg->isEnhancedChecksum = true;
linmsg->statusFlags.TxChecksumEnhanced = true;
}
if(linmsg->data.size())
lin.length = linmsg->data.size() + 2;
else
lin.length = 1;
lin.linStatus = {
linmsg->statusFlags.TxChecksumEnhanced,
linmsg->statusFlags.TxCommander,
linmsg->statusFlags.TxResponder,
linmsg->statusFlags.UpdateResponderOnce,
linmsg->statusFlags.HasUpdatedResponderOnce,
linmsg->statusFlags.BusRecovered,
linmsg->statusFlags.BreakOnly
};
lin.status.linJustBreakSync = linmsg->errFlags.ErrRxBreakSyncOnly;
lin.status.linErrorTXRXMismatch = linmsg->errFlags.ErrTxRxMismatch;
lin.status.linErrorRXBreakNotZero = linmsg->errFlags.ErrRxBreakNotZero;
lin.status.linErrorRXBreakTooShort = linmsg->errFlags.ErrRxBreakTooShort;
lin.status.linErrorRXSyncNot55 = linmsg->errFlags.ErrRxSyncNot55;
lin.status.linErrorRXDataGreaterEight = linmsg->errFlags.ErrRxDataLenOver8;
lin.status.linSyncFrameError = linmsg->errFlags.ErrFrameSync;
lin.status.linIDFrameError = linmsg->errFlags.ErrFrameMessageID;
lin.status.linSlaveByteError = linmsg->errFlags.ErrFrameResponderData;
lin.status.checksumError = linmsg->errFlags.ErrChecksumMatch;
break;
}
default:
// TODO Implement others
break;
switch(type) {
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
auto canmsg = std::static_pointer_cast<CANMessage>(message);
can.arbid = canmsg->arbid;
can.dlcOnWire = canmsg->dlcOnWire;
can.status.extendedFrame = canmsg->isExtended;
can.status.remoteFrame = canmsg->isRemote;
can.status.canfdRTR = canmsg->isRemote;
can.status.canfdFDF = canmsg->isCANFD;
can.status.canfdBRS = canmsg->baudrateSwitch;
can.status.canfdESI = canmsg->errorStateIndicator;
break;
}
break;
}
case Message::Type::CANErrorCount: {
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message);
canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
canerror.status.canBusOff = canerrormsg->busOff;
canerror.netid = (neonetid_t)canerrormsg->network.getNetID();
canerror.type = (neonettype_t)canerrormsg->network.getType();
break;
}
default:
break;
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags;
eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcsAvailable;
//eth.status.xyz = ethmsg->noPadding;
break;
}
default:
// TODO Implement others
break;
}
return neomsg;
}
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
switch((Message::Type)neomessage->messageType) {
case Message::Type::Frame: {
const Network network = ((neomessage_frame_t*)neomessage)->netid;
switch(network.getType()) {
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
auto canmsg = std::make_shared<CANMessage>();
canmsg->network = network;
canmsg->description = can.description;
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
canmsg->arbid = can.arbid;
canmsg->dlcOnWire = can.dlcOnWire;
canmsg->isExtended = can.status.extendedFrame;
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
canmsg->isCANFD = can.status.canfdFDF;
canmsg->baudrateSwitch = can.status.canfdBRS;
canmsg->errorStateIndicator = can.status.canfdESI;
return canmsg;
}
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
auto ethmsg = std::make_shared<EthernetMessage>();
ethmsg->network = network;
ethmsg->description = eth.description;
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
return ethmsg;
}
case Network::Type::LIN: {
neomessage_lin_t& lin = *(neomessage_lin_t*)neomessage;
auto linmsg = std::make_shared<LINMessage>();
linmsg->network = network;
linmsg->description = lin.description;
linmsg->protectedID = lin.header[0];
linmsg->ID = linmsg->protectedID & 0x3F;
linmsg->statusFlags = {
static_cast<bool>(lin.linStatus.txChecksumEnhanced),
static_cast<bool>(lin.linStatus.txCommander),
static_cast<bool>(lin.linStatus.txResponder),
static_cast<bool>(lin.linStatus.updateResponderOnce),
static_cast<bool>(lin.linStatus.hasUpdatedResponderOnce),
static_cast<bool>(lin.linStatus.busRecovered),
static_cast<bool>(lin.linStatus.breakOnly)
};
linmsg->isEnhancedChecksum = linmsg->statusFlags.TxChecksumEnhanced;
linmsg->errFlags = {
static_cast<bool>(lin.linStatus.breakOnly),
static_cast<bool>(lin.status.linJustBreakSync),
static_cast<bool>(lin.status.linErrorTXRXMismatch),
static_cast<bool>(lin.status.linErrorRXBreakNotZero),
static_cast<bool>(lin.status.linErrorRXBreakTooShort),
static_cast<bool>(lin.status.linErrorRXSyncNot55),
static_cast<bool>(lin.status.linErrorRXDataGreaterEight),
static_cast<bool>(lin.status.linSyncFrameError),
static_cast<bool>(lin.status.linIDFrameError),
static_cast<bool>(lin.status.linSlaveByteError),
static_cast<bool>(lin.status.checksumError)
};
if(lin.length > 1) {
auto numHeaderBytes = std::min(lin.length, static_cast<size_t>(3));
linmsg->data.insert(linmsg->data.end(), (lin.header + 1), (lin.header + numHeaderBytes));
linmsg->data.insert(linmsg->data.end(), lin.data, (lin.data + (lin.length - numHeaderBytes)));
linmsg->checksum = linmsg->data.back();
linmsg->data.pop_back();
}
if (linmsg->statusFlags.TxCommander) {
if (linmsg->data.size())
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
else
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
} else if (linmsg->statusFlags.TxResponder) {
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
}
return linmsg;
}
default: break;
}
break;
const Network network = neomessage->netid;
switch(network.getType()) {
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
auto canmsg = std::make_shared<CANMessage>();
canmsg->network = network;
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
canmsg->arbid = can.arbid;
canmsg->isExtended = can.status.extendedFrame;
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
canmsg->isCANFD = can.status.canfdFDF;
canmsg->baudrateSwitch = can.status.canfdBRS;
canmsg->errorStateIndicator = can.status.canfdESI;
return canmsg;
}
default: break;
default:
// TODO Implement others
return std::shared_ptr<Message>();
}
return std::shared_ptr<Message>();
}
@@ -1,31 +0,0 @@
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
#pragma pack(push, 2)
struct Header {
ExtendedCommand command;
uint16_t length;
};
struct Packet {
Header header;
TC10WakeStatus wakeStatus;
TC10SleepStatus sleepStatus;
};
#pragma pack(pop)
std::shared_ptr<TC10StatusMessage> TC10StatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) {
return nullptr;
}
const Packet* packet = (Packet*)bytestream.data();
if (packet->header.command != ExtendedCommand::GetTC10Status) {
return nullptr;
}
if (packet->header.length < sizeof(Packet) - sizeof(Header)) {
return nullptr;
}
return std::make_shared<TC10StatusMessage>(packet->wakeStatus, packet->sleepStatus);
}
+17 -79
View File
@@ -2,34 +2,19 @@
#include "icsneo/communication/command.h"
#include "icsneo/communication/decoder.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include <iostream>
#include <iomanip>
using namespace icsneo;
MultiChannelCommunication::MultiChannelCommunication(device_eventhandler_t err, std::unique_ptr<Driver> com,
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer, std::unique_ptr<Encoder> e,
std::unique_ptr<Decoder> md, size_t vnetCount) :
Communication(err, std::move(com), makeConfiguredPacketizer, std::move(e), std::move(md)), numVnets(vnetCount) {
vnetThreads.resize(numVnets);
vnetQueues.resize(numVnets);
}
void MultiChannelCommunication::spawnThreads() {
for(size_t i = 0; i < numVnets; i++) {
while(vnetQueues[i].pop()) {} // Ensure the queue is empty
vnetThreads[i] = std::thread(&MultiChannelCommunication::vnetReadTask, this, i);
}
hidReadThread = std::thread(&MultiChannelCommunication::hidReadTask, this);
mainChannelReadThread = std::thread(&MultiChannelCommunication::readTask, this);
}
void MultiChannelCommunication::joinThreads() {
closing = true;
if(hidReadThread.joinable())
hidReadThread.join();
for(auto& thread : vnetThreads) {
if(thread.joinable())
thread.join();
}
if(mainChannelReadThread.joinable())
mainChannelReadThread.join();
closing = false;
}
@@ -38,7 +23,7 @@ bool MultiChannelCommunication::sendPacket(std::vector<uint8_t>& bytes) {
return rawWrite(bytes);
}
void MultiChannelCommunication::hidReadTask() {
void MultiChannelCommunication::readTask() {
bool readMore = true;
bool gotPacket = false; // Have we got the first valid packet (don't flag errors otherwise)
std::deque<uint8_t> usbReadFifo;
@@ -50,7 +35,7 @@ void MultiChannelCommunication::hidReadTask() {
while(!closing) {
if(readMore) {
readBytes.clear();
if(driver->readWait(readBytes)) {
if(impl->readWait(readBytes)) {
readMore = false;
usbReadFifo.insert(usbReadFifo.end(), std::make_move_iterator(readBytes.begin()), std::make_move_iterator(readBytes.end()));
}
@@ -66,8 +51,7 @@ void MultiChannelCommunication::hidReadTask() {
if(!CommandTypeIsValid(currentCommandType)) {
// Device to host bytes discarded
if(gotPacket)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
usbReadFifo.pop_front();
continue;
}
@@ -107,7 +91,7 @@ void MultiChannelCommunication::hidReadTask() {
case PreprocessState::GetData:
state = PreprocessState::GetData; // Set state in case we've fallen through, but later need to go around again
if(usbReadFifo.size() < currentReadIndex + currentCommandLength) { // Come back when we have more data
if(usbReadFifo.size() <= currentReadIndex + currentCommandLength) { // Come back we have more data
readMore = true;
continue;
}
@@ -121,67 +105,21 @@ void MultiChannelCommunication::hidReadTask() {
payloadBytes[i] = usbReadFifo[0];
usbReadFifo.pop_front();
}
if(packetizer->input(payloadBytes)) {
for(auto& packet : packetizer->output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue; // Error will have been reported from within decoder
moodycamel::BlockingReaderWriterQueue< std::vector<uint8_t> >* currentQueue = nullptr;
switch(currentCommandType) {
case CommandType::Vnet1_to_HostPC:
currentQueue = &vnetQueues[0];
break;
case CommandType::Vnet2_to_HostPC:
if(numVnets >= 2)
currentQueue = &vnetQueues[1];
break;
case CommandType::Vnet3_to_HostPC:
if(numVnets >= 3)
currentQueue = &vnetQueues[2];
break;
case CommandType::SDCC1_to_HostPC: {
auto msg = std::make_shared<NeoReadMemorySDMessage>();
std::swap(msg->data, payloadBytes);
gotPacket = true;
dispatchMessage(msg);
break;
}
}
if(currentQueue == nullptr) {
state = PreprocessState::SearchForCommand;
break;
}
if(!currentQueue->enqueue(std::move(payloadBytes)) && gotPacket)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
payloadBytes.clear();
gotPacket = true;
state = PreprocessState::SearchForCommand;
break;
}
}
}
}
void MultiChannelCommunication::vnetReadTask(size_t vnetIndex) {
moodycamel::BlockingReaderWriterQueue< std::vector<uint8_t> >& queue = vnetQueues[vnetIndex];
std::vector<uint8_t> payloadBytes;
std::unique_ptr<Packetizer> packetizerLifetime;
Packetizer* vnetPacketizer;
if(vnetIndex == 0)
vnetPacketizer = packetizer.get();
else {
packetizerLifetime = makeConfiguredPacketizer();
vnetPacketizer = packetizerLifetime.get();
}
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
if(queue.wait_dequeue_timed(payloadBytes, std::chrono::milliseconds(250))) {
if(closing)
break;
auto& ringBuffer = driver->getReadBuffer();
ringBuffer.write(payloadBytes);
handleInput(*vnetPacketizer);
}
}
}
-60
View File
@@ -1,60 +0,0 @@
#include "icsneo/communication/packet/a2bpacket.h"
#include <cstring>
#include <vector>
namespace icsneo {
const size_t HardwareA2BPacket::a2bMessageMaxLength = sizeof(HardwareA2BPacket) + 1024;
std::shared_ptr<Message> HardwareA2BPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(HardwareA2BPacket))
{
return nullptr;
}
const HardwareA2BPacket* data = (const HardwareA2BPacket*)bytestream.data();
size_t totalPackedLength = static_cast<size_t>(bytestream.size()) - sizeof(HardwareA2BPacket); // First 28 bytes are message header.
if(totalPackedLength == 0) {
return nullptr;
}
std::shared_ptr<A2BMessage> msg = std::make_shared<A2BMessage>();
msg->numChannels = data->header.channelNum;
msg->channelSize16 = data->header.channelSize16;
msg->monitor = data->header.monitor;
msg->txmsg = data->header.txmsg;
msg->errIndicator = data->header.errIndicator;
msg->syncFrame = data->header.syncFrame;
msg->rfu2 = data->header.rfu2;
msg->timestamp = data->timestamp.TS;
msg->data = std::vector(bytestream.begin() + sizeof(HardwareA2BPacket), bytestream.end());
return msg;
}
bool HardwareA2BPacket::EncodeFromMessage(const A2BMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& /*report*/) {
constexpr size_t a2btxMessageHeaderSize = 6;
size_t audioBufferSize = message.data.size();
size_t totalSize = a2btxMessageHeaderSize + audioBufferSize;
bytestream.resize(totalSize, 0);
uint32_t offset = 0;
bytestream[offset++] = 0;
bytestream[offset++] = 0;
bytestream[offset++] = (uint8_t)(audioBufferSize & 0xFF);
bytestream[offset++] = (uint8_t)((audioBufferSize >> 8) & 0xFF);
bytestream[offset++] = (uint8_t)((message.description >> 8) & 0xFF);
bytestream[offset++] = (uint8_t)(message.description & 0xFF);
std::copy(message.data.begin(), message.data.end(), bytestream.begin() + offset);
return true;
}
}
+149 -139
View File
@@ -1,128 +1,82 @@
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
using namespace icsneo;
static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
if (length <= 8)
return length;
if (fd) {
switch(length) {
case 0x9:
return uint8_t(12);
case 0xa:
return uint8_t(16);
case 0xb:
return uint8_t(20);
case 0xc:
return uint8_t(24);
case 0xd:
return uint8_t(32);
case 0xe:
return uint8_t(48);
case 0xf:
return uint8_t(64);
}
}
return std::nullopt;
}
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
{
if (dataLength <= 8)
return uint8_t(dataLength);
if (fd) {
if (dataLength <= 12)
return uint8_t(0x9);
else if (dataLength <= 16)
return uint8_t(0xA);
else if (dataLength <= 20)
return uint8_t(0xB);
else if (dataLength <= 24)
return uint8_t(0xC);
else if (dataLength <= 32)
return uint8_t(0xD);
else if (dataLength <= 48)
return uint8_t(0xE);
else if (dataLength <= 64)
return uint8_t(0xF);
}
return std::nullopt;
}
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting
auto msg = std::make_shared<CANMessage>();
const bool busOff = data->data[0] & 0b00100000;
// Arb ID
if(data->header.IDE) { // Extended 29-bit ID
msg->arbid = (data->header.SID & 0x7ff) << 18;
msg->arbid |= (data->eid.EID & 0xfff) << 6;
msg->arbid |= (data->dlc.EID2 & 0x3f);
msg->isExtended = true;
} else { // Standard 11-bit ID
msg->arbid = data->header.SID;
}
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
return msg;
} else { // CAN Frame
auto msg = std::make_shared<CANMessage>();
// Arb ID
if(data->header.IDE) { // Extended 29-bit ID
msg->arbid = (data->header.SID & 0x7ff) << 18;
msg->arbid |= (data->eid.EID & 0xfff) << 6;
msg->arbid |= (data->dlc.EID2 & 0x3f);
msg->isExtended = true;
} else { // Standard 11-bit ID
msg->arbid = data->header.SID;
}
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// DLC
uint8_t length = data->dlc.DLC;
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI;
const std::optional<uint8_t> lenFromDLC = CAN_DLCToLength(length, true);
if (lenFromDLC)
length = *lenFromDLC;
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
// We don't want to overread our buffer, though, so make sure we cap the length
length = 8;
}
// Data
// The first 8 bytes are always in the standard place
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
msg->data.resize(length); // This data will be all zeros, but the length will be set
msg->isRemote = true;
} else {
msg->data.reserve(length);
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
// DLC
uint8_t length = data->dlc.DLC;
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI;
if(length > 8) {
switch(length) { // CAN FD Length Decoding
case 0x9:
length = 12;
break;
case 0xa:
length = 16;
break;
case 0xb:
length = 20;
break;
case 0xc:
length = 24;
break;
case 0xd:
length = 32;
break;
case 0xe:
length = 48;
break;
case 0xf:
length = 64;
break;
default:
return nullptr;
}
}
msg->transmitted = data->eid.TXMSG;
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
msg->description = data->stats;
return msg;
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
// We don't want to overread our buffer, though, so make sure we cap the length
length = 8;
}
// Data
// The first 8 bytes are always in the standard place
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
msg->data.resize(length); // This data will be all zeros, but the length will be set
msg->isRemote = true;
} else {
msg->data.reserve(length);
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
}
}
return msg;
}
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
@@ -132,38 +86,93 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
}
const size_t dataSize = message.data.size();
std::optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, message.isCANFD);
if (!dlc.has_value()) {
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD)) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol
}
if (message.dlcOnWire != 0) {
if(message.dlcOnWire > 0xf) {
// The DLC is only a nibble
// It is actually possible to transmit a standard CAN frame with a DLC > 8
// While it is invalid, most controllers will still pass along the received
// frame and 8 bytes of data, so it may be desirable to test behavior with
// these frames. We let you do it if you set `message.dlcOnWire` for transmit.
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
uint8_t lengthNibble = uint8_t(message.data.size());
uint8_t paddingBytes = 0;
if(lengthNibble > 8) {
switch(lengthNibble) {
case 9: paddingBytes++;
case 10: paddingBytes++;
case 11: paddingBytes++;
case 12:
lengthNibble = 0x9;
break;
case 13: paddingBytes++;
case 14: paddingBytes++;
case 15: paddingBytes++;
case 16:
lengthNibble = 0xA;
break;
case 17: paddingBytes++;
case 18: paddingBytes++;
case 19: paddingBytes++;
case 20:
lengthNibble = 0xB;
break;
case 21: paddingBytes++;
case 22: paddingBytes++;
case 23: paddingBytes++;
case 24:
lengthNibble = 0xC;
break;
case 25: paddingBytes++;
case 26: paddingBytes++;
case 27: paddingBytes++;
case 28: paddingBytes++;
case 29: paddingBytes++;
case 30: paddingBytes++;
case 31: paddingBytes++;
case 32:
lengthNibble = 0xD;
break;
case 33: paddingBytes++;
case 34: paddingBytes++;
case 35: paddingBytes++;
case 36: paddingBytes++;
case 37: paddingBytes++;
case 38: paddingBytes++;
case 39: paddingBytes++;
case 40: paddingBytes++;
case 41: paddingBytes++;
case 42: paddingBytes++;
case 43: paddingBytes++;
case 44: paddingBytes++;
case 45: paddingBytes++;
case 46: paddingBytes++;
case 47: paddingBytes++;
case 48:
lengthNibble = 0xE;
break;
case 49: paddingBytes++;
case 50: paddingBytes++;
case 51: paddingBytes++;
case 52: paddingBytes++;
case 53: paddingBytes++;
case 54: paddingBytes++;
case 55: paddingBytes++;
case 56: paddingBytes++;
case 57: paddingBytes++;
case 58: paddingBytes++;
case 59: paddingBytes++;
case 60: paddingBytes++;
case 61: paddingBytes++;
case 62: paddingBytes++;
case 63: paddingBytes++;
case 64:
lengthNibble = 0xF;
break;
default:
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // CAN FD frame may have had an incorrect byte count
}
if (message.dlcOnWire < *dlc) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
if (message.dlcOnWire > *dlc)
dlc = message.dlcOnWire;
}
// The only way this fails is if we're transmitting a DLC > 8 on standard CAN
const uint8_t paddedLength = CAN_DLCToLength(*dlc, message.isCANFD).value_or(8);
const uint8_t paddingBytes = uint8_t(paddedLength - dataSize);
// Pre-allocate as much memory as we will possibly need for speed
result.reserve(16 + dataSize + paddingBytes);
result.reserve(17 + dataSize + paddingBytes);
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
@@ -198,7 +207,7 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
// Status and DLC bits
if(message.isCANFD) {
result.push_back(0x0F); // FD Frame
uint8_t fdStatusByte = *dlc;
uint8_t fdStatusByte = lengthNibble;
if(message.baudrateSwitch)
fdStatusByte |= 0x80; // BRS status bit
// The firmware does not yet support transmitting ESI
@@ -206,12 +215,13 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
} else {
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
result.push_back((statusNibble << 4) | *dlc);
result.push_back((statusNibble << 4) | lengthNibble);
}
// Now finally the payload
result.insert(result.end(), message.data.begin(), message.data.end());
result.resize(result.size() + paddingBytes);
result.push_back(0);
// Fill in the length byte from earlier
result[0] |= result.size() << 4;
@@ -1,45 +0,0 @@
#include "icsneo/communication/packet/componentversionpacket.h"
#include "icsneo/communication/message/componentversionsmessage.h"
using namespace icsneo;
#pragma pack(push, 2)
struct PackedComponentVersion {
uint8_t valid;
uint8_t expansionSlot;
uint8_t componentInfo; // Component specific data (e.g. Linux: boot device)
uint8_t reserved;
uint32_t identifier;
uint32_t dotVersion; // Represents a.b.c.d, a.b.c, or a.b, depending on leading zeros.
uint32_t commitHash;
};
static constexpr size_t MaxReportedVersions = 16;
struct ComponentVersionsResponse {
ExtendedResponseMessage::ResponseHeader header;
uint16_t numVersions;
PackedComponentVersion versions[MaxReportedVersions];
};
#pragma pack(pop)
std::shared_ptr<ComponentVersionsMessage> ComponentVersionPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
auto msg = std::make_shared<ComponentVersionsMessage>();
// Length checks: At least a header and numVersions field.
if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 2) {
return msg; // Empty
}
// Get a reference to the payload to fully validate the length
const auto& response = *reinterpret_cast<const ComponentVersionsResponse*>(bytes.data());
// Expected size is the header, numVersions field, and numVersions ComponentVersion objects.
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 2 + (response.numVersions * sizeof(ComponentVersion));
// If the response is malformed (too small), return an empty message.
if(bytes.size() < expectedSize) {
return msg; // Empty
}
// Unpack into the portable class
for(unsigned int i = 0; i < response.numVersions; ++i) {
const auto& packedVersion = response.versions[i];
msg->versions.emplace_back(packedVersion.valid, packedVersion.componentInfo, packedVersion.identifier, packedVersion.dotVersion, packedVersion.commitHash);
}
return msg;
}
+11 -23
View File
@@ -4,7 +4,7 @@
using namespace icsneo;
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data());
const uint16_t* rawWords = (const uint16_t*)bytestream.data();
@@ -16,15 +16,12 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
if(packet->Length < 4)
return nullptr;
const size_t ethernetFrameSize = packet->Length - (sizeof(uint16_t) * 2);
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize;
const size_t bytestreamActualSize = bytestream.size();
if(bytestreamActualSize < bytestreamExpectedSize)
size_t bytesOnWire = packet->Length - (sizeof(uint16_t) * 2);
if(bytestream.size() < sizeof(HardwareEthernetPacket) + bytesOnWire)
return nullptr;
// Check for oversized packets, noting that some devices will send an extra byte to have an even number of bytes
if(bytestreamActualSize > bytestreamExpectedSize + 1)
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
if(bytestream.size() > sizeof(HardwareEthernetPacket) + bytesOnWire)
std::cout << "There is an extra " << (sizeof(HardwareEthernetPacket) + bytesOnWire) << " bytes at the end" << std::endl;
auto messagePtr = std::make_shared<EthernetMessage>();
EthernetMessage& message = *messagePtr;
@@ -50,7 +47,7 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
// Network ID is also not set, this will be fixed in the Decoder as well
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + (sizeof(HardwareEthernetPacket) - (sizeof(uint16_t) * 2));
const std::vector<uint8_t>::const_iterator dataend = databegin + ethernetFrameSize;
const std::vector<uint8_t>::const_iterator dataend = databegin + bytesOnWire;
message.data.insert(message.data.begin(), databegin, dataend);
return messagePtr;
@@ -59,21 +56,11 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t&) {
const size_t unpaddedSize = message.data.size();
size_t paddedSize = unpaddedSize;
uint16_t description = message.description;
if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60; // Pad out short messages
size_t sizeWithHeader = paddedSize + 4; // DescriptionID and Padded Count
// Description ID Most Significant bit is used to identify preemption frames
if(description & 0x8000)
return false;
if(message.preemptionEnabled) {
sizeWithHeader++; // Make space for the preemption flags
description |= 0x8000;
}
size_t sizeWithHeader = paddedSize + 5; // DescriptionID and Premption Flags
bytestream.reserve(sizeWithHeader + 8); // Also reserve space for the bytes we'll use later on
bytestream.resize(sizeWithHeader);
@@ -84,10 +71,11 @@ bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, s
bytestream[index++] = uint8_t(paddedSize >> 8);
// Description ID, big endian
bytestream[index++] = uint8_t(description >> 8);
bytestream[index++] = uint8_t(description);
bytestream[index++] = uint8_t(message.description >> 8);
bytestream[index++] = uint8_t(message.description);
// The header is one byte larger if preemption is enabled, shifting the data
// Yes, we reserved and allocated space for the preemption flags even if we're not putting them there
// And yes, the data is intended to move over one byte
if(message.preemptionEnabled)
bytestream[index++] = message.preemptionFlags;
-106
View File
@@ -1,106 +0,0 @@
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/packetizer.h"
#include <memory>
#include <cstdint>
#include <iostream>
namespace icsneo
{
std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
if(bytestream.empty() || (bytestream.size() < sizeof(PhyRegisterHeader_t)))
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
auto msg = std::make_shared<EthPhyMessage>();
const PhyRegisterHeader_t* pHeader = reinterpret_cast<const PhyRegisterHeader_t*>(bytestream.data());
const size_t numEntries = static_cast<size_t>(pHeader->numEntries);
if(
(PhyPacketVersion == pHeader->version) &&
(sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) &&
(numEntries <= MaxPhyEntries) &&
((bytestream.size() - sizeof(PhyRegisterHeader_t))
== (sizeof(PhyRegisterPacket_t) * numEntries))
)
{
msg->messages.reserve(numEntries);
const PhyRegisterPacket_t* pFirstEntry = reinterpret_cast<const PhyRegisterPacket_t*>(bytestream.data() + sizeof(PhyRegisterHeader_t));
for(size_t entryIdx{0}; entryIdx < numEntries; ++entryIdx)
{
const PhyRegisterPacket_t* pEntry = (pFirstEntry + entryIdx);
auto phyMessage = std::make_shared<PhyMessage>();
phyMessage->Enabled = (pEntry->Enabled != 0u);
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
phyMessage->Clause45Enable = (pEntry->Clause45Enable != 0u);
phyMessage->version = static_cast<uint8_t>(pEntry->version);
if(phyMessage->Clause45Enable)
phyMessage->clause45 = pEntry->clause45;
else
phyMessage->clause22 = pEntry->clause22;
msg->messages.push_back(phyMessage);
}
}
return msg;
}
bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t messageCount = message.getMessageCount();
if(!messageCount)
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
else if (messageCount > MaxPhyEntries)
{
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
auto byteSize = (messageCount * sizeof(PhyRegisterPacket_t)) + sizeof(PhyRegisterHeader_t);
bytestream.reserve(byteSize);
bytestream.push_back(static_cast<uint8_t>(messageCount & 0xFF));
bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF));
bytestream.push_back(PhyPacketVersion);
bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t)));
for(auto& phyMessage : message.messages)
{
PhyRegisterPacket_t tempPacket;
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
tempPacket.version = (phyMessage->version & 0xF);
if(phyMessage->Clause45Enable)
{
if( (FiveBits < phyMessage->clause45.port) ||
(FiveBits < phyMessage->clause45.device) )
{
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
tempPacket.Clause45Enable = 0x1u;
tempPacket.clause45.port = phyMessage->clause45.port;
tempPacket.clause45.device = phyMessage->clause45.device;
tempPacket.clause45.regAddr = phyMessage->clause45.regAddr;
tempPacket.clause45.regVal = phyMessage->clause45.regVal;
}
else
{
if( (FiveBits < phyMessage->clause22.phyAddr) ||
(FiveBits < phyMessage->clause22.regAddr) )
{
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
tempPacket.Clause45Enable = 0x0u;
tempPacket.clause22.phyAddr = phyMessage->clause22.phyAddr;
tempPacket.clause22.page = phyMessage->clause22.page;
tempPacket.clause22.regAddr = phyMessage->clause22.regAddr;
tempPacket.clause22.regVal = phyMessage->clause22.regVal;
}
uint8_t* pktPtr = reinterpret_cast<uint8_t*>(&tempPacket);
bytestream.insert(bytestream.end(), pktPtr, pktPtr + sizeof(PhyRegisterPacket_t));
}
return true;
}
}
+7 -17
View File
@@ -16,20 +16,13 @@ std::shared_ptr<FlexRayMessage> HardwareFlexRayPacket::DecodeToMessage(const std
// Always get the frame length, even for a symbol
msg->framelen = data->frame_length_12_5ns * 12.5e-9;
msg->channel = data->statusBits.bits.chb ? icsneo::FlexRay::Channel::B : icsneo::FlexRay::Channel::A;
if(data->tss_length_12_5ns == 0xffff) {// Flag value meaning this is a symbol
// These values are only for 10Mbit
// That's the only baudrate supported for now
if (data->frame_length_12_5ns > 480)
msg->symbol = FlexRay::Symbol::Wakeup;
else if (data->frame_length_12_5ns > 264)
msg->symbol = FlexRay::Symbol::CAS;
else
msg->symbol = FlexRay::Symbol::Unknown;
msg->symbol = FlexRay::Symbol::Unknown; // We can't know the symbol yet because this will depend on the baudrate
// Eventually we'll have to get this from the framelen
} else {
msg->tsslen = data->tss_length_12_5ns * 12.5e-9;
msg->channelB = data->statusBits.bits.chb;
if(data->statusBits.bits.bytesRxed >= 5) {
if(data->statusBits.bits.hcrc_error)
msg->headerCRCStatus = FlexRay::CRCStatus::Error;
@@ -50,17 +43,14 @@ std::shared_ptr<FlexRayMessage> HardwareFlexRayPacket::DecodeToMessage(const std
if(msg->headerCRCStatus != FlexRay::CRCStatus::Error) {
msg->reserved0was1 = data->reserved_0;
msg->payloadPreamble = data->payload_preamble;
msg->nullFrame = !data->null_frame;
msg->nullFrame = data->null_frame;
msg->sync = data->sync;
msg->startup = data->startup;
msg->slotid = data->slotid;
msg->cycle = data->cycle;
msg->dynamic = data->statusBits.bits.dynamic;
if(int64_t(numBytes) != int64_t(data->Length) - 4) {
// This is an error, probably need to flag it
} else {
const uint8_t* dataStart = (const uint8_t*)(data) - 4 + sizeof(HardwareFlexRayPacket);
msg->data = std::vector<uint8_t>(dataStart, dataStart + numBytes);
// This is an error, probably need to flag it
}
}
}
@@ -1,38 +0,0 @@
#include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/message/genericbinarystatusmessage.h"
using namespace icsneo;
#pragma pack(push, 2)
struct GenericBinaryStatusResponse {
ExtendedResponseMessage::ResponseHeader header;
size_t size;
uint16_t index;
uint16_t status;
};
#pragma pack(pop)
std::shared_ptr<GenericBinaryStatusMessage> GenericBinaryStatusPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
if(bytes.size() < sizeof(GenericBinaryStatusResponse)) {
return nullptr;
}
auto msg = std::make_shared<GenericBinaryStatusMessage>();
const auto& response = *reinterpret_cast<const GenericBinaryStatusResponse*>(bytes.data());
msg->binarySize = response.size;
msg->binaryIndex = response.index;
msg->binaryStatus = response.status;
return msg;
}
std::vector<uint8_t> GenericBinaryStatusPacket::EncodeArguments(uint16_t binaryIndex) {
std::vector<uint8_t> bytestream(sizeof(GenericBinaryStatusResponse));
auto& parameters = *reinterpret_cast<GenericBinaryStatusResponse*>(bytestream.data());
parameters.index = binaryIndex;
return bytestream;
}
@@ -1,50 +0,0 @@
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include "icsneo/communication/message/hardwareinfo.h"
#include <iostream>
using namespace icsneo;
#pragma pack(push, 1)
typedef struct
{
uint8_t valid;
struct
{
uint8_t day;
uint8_t month;
uint16_t year;
} manufactureDate;
struct
{
uint8_t major;
uint8_t minor;
} hwRev;
uint8_t deviceId;
struct
{
uint8_t major;
uint8_t minor;
} blVersion;
} HardwareInfoFrame;
#pragma pack(pop)
std::shared_ptr<HardwareInfo> HardwareInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
if(bytes.size() < (sizeof(HardwareInfoFrame) + 1)) {
return nullptr;
}
const auto* frame = reinterpret_cast<const HardwareInfoFrame*>(&bytes[1]);
auto msg = std::make_shared<HardwareInfo>();
msg->manufactureDate.day = frame->manufactureDate.day;
msg->manufactureDate.year = frame->manufactureDate.year;
msg->manufactureDate.month = frame->manufactureDate.month;
msg->hardwareRevision.major = frame->hwRev.major;
msg->hardwareRevision.minor = frame->hwRev.minor;
msg->bootloaderVersion.major = frame->blVersion.major;
msg->bootloaderVersion.minor = frame->blVersion.minor;
return msg;
}
-83
View File
@@ -1,83 +0,0 @@
#include "icsneo/communication/packet/i2cpacket.h"
namespace icsneo
{
std::shared_ptr<Message> HardwareI2CPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream)
{
auto msg = std::make_shared<I2CMessage>();
const I2CHeader* packet = reinterpret_cast<const I2CHeader*>(bytestream.data());
const size_t numPayloadBytes = packet->length;
const size_t numControlBytes = packet->CoreMiniBitsI2C.CBLen;
const size_t numDataBytes = numPayloadBytes - numControlBytes;
if( (numPayloadBytes == 0) || (numDataBytes > I2CMaxLength) ||
(sizeof(I2CHeader) != (bytestream.size() - numPayloadBytes)) )
{ return nullptr; }
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->address = (packet->CoreMiniBitsI2C.ID & 0x3FFu);
msg->deviceMode = static_cast<I2CMessage::DeviceMode>(packet->CoreMiniBitsI2C.CT);
msg->direction = static_cast<I2CMessage::Direction>(packet->CoreMiniBitsI2C.DIR);
msg->isExtendedID = static_cast<bool>(packet->CoreMiniBitsI2C.EID & 0x01u);
msg->isTXMsg = static_cast<bool>(packet->CoreMiniBitsI2C.TXMsg & 0x01u);
msg->txTimeout = static_cast<bool>(packet->CoreMiniBitsI2C.TXTimeout & 0x01u);
msg->txNack = static_cast<bool>(packet->CoreMiniBitsI2C.TXNack & 0x01u);
msg->txAborted = static_cast<bool>(packet->CoreMiniBitsI2C.TXAborted & 0x01u);
msg->txLostArb = static_cast<bool>(packet->CoreMiniBitsI2C.TXLostArb & 0x01u);
msg->txError = static_cast<bool>(packet->CoreMiniBitsI2C.TXError & 0x01u);
//We don't care about 0xTRB0Dx in this case...
//copy 0xTRB0STAT even though we likely won't use it either
msg->stats = packet->stats;
msg->timestamp = (packet->timestamp & (0x7FFFFFFFFFFFFFFFull));
//The device will combine the 'control' bytes and data bytes into one payload
//The control bytes will always come before the data
auto cbStart = bytestream.begin() + sizeof(I2CHeader);
auto dataStart = cbStart + numControlBytes;
std::copy(cbStart, dataStart, std::back_inserter(msg->controlBytes));
std::copy(dataStart, bytestream.end(), std::back_inserter(msg->dataBytes));
return msg;
}
bool HardwareI2CPacket::EncodeFromMessage(const I2CMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t numControlBytes = message.controlBytes.size();
const size_t numDataBytes = message.dataBytes.size();
if(I2CMaxLength < numDataBytes)
{
report(APIEvent::Type::I2CMessageExceedsMaxLength, APIEvent::Severity::Error);
return false;
}
if(message.controlBytes.empty() || message.dataBytes.empty())
{
//You'll need to provide a target R/W register in controlBytes
//alternatively, you're expecting to read without providing a dataBytes payload
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
bytestream.push_back(static_cast<uint8_t>(numControlBytes & 0xFFu));
bytestream.push_back(static_cast<uint8_t>((numControlBytes) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>(numDataBytes & 0xFFu));
bytestream.push_back(static_cast<uint8_t>((numDataBytes) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>((message.stats) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>(message.stats & 0xFFu));
if(message.isExtendedID)
{
bytestream.push_back(static_cast<uint8_t>(message.address & 0xFFu));
bytestream.push_back(static_cast<uint8_t>(((message.address) >> 8) & 0x03u) | 0x04u);
} else {
bytestream.push_back(static_cast<uint8_t>(message.address & 0xFFu));
bytestream.push_back(static_cast<uint8_t>(0x00u));
}
if(I2CMessage::Direction::Read == message.direction)
{ bytestream.back() |= static_cast<uint8_t>(0x10u); }
std::copy(message.controlBytes.begin(), message.controlBytes.end(), std::back_inserter(bytestream));
std::copy(message.dataBytes.begin(), message.dataBytes.end(), std::back_inserter(bytestream));
return true;
}
}
-135
View File
@@ -1,135 +0,0 @@
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packetizer.h"
#include <algorithm>
using namespace icsneo;
bool HardwareISO9141Packet::EncodeFromMessage(const ISO9141Message& message, std::vector<uint8_t>& bytestream,
const device_eventhandler_t& report, const Packetizer& packetizer)
{
size_t bytesToSend = message.data.size();
if (message.isInit || message.isBreak)
bytesToSend = 0;
if(bytesToSend > 4200) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol
}
bytestream.clear();
std::vector<uint8_t> packet;
packet.reserve(16);
size_t currentStart = 0;
do {
const bool firstPacket = currentStart == 0;
const uint8_t maxSize = (firstPacket ? 9 : 12);
uint8_t currentSize = maxSize;
if(bytesToSend - currentStart < maxSize)
currentSize = (uint8_t)(bytesToSend - currentStart);
packet.insert(packet.begin(), {
(uint8_t)Network::NetID::RED, // 0x0C for long message
(uint8_t)0, // Size, little endian 16-bit, filled later
(uint8_t)0,
(uint8_t)message.network.getNetID(), // NetID, little endian 16-bit
(uint8_t)(uint16_t(message.network.getNetID()) >> 8)
});
packet.push_back(uint8_t(message.network.getNetID()) + uint8_t((currentSize + (firstPacket ? 6 : 3)) << 4));
packet.push_back(uint8_t(currentSize + (firstPacket ? 5 : 2)));
if(bytesToSend - currentStart > maxSize) // More packets are coming
packet.back() |= 0x40;
if(firstPacket) {
if(message.isInit)
packet.back() |= 0x80;
if(message.isBreak)
packet.back() |= 0x20;
}
// Two bytes for Description ID, big endian
packet.insert(packet.end(), { uint8_t(message.description >> 8), uint8_t(message.description) });
// If we're the first packet and not init/break only, we should put the header in
if(firstPacket && !message.isInit && !message.isBreak)
packet.insert(packet.end(), message.header.begin(), message.header.end());
// Now the data
auto dataIt = message.data.begin() + currentStart;
if(currentSize)
packet.insert(packet.end(), dataIt, dataIt + currentSize);
// Advance for the next packet
currentStart += currentSize;
const uint16_t size = uint16_t(packet.size()) + 2;
packet[1] = uint8_t(size & 0xFF);
packet[2] = uint8_t((size >> 8) & 0xFF);
packetizer.packetWrap(packet, false);
bytestream.insert(bytestream.end(), packet.begin(), packet.end());
packet.clear();
} while(currentStart < bytesToSend);
return true;
}
std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareISO9141Packet& packet = *reinterpret_cast<const HardwareISO9141Packet*>(bytestream.data());
if(!mMsg) {
mMsg = std::make_shared<ISO9141Message>();
mGotPackets = 0;
}
mGotPackets++;
const bool morePacketsComing = packet.c3.frm == 0;
const uint8_t bytesInCurrentMessage = packet.c3.len;
if(mMsg->data.size() + bytesInCurrentMessage > 500) {
mMsg.reset();
return std::shared_ptr<ISO9141Message>();
}
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
mMsg->timestamp = packet.timestamp.TS;
auto* dataStart = packet.data;
if(mGotPackets == 1) {
// Header
if(bytesInCurrentMessage < 3) {
mMsg.reset(); // We don't have the header for some reason
return std::shared_ptr<ISO9141Message>();
}
std::copy(packet.data, packet.data + 3, mMsg->header.begin());
dataStart += 3;
}
// Data
mMsg->data.insert(mMsg->data.end(), dataStart, packet.data + (bytesInCurrentMessage > 8 ? 8 : bytesInCurrentMessage));
if(bytesInCurrentMessage > 8)
mMsg->data.push_back(packet.c1.d8);
if(bytesInCurrentMessage > 9)
mMsg->data.push_back(packet.c2.d9);
if(bytesInCurrentMessage > 10)
mMsg->data.push_back(packet.c2.d10);
if(bytesInCurrentMessage > 11)
mMsg->data.push_back(packet.c3.d11);
if(morePacketsComing)
return std::shared_ptr<ISO9141Message>();
mMsg->transmitted = packet.c1.tx;
mMsg->isInit = packet.c3.init;
mMsg->framingError = packet.c1.options & 0x1;
mMsg->overflowError = packet.c1.options & 0x2;
mMsg->parityError = packet.c1.options & 0x4;
mMsg->rxTimeoutError = packet.c1.options & 0x8;
mMsg->description = packet.stats;
auto ret = mMsg;
mMsg.reset();
return ret;
}
-147
View File
@@ -1,147 +0,0 @@
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/packetizer.h"
namespace icsneo {
std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareLINPacket* packet = reinterpret_cast<const HardwareLINPacket*>(bytestream.data());
size_t numDataBytes = packet->CoreMiniBitsLIN.len;
size_t numHeaderBytes = sizeof(HardwareLINPacket::CoreMiniBitsLIN);
if( (sizeof(HardwareLINPacket) != bytestream.size()) ||
((numDataBytes + numHeaderBytes) > bytestream.size()) )
return nullptr;
if(numDataBytes)
--numDataBytes; //If data is present, there will be a checksum included
auto msg = std::make_shared<LINMessage>(static_cast<uint8_t>(packet->CoreMiniBitsLIN.ID));
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->isEnhancedChecksum = static_cast<bool>(packet->CoreMiniBitsLIN.TxChkSumEnhanced);
/* Minimum one responder byte and one checksum byte. */
if(2u > packet->CoreMiniBitsLIN.len)
msg->linMsgType = LINMessage::Type::LIN_ERROR;
auto dataStart = bytestream.begin() + numHeaderBytes;
std::copy(dataStart, (dataStart+numDataBytes), std::back_inserter(msg->data));
/* If OK, validate the checksum*/
auto isChecksumInvalid = [&]() -> bool {
/* messages with no data have no checksum (e.g. header only) */
if(!msg->data.size())
return true;
uint8_t checkSum = (8 > numDataBytes) ? *(dataStart + numDataBytes) : packet->CoreMiniBitsLIN.LINByte9;
LINMessage::calcChecksum(*msg);
if(checkSum != msg->checksum) {
msg->isEnhancedChecksum = true;
LINMessage::calcChecksum(*msg);
if(checkSum != msg->checksum) {
msg->isEnhancedChecksum = false;
msg->checksum = checkSum;
return true;
}
}
return false;
};
/* if any of the status bits are set, then this is
either a failed reception or a bus status update. */
msg->errFlags =
{
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxOnlyBreak),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxOnlyBreakSync),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrTxRxMismatch),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxBreakNotZero),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxBreakTooShort),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxSyncNot55),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxDataGreater8),
static_cast<bool>(packet->CoreMiniBitsLIN.SyncFerr),
static_cast<bool>(packet->CoreMiniBitsLIN.MidFerr),
static_cast<bool>(packet->CoreMiniBitsLIN.ResponderByteFerr),
isChecksumInvalid(), /* ErrChecksumMatch */
};
msg->statusFlags =
{
static_cast<bool>(packet->CoreMiniBitsLIN.TxChkSumEnhanced),
static_cast<bool>(packet->CoreMiniBitsLIN.TXCommander),
static_cast<bool>(packet->CoreMiniBitsLIN.TXResponder),
static_cast<bool>(packet->CoreMiniBitsLIN.TxAborted),
static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered),
static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly)
};
if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder)
msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG;
else if(msg->statusFlags.BreakOnly)
msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY;
if( msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly ||
msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero ||
msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 ||
msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync ||
msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch ||
msg->errFlags.ErrFrameResponderData )
{ msg->linMsgType = LINMessage::Type::LIN_ERROR; }
msg->timestamp = packet->timestamp;
return msg;
}
bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
uint8_t size = ((std::min<size_t>(8ul, message.data.size()) + 3ul) & 0xFu);
if(size > 3) { ++size; } // add a checksum byte if there's data
switch(message.linMsgType) {
case LINMessage::Type::LIN_HEADER_ONLY:
case LINMessage::Type::LIN_COMMANDER_MSG:
{
size |= 0x80u;
break;
}
case LINMessage::Type::LIN_BREAK_ONLY:
{
size |= 0x20u;
break;
}
case LINMessage::Type::NOT_SET:
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
default:
break;
}
message.protectedID = message.calcProtectedID(message.ID);
bytestream.insert(bytestream.end(),
{
static_cast<uint8_t>(0x00u),
static_cast<uint8_t>(size),
static_cast<uint8_t>((message.description >> 8) & 0xFF),
static_cast<uint8_t>(message.description & 0xFF),
static_cast<uint8_t>(message.protectedID)
});
switch(message.linMsgType) {
case(LINMessage::Type::LIN_COMMANDER_MSG):
case(LINMessage::Type::LIN_UPDATE_RESPONDER):
{
std::copy(message.data.begin(), message.data.end(), std::back_inserter(bytestream));
LINMessage::calcChecksum(message);
bytestream.push_back(message.checksum);
break;
}
default:
break;
}
if(bytestream.size() % 2)
bytestream.push_back(0x41); //padding
return true;
}
} //namespace icsneo
-125
View File
@@ -1,125 +0,0 @@
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/message/livedatamessage.h"
#include <cstring>
#include <vector>
namespace icsneo {
std::shared_ptr<Message> HardwareLiveDataPacket::DecodeToMessage(const std::vector<uint8_t>& bytes, const device_eventhandler_t& report) {
if(bytes.empty() || (bytes.size() < (sizeof(LiveDataHeader) + sizeof(ExtResponseHeader)))) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
const auto header = reinterpret_cast<const ExtResponseHeader*>(bytes.data());
if(ExtendedCommand::LiveData != static_cast<ExtendedCommand>(header->command)) {
report(APIEvent::Type::LiveDataInvalidCommand, APIEvent::Severity::Error);
return nullptr;
}
const auto ldHeader = reinterpret_cast<const LiveDataHeader*>(bytes.data() + sizeof(ExtResponseHeader));
// Versioning check to avoid bad data interpretation between disparate libicsneo and firmware versions
if(icsneo::LiveDataUtil::LiveDataVersion != ldHeader->version) {
report(APIEvent::Type::LiveDataVersionMismatch, APIEvent::Severity::Error);
return nullptr;
}
switch(LiveDataCommand(ldHeader->cmd)) {
case LiveDataCommand::RESPONSE: {
auto retMsg = std::make_shared<LiveDataValueMessage>();
const auto responseBytes = reinterpret_cast<const LiveDataValueResponse*>(ldHeader);
retMsg->handle = responseBytes->handle;
retMsg->cmd = static_cast<LiveDataCommand>(responseBytes->cmd);
retMsg->numArgs = responseBytes->numArgs;
for(uint32_t i = 0; i < retMsg->numArgs; ++i) {
retMsg->values.emplace_back(std::make_shared<LiveDataValue>(responseBytes->values[i]));
}
return retMsg;
}
case LiveDataCommand::STATUS: {
auto retMsg = std::make_shared<LiveDataStatusMessage>();
const auto responseBytes = reinterpret_cast<const LiveDataStatusResponse*>(ldHeader);
retMsg->handle = responseBytes->handle;
retMsg->cmd = static_cast<LiveDataCommand>(responseBytes->cmd);
retMsg->status = responseBytes->status;
retMsg->requestedCommand = static_cast<LiveDataCommand>(responseBytes->requestedCommand);
return retMsg;
}
default: {
report(APIEvent::Type::LiveDataInvalidCommand, APIEvent::Severity::Error);
break;
}
}
return nullptr;
}
bool HardwareLiveDataPacket::EncodeFromMessage(LiveDataMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
uint16_t payloadSize = 0;
switch(message.cmd) {
case LiveDataCommand::SUBSCRIBE: {
auto commandMsg = reinterpret_cast<LiveDataCommandMessage*>(&message);
const auto numArgs = commandMsg->args.size();
if(numArgs) {
payloadSize = static_cast<uint16_t>(sizeof(LiveDataSubscribe) + (sizeof(LiveDataArgument) * (numArgs-1)));
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
LiveDataSubscribe* out = reinterpret_cast<LiveDataSubscribe*>(bytestream.data() + sizeof(ExtendedCommandHeader));
out->version = icsneo::LiveDataUtil::LiveDataVersion;
out->cmd = static_cast<uint32_t>(commandMsg->cmd);
if(!commandMsg->handle)
commandMsg->handle = LiveDataUtil::getNewHandle();
out->handle = commandMsg->handle;
out->numArgs = static_cast<uint32_t>(commandMsg->args.size());
out->freqMs = static_cast<uint32_t>(commandMsg->updatePeriod.count());
out->expireMs = static_cast<uint32_t>(commandMsg->expirationTime.count());
for(size_t i = 0; i < numArgs; ++i) {
out->args[i].objectType = commandMsg->args[i]->objectType;
out->args[i].objectIndex = commandMsg->args[i]->objectIndex;
out->args[i].signalIndex = commandMsg->args[i]->signalIndex;
out->args[i].valueType = commandMsg->args[i]->valueType;
}
} else {
report(APIEvent::Type::LiveDataInvalidArgument, APIEvent::Severity::Error);
return false;
}
break;
}
case LiveDataCommand::UNSUBSCRIBE: {
payloadSize = sizeof(LiveDataHeader);
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
auto ldUnsubMsg = reinterpret_cast<LiveDataHeader*>(bytestream.data() + sizeof(ExtendedCommandHeader));
ldUnsubMsg->version = static_cast<uint32_t>(icsneo::LiveDataUtil::LiveDataVersion);
ldUnsubMsg->cmd = static_cast<uint32_t>(message.cmd);
ldUnsubMsg->handle = static_cast<uint32_t>(message.handle);
break;
}
case LiveDataCommand::CLEAR_ALL: {
payloadSize = sizeof(LiveDataHeader);
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
auto clearMsg = reinterpret_cast<LiveDataHeader*>(bytestream.data() + sizeof(ExtendedCommandHeader));
clearMsg->version = static_cast<uint32_t>(icsneo::LiveDataUtil::LiveDataVersion);
clearMsg->cmd = static_cast<uint32_t>(message.cmd);
break;
}
default: {
report(APIEvent::Type::LiveDataInvalidCommand, APIEvent::Severity::Error);
return false;
}
}
// +1 for AA, another +1 for firmware nuance
uint16_t fullSize = static_cast<uint16_t>(1 + sizeof(ExtendedCommandHeader) + payloadSize) + 1;
ExtendedCommandHeader* header = reinterpret_cast<ExtendedCommandHeader*>(bytestream.data());
if(!header) {
report(APIEvent::Type::LiveDataEncoderError, APIEvent::Severity::Error);
return false;
}
header->netid = static_cast<uint8_t>(Network::NetID::Main51);
header->fullLength = fullSize;
header->command = static_cast<uint8_t>(Command::Extended);
header->extendedCommand = static_cast<uint16_t>(ExtendedCommand::LiveData);
header->payloadLength = payloadSize;
return true;
}
} // namespace icsneo
@@ -1,12 +0,0 @@
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
using namespace icsneo;
std::shared_ptr<LogicalDiskInfoMessage> LogicalDiskInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
// Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(LogicalDiskInfoPacket))
return {};
const LogicalDiskInfoPacket* packet = reinterpret_cast<const LogicalDiskInfoPacket*>(bytestream.data());
return std::make_shared<LogicalDiskInfoMessage>(packet->isConnected != 0, packet->numSectors, packet->hiddenSectors, packet->bytesPerSector);
}
-79
View File
@@ -1,79 +0,0 @@
#include "icsneo/communication/packet/mdiopacket.h"
namespace icsneo
{
const size_t HardwareMDIOPacket::mdioDataSize = 2;
std::shared_ptr<Message> HardwareMDIOPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream)
{
auto msg = std::make_shared<MDIOMessage>();
const HardwareMDIOPacket* packet = reinterpret_cast<const HardwareMDIOPacket*>(bytestream.data());
if((sizeof(HardwareMDIOPacket) != (bytestream.size())) || (packet->length != 0))
{
return nullptr;
}
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->clause = static_cast<MDIOMessage::Clause>(packet->header.ST);
msg->direction = static_cast<MDIOMessage::Direction>((packet->header.OP & 0x2) ? 1 : 0);
msg->isTXMsg = static_cast<bool>(packet->header.TRANSMIT & 0x01u);
msg->phyAddress = (packet->header.PHY_ADDR & 0x1Fu);
if (msg->clause == MDIOMessage::Clause::Clause45)
{ // 16-bit register address
msg->devAddress = (packet->header.C45_DEVTYPE & 0x1Fu);
msg->regAddress = (packet->header.REG_ADDR & 0xFFFFu);
}
else
{ // 5-bit register address
msg->devAddress = 0;
msg->regAddress = (packet->header.REG_ADDR & 0x1Fu);
}
msg->isTXMsg = static_cast<bool>(packet->header.TRANSMIT & 0x01u);
msg->txTimeout = static_cast<bool>(packet->header.ERR_TIMEOUT & 0x01u);
msg->txAborted = static_cast<bool>(packet->header.ERR_JOB_CANCELLED & 0x01u);
msg->txInvalidBus = static_cast<bool>(packet->header.ERR_INVALID_BUS & 0x01u);
msg->txInvalidPhyAddr = static_cast<bool>(packet->header.ERR_INVALID_PHYADDR & 0x01u);
msg->txInvalidRegAddr = static_cast<bool>(packet->header.ERR_INVALID_REGADDR & 0x01u);
msg->txInvalidClause = static_cast<bool>(packet->header.ERR_UNSUPPORTED_CLAUSE & 0x01u);
msg->txInvalidOpcode = static_cast<bool>(packet->header.ERR_UNSUPPORTED_OPCODE & 0x01u);
//We don't care about 0xTRB0Dx in this case...
//copy 0xTRB0STAT even though we likely won't use it either
msg->description = packet->stats;
msg->timestamp = (packet->timestamp & (0x7FFFFFFFFFFFFFFFull));
std::copy(packet->data, packet->data + mdioDataSize, std::back_inserter(msg->data));
return msg;
}
bool HardwareMDIOPacket::EncodeFromMessage(const MDIOMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t numDataBytes = message.data.size();
if(mdioDataSize < numDataBytes)
{
report(APIEvent::Type::MDIOMessageExceedsMaxLength, APIEvent::Severity::Error);
return false;
}
uint8_t st = (message.clause == MDIOMessage::Clause::Clause45) ? 0x0 : 0x1;
uint8_t op = (message.direction == MDIOMessage::Direction::Read) ? 0x2 : 0x1;
uint8_t phyAddr = message.phyAddress & 0x1F;
uint16_t regAddr = (message.clause == MDIOMessage::Clause::Clause45) ? message.regAddress : message.regAddress & 0x1F;
uint8_t c45DevType = (message.clause == MDIOMessage::Clause::Clause45) ? message.devAddress & 0x1F : 0;
bytestream.push_back(static_cast<uint8_t>((message.description >> 8) & 0xFF)); // MSB first
bytestream.push_back(static_cast<uint8_t>(message.description & 0xFF)); // LSB
bytestream.push_back(op); // opcode
bytestream.push_back(st); // st (clause)
bytestream.push_back(phyAddr); // st (clause)
bytestream.push_back(c45DevType); // clause 45 device type
bytestream.push_back(regAddr & 0xFF); // reg addr LSB
bytestream.push_back((regAddr >> 8) & 0xFF); // reg addr MSB
std::copy(message.data.begin(), message.data.end(), std::back_inserter(bytestream));
return true;
}
}
@@ -1,31 +0,0 @@
#include <iostream>
#include "icsneo/communication/packet/scriptstatuspacket.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
using namespace icsneo;
std::shared_ptr<ScriptStatusMessage> ScriptStatus::DecodeToMessage(const std::vector<uint8_t>& bytestream){
if(bytestream.size() != sizeof(ScriptStatus))
return {};
auto msg = std::make_shared<ScriptStatusMessage>();
const auto& decoded = *reinterpret_cast<const ScriptStatus*>(bytestream.data());
msg->isCoreminiRunning = decoded.status.isRunning;
msg->isEncrypted = decoded.status.isEncrypted;
msg->sectorOverflows = decoded.sectorOverflows;
msg->numRemainingSectorBuffers = decoded.numRemainingSectorBuffers;
msg->lastSector = decoded.lastSector;
msg->readBinSize = decoded.readBinSize;
msg->minSector = decoded.minSector;
msg->maxSector = decoded.maxSector;
msg->currentSector = decoded.currentSector;
msg->coreminiCreateTime = ((uint64_t)decoded.coreminiCreateTimeMsb << 32) | decoded.coreminiCreateTimeLsb;
msg->fileChecksum = decoded.fileChecksum;
msg->coreminiVersion = decoded.coreminiVersion;
msg->coreminiHeaderSize = decoded.coreminiHeaderSize;
msg->diagnosticErrorCode = decoded.diagErrCode;
msg->diagnosticErrorCodeCount = decoded.diagErrCodeCount;
msg->maxCoreminiSizeKB = decoded.maxCoreminiSizeKB;
return msg;
}
@@ -1,44 +0,0 @@
#include "icsneo/communication/packet/supportedfeaturespacket.h"
#include "icsneo/communication/message/supportedfeaturesmessage.h"
using namespace icsneo;
static constexpr uint16_t SupportedFeaturesCommandVersion = 1;
static constexpr size_t NumSupportedFeaturesFields =
(static_cast<size_t>(SupportedFeature::numSupportedFeatures) + 31) / 32;
#pragma pack(push, 2)
struct SupportedFeaturesResponse {
ExtendedResponseMessage::ResponseHeader header;
uint16_t cmdVersion;
uint16_t numValidBits;
uint32_t featuresFields[NumSupportedFeaturesFields];
};
#pragma pack(pop)
std::shared_ptr<SupportedFeaturesMessage> SupportedFeaturesPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
auto msg = std::make_shared<SupportedFeaturesMessage>();
// Length check: At least a header, a 2-byte cmdVersion field, and a 2-byte numValidBits field.
if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 4) {
return msg; // Empty
}
// Get a reference to the payload to fully validate the length
const auto& response = *reinterpret_cast<const SupportedFeaturesResponse*>(bytes.data());
if(response.cmdVersion != SupportedFeaturesCommandVersion) {
return msg;
}
// Expected size is the header, cmdVersion and numValidBits fields, plus the number of 32-bit bitfields in the response based on numValidBits
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 4 + ((response.numValidBits + 31) / 32) * 4;
// If the response is malformed (too small), return an empty message
if(bytes.size() < expectedSize) {
return msg; // Empty
}
unsigned int loopLimit = std::min<unsigned int>(response.numValidBits, static_cast<unsigned int>(SupportedFeature::numSupportedFeatures));
for(unsigned int i = 0; i < loopLimit; ++i) {
uint32_t wordOffset = i / 32;
uint32_t bitOffset = i % 32;
if((response.featuresFields[wordOffset] >> bitOffset) & 1) {
msg->features.insert(static_cast<SupportedFeature>(i));
}
}
return msg;
}
-39
View File
@@ -1,39 +0,0 @@
#include "icsneo/communication/packet/versionpacket.h"
using namespace icsneo;
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < 3) // Not enough bytes to decode
return std::shared_ptr<VersionMessage>();
auto msg = std::make_shared<VersionMessage>(VersionMessage::MainChip);
msg->Versions.emplace_back();
std::optional<DeviceAppVersion>& version = msg->Versions.back();
version.emplace();
version->major = bytestream[1];
version->minor = bytestream[2];
return msg;
}
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) {
auto msg = std::make_shared<VersionMessage>(VersionMessage::SecondaryChips);
size_t bytesLeft = bytestream.size();
if(bytesLeft)
bytesLeft--; // Disregard command byte
while(bytesLeft >= 3) {
const bool versionValid = bytestream[bytestream.size() - bytesLeft + 0];
msg->Versions.emplace_back();
std::optional<DeviceAppVersion>& version = msg->Versions.back();
if(versionValid) {
version.emplace();
version->major = bytestream[bytestream.size() - bytesLeft + 1];
version->minor = bytestream[bytestream.size() - bytesLeft + 2];
}
bytesLeft -= std::min<size_t>(3, bytesLeft);
}
return msg;
}
-100
View File
@@ -1,100 +0,0 @@
#include "icsneo/communication/packet/wivicommandpacket.h"
#include "icsneo/communication/message/wiviresponsemessage.h"
#include <cstring>
using namespace icsneo;
std::shared_ptr<WiVI::ResponseMessage> WiVI::CommandPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(WiVI::CommandPacket::Header))
return {};
auto msg = std::make_shared<WiVI::ResponseMessage>();
const auto& header = *reinterpret_cast<const WiVI::CommandPacket::Header*>(bytestream.data());
switch(header.cmd) {
case WiVI::Command::Result: {
if(bytestream.size() < sizeof(WiVI::CommandPacket::Result))
return {};
const auto& decoded = *reinterpret_cast<const WiVI::CommandPacket::Result*>(bytestream.data());
msg->responseTo = decoded.responseTo;
msg->success = decoded.result != 0;
break;
}
case WiVI::Command::GetSignal: {
// Use the SetSignal structure since it matches the response
if(bytestream.size() < sizeof(WiVI::CommandPacket::SetSignal))
return {};
const auto& setSignal = *reinterpret_cast<const WiVI::CommandPacket::SetSignal*>(bytestream.data());
msg->responseTo = WiVI::Command::GetSignal;
msg->value = setSignal.value.ValueInt32;
break;
}
case WiVI::Command::GetAll: {
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll))
return {};
const auto& getAll = *reinterpret_cast<const WiVI::CommandPacket::GetAll*>(bytestream.data());
msg->responseTo = WiVI::Command::GetAll;
msg->info.emplace();
msg->info->sleepRequest = getAll.sleepRequest;
msg->info->connectionTimeoutMinutes = getAll.connectionTimeoutMinutes;
// Check that we have enough data for the capture infos
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll) + (sizeof(WiVI::CaptureInfo) * getAll.numCaptureInfos))
return {};
msg->info->captures.resize(getAll.numCaptureInfos);
for(uint16_t i = 0; i < getAll.numCaptureInfos; i++)
msg->info->captures[i] = getAll.captureInfos[i];
break;
}
default: // Unknown command response
return {};
}
return msg;
}
std::vector<uint8_t> WiVI::CommandPacket::GetSignal::Encode(WiVI::SignalType type) {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetSignal));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetSignal*>(ret.data());
frame.header.cmd = WiVI::Command::GetSignal;
frame.header.length = sizeof(frame) - sizeof(frame.header);
frame.type = type;
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::SetSignal::Encode(WiVI::SignalType type, CoreMiniFixedPointValue value) {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::SetSignal));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::SetSignal*>(ret.data());
frame.header.cmd = WiVI::Command::SetSignal;
frame.header.length = sizeof(frame) - sizeof(frame.header);
frame.type = type;
frame.value = value;
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::GetAll::Encode() {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetAll));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetAll*>(ret.data());
frame.header.cmd = WiVI::Command::GetAll;
frame.header.length = sizeof(frame) - sizeof(frame.header);
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::ClearUploads::Encode(const std::vector<uint8_t>& bitmask) {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::ClearUploads) + bitmask.size());
auto& frame = *reinterpret_cast<WiVI::CommandPacket::ClearUploads*>(ret.data());
frame.header.cmd = WiVI::Command::ClearUploads;
frame.header.length = uint16_t(ret.size() - sizeof(frame.header));
memcpy(frame.bitmask, bitmask.data(), bitmask.size());
return ret;
}
+68 -85
View File
@@ -1,4 +1,5 @@
#include "icsneo/communication/packetizer.h"
#include <iostream>
#include <iomanip>
using namespace icsneo;
@@ -12,11 +13,11 @@ uint8_t Packetizer::ICSChecksum(const std::vector<uint8_t>& data) {
return (uint8_t)checksum;
}
std::vector<uint8_t>& Packetizer::packetWrap(std::vector<uint8_t>& data, bool shortFormat) const {
std::vector<uint8_t>& Packetizer::packetWrap(std::vector<uint8_t>& data, bool shortFormat) {
if(shortFormat) {
// Some devices don't use the checksum, so might as well not calculate it if that's the case
// Either way the byte is still expected to be present in the bytestream for short messages
data.push_back(disableChecksum ? 0x00 : ICSChecksum(data));
data.push_back(disableChecksum ? 0x00 : ICSChecksum(data));
}
data.insert(data.begin(), 0xAA);
if(align16bit && data.size() % 2 == 1) // Some devices always expect 16-bit aligned data
@@ -24,8 +25,9 @@ std::vector<uint8_t>& Packetizer::packetWrap(std::vector<uint8_t>& data, bool sh
return data;
}
bool Packetizer::input(RingBuffer& bytes) {
bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
bool haveEnoughData = true;
bytes.insert(bytes.end(), inputBytes.begin(), inputBytes.end());
while(haveEnoughData) {
switch(state) {
@@ -39,6 +41,7 @@ bool Packetizer::input(RingBuffer& bytes) {
state = ReadState::ParseHeader;
currentIndex = 1;
} else {
std::cerr << "Discarding byte " << std::hex << std::setw(2) << std::setfill('0') << int(bytes.front()) << std::endl;
bytes.pop_front(); // Discard
}
break;
@@ -47,97 +50,59 @@ bool Packetizer::input(RingBuffer& bytes) {
haveEnoughData = false;
break;
}
packetLength = bytes[1] >> 4 & 0xF;
packet.network = Network(bytes[1] & 0xF); // Lower nibble of the second byte is the network ID
if(packetLength == 0) {
packetLength = bytes[1] >> 4 & 0xf; // Upper nibble of the second byte denotes the packet length
packet.network = Network(bytes[1] & 0xf); // Lower nibble of the second byte is the network ID
if(packetLength == 0) { // A length of zero denotes a long style packet
state = ReadState::ParseLongStylePacketHeader;
break;
} else if(packetLength == 0xA && packet.network == Network::NetID::DiskData) {
state = ReadState::ParseDiskDataHeader;
break;
checksum = false;
headerSize = 6;
} else {
state = ReadState::GetData;
checksum = true; // Even if checksum is not explicitly disallowed, we enable it here, as this goes into length calculation
headerSize = 2;
packetLength += 2; // The packet length given in short packets does not include header
}
checksum = true; // Even if checksum is not explicitly disallowed, we enable it here, as this goes into length calculation
headerSize = 2;
packetLength += 2; // The packet length given in short packets does not include header
currentIndex++;
state = ReadState::GetData;
break;
case ReadState::ParseLongStylePacketHeader:
if(bytes.size() < 6) {
haveEnoughData = false;
break;
}
packetLength = bytes[2]; // Long packets have a little endian length on bytes 3 and 4
packetLength |= bytes[3] << 8;
packet.network = Network(((bytes[5] << 8) | bytes[4]), false); // Long packets have their netid stored as little endian on bytes 5 and 6. Devices never send actual VNET IDs so we must not perform ID expansion here.
packet.network = Network((bytes[5] << 8) | bytes[4]); // Long packets have their netid stored as little endian on bytes 5 and 6
currentIndex += 4;
/* Long packets can't have a length less than 6, because that would indicate a negative payload size.
* Unlike the short packet length, the long packet length encompasses everything from the 0xAA to the
* end of the payload. The short packet length, for reference, only encompasses the length of the actual
* payload, and not the header or checksum.
*/
if(packetLength < 6 || packetLength > 4000) {
/* Long packets can't have a length less than 4, because that would indicate a negative payload size.
* Unlike the short packet length, the long packet length encompasses everything from the 0xAA to the
* end of the payload. The short packet length, for reference, only encompasses the length of the actual
* payload, and not the header or checksum.
*/
if(packetLength < 4 || packetLength > 4000) {
std::cerr << "====================================\n";
std::cerr << "An improper packet has occurred!\n";
std::cerr << "Packet: (" << std::dec << packetLength << ")\n";
std::cerr << '\t';
for(auto i = 0; i < std::min(packetLength, 16); i++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(bytes[i]) << ' ';
std::cerr << std::endl;
std::cerr << "Previous: (" << std::dec << previousPacket.data.size() << ") " << previousPacket.network << '\n';
for(auto i = 0; i < previousPacket.data.size(); i += 16) {
std::cerr << '\t';
for(auto j = 0; j < 16 && (i + j) < previousPacket.data.size(); j++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(previousPacket.data[i+j]) << ' ';
std::cerr << std::endl;
}
std::cerr << "====================================\n";
bytes.pop_front();
EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
state = ReadState::SearchForHeader;
break;
} else {
state = ReadState::GetData;
}
checksum = false;
headerSize = 6;
currentIndex += 5;
state = ReadState::GetData;
break;
case ReadState::ParseDiskDataHeader:
if(bytes.size() < 3) {
haveEnoughData = false;
break;
}
if(bytes[2] != 0xAA) {
bytes.pop_front();
state = ReadState::SearchForHeader;
break;
}
if(bytes.size() < 4) {
haveEnoughData = false;
break;
}
if(bytes[3] != 0x55) {
bytes.pop_front();
state = ReadState::SearchForHeader;
break;
}
if(bytes.size() < 5) {
haveEnoughData = false;
break;
}
if(bytes[4] != 0x55) {
bytes.pop_front();
state = ReadState::SearchForHeader;
break;
}
if(bytes.size() < 7) {
haveEnoughData = false;
break;
}
packetLength = bytes[5] | (bytes[6] << 8);
checksum = false;
headerSize = 7;
packetLength += headerSize;
currentIndex += 6;
state = ReadState::GetData;
break;
case ReadState::GetData:
// We do not include the checksum in packetLength so it doesn't get copied into the payload buffer
@@ -149,25 +114,43 @@ bool Packetizer::input(RingBuffer& bytes) {
packet.data.clear();
if(packetLength > 0)
packet.data.resize(packetLength - headerSize);
bytes.read(packet.data.data(), currentIndex, (packetLength - currentIndex));
currentIndex = packetLength;
auto i = 0;
while(currentIndex < packetLength)
packet.data[i++] = bytes[currentIndex++];
if(disableChecksum || !checksum || bytes[currentIndex] == ICSChecksum(packet.data)) {
// Got a good packet
gotGoodPackets = true;
processedPackets.push_back(std::make_shared<Packet>(packet));
bytes.pop(packetLength);
if(packet.network == Network::NetID::DiskData && (packetLength - headerSize) % 2 == 0) {
for (auto a = 0; a < packetLength; a++)
bytes.pop_front();
}
} else {
if(gotGoodPackets) // Don't complain unless we've already gotten a good packet, in case we started in the middle of a stream
report(APIEvent::Type::PacketChecksumError, APIEvent::Severity::Error);
std::cerr << "====================================\n";
std::cerr << "A checksum error has occurred!\n";
std::cerr << "Packet: (" << std::dec << packet.data.size() << ") " << packet.network << '\n';
for(auto i = 0; i < packet.data.size(); i += 16) {
std::cerr << '\t';
for(auto j = 0; j < 16 && (i + j) < packet.data.size(); j++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(packet.data[i+j]) << ' ';
std::cerr << std::endl;
}
std::cerr << "Previous: (" << std::dec << previousPacket.data.size() << ") " << previousPacket.network << '\n';
for(auto i = 0; i < previousPacket.data.size(); i += 16) {
std::cerr << '\t';
for(auto j = 0; j < 16 && (i + j) < previousPacket.data.size(); j++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(previousPacket.data[i+j]) << ' ';
std::cerr << std::endl;
}
std::cerr << "====================================\n";
bytes.pop_front(); // Drop the first byte so it doesn't get picked up again
}
previousPacket = packet;
// Reset for the next packet
currentIndex = 0;
state = ReadState::SearchForHeader;
-91
View File
@@ -1,91 +0,0 @@
#include "icsneo/communication/ringbuffer.h"
#include <stdexcept>
namespace icsneo {
RingBuffer::RingBuffer(size_t bufferSize) : readCursor(0), writeCursor(0) {
// round the buffer size to the nearest power of 2
bufferSize = RoundUp(bufferSize);
mask = bufferSize - 1;
buf = new uint8_t[bufferSize];
}
RingBuffer::~RingBuffer() {
delete[] buf;
buf = nullptr;
}
const uint8_t& RingBuffer::operator[](size_t offset) const {
return get(offset);
}
size_t RingBuffer::size() const {
// The values in the cursors are monotonic, i.e. they only ever increment. They can be considered to be the total number of elements ever written or read
auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed);
auto currentReadCursor = readCursor.load(std::memory_order_relaxed);
// Using unmasked values, writeCursor is guaranteed to be >= readCursor. If they are equal that means the buffer is empty
return currentWriteCursor - currentReadCursor;
}
void RingBuffer::pop_front() {
pop(1);
}
void RingBuffer::pop(size_t count) {
if (size() < count) {
throw std::runtime_error("RingBuffer: Underflow");
}
readCursor.fetch_add(count, std::memory_order_release);
}
const uint8_t& RingBuffer::get(size_t offset) const {
if (offset >= size()) {
throw std::runtime_error("RingBuffer: Index out of range");
}
auto currentReadCursor = readCursor.load(std::memory_order_acquire);
return *resolve(currentReadCursor, offset);
}
bool RingBuffer::write(const uint8_t* addr, size_t length) {
const auto freeSpace = (capacity() - size());
if (length > freeSpace) {
return false;
}
auto currentWriteCursor = writeCursor.load(std::memory_order_relaxed);
auto spaceAtEnd = std::min(freeSpace, capacity() - (currentWriteCursor & mask)); // number of bytes from (masked) writeCursor to the end of the writable space (i.e. we reach the masked read cursor or the end of the buffer)
auto firstCopySize = std::min(spaceAtEnd, length);
(void)memcpy(resolve(currentWriteCursor, 0), addr, firstCopySize);
if (firstCopySize < length)
{
(void)memcpy(buf, &addr[firstCopySize], length - firstCopySize);
}
writeCursor.store(currentWriteCursor + length, std::memory_order_release);
return true;
}
bool RingBuffer::write(const std::vector<uint8_t>& source) {
return write(source.data(), source.size());
}
bool RingBuffer::read(uint8_t* dest, size_t startIndex, size_t length) const {
auto currentSize = size();
if ((startIndex >= currentSize) || ((startIndex + length) > size())) {
return false;
}
auto currentReadCursor = readCursor.load(std::memory_order_relaxed);
auto bytesAtEnd = std::min<size_t>(capacity() - ((currentReadCursor + startIndex) & mask), length);
const auto bytesAtStart = (length - bytesAtEnd);
(void)memcpy(dest, resolve(currentReadCursor, startIndex), bytesAtEnd);
if (bytesAtStart > 0) {
(void)memcpy(&dest[bytesAtEnd], buf, bytesAtStart);
}
return true;
}
void RingBuffer::clear() {
pop(size());
}
}
+69 -3043
View File
File diff suppressed because it is too large Load Diff
+173 -422
View File
@@ -1,422 +1,173 @@
#include "icsneo/device/devicefinder.h"
#include "icsneo/platform/devices.h"
#include "icsneo/device/founddevice.h"
#include "generated/extensions/builtin.h"
#ifdef ICSNEO_ENABLE_FIRMIO
#include "icsneo/platform/firmio.h"
#endif
#ifdef ICSNEO_ENABLE_RAW_ETHERNET
#include "icsneo/platform/pcap.h"
#endif
#ifdef ICSNEO_ENABLE_CDCACM
#include "icsneo/platform/cdcacm.h"
#endif
#ifdef ICSNEO_ENABLE_FTDI
#include "icsneo/platform/ftdi.h"
#endif
#ifdef ICSNEO_ENABLE_FTD3XX
#include "icsneo/platform/ftd3xx.h"
#endif
#ifdef ICSNEO_ENABLE_TCP
#include "icsneo/platform/tcp.h"
#endif
using namespace icsneo;
template<typename T>
static void makeIfSerialMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
// Relies on the subclass to have a `static constexpr const char* SERIAL_START = "XX"`
// and also a public constructor `T(const FoundDevice& dev)`
// Use macro ICSNEO_FINDABLE_DEVICE() to create these
if(dev.serial[0] == T::SERIAL_START[0] && dev.serial[1] == T::SERIAL_START[1])
into.push_back(std::make_shared<T>(dev));
}
template<typename T>
static void makeIfPIDMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
// Relies on the subclass to have a `static constexpr uint16_t PRODUCT_ID = 0x1111`
// and also a public constructor `T(const FoundDevice& dev)`
// Use macro ICSNEO_FINDABLE_DEVICE_BY_PID() to create these
if(dev.productId == T::PRODUCT_ID)
into.push_back(std::make_shared<T>(dev));
}
template<typename T>
static void makeIfSerialRangeMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
// Relies on the subclass to have
// `static constexpr uint32_t SERIAL_RANGE_LOW = 0x12345678`
// `static constexpr uint32_t SERIAL_RANGE_HIGH = 0x12345678`
// and also a public constructor `T(const FoundDevice& dev)`
// Use macro ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE() to create these
uint32_t serialNum = Device::SerialStringToNum(dev.serial);
if(serialNum >= Device::SerialStringToNum(T::SERIAL_RANGE_LOW) && serialNum <= Device::SerialStringToNum(T::SERIAL_RANGE_HIGH))
into.push_back(std::make_shared<T>(dev));
}
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
static std::vector<FoundDevice> newDriverFoundDevices;
newDriverFoundDevices.clear();
#ifdef ICSNEO_ENABLE_FIRMIO
FirmIO::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_TCP
TCP::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_RAW_ETHERNET
PCAP::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_CDCACM
CDCACM::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_FTDI
FTDI::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_FTD3XX
FTD3XX::Find(newDriverFoundDevices);
#endif
// Weak because we don't want to keep devices open if they go out of scope elsewhere
static std::vector<std::weak_ptr<Device>> foundDevices;
// Remove Devices that have dropped out of scope or are no longer present
for (auto it = foundDevices.begin(); it != foundDevices.end(); ) {
if (const auto device = it->lock()) {
if (std::none_of(newDriverFoundDevices.begin(), newDriverFoundDevices.end(),
[&](const auto& driverDevice) {
return std::string(driverDevice.serial) == device->getSerial();
}
)) {
it = foundDevices.erase(it); // Device not found by drivers but pointer has a >0 use_count, error?
} else {
++it; // Valid weak pointer and device found by drivers
}
} else {
it = foundDevices.erase(it); // Weak pointer has a zero use_count
}
}
// Remove existing driver devices so we only create new ones
for (auto it = newDriverFoundDevices.begin(); it != newDriverFoundDevices.end(); ) {
if (std::any_of(foundDevices.begin(), foundDevices.end(),
[&](const auto& weakDevice) {
const auto device = weakDevice.lock();
return device && std::string(it->serial) == device->getSerial();
}
)) {
it = newDriverFoundDevices.erase(it);
} else {
++it;
}
}
std::vector<std::shared_ptr<Device>> newFoundDevices;
newFoundDevices.reserve(newDriverFoundDevices.size());
// Offer found devices to each of the subclasses
for (const FoundDevice& dev : newDriverFoundDevices) {
#ifdef __ETHERBADGE_H_
makeIfSerialMatches<EtherBADGE>(dev, newFoundDevices);
#endif
#ifdef __NEOOBD2PRO_H_
makeIfSerialMatches<NeoOBD2PRO>(dev, newFoundDevices);
#endif
#ifdef __NEOOBD2SIM_H_
makeIfSerialMatches<NeoOBD2SIM>(dev, newFoundDevices);
#endif
#ifdef __NEOVICONNECT_H_
makeIfSerialMatches<NeoVIConnect>(dev, newFoundDevices);
#endif
#ifdef __NEOVIFIRE_H_
makeIfPIDMatches<NeoVIFIRE>(dev, newFoundDevices);
#endif
#ifdef __NEOVIFIRE2_H_
makeIfSerialMatches<NeoVIFIRE2>(dev, newFoundDevices);
#endif
#ifdef __NEOVIFIRE3_H_
makeIfSerialMatches<NeoVIFIRE3>(dev, newFoundDevices);
#endif
#ifdef __NEOVIFIRE3FLEXRAY_H_
makeIfSerialMatches<NeoVIFIRE3FlexRay>(dev, newFoundDevices);
#endif
#ifdef __NEOVIRED2_H_
makeIfSerialMatches<NeoVIRED2>(dev, newFoundDevices);
#endif
#ifdef __NEOVIION_H_
makeIfPIDMatches<NeoVIION>(dev, newFoundDevices);
#endif
#ifdef __NEOVIPLASMA_H_
makeIfPIDMatches<NeoVIPLASMA>(dev, newFoundDevices);
#endif
#ifdef __RADA2B_H_
makeIfSerialMatches<RADA2B>(dev, newFoundDevices);
#endif
#ifdef __RADCOMET_H_
makeIfSerialRangeMatches<RADComet>(dev, newFoundDevices);
#endif
#ifdef __RADCOMET2_H_
makeIfSerialRangeMatches<RADComet2>(dev, newFoundDevices);
#endif
#ifdef __RADCOMET3_H_
makeIfSerialMatches<RADComet3>(dev, newFoundDevices);
#endif
#ifdef __RADMOONT1S_H_
makeIfSerialMatches<RADMoonT1S>(dev, newFoundDevices);
#endif
#ifdef __RADEPSILON_H_
makeIfSerialMatches<RADEpsilon>(dev, newFoundDevices);
#endif
#ifdef __RADGALAXY_H_
makeIfSerialMatches<RADGalaxy>(dev, newFoundDevices);
#endif
#ifdef __RADMARS_H_
makeIfSerialMatches<RADMars>(dev, newFoundDevices);
#endif
#ifdef __RADGIGASTAR_H_
makeIfSerialMatches<RADGigastar>(dev, newFoundDevices);
#endif
#ifdef __RADGIGASTAR2_H_
makeIfSerialMatches<RADGigastar2>(dev, newFoundDevices);
#endif
#ifdef __RADJUPITER_H_
makeIfSerialMatches<RADJupiter>(dev, newFoundDevices);
#endif
#ifdef __RADMOON2_H_
makeIfSerialMatches<RADMoon2>(dev, newFoundDevices);
#endif
#ifdef __RADMOON2ZL_H_
makeIfSerialMatches<RADMoon2ZL>(dev, newFoundDevices);
#endif
#ifdef __RADMOON3_H_
makeIfSerialMatches<RADMoon3>(dev, newFoundDevices);
#endif
#ifdef __RADMOONDUO_H_
makeIfSerialMatches<RADMoonDuo>(dev, newFoundDevices);
#endif
#ifdef __RADPLUTO_H_
makeIfSerialMatches<RADPluto>(dev, newFoundDevices);
#endif
#ifdef __RADSTAR2_H_
makeIfSerialMatches<RADStar2>(dev, newFoundDevices);
#endif
#ifdef __RADSUPERMOON_H_
makeIfSerialMatches<RADSupermoon>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN3_H_
makeIfPIDMatches<ValueCAN3>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN4_1_H_
makeIfSerialMatches<ValueCAN4_1>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN4_2_H_
makeIfSerialMatches<ValueCAN4_2>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN4_2EL_H_
makeIfSerialMatches<ValueCAN4_2EL>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN4_4_H_
makeIfSerialMatches<ValueCAN4_4>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN4INDUSTRIAL_H_
makeIfSerialMatches<ValueCAN4Industrial>(dev, newFoundDevices);
#endif
#ifdef __VIVIDCAN_H_
makeIfSerialMatches<VividCAN>(dev, newFoundDevices);
#endif
}
for(auto& device : newFoundDevices) {
AddBuiltInExtensionsTo(device);
}
// Grab a weak pointer from the new devices
foundDevices.insert(foundDevices.end(), newFoundDevices.begin(), newFoundDevices.end());
// Upgrade to shared for the return
return std::vector<std::shared_ptr<Device>>(foundDevices.begin(), foundDevices.end());
}
const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
static std::vector<DeviceType> supportedDevices = {
#ifdef __ETHERBADGE_H_
EtherBADGE::DEVICE_TYPE,
#endif
#ifdef __NEOOBD2PRO_H_
NeoOBD2PRO::DEVICE_TYPE,
#endif
#ifdef __NEOOBD2SIM_H_
NeoOBD2SIM::DEVICE_TYPE,
#endif
#ifdef __NEOVIRED2_H_
NeoVIRED2::DEVICE_TYPE,
#endif
#ifdef __NEOVICONNECT_H_
NeoVIConnect::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE_H_
NeoVIFIRE::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE2_H_
NeoVIFIRE2::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE3_H_
NeoVIFIRE3::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE3FLEXRAY_H_
NeoVIFIRE3FlexRay::DEVICE_TYPE,
#endif
#ifdef __NEOVIION_H_
NeoVIION::DEVICE_TYPE,
#endif
#ifdef __NEOVIPLASMA_H_
NeoVIPLASMA::DEVICE_TYPE,
#endif
#ifdef __RADA2B_H_
RADA2B::DEVICE_TYPE,
#endif
#ifdef __RADCOMET_H_
RADComet::DEVICE_TYPE,
#endif
#ifdef __RADCOMET3_H_
RADComet3::DEVICE_TYPE,
#endif
#ifdef __RADMOONT1S_H_
RADMoonT1S::DEVICE_TYPE,
#endif
#ifdef __RADEPSILON_H_
RADEpsilon::DEVICE_TYPE,
#endif
#ifdef __RADGALAXY_H_
RADGalaxy::DEVICE_TYPE,
#endif
#ifdef __RADMARS_H_
RADMars::DEVICE_TYPE,
#endif
#ifdef __RADGIGASTAR_H_
RADGigastar::DEVICE_TYPE,
#endif
#ifdef __RADGIGASTAR2_H_
RADGigastar2::DEVICE_TYPE,
#endif
#if defined __RADMOON2_H_ || defined __RADMOON2ZL_H_
RADMoon2::DEVICE_TYPE,
#endif
#ifdef __RADMOON3_H_
RADMoon3::DEVICE_TYPE,
#endif
#ifdef __RADMOONDUO_H_
RADMoonDuo::DEVICE_TYPE,
#endif
#ifdef __RADPLUTO_H_
RADPluto::DEVICE_TYPE,
#endif
#ifdef __RADSTAR2_H_
RADStar2::DEVICE_TYPE,
#endif
#ifdef __RADSUPERMOON_H_
RADSupermoon::DEVICE_TYPE,
#endif
#ifdef __VALUECAN3_H_
ValueCAN3::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_1_H_
ValueCAN4_1::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_2_H_
ValueCAN4_2::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_2EL_H_
ValueCAN4_2EL::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_4_H_
ValueCAN4_4::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4INDUSTRIAL_H_
ValueCAN4Industrial::DEVICE_TYPE,
#endif
#ifdef __VIVIDCAN_H_
VividCAN::DEVICE_TYPE,
#endif
};
return supportedDevices;
}
#include "icsneo/device/devicefinder.h"
#include "icsneo/platform/devices.h"
using namespace icsneo;
static bool supportedDevicesCached = false;
static std::vector<DeviceType> supportedDevices = {
#ifdef __NEOOBD2PRO_H_
NeoOBD2PRO::DEVICE_TYPE,
#endif
#ifdef __NEOOBD2SIM_H_
NeoOBD2SIM::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE_H_
NeoVIFIRE::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE2ETH_H_
NeoVIFIRE2ETH::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE2USB_H_
NeoVIFIRE2USB::DEVICE_TYPE,
#endif
#ifdef __NEOVIION_H_
NeoVIION::DEVICE_TYPE,
#endif
#ifdef __NEOVIPLASMA_H_
NeoVIPLASMA::DEVICE_TYPE,
#endif
#ifdef __RADGALAXY_H_
RADGalaxy::DEVICE_TYPE,
#endif
#ifdef __RADPLUTOUSB_H_
RADPlutoUSB::DEVICE_TYPE,
#endif
#ifdef __RADSTAR2ETH_H_
RADStar2ETH::DEVICE_TYPE,
#endif
#ifdef __RADSTAR2USB_H_
RADStar2USB::DEVICE_TYPE,
#endif
#ifdef __RADSUPERMOON_H_
RADSupermoon::DEVICE_TYPE,
#endif
#ifdef __VALUECAN3_H_
ValueCAN3::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_1_H_
ValueCAN4_1::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_2_H_
ValueCAN4_2::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_2EL_H_
ValueCAN4_2EL::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_4_H_
ValueCAN4_4::DEVICE_TYPE,
#endif
#ifdef __VIVIDCAN_H_
VividCAN::DEVICE_TYPE,
#endif
};
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
std::vector<std::shared_ptr<Device>> foundDevices;
std::vector<std::vector<std::shared_ptr<Device>>> findResults;
#ifdef __NEOOBD2PRO_H_
findResults.push_back(NeoOBD2PRO::Find());
#endif
#ifdef __NEOOBD2SIM_H_
findResults.push_back(NeoOBD2SIM::Find());
#endif
#ifdef __NEOVIFIRE_H_
findResults.push_back(NeoVIFIRE::Find());
#endif
#ifdef __NEOVIFIRE2ETH_H_
findResults.push_back(NeoVIFIRE2ETH::Find());
#endif
#ifdef __NEOVIFIRE2USB_H_
findResults.push_back(NeoVIFIRE2USB::Find());
#endif
#ifdef __NEOVIION_H_
findResults.push_back(NeoVIION::Find());
#endif
#ifdef __NEOVIPLASMA_H_
findResults.push_back(NeoVIPLASMA::Find());
#endif
#ifdef __RADGALAXY_H_
findResults.push_back(RADGalaxy::Find());
#endif
#ifdef __RADPLUTOUSB_H_
findResults.push_back(RADPlutoUSB::Find());
#endif
#ifdef __RADSTAR2ETH_H_
findResults.push_back(RADStar2ETH::Find());
#endif
#ifdef __RADSTAR2USB_H_
findResults.push_back(RADStar2USB::Find());
#endif
#ifdef __RADSUPERMOON_H_
findResults.push_back(RADSupermoon::Find());
#endif
#ifdef __VALUECAN3_H_
findResults.push_back(ValueCAN3::Find());
#endif
#ifdef __VALUECAN4_1_H_
findResults.push_back(ValueCAN4_1::Find());
#endif
#ifdef __VALUECAN4_2_H_
findResults.push_back(ValueCAN4_2::Find());
#endif
#ifdef __VALUECAN4_2EL_H_
findResults.push_back(ValueCAN4_2EL::Find());
#endif
#ifdef __VALUECAN4_4_H_
findResults.push_back(ValueCAN4_4::Find());
#endif
#ifdef __VIVIDCAN_H_
findResults.push_back(VividCAN::Find());
#endif
for(auto& results : findResults) {
if(results.size())
foundDevices.insert(foundDevices.end(), std::make_move_iterator(results.begin()), std::make_move_iterator(results.end()));
}
return foundDevices;
}
const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
if(!supportedDevicesCached) {
supportedDevices.erase(std::unique(supportedDevices.begin(), supportedDevices.end()), supportedDevices.end());
supportedDevicesCached = true;
}
return supportedDevices;
}
+30 -615
View File
@@ -3,464 +3,28 @@
using namespace icsneo;
void FlexRay::Controller::_setStatus(std::shared_ptr<FlexRayControlMessage> msg) {
std::lock_guard<std::mutex> lk(statusLock);
status = msg;
}
std::shared_ptr<FlexRayControlMessage> FlexRay::Controller::getStatus() const {
std::lock_guard<std::mutex> lk(statusLock);
return status;
}
std::pair<const FlexRay::Cluster::Configuration&, const FlexRay::Controller::Configuration&> FlexRay::Controller::getConfiguration() const {
return { clusterConfig, controllerConfig };
void FlexRay::Controller::_setStatus(std::shared_ptr<FlexRayControlMessage> msg) {
std::lock_guard<std::mutex> lk(statusLock);
status = msg;
}
void FlexRay::Controller::setConfiguration(Cluster::Configuration clConfig, Controller::Configuration coConfig) {
configDirty = true;
clusterConfig = clConfig;
controllerConfig = coConfig;
void FlexRay::Controller::getReady() {
}
void FlexRay::Controller::addMessageBuffer(MessageBuffer buffer) {
configDirty = true;
messageBuffers.emplace_back(std::make_shared<MessageBuffer>(buffer));
}
void FlexRay::Controller::clearMessageBuffers() {
configDirty = true;
messageBuffers.clear();
}
bool FlexRay::Controller::wakeup(std::chrono::milliseconds timeout) {
return setCurrentPOCCommand(FlexRay::POCCommand::Wakeup, true, timeout);
}
bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
const auto initialTimeout = timeout;
const auto functionBegin = std::chrono::steady_clock::now();
const auto updateTimeout = [&initialTimeout, &functionBegin, &timeout]() {
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(initialTimeout - (std::chrono::steady_clock::now() - functionBegin));
};
auto statusPair = getCurrentPOCStatus(timeout);
const auto& pocStatus = statusPair.second;
if(!statusPair.first)
return false;
updateTimeout();
if(pocStatus != POCStatus::Config) {
if(!enterConfig(timeout))
return false;
updateTimeout();
}
if(!setCurrentPOCCommand(POCCommand::ClearRAMs, true, timeout))
return false;
const auto start = std::chrono::steady_clock::now();
bool carbusy = isClearAllRAMBusy();
while(carbusy && (std::chrono::steady_clock::now() - start) < timeout) {
carbusy = isClearAllRAMBusy();
}
if(carbusy) // timeout
return false;
updateTimeout();
std::vector<std::pair<ERAYRegister, uint32_t>> registerWrites;
registerWrites.reserve(18);
registerWrites.push_back({ ERAYRegister::SUCC1,
((controllerConfig.KeySlotUsedForStartup & 0x1) << 8) | // TXST
((controllerConfig.KeySlotUsedForSync & 0x1) << 9) | // TXSY
((clusterConfig.ColdStartAttempts & 0x1f) << 11) | // CSA
((controllerConfig.AllowPassiveToActiveCyclePairs & 0x1f) << 16) | // PTA
((controllerConfig.WakeupOnChannelB & 0x1) << 21) | // WUCS
((controllerConfig.KeySlotOnlyEnabled & 0x1) << 22) | // TSM
((controllerConfig.AllowHaltDueToClock & 0x1) << 23) | // HCSE
((controllerConfig.MTSOnA & 0x1) << 24) | // MTSA
((controllerConfig.MTSOnB & 0x1) << 25) | // MTSB
((controllerConfig.ChannelA & 0x1) << 26) | // CCHA
((controllerConfig.ChannelB & 0x1) << 27) // CCHB
});
registerWrites.push_back({ ERAYRegister::SUCC2,
((controllerConfig.ListenTimeout & 0x1fffff)) |
((clusterConfig.ListenNoiseMacroticks - 1) << 24)
});
registerWrites.push_back({ ERAYRegister::SUCC3,
(clusterConfig.MaxWithoutClockCorrectionPassive & 0xF) |
((clusterConfig.MaxWithoutClockCorrectionFatal) << 4)
});
registerWrites.push_back({ ERAYRegister::NEMC,
clusterConfig.NetworkManagementVectorLengthBytes
});
registerWrites.push_back({ ERAYRegister::PRTC1,
(clusterConfig.TransmissionStartSequenceDurationBits & 0xF) |
((clusterConfig.CASRxLowMax & 0x3F) << 4) |
((clusterConfig.StrobePointPosition & 0x3) << 12) |
((clusterConfig.Speed & 0x3) << 14) |
((clusterConfig.WakeupRxWindowBits & 0x1ff) << 16) |
((controllerConfig.WakeupPattern) << 26)
});
registerWrites.push_back({ ERAYRegister::PRTC2,
(clusterConfig.WakeupRxIdleBits) |
((clusterConfig.WakeupRxLowBits) << 8) |
((clusterConfig.WakeupTxIdleBits) << 16) |
((clusterConfig.WakeupTxActiveBits) << 24)
});
registerWrites.push_back({ ERAYRegister::MHDC,
(clusterConfig.PayloadLengthOfStaticSlotInWords) |
((controllerConfig.LatestTxMinislot) << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC1,
controllerConfig.MicroPerCycle
});
registerWrites.push_back({ ERAYRegister::GTUC2,
(clusterConfig.SyncFrameIDCountMax << 16) |
clusterConfig.MacroticksPerCycle
});
registerWrites.push_back({ ERAYRegister::GTUC3,
(controllerConfig.MicroInitialOffsetA) |
((controllerConfig.MicroInitialOffsetB) << 8) |
((controllerConfig.MacroInitialOffsetA) << 16) |
((controllerConfig.MacroInitialOffsetB) << 24)
});
registerWrites.push_back({ ERAYRegister::GTUC4,
((clusterConfig.MacroticksPerCycle - clusterConfig.NetworkIdleTimeMacroticks - 1) & 0xFFFF) |
((clusterConfig.OffsetCorrectionStartMacroticks - 1) << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC5,
controllerConfig.DelayCompensationAMicroticks |
(controllerConfig.DelayCompensationBMicroticks << 8) |
(controllerConfig.ClusterDriftDamping << 16) |
(controllerConfig.DecodingCorrectionMicroticks << 24)
});
registerWrites.push_back({ ERAYRegister::GTUC6,
controllerConfig.AcceptStartupRangeMicroticks |
(controllerConfig.RateCorrectionOutMicroticks << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC7,
(clusterConfig.StaticSlotMacroticks) |
(clusterConfig.NumberOfStaticSlots << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC8,
clusterConfig.MinislotDurationMacroticks |
(clusterConfig.NumberOfMinislots << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC9,
clusterConfig.ActionPointOffset |
(clusterConfig.MinislotActionPointOffsetMacroticks << 8) |
(clusterConfig.DynamicSlotIdlePhaseMinislots << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC10,
controllerConfig.OffsetCorrectionOutMicroticks |
(controllerConfig.RateCorrectionOutMicroticks << 16)
});
registerWrites.push_back({ ERAYRegister::GTUC11,
controllerConfig.ExternOffsetCorrectionControl |
(controllerConfig.ExternRateCorrectionControl << 8) |
(controllerConfig.ExternOffsetCorrectionMicroticks << 16) |
(controllerConfig.ExternRateCorrectionMicroticks << 24)
});
std::vector<std::shared_ptr<MessageBuffer>> staticTx;
std::vector<std::shared_ptr<MessageBuffer>> dynamicTx;
// Add key slot messages
std::shared_ptr<MessageBuffer> first = std::make_shared<MessageBuffer>();
bool firstIsInMessageBuffers = false;
bool firstUsed = false;
std::shared_ptr<MessageBuffer> second = std::make_shared<MessageBuffer>();
bool secondIsInMessageBuffers = false;
bool secondUsed = false;
if(controllerConfig.KeySlotUsedForSync || controllerConfig.KeySlotOnlyEnabled) {
first->isStartup = controllerConfig.KeySlotUsedForStartup;
first->isSync = controllerConfig.KeySlotUsedForSync;
first->isTransmit = true;
first->channelA = true;
first->channelB = !controllerConfig.TwoKeySlotMode && controllerConfig.ChannelB;
first->frameID = controllerConfig.KeySlotID;
first->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
first->baseCycle = 0;
first->cycleRepetition = 1;
first->continuousMode = false;
staticTx.push_back(first);
firstUsed = true;
if(controllerConfig.TwoKeySlotMode) {
second->isStartup = controllerConfig.KeySlotUsedForStartup;
second->isSync = controllerConfig.KeySlotUsedForSync;
second->isTransmit = true;
second->channelB =true;
second->frameID = controllerConfig.SecondKeySlotID;
second->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
second->baseCycle = 0;
second->cycleRepetition = 1;
second->continuousMode = false;
staticTx.push_back(second);
secondUsed = true;
}
}
for(auto& buf : messageBuffers) {
if(!buf->isTransmit)
continue; // Only transmit frames need to be written to the controller
if((controllerConfig.KeySlotUsedForSync || controllerConfig.KeySlotOnlyEnabled) && buf->frameID == controllerConfig.KeySlotID) {
first = buf;
staticTx[0] = buf;
// Enforce keyslot rules
first->isStartup = controllerConfig.KeySlotUsedForStartup;
first->isSync = controllerConfig.KeySlotUsedForSync;
first->isDynamic = false;
// Suppress default buffer
firstIsInMessageBuffers = true;
continue;
}
else if(controllerConfig.TwoKeySlotMode && buf->frameID == controllerConfig.SecondKeySlotID) {
second = buf;
staticTx[1] = buf;
buf->isDynamic = false;
// Enforce keyslot rules
second->isStartup = controllerConfig.KeySlotUsedForStartup;
second->isSync = controllerConfig.KeySlotUsedForSync;
second->isDynamic = false;
// Suppress default buffer
secondIsInMessageBuffers = true;
continue;
}
if(buf->isDynamic)
dynamicTx.push_back(buf);
else
staticTx.push_back(buf);
}
// If the user is using the default coldstart messages, they need to be added to the list for transmit
if(firstUsed && !firstIsInMessageBuffers)
messageBuffers.push_back(first);
if(secondUsed && !secondIsInMessageBuffers)
messageBuffers.push_back(second);
int64_t totalBuffers = staticTx.size() + dynamicTx.size();
if(totalBuffers > 128) // TODO warn
totalBuffers = 128;
registerWrites.push_back({ ERAYRegister::MRC,
(uint8_t(staticTx.size())) | // FDB[7:0] message buffers exclusively for the static segment
// FFB[7:0] set to 0x80, No message buffer assigned to the FIFO
(0x80 << 8) |
(uint8_t(totalBuffers - 1) << 16) |
(controllerConfig.TwoKeySlotMode << 26)
});
for(const auto& regpair : registerWrites) {
if(!writeRegister(regpair.first, regpair.second, false, timeout))
return false;
updateTimeout();
}
uint16_t dataPointer = static_cast<uint16_t>((totalBuffers + 1) * 4);
for(uint16_t i = 0; i < totalBuffers; i++) {
MessageBuffer& buf = *(i < (int)staticTx.size() ? staticTx[i] : dynamicTx[i - staticTx.size()]);
if(buf.frameID == 0)
buf.frameID = static_cast<uint16_t>(i | (1 << 10));
uint32_t hs1 = (
(buf.frameID) |
(CalculateCycleFilter(buf.baseCycle, buf.cycleRepetition) << 16) |
((buf.channelA & 0x1) << 24) |
((buf.channelB & 0x1) << 25) |
((buf.isTransmit & 0x1) << 26) | // CFG
((buf.isNMFrame & 0x1) << 27) | // PPIT
((!buf.continuousMode & 0x1) << 28) | // TXM
((0 & 0x1) << 29) // MBI, disabled for now but we might want confirmations in the future
);
uint32_t hs2 = (
CalculateHCRC(buf) |
(((buf.frameLengthBytes + 1) / 2) << 16)
);
uint32_t hs3 = dataPointer;
buf._dataPointer = dataPointer;
buf._id = i;
dataPointer += buf.frameLengthBytes / 4;
dataPointer += dataPointer % 4; // must be a 4 byte boundary
if(!writeRegister(ERAYRegister::WRHS1, hs1, true, timeout))
return false;
updateTimeout();
if(!writeRegister(ERAYRegister::WRHS2, hs2, true, timeout))
return false;
updateTimeout();
if(!writeRegister(ERAYRegister::WRHS3, hs3, true, timeout))
return false;
updateTimeout();
if(!writeRegister(ERAYRegister::IBCM, 1, true, timeout))
return false;
const auto ibcmstart = std::chrono::steady_clock::now();
bool ibcmbusy = isInputBufferHostBusy();
while(ibcmbusy && (std::chrono::steady_clock::now() - ibcmstart) < timeout) {
ibcmbusy = isInputBufferHostBusy();
}
if(ibcmbusy) // timeout
return false;
updateTimeout();
if(!writeRegister(ERAYRegister::IBCR, i, true, timeout))
return false;
updateTimeout();
}
configDirty = false;
return true;
}
bool FlexRay::Controller::getReady(std::chrono::milliseconds timeout) {
const auto initialTimeout = timeout;
const auto functionBegin = std::chrono::steady_clock::now();
const auto updateTimeout = [&initialTimeout, &functionBegin, &timeout]() {
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(initialTimeout - (std::chrono::steady_clock::now() - functionBegin));
};
// Initial sanity check that we have communication with the controller
auto endian = readRegister(ERAYRegister::ENDN, timeout);
if (!endian.first || endian.second != 0x87654321)
return false;
updateTimeout();
auto statusPair = getCurrentPOCStatus(timeout);
const auto& pocStatus = statusPair.second;
if(!statusPair.first)
return false;
updateTimeout();
if(pocStatus == POCStatus::Ready && !configDirty) {
// Already in the desired state
if(allowColdstart && !setCurrentPOCCommand(FlexRay::POCCommand::AllowColdstart, true, timeout))
return false;
return true;
}
if(pocStatus != POCStatus::Config) {
// Must enter config before continuing
if(!enterConfig(timeout))
return false;
updateTimeout();
// Reconfigure if necessary
if(configDirty && !configure(timeout))
return false;
updateTimeout();
}
// Enter the READY state
if(!lockConfiguration(timeout))
return false;
updateTimeout();
// Signal that we'd like to coldstart, if necessary
if(allowColdstart && !setCurrentPOCCommand(FlexRay::POCCommand::AllowColdstart, true, timeout))
return false;
return true;
}
bool FlexRay::Controller::start(std::chrono::milliseconds timeout) {
const auto initialTimeout = timeout;
const auto functionBegin = std::chrono::steady_clock::now();
const auto updateTimeout = [&initialTimeout, &functionBegin, &timeout]() {
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(initialTimeout - (std::chrono::steady_clock::now() - functionBegin));
};
// First make sure we're ready to start (configured/ready state)
if(!getReady(timeout))
return false;
updateTimeout();
// Wakeup the network if necessary
if(wakeupBeforeStart && !wakeup(timeout))
return false;
updateTimeout();
// And finally run
if(!setCurrentPOCCommand(FlexRay::POCCommand::Run, false, timeout))
return false;
return true;
}
bool FlexRay::Controller::transmit(const std::shared_ptr<FlexRayMessage>& frmsg) {
bool success = false;
for(const auto& buf : messageBuffers) {
if(!buf->isTransmit)
continue;
if(frmsg->slotid != buf->frameID)
continue;
if(CalculateCycleFilter(frmsg->cycle, frmsg->cycleRepetition) != CalculateCycleFilter(buf->baseCycle, buf->cycleRepetition))
continue;
FlexRay::Channel bufChannel = FlexRay::Channel::None;
if(buf->channelA && buf->channelB)
bufChannel = FlexRay::Channel::AB;
else if(buf->channelA)
bufChannel = FlexRay::Channel::A;
else if(buf->channelB)
bufChannel = FlexRay::Channel::B;
if(frmsg->channel != bufChannel)
continue;
// If we have added changed our configuration, such as adding a message buffer, we will need to reconfigure
if(configDirty && lastSeenRunning)
start();
// This is a message buffer we want to fill
if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteMessageBufferArgs(index, buf->_id, frmsg->data, buf->frameLengthBytes)))
continue;
success = true;
}
return success;
}
bool FlexRay::Controller::halt(std::chrono::milliseconds timeout) {
return setCurrentPOCCommand(POCCommand::Halt, true, timeout);
}
bool FlexRay::Controller::freeze(std::chrono::milliseconds timeout) {
return setCurrentPOCCommand(POCCommand::Freeze, true, timeout);
}
bool FlexRay::Controller::triggerMTS(std::chrono::milliseconds timeout) {
// triggerMTS will do nothing unless either MTSOnA or MTSOnB (or both) are set at configure time
return setCurrentPOCCommand(POCCommand::SendMTS, true, timeout);
void FlexRay::Controller::start() {
if(true) // TODO something
getReady();
if(wakeupBeforeStart)
setCurrentPOCCommand(FlexRay::POCCommand::Wakeup);
if(allowColdstart)
setCurrentPOCCommand(FlexRay::POCCommand::AllowColdstart);
setCurrentPOCCommand(FlexRay::POCCommand::Run);
}
std::pair<bool, FlexRay::POCCommand> FlexRay::Controller::getCurrentPOCCommand(std::chrono::milliseconds timeout) const {
@@ -470,176 +34,38 @@ std::pair<bool, FlexRay::POCCommand> FlexRay::Controller::getCurrentPOCCommand(s
bool FlexRay::Controller::setCurrentPOCCommand(FlexRay::POCCommand cmd, bool checkForSuccess, std::chrono::milliseconds timeout) {
const auto beforeWrite = std::chrono::steady_clock::now();
if(!writeRegister(ERAYRegister::SUCC1, uint32_t(cmd), 0xF, true, timeout))
if(!writeRegister(ERAYRegister::SUCC1, uint32_t(cmd), true, timeout))
return false;
if(!checkForSuccess)
return true;
const auto writeDuration = std::chrono::steady_clock::now() - beforeWrite;
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - writeDuration);
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(writeDuration - timeout);
if(timeout.count() <= 0)
return false; // Out of time!
const bool success = wasCommandSuccessful(timeout);
if(success) {
switch(cmd) {
case FlexRay::POCCommand::Run:
lastSeenRunning = true;
break;
case FlexRay::POCCommand::Halt:
case FlexRay::POCCommand::Freeze:
lastSeenRunning = false;
break;
default: break;
}
}
return success;
return wasCommandSuccessful(timeout);
}
bool FlexRay::Controller::wasCommandSuccessful(std::chrono::milliseconds timeout) const {
const auto start = std::chrono::steady_clock::now();
bool pocBusy = isPOCBusy();
while(pocBusy && (std::chrono::steady_clock::now() - start) < timeout) {
pocBusy = isPOCBusy();
}
if(pocBusy) // timeout
return false;
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - (std::chrono::steady_clock::now() - start));
const auto val = getCurrentPOCCommand(timeout);
return val.first && val.second != FlexRay::POCCommand::CommandNotAccepted;
}
std::pair<bool, FlexRay::POCStatus> FlexRay::Controller::getCurrentPOCStatus(std::chrono::milliseconds timeout) const {
auto regpair = readRegister(ERAYRegister::CCSV, timeout);
return { regpair.first, FlexRay::POCStatus(regpair.second & 0x3F) };
}
bool FlexRay::Controller::lockConfiguration(std::chrono::milliseconds timeout) {
// This is not anything super special, just the way to get the ERAY out of POC:config
// See the ERAY Users Manaual section 4.3.1
auto beforeWrite = std::chrono::steady_clock::now();
if(!writeRegister(ERAYRegister::LCK, 0xCE, true, timeout))
return false;
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - (std::chrono::steady_clock::now() - beforeWrite));
if(timeout.count() <= 0)
return false; // Out of time!
beforeWrite = std::chrono::steady_clock::now();
if(!writeRegister(ERAYRegister::LCK, 0x31, true, timeout))
return false;
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - (std::chrono::steady_clock::now() - beforeWrite));
return setCurrentPOCCommand(POCCommand::Ready, true, timeout);
}
bool FlexRay::Controller::enterConfig(std::chrono::milliseconds timeout) {
const auto initialTimeout = timeout;
const auto functionBegin = std::chrono::steady_clock::now();
const auto updateTimeout = [&initialTimeout, &functionBegin, &timeout]() {
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(initialTimeout - (std::chrono::steady_clock::now() - functionBegin));
};
auto statusPair = getCurrentPOCStatus(timeout);
const auto& pocStatus = statusPair.second;
if(!statusPair.first)
return false;
updateTimeout();
if(pocStatus != FlexRay::POCStatus::Ready &&
pocStatus != FlexRay::POCStatus::Config &&
pocStatus != FlexRay::POCStatus::DefaultConfig &&
pocStatus != FlexRay::POCStatus::Halt) {
if(!setCurrentPOCCommand(FlexRay::POCCommand::Freeze, true, timeout))
return false;
updateTimeout();
}
// If we're halted, we first go into DEFAULT_CONFIG before entering CONFIG
// Unintuitively, this enters DEFAULT_CONFIG
if(!setCurrentPOCCommand(FlexRay::POCCommand::Config, true, timeout))
return false;
updateTimeout();
// Now this enters CONFIG
return setCurrentPOCCommand(FlexRay::POCCommand::Config, true, timeout);
}
uint16_t FlexRay::Controller::CalculateHCRC(const MessageBuffer& buf) {
uint16_t ret = 0x1A;
auto addBit = [&ret](uint8_t bit) {
bit = bit ? 1 : 0;
int crcNxt; //CRCNXT = NXTBIT EXOR CRC_RG(14);
if (ret & (1<<10))
crcNxt = bit ^ 1;
else
crcNxt = bit ^ 0;
crcNxt &= 0x01;
// CRC_RG(14:1) = CRC_RG(13:0); // shift left by
ret <<= 1;
ret &= 0x7FE; // clear first bit
if (crcNxt) //CRC_RG(14:0) = CRC_RG(14:0) EXOR (4599hex);
ret ^= 0x385;
};
addBit(buf.isStartup);
addBit(buf.isSync);
for(auto i = 0; i < 11; i++)
addBit(buf.frameID & (1 << (10 - i)));
for(auto i = 0; i < 7; i++)
addBit(((buf.frameLengthBytes + 1) / 2) & (1 << (6 - i)));
return ret;
}
uint16_t FlexRay::Controller::CalculateCycleFilter(uint8_t baseCycle, uint8_t cycleRepetition) {
uint8_t cycleRepCode = 0;
switch(cycleRepetition) {
case 1: cycleRepCode = 0b1; break;
case 2: cycleRepCode = 0b10; break;
case 4: cycleRepCode = 0b100; break;
case 8: cycleRepCode = 0b1000; break;
case 16: cycleRepCode = 0b10000; break;
case 32: cycleRepCode = 0b100000; break;
case 64: cycleRepCode = 0b1000000; break;
}
return (cycleRepCode | baseCycle);
}
std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, std::chrono::milliseconds timeout) const {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(icsneo::Network::NetID::FlexRayControl);
if(timeout.count() <= 20)
return {false, 0}; // Out of time!
std::lock_guard<std::mutex> lk(readRegisterLock);
device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildReadCCRegsArgs(index, uint16_t(reg)));
std::shared_ptr<FlexRayControlMessage> resp;
std::chrono::steady_clock::time_point lastSent;
do {
const auto waitTime = std::chrono::steady_clock::now();
auto msg = device.com->waitForMessageSync([this, &lastSent, &reg, &timeout]() {
if(timeout.count() < 20)
return true; // Might not have time to receive the response, so don't request
if(std::chrono::steady_clock::now() - lastSent < std::chrono::milliseconds(40))
return true; // Don't send too fast
if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildReadCCRegsArgs(index, uint16_t(reg))))
return false; // Command failed to send
lastSent = std::chrono::steady_clock::now();
return true;
}, filter, timeout);
const auto start = std::chrono::steady_clock::now();
while(!resp && (std::chrono::steady_clock::now() - start) < timeout) {
auto msg = device.com->waitForMessageSync(MessageFilter(icsneo::Network::NetID::FlexRayControl), timeout);
if(auto frmsg = std::dynamic_pointer_cast<FlexRayControlMessage>(msg)) {
if(frmsg->decoded && frmsg->controller == index && frmsg->opcode == FlexRay::Opcode::ReadCCRegs)
resp = frmsg;
}
if(resp)
break;
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - waitTime);
} while(timeout.count() > 0);
if(resp && !resp->registers.empty())
}
if(resp)
return {true, resp->registers[0]};
else
return {false, 0};
@@ -657,23 +83,15 @@ bool FlexRay::Controller::writeRegister(
bool waitForPOCReady,
std::chrono::milliseconds timeout) {
if(waitForPOCReady) {
const auto start = std::chrono::steady_clock::now();
bool pocBusy = isPOCBusy();
while(pocBusy && (std::chrono::steady_clock::now() - start) < timeout) {
pocBusy = isPOCBusy();
}
if(pocBusy) // timeout
return false;
}
if(mask != 0xffffffff) {
const auto beforeRead = std::chrono::steady_clock::now();
auto pair = readRegister(reg, timeout);
if(!pair.first)
return false; // Couldn't read, so we don't want to try to write anything
auto readDuration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - beforeRead);
timeout -= readDuration;
timeout = readDuration - timeout;
if(timeout.count() <= 0)
return false; // Out of time!
pair.second &= ~mask;
pair.second |= value & mask;
value = pair.second;
@@ -686,8 +104,6 @@ bool FlexRay::Controller::writeRegister(
uint32_t value,
bool waitForPOCReady,
std::chrono::milliseconds timeout) {
if(timeout.count() <= 0)
return false; // Out of time!
if(waitForPOCReady) {
const auto start = std::chrono::steady_clock::now();
@@ -699,7 +115,6 @@ bool FlexRay::Controller::writeRegister(
return false;
}
if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteCCRegArgs(index, uint16_t(reg), value)))
return false;
return true; // The device does not confirm the the command, if it did we'd put that here
device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteCCRegArgs(index, uint16_t(reg), value));
return true; // Does the device send anything back to tell us this actually happened?
}
+10 -44
View File
@@ -1,41 +1,26 @@
#include "icsneo/device/extensions/flexray/extension.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/message/flexray/flexraymessage.h"
using namespace icsneo;
FlexRay::Extension::Extension(Device& device, const std::vector<Network>& controllerNetworks) : DeviceExtension(device) {
for(uint8_t i = 0; i < controllerNetworks.size(); i++)
controllers.emplace_back(std::make_shared<FlexRay::Controller>(device, i, controllerNetworks[i]));
}
void FlexRay::Extension::onGoOnline() {
for(auto& controller : controllers) {
if(controller->getStartWhenGoingOnline())
controller->getReady();
}
for(auto& controller : controllers) {
if(controller->getStartWhenGoingOnline())
controller->start();
}
}
void FlexRay::Extension::onGoOffline() {
for(auto& controller : controllers)
controller->halt();
FlexRay::Extension::Extension(Device& device, uint8_t controllerCount) : DeviceExtension(device) {
for(uint8_t i = 0; i < controllerCount; i++)
controllers.emplace_back(std::make_shared<FlexRay::Controller>(device, i));
}
void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) {
switch(message->type) {
case Message::Type::FlexRayControl: {
switch(message->network.getNetID()) {
case Network::NetID::FlexRayControl: {
auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message);
if(!msg || !msg->decoded)
return;
switch(msg->opcode) {
case FlexRay::Opcode::ReadCCStatus:
if(msg->controller >= controllers.size())
return; // TODO error
controllers[msg->controller]->_setStatus(msg);
if(auto status = std::dynamic_pointer_cast<FlexRayControlMessage>(message)) { // TODO else report error?
if(status->controller >= controllers.size())
return; // TODO error
controllers[status->controller]->_setStatus(status);
}
break;
}
break;
@@ -43,23 +28,4 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
default:
break;
}
}
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) {
if(!frame || frame->network.getType() != Network::Type::FlexRay)
return true; // Don't hook non-FlexRay messages
success = false;
std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(frame);
if(!frmsg)
return false;
for(auto& controller : controllers) {
if(controller->getNetwork() != frame->network)
continue;
success |= controller->transmit(frmsg);
}
return false;
}
+58 -496
View File
@@ -4,23 +4,23 @@
using namespace icsneo;
std::optional<uint16_t> IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& settings, std::optional<size_t> knownSize) {
const uint16_t* p = reinterpret_cast<const uint16_t*>(settings.data());
size_t words = std::min(knownSize.value_or(0), settings.size());
uint16_t IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& settings) {
uint16_t gs_crc = 0;
const uint16_t* p = (const uint16_t*)settings.data();
size_t words = settings.size();
if(words % 2 == 1)
return std::nullopt; // Somehow settings is not word aligned
return 0xFFFF; // Somehow settings is not word aligned
words /= 2;
uint16_t gsCrc = 0;
while(words--) {
uint16_t temp = *p;
for (int i = 0; i < 16; i++) {
bool iBit = temp & 1;
int iCrcNxt;
//CRCNXT = NXTBIT EXOR CRC_RG(15);
if (gsCrc & (1 << 15))
if (gs_crc & (1 << 15))
iCrcNxt = iBit ^ 1;
else
iCrcNxt = iBit;
@@ -28,18 +28,18 @@ std::optional<uint16_t> IDeviceSettings::CalculateGSChecksum(const std::vector<u
// CRC_RG(15:1) = CRC_RG(14:0); // shift left by
gsCrc = gsCrc << 1;
gsCrc = gsCrc & 0xFFFE;// clear first bit
gs_crc = gs_crc << 1;
gs_crc = gs_crc & 0xFFFE;// clear first bit
if (iCrcNxt)//CRC_RG(14:0) = CRC_RG(14:0) EXOR (4599hex);
gsCrc = gsCrc ^ 0xa001;
gs_crc = gs_crc ^ 0xa001;
temp >>= 1;
}
p++;
}
return gsCrc;
return gs_crc;
}
CANBaudrate IDeviceSettings::GetEnumValueForBaudrate(int64_t baudrate) {
@@ -128,37 +128,6 @@ int64_t IDeviceSettings::GetBaudrateValueForEnum(CANBaudrate enumValue) {
}
}
bool IDeviceSettings::ValidateLINBaudrate(int64_t baudrate) {
switch(baudrate) {
case 4800:
// fallthrough
case 9600:
// fallthrough
case 10400:
// fallthrough
case 10417:
// fallthrough
case 10504:
// fallthrough
case 10593:
// fallthrough
case 10684:
// fallthrough
case 10776:
// fallthrough
case 10870:
// fallthrough
case 10965:
// fallthrough
case 11062:
// fallthrough
case 19200:
return true;
default:
return false;
}
}
bool IDeviceSettings::refresh(bool ignoreChecksum) {
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
@@ -175,40 +144,30 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) {
return false;
}
constexpr size_t GsSize = 3 * sizeof(uint16_t);
if(rxSettings.size() < GsSize) { // We need to at least have the header of GLOBAL_SETTINGS
if(rxSettings.size() < 6) { // We need to at least have the header of GLOBAL_SETTINGS
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
// The length of the settings structure sent to us
// This is the length the firmware thinks the current version of the structure is
const size_t rxLen = rxSettings.size() - GsSize;
constexpr size_t gs_size = 3 * sizeof(uint16_t);
size_t rxLen = rxSettings.size() - gs_size;
const uint16_t gsVersion = rxSettings[0] | (rxSettings[1] << 8);
uint16_t gs_version = rxSettings[0] | (rxSettings[1] << 8);
uint16_t gs_len = rxSettings[2] | (rxSettings[3] << 8);
uint16_t gs_chksum = rxSettings[4] | (rxSettings[5] << 8);
rxSettings.erase(rxSettings.begin(), rxSettings.begin() + gs_size);
// The length of the settings last saved
// If the firmware is updated, it will have either extended (with zeros) or truncated
// the structure, but this value will continue to be set to the last saved value
const uint16_t gsLen = rxSettings[2] | (rxSettings[3] << 8);
const uint16_t gsChecksum = rxSettings[4] | (rxSettings[5] << 8);
rxSettings.erase(rxSettings.begin(), rxSettings.begin() + GsSize);
if(gsVersion != GS_VERSION) {
if(gs_version != 5) {
report(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
return false;
}
if(rxLen < gsLen) {
// We got less data, i.e. the firmware thinks the strucure is smaller than what
// was last saved. Usually this is due to a firmware downgrade. We'll ignore the
// checksum for now, because it will definitely be wrong.
ignoreChecksum = true;
if(rxLen != gs_len) {
report(APIEvent::Type::SettingsLengthError, APIEvent::Severity::Error);
return false;
}
// We check the checksum against the data last saved
if(!ignoreChecksum && gsChecksum != CalculateGSChecksum(rxSettings, gsLen)) {
if(!ignoreChecksum && gs_chksum != CalculateGSChecksum(rxSettings)) {
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return false;
}
@@ -218,7 +177,7 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) {
settingsLoaded = true;
// TODO Warn user that their API version differs from the device firmware version
//if(settings.size() != structSize)
//if(settings.size() != structSize)
return settingsLoaded;
}
@@ -246,26 +205,17 @@ bool IDeviceSettings::apply(bool temporary) {
bytestream[2] = GS_VERSION >> 8;
bytestream[3] = (uint8_t)settings.size();
bytestream[4] = (uint8_t)(settings.size() >> 8);
std::optional<uint16_t> gsChecksum = CalculateGSChecksum(settings);
if(!gsChecksum) {
// Could not calculate the checksum for some reason
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return false;
}
bytestream[5] = (uint8_t)*gsChecksum;
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
uint16_t gs_checksum = CalculateGSChecksum(settings);
bytestream[5] = (uint8_t)gs_checksum;
bytestream[6] = (uint8_t)(gs_checksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
// Pause I/O with the device while the settings are applied
applyingSettings = true;
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
com->sendCommand(Command::SetSettings, bytestream);
std::shared_ptr<Message> msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) { // We did not receive a response
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
@@ -275,22 +225,16 @@ bool IDeviceSettings::apply(bool temporary) {
refresh(true); // Refresh ignoring checksum
// The device might modify the settings once they are applied, however in this case it does not update the checksum
// We refresh to get these updates, update the checksum, and send it back so it's all in sync
gsChecksum = CalculateGSChecksum(settings);
if(!gsChecksum) {
// Could not calculate the checksum for some reason
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return false;
}
bytestream[5] = (uint8_t)*gsChecksum;
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
gs_checksum = CalculateGSChecksum(settings);
bytestream[5] = (uint8_t)gs_checksum;
bytestream[6] = (uint8_t)(gs_checksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
com->sendCommand(Command::SetSettings, bytestream);
msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
@@ -298,20 +242,17 @@ bool IDeviceSettings::apply(bool temporary) {
}
if(!temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings);
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
com->sendCommand(Command::SaveSettings);
msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000));
}
applyingSettings = false;
refresh(); // Refresh our buffer with what the device has, whether we were successful or not
bool ret = (msg && msg->data[0] == 1); // Device sends 0x01 for success
if(!ret) {
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
}
return ret;
return ret;
}
bool IDeviceSettings::applyDefaults(bool temporary) {
@@ -325,14 +266,11 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
return false;
}
applyingSettings = true;
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings);
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000)));
com->sendCommand(Command::SetDefaultSettings);
std::shared_ptr<Message> msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
@@ -352,22 +290,16 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
bytestream[2] = GS_VERSION >> 8;
bytestream[3] = (uint8_t)settings.size();
bytestream[4] = (uint8_t)(settings.size() >> 8);
const std::optional<uint16_t> gsChecksum = CalculateGSChecksum(settings);
if(!gsChecksum) {
// Could not calculate the checksum for some reason
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return false;
}
bytestream[5] = (uint8_t)*gsChecksum;
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
uint16_t gs_checksum = CalculateGSChecksum(settings);
bytestream[5] = (uint8_t)gs_checksum;
bytestream[6] = (uint8_t)(gs_checksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
com->sendCommand(Command::SetSettings, bytestream);
msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
@@ -375,20 +307,17 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
}
if(!temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings);
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
com->sendCommand(Command::SaveSettings);
msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000));
}
applyingSettings = false;
refresh(); // Refresh our buffer with what the device has, whether we were successful or not
bool ret = (msg && msg->data[0] == 1); // Device sends 0x01 for success
if(!ret) {
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
}
return ret;
return ret;
}
int64_t IDeviceSettings::getBaudrateFor(Network net) const {
@@ -406,7 +335,7 @@ int64_t IDeviceSettings::getBaudrateFor(Network net) const {
case Network::Type::CAN: {
const CAN_SETTINGS* cfg = getCANSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::CANSettingsNotAvailable, APIEvent::Severity::Error);
report(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
@@ -417,43 +346,6 @@ int64_t IDeviceSettings::getBaudrateFor(Network net) const {
}
return baudrate;
}
case Network::Type::SWCAN: {
const SWCAN_SETTINGS* cfg = getSWCANSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
int64_t baudrate = GetBaudrateValueForEnum((CANBaudrate)cfg->Baudrate);
if(baudrate == -1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return -1;
}
return baudrate;
}
case Network::Type::LSFTCAN: {
const CAN_SETTINGS* cfg = getLSFTCANSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LSFTCANSettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
int64_t baudrate = GetBaudrateValueForEnum((CANBaudrate)cfg->Baudrate);
if(baudrate == -1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return -1;
}
return baudrate;
}
case Network::Type::LIN: {
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
return cfg->Baudrate;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return -1;
@@ -488,7 +380,7 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
report(APIEvent::Type::CANSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
@@ -505,7 +397,7 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
report(APIEvent::Type::LSFTCANSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
@@ -522,7 +414,7 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
report(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
@@ -533,21 +425,6 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values
return true;
}
case Network::Type::LIN: {
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
bool valid = ValidateLINBaudrate(baudrate);
if(!valid) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return false;
}
cfg->Baudrate = (uint32_t)baudrate;
return true;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
@@ -557,7 +434,6 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
int64_t IDeviceSettings::getFDBaudrateFor(Network net) const {
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
if(!settingsLoaded) {
@@ -625,320 +501,6 @@ bool IDeviceSettings::setFDBaudrateFor(Network net, int64_t baudrate) {
}
}
bool IDeviceSettings::isTerminationSupportedFor(Network net) const {
for(const auto& group : getTerminationGroups()) {
for(const auto& supportedNet : group) {
if(net == supportedNet)
return true;
}
}
return false;
}
bool IDeviceSettings::canTerminationBeEnabledFor(Network net) const {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
// Even though we will not be writing here, if the settings are read only the termination will not be enablable
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
// Reference the mutable termination enables as we want to allow a disable/enable within a group without applying
ICSNEO_UNALIGNED(const uint64_t*) currentQueuedTerminationEnables = const_cast<IDeviceSettings*>(this)->getMutableTerminationEnables();
if(currentQueuedTerminationEnables == nullptr) {
report(APIEvent::Type::TerminationNotSupportedDevice, APIEvent::Severity::Error);
return false;
}
for(const auto& group : getTerminationGroups()) {
bool found = false;
for(const auto& supportedNet : group) {
if(net == supportedNet) {
found = true;
break;
}
}
if(found) {
for(const auto& supportedNet : group) {
// Allow termination on the current network even if it's already enabled
if(net == supportedNet)
continue;
const auto cmNet = supportedNet.getCoreMini();
if(!cmNet.has_value() || uint64_t(*cmNet) >= 64) {
// Hitting this assert means that a supported network has an invalid CoreMini Network ID
assert(false);
continue;
}
// If this network is enabled, it excludes the queried network from being enabled
if((*currentQueuedTerminationEnables >> uint64_t(*cmNet)) & 0x1) {
report(APIEvent::Type::AnotherInTerminationGroupEnabled, APIEvent::Severity::Error);
return false;
}
}
return true;
}
}
return false;
}
std::optional<bool> IDeviceSettings::isTerminationEnabledFor(Network net) const {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return std::nullopt;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
ICSNEO_UNALIGNED(const uint64_t*) terminationEnables = getTerminationEnables();
if(terminationEnables == nullptr) {
report(APIEvent::Type::TerminationNotSupportedDevice, APIEvent::Severity::Error);
return std::nullopt;
}
const auto cmNet = net.getCoreMini();
if(!cmNet.has_value() || uint64_t(*cmNet) >= 64 || !isTerminationSupportedFor(net)) {
report(APIEvent::Type::TerminationNotSupportedNetwork, APIEvent::Severity::Error);
return std::nullopt;
}
return (*terminationEnables >> uint64_t(*cmNet)) & 0x1;
}
bool IDeviceSettings::setTerminationFor(Network net, bool enabled) {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
ICSNEO_UNALIGNED(uint64_t*) terminationEnables = getMutableTerminationEnables();
if(terminationEnables == nullptr) {
report(APIEvent::Type::TerminationNotSupportedDevice, APIEvent::Severity::Error);
return false;
}
// This function reports its own error statuses
if(!canTerminationBeEnabledFor(net))
return false;
const auto cmNet = net.getCoreMini();
if(!cmNet.has_value() || uint8_t(*cmNet) >= 64) {
report(APIEvent::Type::TerminationNotSupportedNetwork, APIEvent::Severity::Error);
return false;
}
const uint64_t mask = 1ull << uint8_t(*cmNet);
if(enabled)
*terminationEnables |= mask;
else
*terminationEnables &= ~mask;
return true;
}
std::optional<bool> IDeviceSettings::isCommanderResistorEnabledFor(Network net) const {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return std::nullopt;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
switch(net.getType()) {
case Network::Type::LIN: {
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
return (cfg->CommanderResistor != RESISTOR_OFF);
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return std::nullopt;
}
}
bool IDeviceSettings::setCommanderResistorFor(Network net, bool resistor_on) {
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
switch(net.getType()) {
case Network::Type::LIN: {
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
cfg->CommanderResistor = resistor_on ? RESISTOR_ON : RESISTOR_OFF;
return true;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
}
std::optional<LINMode> IDeviceSettings::getLINModeFor(Network net) const {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return std::nullopt;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
switch(net.getType()) {
case Network::Type::LIN: {
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
return static_cast<LINMode>(cfg->Mode);
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return std::nullopt;
}
}
bool IDeviceSettings::setLINModeFor(Network net, LINMode mode) {
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
switch(net.getType()) {
case Network::Type::LIN: {
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
cfg->Mode = static_cast<uint8_t>(mode);
return true;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
}
std::optional<uint8_t> IDeviceSettings::getLINCommanderResponseTimeFor(Network net) const {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return std::nullopt;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
switch(net.getType()) {
case Network::Type::LIN: {
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return std::nullopt;
}
return cfg->numBitsDelay;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return std::nullopt;
}
}
bool IDeviceSettings::setLINCommanderResponseTimeFor(Network net, uint8_t bits) {
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
switch(net.getType()) {
case Network::Type::LIN: {
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
if(cfg == nullptr) {
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
cfg->numBitsDelay = bits;
return true;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
}
template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure) {
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
@@ -954,7 +516,7 @@ template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure)
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
// This function is only called from C++ so the caller's structure size and ours should never differ
if(sizeof(T) != structSize) {
report(APIEvent::Type::SettingsStructureMismatch, APIEvent::Severity::Error);
-13
View File
@@ -1,13 +0,0 @@
#include "icsneo/device/neodevice.h"
#include "icsneo/device/founddevice.h"
#include <cstring>
neodevice_t::neodevice_t() : device(nullptr), handle(0), type(0) {
memset(serial, 0, sizeof(serial));
}
neodevice_t::neodevice_t(const icsneo::FoundDevice& found, devicetype_t inType)
: device(nullptr), handle(found.handle), type(inType) {
static_assert(sizeof(found.serial) == sizeof(serial), "Serial sizes should match!");
memcpy(serial, found.serial, sizeof(serial));
}
-127
View File
@@ -1,127 +0,0 @@
#include "icsneo/disk/diskreaddriver.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
std::optional<uint64_t> ReadDriver::readLogicalDisk(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, Disk::MemoryType memType) {
std::vector<uint8_t>& cache = memType == Disk::MemoryType::SD ? cacheSD : cacheEEPROM;
uint64_t& cachePos = memType == Disk::MemoryType::SD ? cachePosSD : cachePosEEPROM;
if(amount == 0)
return 0;
pos += vsaOffset;
// First read from the cache
std::optional<uint64_t> ret = readFromCache(pos, into, amount);
if(ret == amount) // Full cache hit, we're done
return ret;
const uint64_t totalAmount = amount;
if(ret.has_value()) { // Partial cache hit
pos += *ret;
into += *ret;
amount -= *ret;
}
// Read into here if we can't read directly into the user buffer
// That would be the case either if we don't want some at the
// beginning or end of the block.
std::vector<uint8_t> alignedReadBuffer;
const uint32_t idealBlockSize = getBlockSizeBounds().second;
const uint64_t startBlock = pos / idealBlockSize;
const uint32_t posWithinFirstBlock = static_cast<uint32_t>(pos % idealBlockSize);
uint64_t blocks = amount / idealBlockSize + (amount % idealBlockSize ? 1 : 0);
if(blocks * idealBlockSize - posWithinFirstBlock < amount)
blocks++; // We need one more block to get the last partial block's worth
uint64_t blocksProcessed = 0;
while(blocksProcessed < blocks && timeout >= std::chrono::milliseconds::zero()) {
const uint64_t currentBlock = startBlock + blocksProcessed;
uint64_t intoOffset = blocksProcessed * idealBlockSize;;
if(intoOffset < posWithinFirstBlock)
intoOffset = 0;
else
intoOffset -= posWithinFirstBlock;
const uint32_t posWithinCurrentBlock = (blocksProcessed ? 0 : posWithinFirstBlock);
uint32_t curAmt = idealBlockSize - posWithinCurrentBlock;
const auto amountLeft = totalAmount - ret.value_or(0);
if(curAmt > amountLeft)
curAmt = static_cast<uint32_t>(amountLeft);
const bool useAlignedReadBuffer = (posWithinCurrentBlock != 0 || curAmt != idealBlockSize);
if(useAlignedReadBuffer && alignedReadBuffer.size() < idealBlockSize)
alignedReadBuffer.resize(idealBlockSize);
auto start = std::chrono::high_resolution_clock::now();
auto readAmount = readLogicalDiskAligned(com, report, currentBlock * idealBlockSize,
useAlignedReadBuffer ? alignedReadBuffer.data() : (into + intoOffset), idealBlockSize, timeout, memType);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
if(!readAmount.has_value() || *readAmount < curAmt) {
if(timeout < std::chrono::milliseconds::zero())
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
else
report((blocksProcessed || readAmount.value_or(0u) != 0u) ? APIEvent::Type::EOFReached :
APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
break;
}
if(useAlignedReadBuffer)
memcpy(into + intoOffset, alignedReadBuffer.data() + posWithinCurrentBlock, curAmt);
if(!ret)
ret.emplace();
*ret += std::min<uint64_t>(*readAmount, curAmt);
blocksProcessed++;
if(blocksProcessed == blocks) {
// Last block, add to the cache
if(useAlignedReadBuffer) {
cache = std::move(alignedReadBuffer);
} else {
if(cache.size() != idealBlockSize)
cache.resize(idealBlockSize);
memcpy(cache.data(), into + intoOffset, idealBlockSize);
}
cachePos = currentBlock * idealBlockSize;
cachedAt = std::chrono::steady_clock::now();
}
}
return ret;
}
void ReadDriver::invalidateCache(uint64_t pos, uint64_t amount, MemoryType memType) {
std::vector<uint8_t>& cache = memType == Disk::MemoryType::SD ? cacheSD : cacheEEPROM;
uint64_t cachePos = memType == Disk::MemoryType::SD ? cachePosSD : cachePosEEPROM;
if(pos <= cachePos + cache.size() && pos + amount >= cachePos)
cache.clear();
}
std::optional<uint64_t> ReadDriver::readFromCache(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds staleAfter, MemoryType memType) {
std::vector<uint8_t>& cache = memType == Disk::MemoryType::SD ? cacheSD : cacheEEPROM;
uint64_t cachePos = memType == Disk::MemoryType::SD ? cachePosSD : cachePosEEPROM;
if(cache.empty())
return std::nullopt; // Nothing in the cache
if(cachedAt + staleAfter < std::chrono::steady_clock::now())
return std::nullopt; // Cache is stale
if(pos > cachePos + cache.size() || pos < cachePos)
return std::nullopt; // Cache miss
const auto cacheOffset = pos - cachePos;
const auto copyAmount = std::min<uint64_t>(cache.size() - cacheOffset, amount);
memcpy(into, cache.data() + cacheOffset, static_cast<size_t>(copyAmount));
return copyAmount;
}
-88
View File
@@ -1,88 +0,0 @@
#include "icsneo/disk/diskwritedriver.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
std::optional<uint64_t> WriteDriver::writeLogicalDisk(Communication& com, device_eventhandler_t report, ReadDriver& readDriver,
uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) {
if(amount == 0)
return 0;
std::optional<uint64_t> ret;
const uint32_t idealBlockSize = getBlockSizeBounds().second;
// Write from here if we need to read-modify-write a block
// That would be the case either if we don't want some at the
// beginning or end of the block.
std::vector<uint8_t> alignedWriteBuffer(idealBlockSize);
pos += vsaOffset;
const uint64_t startBlock = pos / idealBlockSize;
const uint32_t posWithinFirstBlock = static_cast<uint32_t>(pos % idealBlockSize);
uint64_t blocks = amount / idealBlockSize + (amount % idealBlockSize ? 1 : 0);
if(blocks * idealBlockSize - posWithinFirstBlock < amount)
blocks++; // We need one more block to get the last partial block's worth
uint64_t blocksProcessed = 0;
while(blocksProcessed < blocks && timeout >= std::chrono::milliseconds::zero()) {
const uint64_t currentBlock = startBlock + blocksProcessed;
uint64_t fromOffset = blocksProcessed * idealBlockSize;
if(fromOffset < posWithinFirstBlock)
fromOffset = 0;
else
fromOffset -= posWithinFirstBlock;
const uint32_t posWithinCurrentBlock = (blocksProcessed ? 0 : posWithinFirstBlock);
uint32_t curAmt = idealBlockSize - posWithinCurrentBlock;
const auto amountLeft = amount - ret.value_or(0);
if(curAmt > amountLeft)
curAmt = static_cast<uint32_t>(amountLeft);
auto start = std::chrono::high_resolution_clock::now();
const auto reportFromRead = [&report, &blocksProcessed](APIEvent::Type t, APIEvent::Severity s) {
if(t == APIEvent::Type::ParameterOutOfRange && blocksProcessed)
t = APIEvent::Type::EOFReached;
report(t, s);
};
const bool useAlignedWriteBuffer = (posWithinCurrentBlock != 0 || curAmt != idealBlockSize);
if(useAlignedWriteBuffer) {
auto read = readDriver.readLogicalDisk(com, reportFromRead, currentBlock * idealBlockSize,
alignedWriteBuffer.data(), idealBlockSize, timeout, memType);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
if(read != idealBlockSize)
break; // readLogicalDisk reports its own errors
memcpy(alignedWriteBuffer.data() + posWithinCurrentBlock, from + fromOffset, curAmt);
}
start = std::chrono::high_resolution_clock::now();
auto bytesTransferred = writeLogicalDiskAligned(com, report, currentBlock * idealBlockSize,
useAlignedWriteBuffer ? alignedWriteBuffer.data() : (from + fromOffset), idealBlockSize, timeout, memType);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
if(!bytesTransferred.has_value() || *bytesTransferred < curAmt) {
if(timeout < std::chrono::milliseconds::zero())
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
else
report((blocksProcessed || bytesTransferred.value_or(0u) != 0u) ? APIEvent::Type::EOFReached :
APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
break;
}
if(!ret)
ret.emplace();
*ret += std::min<uint64_t>(*bytesTransferred, curAmt);
blocksProcessed++;
}
// No matter how much succeeded, to be safe, we'll invalidate anything
// we may have even tried to write, since it may have succeeded without
// notifying, etc.
readDriver.invalidateCache(pos, amount, memType);
return ret;
}
-97
View File
@@ -1,97 +0,0 @@
#include "icsneo/disk/extextractordiskreaddriver.h"
#include "icsneo/communication/message/diskdatamessage.h"
//#define ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
#include <iostream>
#endif
using namespace icsneo;
using namespace icsneo::Disk;
std::optional<uint64_t> ExtExtractorDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) {
if(amount > getBlockSizeBounds().second)
return std::nullopt;
if(amount % getBlockSizeBounds().first != 0)
return std::nullopt;
if(pos % getBlockSizeBounds().first != 0)
return std::nullopt;
std::optional<uint64_t> ret;
unsigned int attempts = 4;
while (attempts-- > 0)
{
ret = attemptReadLogicalDiskAligned(com, report, pos, into, amount, timeout, memType);
if (ret.has_value())
break;
}
return ret;
}
std::optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
uint64_t sector = pos / SectorSize;
uint64_t largeSectorCount = amount / SectorSize;
uint32_t sectorCount = uint32_t(largeSectorCount);
if (largeSectorCount != uint64_t(sectorCount))
return std::nullopt;
std::condition_variable cv;
std::mutex mutex;
uint8_t* intoOffset = into;
int64_t remaining = amount;
bool complete = false;
const auto handle = com.addMessageCallback(std::make_shared<MessageCallback>([&](std::shared_ptr<Message> message) {
if(remaining > 0) {
const auto diskdata = std::static_pointer_cast<DiskDataMessage>(message);
const auto& data = diskdata->data;
std::copy(data.data(), data.data() + data.size(), intoOffset);
intoOffset += data.size();
remaining -= data.size();
if(remaining == 0) {
{
std::scoped_lock<std::mutex> lk(mutex);
complete = true;
}
cv.notify_all();
}
}
}, std::make_shared<MessageFilter>(Network::NetID::DiskData)));
if(!com.sendCommand(ExtendedCommand::Extract, {
uint8_t(sector & 0xff),
uint8_t((sector >> 8) & 0xff),
uint8_t((sector >> 16) & 0xff),
uint8_t((sector >> 24) & 0xff),
uint8_t((sector >> 32) & 0xff),
uint8_t((sector >> 40) & 0xff),
uint8_t((sector >> 48) & 0xff),
uint8_t((sector >> 56) & 0xff),
uint8_t(sectorCount & 0xff),
uint8_t((sectorCount >> 8) & 0xff),
uint8_t((sectorCount >> 16) & 0xff),
uint8_t((sectorCount >> 24) & 0xff),
})) {
return std::nullopt;
}
std::unique_lock<std::mutex> lk(mutex);
const auto successful = cv.wait_for(lk, timeout, [&](){ return complete; });
com.removeMessageCallback(handle);
if(!successful)
return std::nullopt;
return amount - remaining;
}
-48
View File
@@ -1,48 +0,0 @@
#include "icsneo/disk/fat.h"
#include "icsneo/disk/diskdriver.h"
#include "ff.h"
#include "diskio.h"
#include <mutex>
using namespace icsneo;
// The FAT driver can only be accessed by one caller at a time, since it relies on globals
static std::mutex fatDriverMutex;
static std::function< std::optional<uint64_t>(uint64_t pos, uint8_t* into, uint64_t amount) > diskReadFn;
extern "C" DRESULT disk_read(BYTE, BYTE* buff, LBA_t sector, UINT count) {
static_assert(Disk::SectorSize == 512, "FatFs expects 512 byte sectors");
const uint64_t expected = count * uint64_t(Disk::SectorSize);
const auto res = diskReadFn(sector * uint64_t(Disk::SectorSize), buff, expected);
if (!res.has_value())
return RES_NOTRDY;
return res == expected ? RES_OK : RES_ERROR;
}
extern "C" DSTATUS disk_initialize(BYTE) {
return RES_OK;
}
extern "C" DSTATUS disk_status(BYTE) {
return RES_OK;
}
static uint64_t ClusterToSector(const FATFS& fs, DWORD cluster) {
return fs.database + (LBA_t)fs.csize * (cluster - 2);
}
std::optional<uint64_t> Disk::FindVSAInFAT(std::function< std::optional<uint64_t>(uint64_t pos, uint8_t* into, uint64_t amount) > diskRead) {
std::lock_guard<std::mutex> lk(fatDriverMutex);
diskReadFn = diskRead;
FATFS fs = {};
if (f_mount(&fs, (const TCHAR*)_TEXT(""), 0) != FR_OK)
return std::nullopt;
FIL logData = {};
if (f_open(&logData, (const TCHAR*)_TEXT("0:\\LOG_DATA.VSA"), FA_READ) != FR_OK)
return std::nullopt;
return ClusterToSector(fs, logData.obj.sclust) * uint64_t(Disk::SectorSize);
}
-95
View File
@@ -1,95 +0,0 @@
#include "icsneo/disk/neomemorydiskdriver.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flashmemorymessage.h"
#include <cstring>
#include <iostream>
using namespace icsneo;
using namespace icsneo::Disk;
std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) {
const auto filter = std::make_shared<MessageFilter>((memType == MemoryType::SD ? Network::NetID::NeoMemorySDRead : Network::NetID::RED_INT_MEMORYREAD));
filter->includeInternalInAny = true;
if(pos % SectorSize != 0)
return std::nullopt;
if(amount != SectorSize)
return std::nullopt;
const uint64_t currentSector = pos / SectorSize;
const uint8_t memLocation = (uint8_t)memType;
uint64_t numWords = amount / 2;
auto msg = com.waitForMessageSync([&currentSector, &memLocation, &com, &numWords] {
return com.sendCommand(Command::NeoReadMemory, {
memLocation,
uint8_t(currentSector & 0xFF),
uint8_t((currentSector >> 8) & 0xFF),
uint8_t((currentSector >> 16) & 0xFF),
uint8_t((currentSector >> 24) & 0xFF),
uint8_t(numWords & 0xFF),
uint8_t((numWords >> 8) & 0xFF),
uint8_t((numWords >> 16) & 0xFF),
uint8_t((numWords >> 24) & 0xFF)
});
}, filter, timeout);
if(!msg)
return 0;
if(memType == MemoryType::SD) {
const auto mem = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
if(!mem || mem->data.size() != SectorSize) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return std::nullopt;
}
memcpy(into, mem->data.data(), SectorSize);
} else { // flash
const auto mem = std::dynamic_pointer_cast<FlashMemoryMessage>(msg);
if(!mem || mem->data.size() != SectorSize) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return std::nullopt;
}
memcpy(into, mem->data.data(), SectorSize);
}
return SectorSize;
}
std::optional<uint64_t> NeoMemoryDiskDriver::writeLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout, MemoryType memType) {
static std::shared_ptr<MessageFilter> NeoMemoryDone = std::make_shared<MessageFilter>(Network::NetID::NeoMemoryWriteDone);
if(pos % SectorSize != 0)
return std::nullopt;
if(amount != SectorSize)
return std::nullopt;
const uint64_t currentSector = pos / SectorSize;
const uint8_t memLocation = (uint8_t)memType;
uint64_t numWords = amount / 2;
auto msg = com.waitForMessageSync([&currentSector, &memLocation, &com, from, amount, &numWords] {
std::vector<uint8_t> command = {
memLocation,
uint8_t(currentSector & 0xFF),
uint8_t((currentSector >> 8) & 0xFF),
uint8_t((currentSector >> 16) & 0xFF),
uint8_t((currentSector >> 24) & 0xFF),
uint8_t(numWords & 0xFF),
uint8_t((numWords >> 8) & 0xFF),
};
command.insert(command.end(), from, from + amount);
return com.sendCommand(Command::NeoWriteMemory, command);
}, NeoMemoryDone, timeout);
if(!msg)
return std::nullopt;
return SectorSize;
}
-28
View File
@@ -1,28 +0,0 @@
#include "icsneo/disk/nulldiskdriver.h"
using namespace icsneo;
using namespace icsneo::Disk;
std::optional<uint64_t> NullDriver::readLogicalDisk(Communication&, device_eventhandler_t report,
uint64_t, uint8_t*, uint64_t, std::chrono::milliseconds, MemoryType) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
std::optional<uint64_t> NullDriver::readLogicalDiskAligned(Communication&, device_eventhandler_t report,
uint64_t, uint8_t*, uint64_t, std::chrono::milliseconds, MemoryType) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
std::optional<uint64_t> NullDriver::writeLogicalDisk(Communication&, device_eventhandler_t report, ReadDriver&,
uint64_t, const uint8_t*, uint64_t, std::chrono::milliseconds, MemoryType) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
std::optional<uint64_t> NullDriver::writeLogicalDiskAligned(Communication&, device_eventhandler_t report,
uint64_t, const uint8_t*, uint64_t, std::chrono::milliseconds, MemoryType) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
-69
View File
@@ -1,69 +0,0 @@
#include "icsneo/disk/plasiondiskreaddriver.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/multichannelcommunication.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
std::optional<uint64_t> PlasionDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, MemoryType) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
if(amount > getBlockSizeBounds().second)
return std::nullopt;
if(amount % getBlockSizeBounds().first != 0)
return std::nullopt;
if(pos % getBlockSizeBounds().first != 0)
return std::nullopt;
uint64_t largeSector = pos / SectorSize;
uint32_t sector = uint32_t(largeSector);
if (largeSector != uint64_t(sector))
return std::nullopt;
std::mutex m;
std::condition_variable cv;
uint32_t copied = 0;
bool error = false;
std::unique_lock<std::mutex> lk(m);
auto cb = com.addMessageCallback(std::make_shared<MessageCallback>([&](std::shared_ptr<Message> msg) {
std::unique_lock<std::mutex> lk(m);
const auto sdmsg = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
if(!sdmsg || amount < copied + sdmsg->data.size()) {
error = true;
lk.unlock();
cv.notify_all();
return;
}
memcpy(into + copied, sdmsg->data.data(), sdmsg->data.size());
copied += uint32_t(sdmsg->data.size());
if(copied == amount) {
lk.unlock();
cv.notify_all();
}
}, NeoMemorySDRead));
com.rawWrite({
uint8_t(MultiChannelCommunication::CommandType::HostPC_from_SDCC1),
uint8_t(sector & 0xFF),
uint8_t((sector >> 8) & 0xFF),
uint8_t((sector >> 16) & 0xFF),
uint8_t((sector >> 24) & 0xFF),
uint8_t(amount & 0xFF),
uint8_t((amount >> 8) & 0xFF),
});
bool hitTimeout = !cv.wait_for(lk, timeout, [&copied, &error, &amount] { return error || copied == amount; });
com.removeMessageCallback(cb);
if(hitTimeout)
return std::nullopt;
return amount;
}
-43
View File
@@ -1,43 +0,0 @@
#include "icsneo/disk/vsa/vsa.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include <iostream>
using namespace icsneo;
// VSA Base Class Functions
// VSAMessage Class Functions
std::shared_ptr<Packet> VSAMessage::getPacket() const
{
auto packet = std::make_shared<Packet>();
packet->network = network;
reservePacketData(packet);
packet->data.insert(packet->data.end(), payload.begin(), payload.end());
return packet;
}
// VSAExtendedMessage Class Functions
void VSAExtendedMessage::appendPacket(std::shared_ptr<Packet> packet) const
{
packet->data.insert(packet->data.end(), payload.begin(), payload.end());
// Set the network if not already set (Happens in AA0F records)
if(packet->network.getNetID() == Network::NetID::Invalid) {
packet->network = network;
}
}
void VSAExtendedMessage::truncatePacket(std::shared_ptr<Packet> packet)
{
static constexpr auto EthernetLengthOffset = 26u;
switch(packet->network.getType()) {
case Network::Type::Ethernet:
{
const auto& packetLength = *reinterpret_cast<uint16_t*>(packet->data.data() + EthernetLengthOffset);
const size_t ethernetFrameSize = packetLength - (sizeof(uint16_t) * 2);
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize;
packet->data.resize(bytestreamExpectedSize);
}
break;
}
}
-26
View File
@@ -1,26 +0,0 @@
#include "icsneo/disk/vsa/vsa02.h"
using namespace icsneo;
VSA02::VSA02(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA02);
constantIndex = *reinterpret_cast<uint16_t*>(recordBytes + 2);
flags = *reinterpret_cast<Flags*>(recordBytes + 4);
pieceCount = recordBytes[5];
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
samples.insert(samples.end(), recordBytes + 14, recordBytes + 30);
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
doChecksum(recordBytes);
}
void VSA02::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 15; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}
-24
View File
@@ -1,24 +0,0 @@
#include "icsneo/disk/vsa/vsa03.h"
using namespace icsneo;
VSA03::VSA03(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA03);
eventType = static_cast<EventType>(*reinterpret_cast<uint16_t*>(recordBytes + 2));
eventData = *reinterpret_cast<uint16_t*>(recordBytes + 4);
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
doChecksum(recordBytes);
}
void VSA03::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 7; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}
-24
View File
@@ -1,24 +0,0 @@
#include "icsneo/disk/vsa/vsa04.h"
using namespace icsneo;
VSA04::VSA04(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA04);
flags = *reinterpret_cast<Flags*>(recordBytes + 2);
partitionIndex = *reinterpret_cast<uint16_t*>(recordBytes + 4);
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
doChecksum(recordBytes);
}
void VSA04::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 7; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}
-23
View File
@@ -1,23 +0,0 @@
#include "icsneo/disk/vsa/vsa05.h"
using namespace icsneo;
VSA05::VSA05(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA05);
errorType = static_cast<ErrorType>(*reinterpret_cast<uint16_t*>(recordBytes + 2));
errorNetwork = *reinterpret_cast<uint16_t*>(recordBytes + 4);
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
}
void VSA05::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 7; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}
-25
View File
@@ -1,25 +0,0 @@
#include "icsneo/disk/vsa/vsa06.h"
using namespace icsneo;
VSA06::VSA06(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA06);
savedSectors.insert(savedSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 2), reinterpret_cast<uint32_t*>(recordBytes + 18));
error = *reinterpret_cast<uint16_t*>(recordBytes + 18);
savedSectorsHigh = *reinterpret_cast<uint16_t*>(recordBytes + 20);
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
doChecksum(recordBytes);
}
void VSA06::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 15; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}
-25
View File
@@ -1,25 +0,0 @@
#include "icsneo/disk/vsa/vsa07.h"
using namespace icsneo;
VSA07::VSA07(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA07);
lastSector = *reinterpret_cast<uint32_t*>(recordBytes + 2);
currentSector = *reinterpret_cast<uint32_t*>(recordBytes + 6);
reserved.insert(reserved.end(), recordBytes + 10, recordBytes + 22);
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
doChecksum(recordBytes);
}
void VSA07::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 15; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}
-24
View File
@@ -1,24 +0,0 @@
#include "icsneo/disk/vsa/vsa08.h"
using namespace icsneo;
VSA08::VSA08(uint8_t* const recordBytes)
: VSA()
{
setType(VSA::Type::AA08);
troubleSramCount.insert(troubleSramCount.end(), recordBytes + 2, recordBytes + 6);
troubleSectors.insert(troubleSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 6), reinterpret_cast<uint32_t*>(recordBytes + 20));
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
doChecksum(recordBytes);
}
void VSA08::doChecksum(uint8_t* recordBytes)
{
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
uint16_t sum = 0;
for(size_t i = 0; i < 15; i++) {
sum += words[i];
}
setChecksumFailed(sum != checksum);
}

Some files were not shown because too many files have changed in this diff Show More