diff --git a/CMakeLists.txt b/CMakeLists.txt index 79e4454..2fed4e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,9 @@ 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) set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap") +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) if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) @@ -86,30 +89,55 @@ endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(PLATFORM_SRC - platform/windows/pcap.cpp platform/windows/registry.cpp - platform/windows/vcp.cpp - platform/windows/internal/pcapdll.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 - platform/posix/ftdi.cpp - platform/posix/pcap.cpp - platform/posix/cdcacm.cpp - ) - if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(PLATFORM_SRC) + + if(LIBICSNEO_ENABLE_RAW_ETHERNET) list(APPEND PLATFORM_SRC - platform/posix/darwin/cdcacmdarwin.cpp + platform/posix/pcap.cpp ) - else() # Linux or other + endif() + + if(LIBICSNEO_ENABLE_FTDI) list(APPEND PLATFORM_SRC - platform/posix/linux/cdcacmlinux.cpp + platform/posix/ftdi.cpp ) - if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - message(WARNING - "There is no 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() + + 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() endif() @@ -149,6 +177,7 @@ set(SRC_FILES device/idevicesettings.cpp device/devicefinder.cpp device/device.cpp + device/neodevice.cpp disk/diskreaddriver.cpp disk/diskwritedriver.cpp disk/nulldiskdriver.cpp @@ -220,6 +249,15 @@ 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_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() # fatfs add_subdirectory(third-party/fatfs) diff --git a/communication/ethernetpacketizer.cpp b/communication/ethernetpacketizer.cpp index 7fd52eb..87d501f 100644 --- a/communication/ethernetpacketizer.cpp +++ b/communication/ethernetpacketizer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include using namespace icsneo; @@ -74,7 +75,7 @@ bool EthernetPacketizer::inputUp(std::vector bytes) { memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0) return false; // Packet is not addressed to us or broadcast - if(memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0) + if(!allowInPacketsFromAnyMAC && memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0) return false; // Not a packet from the device we're concerned with // Handle single packets diff --git a/device/devicefinder.cpp b/device/devicefinder.cpp index 45537ce..a84a38f 100644 --- a/device/devicefinder.cpp +++ b/device/devicefinder.cpp @@ -1,265 +1,155 @@ #include "icsneo/device/devicefinder.h" #include "icsneo/platform/devices.h" +#include "icsneo/device/founddevice.h" #include "generated/extensions/builtin.h" +#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 + using namespace icsneo; -static bool supportedDevicesCached = false; -static std::vector supportedDevices = { +template +static void makeIfSerialMatches(const FoundDevice& dev, std::vector>& 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(dev)); +} - #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 __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 __RADEPSILON_H_ - RADEpsilon::DEVICE_TYPE, - #endif - - #ifdef __RADGALAXY_H_ - RADGalaxy::DEVICE_TYPE, - #endif - - #ifdef __RADMARS_ETH_H_ - RADMarsETH::DEVICE_TYPE, - #endif - - #ifdef __RADMARS_USB_H_ - RADMarsUSB::DEVICE_TYPE, - #endif - - #ifdef __RADGIGASTAR_ETH_H_ - RADGigastarETH::DEVICE_TYPE, - #endif - - #ifdef __RADGIGASTAR_USB_H_ - RADGigastarUSB::DEVICE_TYPE, - #endif - - #ifdef __RADMOON2_H_ - RADMoon2::DEVICE_TYPE, - #endif - - #ifdef __RADMOONDUO_H_ - RADMoonDuo::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_ETH_H_ - ValueCAN4_2EL_ETH::DEVICE_TYPE, - #endif - - #ifdef __VALUECAN4_2EL_USB_H_ - ValueCAN4_2EL_USB::DEVICE_TYPE, - #endif - - #ifdef __VALUECAN4_4_H_ - ValueCAN4_4::DEVICE_TYPE, - #endif - - #ifdef __VALUECAN4INDUSTRIAL_ETH_H_ - ValueCAN4IndustrialETH::DEVICE_TYPE, - #endif - - #ifdef __VALUECAN4INDUSTRIAL_USB_H_ - ValueCAN4IndustrialUSB::DEVICE_TYPE, - #endif - - #ifdef __VIVIDCAN_H_ - VividCAN::DEVICE_TYPE, - #endif - -}; +template +static void makeIfPIDMatches(const FoundDevice& dev, std::vector>& 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(dev)); +} std::vector> DeviceFinder::FindAll() { + static std::vector driverFoundDevices; + driverFoundDevices.clear(); + + #ifdef ICSNEO_ENABLE_RAW_ETHERNET + PCAP::Find(driverFoundDevices); + #endif + + #ifdef ICSNEO_ENABLE_CDCACM + CDCACM::Find(driverFoundDevices); + #endif + + #ifdef ICSNEO_ENABLE_FTDI + FTDI::Find(driverFoundDevices); + #endif + std::vector> foundDevices; - std::vector>> findResults; -#if defined(LIBICSNEO_HAVE_PCAP) && LIBICSNEO_HAVE_PCAP == 1 - auto pcapDevices = PCAP::FindAll(); -#endif + // Offer found devices to each of the subclasses + for (const FoundDevice& dev : driverFoundDevices) { + #ifdef __ETHERBADGE_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __ETHERBADGE_H_ - findResults.push_back(EtherBADGE::Find()); - #endif - - #ifdef __NEOOBD2PRO_H_ - findResults.push_back(NeoOBD2PRO::Find()); - #endif + #ifdef __NEOOBD2PRO_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __NEOOBD2SIM_H_ - findResults.push_back(NeoOBD2SIM::Find()); - #endif + #ifdef __NEOOBD2SIM_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __NEOVIFIRE_H_ - findResults.push_back(NeoVIFIRE::Find()); - #endif + #ifdef __NEOVIFIRE_H_ + makeIfPIDMatches(dev, foundDevices); + #endif - #ifdef __NEOVIFIRE2ETH_H_ - findResults.push_back(NeoVIFIRE2ETH::Find(pcapDevices)); - #endif + #ifdef __NEOVIFIRE2_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __NEOVIFIRE2USB_H_ - findResults.push_back(NeoVIFIRE2USB::Find()); - #endif + #ifdef __NEOVIRED2_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __NEOVIRED2_H_ - findResults.push_back(NeoVIRED2::Find(pcapDevices)); - #endif + #ifdef __NEOVIION_H_ + makeIfPIDMatches(dev, foundDevices); + #endif - #ifdef __NEOVIION_H_ - findResults.push_back(NeoVIION::Find()); - #endif + #ifdef __NEOVIPLASMA_H_ + makeIfPIDMatches(dev, foundDevices); + #endif - #ifdef __NEOVIPLASMA_H_ - findResults.push_back(NeoVIPLASMA::Find()); - #endif + #ifdef __RADEPSILON_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADEPSILON_H_ - findResults.push_back(RADEpsilon::Find()); - #endif + #ifdef __RADGALAXY_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADGALAXY_H_ - findResults.push_back(RADGalaxy::Find(pcapDevices)); - #endif + #ifdef __RADMARS_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADMARS_ETH_H_ - findResults.push_back(RADMarsETH::Find(pcapDevices)); - #endif + #ifdef __RADGIGASTAR_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADMARS_USB_H_ - findResults.push_back(RADMarsUSB::Find()); - #endif + #ifdef __RADMOON2_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADGIGASTAR_ETH_H_ - findResults.push_back(RADGigastarETH::Find(pcapDevices)); - #endif + #ifdef __RADMOONDUO_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADGIGASTAR_USB_H_ - findResults.push_back(RADGigastarUSB::Find()); - #endif + #ifdef __RADPLUTO_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADMOON2_H_ - findResults.push_back(RADMoon2::Find()); - #endif + #ifdef __RADSTAR2_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADMOONDUO_H_ - findResults.push_back(RADMoonDuo::Find()); - #endif + #ifdef __RADSUPERMOON_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADPLUTOUSB_H_ - findResults.push_back(RADPlutoUSB::Find()); - #endif + #ifdef __VALUECAN3_H_ + makeIfPIDMatches(dev, foundDevices); + #endif - #ifdef __RADSTAR2ETH_H_ - findResults.push_back(RADStar2ETH::Find(pcapDevices)); - #endif + #ifdef __VALUECAN4_1_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADSTAR2USB_H_ - findResults.push_back(RADStar2USB::Find()); - #endif + #ifdef __VALUECAN4_2_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __RADSUPERMOON_H_ - findResults.push_back(RADSupermoon::Find()); - #endif + #ifdef __VALUECAN4_2EL_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __VALUECAN3_H_ - findResults.push_back(ValueCAN3::Find()); - #endif + #ifdef __VALUECAN4_4_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __VALUECAN4_1_H_ - findResults.push_back(ValueCAN4_1::Find()); - #endif + #ifdef __VALUECAN4INDUSTRIAL_H_ + makeIfSerialMatches(dev, foundDevices); + #endif - #ifdef __VALUECAN4_2_H_ - findResults.push_back(ValueCAN4_2::Find()); - #endif - - #ifdef __VALUECAN4_2EL_ETH_H_ - findResults.push_back(ValueCAN4_2EL_ETH::Find(pcapDevices)); - #endif - - #ifdef __VALUECAN4_2EL_USB_H_ - findResults.push_back(ValueCAN4_2EL_USB::Find()); - #endif - - #ifdef __VALUECAN4_4_H_ - findResults.push_back(ValueCAN4_4::Find()); - #endif - - #ifdef __VALUECAN4INDUSTRIAL_ETH_H_ - findResults.push_back(ValueCAN4IndustrialETH::Find(pcapDevices)); - #endif - - #ifdef __VALUECAN4INDUSTRIAL_USB_H_ - findResults.push_back(ValueCAN4IndustrialUSB::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())); + #ifdef __VIVIDCAN_H_ + makeIfSerialMatches(dev, foundDevices); + #endif } for(auto& device : foundDevices) { @@ -270,9 +160,105 @@ std::vector> DeviceFinder::FindAll() { } const std::vector& DeviceFinder::GetSupportedDevices() { - if(!supportedDevicesCached) { - supportedDevices.erase(std::unique(supportedDevices.begin(), supportedDevices.end()), supportedDevices.end()); - supportedDevicesCached = true; - } + static std::vector 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 __NEOVIFIRE_H_ + NeoVIFIRE::DEVICE_TYPE, + #endif + + #ifdef __NEOVIFIRE2_H_ + NeoVIFIRE2::DEVICE_TYPE, + #endif + + #ifdef __NEOVIION_H_ + NeoVIION::DEVICE_TYPE, + #endif + + #ifdef __NEOVIPLASMA_H_ + NeoVIPLASMA::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 __RADMOON2_H_ + RADMoon2::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; } diff --git a/device/neodevice.cpp b/device/neodevice.cpp new file mode 100644 index 0000000..0376330 --- /dev/null +++ b/device/neodevice.cpp @@ -0,0 +1,13 @@ +#include "icsneo/device/neodevice.h" +#include "icsneo/device/founddevice.h" +#include + +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)); +} diff --git a/include/icsneo/communication/communication.h b/include/icsneo/communication/communication.h index ee9c2a9..72336ca 100644 --- a/include/icsneo/communication/communication.h +++ b/include/icsneo/communication/communication.h @@ -26,14 +26,14 @@ namespace icsneo { class Communication { public: + // Note that the Packetizer is not created by the constructor, + // and should be done once the Communication module is in place. Communication( device_eventhandler_t report, std::unique_ptr&& driver, std::function()> makeConfiguredPacketizer, std::unique_ptr&& e, - std::unique_ptr&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), report(report), driver(std::move(driver)) { - packetizer = makeConfiguredPacketizer(); - } + std::unique_ptr&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), driver(std::move(driver)), report(report) {} virtual ~Communication(); bool open(); @@ -77,10 +77,10 @@ public: std::unique_ptr packetizer; std::unique_ptr encoder; std::unique_ptr decoder; + std::unique_ptr driver; device_eventhandler_t report; protected: - std::unique_ptr driver; static int messageCallbackIDCounter; std::mutex messageCallbacksLock; std::map messageCallbacks; diff --git a/include/icsneo/communication/driver.h b/include/icsneo/communication/driver.h index a39ec36..21e6798 100644 --- a/include/icsneo/communication/driver.h +++ b/include/icsneo/communication/driver.h @@ -27,6 +27,7 @@ public: virtual bool read(std::vector& bytes, size_t limit = 0); virtual bool readWait(std::vector& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0); virtual bool write(const std::vector& bytes); + virtual bool isEthernet() const { return false; } device_eventhandler_t report; diff --git a/include/icsneo/communication/ethernetpacketizer.h b/include/icsneo/communication/ethernetpacketizer.h index 9494252..ef97cec 100644 --- a/include/icsneo/communication/ethernetpacketizer.h +++ b/include/icsneo/communication/ethernetpacketizer.h @@ -61,6 +61,7 @@ public: uint8_t hostMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF }; uint8_t deviceMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + bool allowInPacketsFromAnyMAC = false; // Used when discovering devices private: bool reassembling = false; diff --git a/include/icsneo/device/device.h b/include/icsneo/device/device.h index 8c9199f..2e439a8 100644 --- a/include/icsneo/device/device.h +++ b/include/icsneo/device/device.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "icsneo/api/eventmanager.h" @@ -16,6 +17,7 @@ #include "icsneo/device/nullsettings.h" #include "icsneo/device/devicetype.h" #include "icsneo/device/deviceversion.h" +#include "icsneo/device/founddevice.h" #include "icsneo/disk/diskreaddriver.h" #include "icsneo/disk/diskwritedriver.h" #include "icsneo/disk/nulldiskdriver.h" @@ -32,6 +34,20 @@ #include "icsneo/platform/optional.h" #include "icsneo/platform/nodiscard.h" +#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \ + static constexpr DeviceType::Enum DEVICE_TYPE = type; \ + className(const FoundDevice& dev) : className(neodevice_t(dev, DEVICE_TYPE), dev.makeDriver) {} + +// Devices which are discernable by the first two characters of their serial +#define ICSNEO_FINDABLE_DEVICE(className, type, serialStart) \ + static constexpr const char* SERIAL_START = serialStart; \ + ICSNEO_FINDABLE_DEVICE_BASE(className, type) + +// Devices which are discernable by their USB PID +#define ICSNEO_FINDABLE_DEVICE_BY_PID(className, type, pid) \ + static constexpr const uint16_t PRODUCT_ID = pid; \ + ICSNEO_FINDABLE_DEVICE_BASE(className, type) + namespace icsneo { class DeviceExtension; @@ -46,7 +62,6 @@ public: uint16_t getTimestampResolution() const; DeviceType getType() const { return DeviceType(data.type); } - uint16_t getProductId() const { return productId; } std::string getSerial() const { return data.serial; } uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); } const neodevice_t& getNeoDevice() const { return data; } @@ -308,7 +323,6 @@ public: std::unique_ptr settings; protected: - uint16_t productId = 0; bool online = false; int messagePollingCallbackID = 0; int internalHandlerCallbackID = 0; @@ -323,21 +337,23 @@ protected: std::array, 2> miscAnalog; // START Initialization Functions - Device(neodevice_t neodevice = { 0 }) { - data = neodevice; + Device(neodevice_t neodevice) : data(neodevice) { data.device = this; } - template - void initialize() { + template + void initialize(const driver_factory_t& makeDriver) { report = makeEventHandler(); - auto driver = makeDriver(); - setupDriver(*driver); auto encoder = makeEncoder(); setupEncoder(*encoder); auto decoder = makeDecoder(); setupDecoder(*decoder); - com = makeCommunication(std::move(driver), std::bind(&Device::makeConfiguredPacketizer, this), std::move(encoder), std::move(decoder)); + com = makeCommunication( + makeDriver(report, getWritableNeoDevice()), + std::bind(&Device::makeConfiguredPacketizer, this), + std::move(encoder), + std::move(decoder) + ); setupCommunication(*com); settings = makeSettings(com); setupSettings(*settings); @@ -354,10 +370,6 @@ protected: }; } - template - std::unique_ptr makeDriver() { return std::unique_ptr(new Driver(report, getWritableNeoDevice())); } - virtual void setupDriver(Driver&) {} - virtual std::unique_ptr makePacketizer() { return std::unique_ptr(new Packetizer(report)); } virtual void setupPacketizer(Packetizer&) {} std::unique_ptr makeConfiguredPacketizer() { @@ -377,7 +389,9 @@ protected: std::function()> makeConfiguredPacketizer, std::unique_ptr e, std::unique_ptr d) { return std::make_shared(report, std::move(t), makeConfiguredPacketizer, std::move(e), std::move(d)); } - virtual void setupCommunication(Communication&) {} + virtual void setupCommunication(Communication& communication) { + communication.packetizer = communication.makeConfiguredPacketizer(); + } template std::unique_ptr makeSettings(std::shared_ptr com) { diff --git a/include/icsneo/device/founddevice.h b/include/icsneo/device/founddevice.h new file mode 100644 index 0000000..0f05eb6 --- /dev/null +++ b/include/icsneo/device/founddevice.h @@ -0,0 +1,21 @@ +#ifndef __FOUNDDEVICE_H_ +#define __FOUNDDEVICE_H_ + +#include "icsneo/communication/driver.h" +#include "icsneo/device/neodevice.h" + +namespace icsneo { + +typedef std::function< std::unique_ptr(device_eventhandler_t err, neodevice_t& forDevice) > driver_factory_t; + +class FoundDevice { +public: + neodevice_handle_t handle = 0; + char serial[7] = {}; + uint16_t productId = 0; + driver_factory_t makeDriver; +}; + +} // namespace icsneo + +#endif // __FOUNDDEVICE_H_ \ No newline at end of file diff --git a/include/icsneo/device/neodevice.h b/include/icsneo/device/neodevice.h index e1ae7ce..94395fb 100644 --- a/include/icsneo/device/neodevice.h +++ b/include/icsneo/device/neodevice.h @@ -9,6 +9,7 @@ namespace icsneo { class Device; +class FoundDevice; } typedef icsneo::Device* devicehandle_t; @@ -20,7 +21,13 @@ typedef int32_t neodevice_handle_t; #pragma pack(push, 1) +#ifdef __cplusplus +typedef struct neodevice_t { + neodevice_t(); + neodevice_t(const icsneo::FoundDevice& found, devicetype_t inType); +#else typedef struct { +#endif devicehandle_t device; // Pointer back to the C++ device object neodevice_handle_t handle; // Handle for use by the underlying driver devicetype_t type; diff --git a/include/icsneo/device/tree/etherbadge/etherbadge.h b/include/icsneo/device/tree/etherbadge/etherbadge.h index 7489614..9e8ed96 100644 --- a/include/icsneo/device/tree/etherbadge/etherbadge.h +++ b/include/icsneo/device/tree/etherbadge/etherbadge.h @@ -7,7 +7,6 @@ #include "icsneo/device/devicetype.h" #include "icsneo/communication/packetizer.h" #include "icsneo/communication/decoder.h" -#include "icsneo/platform/cdcacm.h" #include "icsneo/device/tree/etherbadge/etherbadgesettings.h" namespace icsneo { @@ -15,49 +14,35 @@ namespace icsneo { class EtherBADGE : public Device { public: // Serial numbers start with EB - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::EtherBADGE; - static constexpr const uint16_t PRODUCT_ID = 0x1107; - static constexpr const char* SERIAL_START = "EB"; - - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new EtherBADGE(neodevice)); - - return found; - } + // USB PID is 0x1107, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(EtherBADGE, DeviceType::EtherBADGE, "EB"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { Network::NetID::HSCAN, - Network::NetID::LIN, - Network::NetID::OP_Ethernet1 }; return supportedNetworks; } - EtherBADGE(neodevice_t neodevice) : Device(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; - initialize(); +protected: + EtherBADGE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } -protected: virtual void setupEncoder(Encoder& encoder) override { Device::setupEncoder(encoder); encoder.supportCANFD = true; } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } bool requiresVehiclePower() const override { return false; } }; diff --git a/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h b/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h index 9be6392..15712d3 100644 --- a/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h +++ b/include/icsneo/device/tree/neoobd2pro/neoobd2pro.h @@ -5,23 +5,14 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/cdcacm.h" namespace icsneo { class NeoOBD2PRO : public Device { public: - // Serial numbers are NP**** - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::OBD2_PRO; - static constexpr const uint16_t PRODUCT_ID = 0x1103; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new NeoOBD2PRO(neodevice)); - - return found; - } + // Serial numbers start with NP + // USB PID is 0x1103, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(NeoOBD2PRO, DeviceType::OBD2_PRO, "NP"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -32,19 +23,17 @@ public: } private: - NeoOBD2PRO(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + NeoOBD2PRO(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } bool requiresVehiclePower() const override { return false; } }; diff --git a/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h b/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h index 65f7b81..ed13ffb 100644 --- a/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h +++ b/include/icsneo/device/tree/neoobd2sim/neoobd2sim.h @@ -5,23 +5,14 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/cdcacm.h" namespace icsneo { class NeoOBD2SIM : public Device { public: - // Serial numbers are OS**** - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::OBD2_SIM; - static constexpr const uint16_t PRODUCT_ID = 0x1100; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new NeoOBD2SIM(neodevice)); - - return found; - } + // Serial numbers start with OS + // USB PID is 0x1100, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(NeoOBD2SIM, DeviceType::OBD2_SIM, "OS"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -32,19 +23,17 @@ public: } private: - NeoOBD2SIM(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + NeoOBD2SIM(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } bool requiresVehiclePower() const override { return false; } }; diff --git a/include/icsneo/device/tree/neovifire/neovifire.h b/include/icsneo/device/tree/neovifire/neovifire.h index 85699ea..ff7a17c 100644 --- a/include/icsneo/device/tree/neovifire/neovifire.h +++ b/include/icsneo/device/tree/neovifire/neovifire.h @@ -5,23 +5,14 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/ftdi.h" #include "icsneo/device/tree/neovifire/neovifiresettings.h" namespace icsneo { class NeoVIFIRE : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::FIRE; - static constexpr const uint16_t PRODUCT_ID = 0x0701; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID)) - found.emplace_back(new NeoVIFIRE(neodevice)); // Creation of the shared_ptr - - return found; - } + // USB PID is 0x0701, standard driver is FTDI + ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIFIRE, DeviceType::FIRE, 0x0701); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -67,19 +58,17 @@ public: } private: - NeoVIFIRE(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + NeoVIFIRE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/neovifire2/neovifire2.h b/include/icsneo/device/tree/neovifire2/neovifire2.h index 8904e7e..c799eea 100644 --- a/include/icsneo/device/tree/neovifire2/neovifire2.h +++ b/include/icsneo/device/tree/neovifire2/neovifire2.h @@ -5,15 +5,16 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/ftdi.h" #include "icsneo/device/tree/neovifire2/neovifire2settings.h" namespace icsneo { class NeoVIFIRE2 : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::FIRE2; - static constexpr const char* SERIAL_START = "CY"; + // Serial numbers start with CY + // USB PID is 0x1000, standard driver is FTDI + // Ethernet MAC allocation is 0x04, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(NeoVIFIRE2, DeviceType::FIRE2, "CY"); enum class SKU { Standard, @@ -87,8 +88,22 @@ public: } protected: - NeoVIFIRE2(neodevice_t neodevice) : Device(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; + NeoVIFIRE2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); + } + + void setupSettings(IDeviceSettings& ssettings) override { + if(com->driver->isEthernet()) { + // TODO Check firmware version, old firmwares will reset Ethernet settings on settings send + ssettings.readonly = true; + } + } + + bool currentDriverSupportsDFU() const override { return com->driver->isEthernet(); } + + void setupPacketizer(Packetizer& packetizer) override { + Device::setupPacketizer(packetizer); + packetizer.align16bit = !com->driver->isEthernet(); } virtual void setupEncoder(Encoder& encoder) override { @@ -96,13 +111,13 @@ protected: encoder.supportCANFD = true; } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void handleDeviceStatus(const std::shared_ptr& message) override { if(message->data.size() < sizeof(neovifire2_status_t)) diff --git a/include/icsneo/device/tree/neovifire2/neovifire2eth.h b/include/icsneo/device/tree/neovifire2/neovifire2eth.h deleted file mode 100644 index 3cd02a0..0000000 --- a/include/icsneo/device/tree/neovifire2/neovifire2eth.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef __NEOVIFIRE2ETH_H_ -#define __NEOVIFIRE2ETH_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/neovifire2/neovifire2.h" -#include "icsneo/platform/pcap.h" -#include - -namespace icsneo { - -class NeoVIFIRE2ETH : public NeoVIFIRE2 { -public: - static constexpr const uint16_t PRODUCT_ID = 0x0004; - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new NeoVIFIRE2ETH({})); - for (auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for (auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if (!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a FIRE 2 - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.push_back(std::make_shared(std::move(device))); - break; - } - } - - return found; - } - - NeoVIFIRE2ETH(neodevice_t neodevice) : NeoVIFIRE2(neodevice) { - initialize(); - productId = PRODUCT_ID; - } - - bool currentDriverSupportsDFU() const override { return false; } - -protected: - void setupSettings(IDeviceSettings& ssettings) override { - // TODO Check firmware version, old firmwares will reset Ethernet settings on settings send - ssettings.readonly = true; - } - - void setupPacketizer(Packetizer& packetizer) override { - NeoVIFIRE2::setupPacketizer(packetizer); - packetizer.align16bit = false; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/neovifire2/neovifire2usb.h b/include/icsneo/device/tree/neovifire2/neovifire2usb.h deleted file mode 100644 index 04e73f7..0000000 --- a/include/icsneo/device/tree/neovifire2/neovifire2usb.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __NEOVIFIRE2USB_H_ -#define __NEOVIFIRE2USB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/neovifire2/neovifire2.h" -#include "icsneo/platform/ftdi.h" - -namespace icsneo { - -class NeoVIFIRE2USB : public NeoVIFIRE2 { -public: - static constexpr const uint16_t PRODUCT_ID = 0x1000; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID)) - found.emplace_back(new NeoVIFIRE2USB(neodevice)); // Creation of the shared_ptr - - return found; - } - -private: - NeoVIFIRE2USB(neodevice_t neodevice) : NeoVIFIRE2(neodevice) { - initialize(); - productId = PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/neovired2/neovired2.h b/include/icsneo/device/tree/neovired2/neovired2.h index 1bca6ca..f4ca791 100644 --- a/include/icsneo/device/tree/neovired2/neovired2.h +++ b/include/icsneo/device/tree/neovired2/neovired2.h @@ -3,7 +3,6 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/pcap.h" #include "icsneo/disk/extextractordiskreaddriver.h" #include "icsneo/disk/neomemorydiskdriver.h" #include "icsneo/device/tree/neovired2/neovired2settings.h" @@ -12,41 +11,9 @@ namespace icsneo { class NeoVIRED2 : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RED2; - static constexpr const char* SERIAL_START = "D2"; - static constexpr const uint16_t PRODUCT_ID = 0x000E; - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new NeoVIRED2({})); - for (auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for (auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if (!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a RED 2 - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.emplace_back(new NeoVIRED2(std::move(device))); - break; - } - } - - return found; - } + // Serial numbers start with D2 + // Ethernet MAC allocation is 0x0E, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(NeoVIRED2, DeviceType::RED2, "D2"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -68,10 +35,8 @@ public: } protected: - NeoVIRED2(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } virtual void setupEncoder(Encoder& encoder) override { @@ -84,13 +49,13 @@ protected: packetizer.align16bit = false; } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/plasion/neoviion.h b/include/icsneo/device/tree/plasion/neoviion.h index 1a92b1e..47a2860 100644 --- a/include/icsneo/device/tree/plasion/neoviion.h +++ b/include/icsneo/device/tree/plasion/neoviion.h @@ -5,7 +5,6 @@ #include "icsneo/device/tree/plasion/plasion.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/ftdi.h" #include "icsneo/disk/plasiondiskreaddriver.h" #include "icsneo/disk/neomemorydiskdriver.h" @@ -13,22 +12,12 @@ namespace icsneo { class NeoVIION : public Plasion { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::ION; - static constexpr const uint16_t PRODUCT_ID = 0x0901; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID)) - found.emplace_back(new NeoVIION(neodevice)); - - return found; - } + // USB PID is 0x0901, standard driver is FTDI + ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIION, DeviceType::ION, 0x0901); private: - NeoVIION(neodevice_t neodevice) : Plasion(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + NeoVIION(neodevice_t neodevice, const driver_factory_t& makeDriver) : Plasion(neodevice) { + initialize(makeDriver); } virtual std::shared_ptr makeCommunication( diff --git a/include/icsneo/device/tree/plasion/neoviplasma.h b/include/icsneo/device/tree/plasion/neoviplasma.h index a09c05e..1b40c1a 100644 --- a/include/icsneo/device/tree/plasion/neoviplasma.h +++ b/include/icsneo/device/tree/plasion/neoviplasma.h @@ -5,28 +5,17 @@ #include "icsneo/device/tree/plasion/plasion.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/ftdi.h" namespace icsneo { class NeoVIPLASMA : public Plasion { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::PLASMA; - static constexpr const uint16_t PRODUCT_ID = 0x0801; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID)) - found.emplace_back(new NeoVIPLASMA(neodevice)); - - return found; - } + // USB PID is 0x0801, standard driver is FTDI + ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIPLASMA, DeviceType::PLASMA, 0x0801); private: - NeoVIPLASMA(neodevice_t neodevice) : Plasion(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + NeoVIPLASMA(neodevice_t neodevice, const driver_factory_t& makeDriver) : Plasion(neodevice) { + initialize(makeDriver); } virtual std::shared_ptr makeCommunication( diff --git a/include/icsneo/device/tree/plasion/plasion.h b/include/icsneo/device/tree/plasion/plasion.h index 8afbe29..5d7c3e8 100644 --- a/include/icsneo/device/tree/plasion/plasion.h +++ b/include/icsneo/device/tree/plasion/plasion.h @@ -5,7 +5,6 @@ #include "icsneo/device/device.h" #include "icsneo/communication/multichannelcommunication.h" -#include "icsneo/platform/ftdi.h" #include "icsneo/device/extensions/flexray/extension.h" namespace icsneo { @@ -45,6 +44,8 @@ public: size_t getEthernetActivationLineCount() const override { return 1; } protected: + using Device::Device; + // TODO This is done so that Plasion can still transmit it's basic networks, awaiting slave VNET support virtual bool isSupportedRXNetwork(const Network&) const override { return true; } virtual bool isSupportedTXNetwork(const Network&) const override { return true; } @@ -55,7 +56,7 @@ protected: addExtension(std::make_shared(*this, flexRayControllers)); } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); // TODO Check configuration for FlexRay ColdStart mode, disable FlexRay 2 if so @@ -87,9 +88,6 @@ protected: const fire2vnet_status_t* status = reinterpret_cast(message->data.data()); ethActivationStatus = status->ethernetActivationLineEnabled; } - -public: - Plasion(neodevice_t neodevice) : Device(neodevice) {} }; } diff --git a/include/icsneo/device/tree/radepsilon/radepsilon.h b/include/icsneo/device/tree/radepsilon/radepsilon.h index 9858bd9..9b35b6e 100644 --- a/include/icsneo/device/tree/radepsilon/radepsilon.h +++ b/include/icsneo/device/tree/radepsilon/radepsilon.h @@ -3,23 +3,14 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/cdcacm.h" namespace icsneo { class RADEpsilon : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADEpsilon; - static constexpr const char* SERIAL_START = "RE"; - static constexpr const uint16_t PRODUCT_ID = 0x1109; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADEpsilon(neodevice)); - - return found; - } + // Serial numbers start with RE + // USB PID is 0x1109, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(RADEpsilon, DeviceType::RADEpsilon, "RE"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -34,10 +25,8 @@ public: } protected: - RADEpsilon(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + RADEpsilon(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } virtual void setupEncoder(Encoder& encoder) override { @@ -45,13 +34,13 @@ protected: encoder.supportCANFD = true; } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/radgalaxy/radgalaxy.h b/include/icsneo/device/tree/radgalaxy/radgalaxy.h index e534216..fefbdef 100644 --- a/include/icsneo/device/tree/radgalaxy/radgalaxy.h +++ b/include/icsneo/device/tree/radgalaxy/radgalaxy.h @@ -5,7 +5,6 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/platform/pcap.h" #include "icsneo/communication/packetizer.h" #include "icsneo/communication/decoder.h" #include "icsneo/device/tree/radgalaxy/radgalaxysettings.h" @@ -15,41 +14,8 @@ namespace icsneo { class RADGalaxy : public Device { public: // Serial numbers start with RG - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGalaxy; - static constexpr const uint16_t PRODUCT_ID = 0x0003; - static constexpr const char* SERIAL_START = "RG"; - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new RADGalaxy({})); - for(auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for(auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if(!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a RADGalaxy - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.emplace_back(new RADGalaxy(std::move(device))); - break; - } - } - - return found; - } + // Ethernet MAC allocation is 0x03, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(RADGalaxy, DeviceType::RADGalaxy, "RG"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -85,15 +51,13 @@ public: return supportedNetworks; } - RADGalaxy(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; - } - size_t getEthernetActivationLineCount() const override { return 1; } protected: + RADGalaxy(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); + } + void setupPacketizer(Packetizer& packetizer) override { Device::setupPacketizer(packetizer); packetizer.disableChecksum = true; diff --git a/include/icsneo/device/tree/radgigastar/radgigastar.h b/include/icsneo/device/tree/radgigastar/radgigastar.h index 983d399..d126f2b 100644 --- a/include/icsneo/device/tree/radgigastar/radgigastar.h +++ b/include/icsneo/device/tree/radgigastar/radgigastar.h @@ -11,16 +11,18 @@ namespace icsneo { class RADGigastar : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGigastar; - static constexpr const char* SERIAL_START = "GS"; + // Serial numbers start with GS + // USB PID is 0x1204, standard driver is FTDI3 + // Ethernet MAC allocation is 0x0F, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(RADGigastar, DeviceType::RADGigastar, "GS"); size_t getEthernetActivationLineCount() const override { return 1; } bool getEthPhyRegControlSupported() const override { return true; } protected: - RADGigastar(neodevice_t neodevice) : Device(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; + RADGigastar(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } void setupPacketizer(Packetizer& packetizer) override { diff --git a/include/icsneo/device/tree/radgigastar/radgigastareth.h b/include/icsneo/device/tree/radgigastar/radgigastareth.h deleted file mode 100644 index 95e95f7..0000000 --- a/include/icsneo/device/tree/radgigastar/radgigastareth.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __RADGIGASTAR_ETH_H_ -#define __RADGIGASTAR_ETH_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radgigastar/radgigastar.h" -#include "icsneo/platform/pcap.h" - -namespace icsneo { - -class RADGigastarETH : public RADGigastar { -public: - static constexpr const uint16_t PRODUCT_ID = 0x000F; - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new RADGigastarETH({})); - for (auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for (auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if (!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a RADGigastar - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.push_back(std::shared_ptr(new RADGigastarETH(std::move(device)))); - break; - } - } - - return found; - } - -private: - RADGigastarETH(neodevice_t neodevice) : RADGigastar(neodevice) { - initialize(); - productId = PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radgigastar/radgigastarusb.h b/include/icsneo/device/tree/radgigastar/radgigastarusb.h deleted file mode 100644 index f4b10bb..0000000 --- a/include/icsneo/device/tree/radgigastar/radgigastarusb.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __RADGIGASTAR_USB_H_ -#define __RADGIGASTAR_USB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radgigastar/radgigastar.h" -#include "icsneo/platform/ftdi3.h" - -namespace icsneo { - -class RADGigastarUSB : public RADGigastar { -public: - static constexpr const uint16_t PRODUCT_ID = 0x1204; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI3::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADGigastarUSB(neodevice)); // Creation of the shared_ptr - - return found; - } - -private: - RADGigastarUSB(neodevice_t neodevice) : RADGigastar(neodevice) { - initialize(); - productId = PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radmars/radmars.h b/include/icsneo/device/tree/radmars/radmars.h index 68ad170..67eaa32 100644 --- a/include/icsneo/device/tree/radmars/radmars.h +++ b/include/icsneo/device/tree/radmars/radmars.h @@ -11,14 +11,16 @@ namespace icsneo { class RADMars : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADMars; - static constexpr const char* SERIAL_START = "GL"; + // Serial numbers start with GL (previously, RAD-Gigalog) + // USB PID is 0x1203, standard driver is FTDI3 + // Ethernet MAC allocation is 0x0A, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(RADMars, DeviceType::RADMars, "GL"); size_t getEthernetActivationLineCount() const override { return 1; } protected: - RADMars(neodevice_t neodevice) : Device(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; + RADMars(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } void setupPacketizer(Packetizer& packetizer) override { diff --git a/include/icsneo/device/tree/radmars/radmarseth.h b/include/icsneo/device/tree/radmars/radmarseth.h deleted file mode 100644 index 59285bc..0000000 --- a/include/icsneo/device/tree/radmars/radmarseth.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __RADMARS_ETH_H_ -#define __RADMARS_ETH_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radmars/radmars.h" -#include "icsneo/platform/pcap.h" - -namespace icsneo { - -class RADMarsETH : public RADMars { -public: - static constexpr const uint16_t PRODUCT_ID = 0x000A; - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new RADMarsETH({})); - for (auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for (auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if (!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a RAD-Mars - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.push_back(std::shared_ptr(new RADMarsETH(std::move(device)))); - break; - } - } - - return found; - } - -private: - RADMarsETH(neodevice_t neodevice) : RADMars(neodevice) { - initialize(); - productId = PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radmars/radmarsusb.h b/include/icsneo/device/tree/radmars/radmarsusb.h deleted file mode 100644 index 0b2c3f9..0000000 --- a/include/icsneo/device/tree/radmars/radmarsusb.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __RADMARS_USB_H_ -#define __RADMARS_USB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radmars/radmars.h" -#include "icsneo/platform/ftdi3.h" - -namespace icsneo { - -class RADMarsUSB : public RADMars { -public: - static constexpr const uint16_t PRODUCT_ID = 0x1203; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI3::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADMarsUSB(neodevice)); // Creation of the shared_ptr - - return found; - } - -private: - RADMarsUSB(neodevice_t neodevice) : RADMars(neodevice) { - initialize(); - productId = PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radmoon2/radmoon2.h b/include/icsneo/device/tree/radmoon2/radmoon2.h index cc536ae..e996ed9 100644 --- a/include/icsneo/device/tree/radmoon2/radmoon2.h +++ b/include/icsneo/device/tree/radmoon2/radmoon2.h @@ -6,15 +6,14 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" #include "icsneo/device/tree/radmoon2/radmoon2settings.h" -#include "icsneo/platform/ftdi3.h" namespace icsneo { class RADMoon2 : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADMoon2; - static constexpr const uint16_t PRODUCT_ID = 0x1202; - static constexpr const char* SERIAL_START = "RM"; + // Serial numbers start with RM + // USB PID is 0x1202, standard driver is FTDI3 + ICSNEO_FINDABLE_DEVICE(RADMoon2, DeviceType::RADMoon2, "RM"); enum class SKU { Standard, @@ -22,15 +21,6 @@ public: APM1000E_CLK, // Clock Option and Keysight Branding }; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI3::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADMoon2(neodevice)); - - return found; - } - SKU getSKU() const { switch(getSerial().back()) { case 'A': @@ -70,10 +60,8 @@ public: bool getEthPhyRegControlSupported() const override { return true; } protected: - RADMoon2(neodevice_t neodevice) : Device(neodevice) { - initialize(); - productId = PRODUCT_ID; - getWritableNeoDevice().type = DEVICE_TYPE; + RADMoon2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } void setupPacketizer(Packetizer& packetizer) override { diff --git a/include/icsneo/device/tree/radmoonduo/radmoonduo.h b/include/icsneo/device/tree/radmoonduo/radmoonduo.h index b829e42..cfe7d84 100644 --- a/include/icsneo/device/tree/radmoonduo/radmoonduo.h +++ b/include/icsneo/device/tree/radmoonduo/radmoonduo.h @@ -6,24 +6,14 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" #include "icsneo/device/tree/radmoonduo/radmoonduosettings.h" -#include "icsneo/platform/cdcacm.h" namespace icsneo { class RADMoonDuo : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADMoonDuo; - static constexpr const uint16_t PRODUCT_ID = 0x1106; - static constexpr const char* SERIAL_START = "MD"; - - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADMoonDuo(neodevice)); - - return found; - } + // Serial numbers start with MD + // USB PID is 1106, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(RADMoonDuo, DeviceType::RADMoonDuo, "MD"); static const std::vector& GetSupportedNetworks() { // If Converter1 Target is set to USB/CM, OP_Ethernet2 will be exposed to the PC @@ -36,10 +26,8 @@ public: bool getEthPhyRegControlSupported() const override { return true; } protected: - RADMoonDuo(neodevice_t neodevice) : Device(neodevice) { - initialize(); - productId = PRODUCT_ID; - getWritableNeoDevice().type = DEVICE_TYPE; + RADMoonDuo(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } virtual void setupEncoder(Encoder& encoder) override { diff --git a/include/icsneo/device/tree/radpluto/radpluto.h b/include/icsneo/device/tree/radpluto/radpluto.h index bf25879..038cb2f 100644 --- a/include/icsneo/device/tree/radpluto/radpluto.h +++ b/include/icsneo/device/tree/radpluto/radpluto.h @@ -5,8 +5,6 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" -#include "icsneo/communication/packetizer.h" -#include "icsneo/communication/decoder.h" #include "icsneo/device/tree/radpluto/radplutosettings.h" namespace icsneo { @@ -14,9 +12,8 @@ namespace icsneo { class RADPluto : public Device { public: // Serial numbers start with PL - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADPluto; - static constexpr const uint16_t PRODUCT_ID = 0x1104; - static constexpr const char* SERIAL_START = "PL"; + // USB PID is 1104, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(RADPluto, DeviceType::RADPluto, "PL"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -35,27 +32,26 @@ public: return supportedNetworks; } - RADPluto(neodevice_t neodevice) : Device(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; - } - bool getEthPhyRegControlSupported() const override { return true; } protected: + RADPluto(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); + } + virtual void setupEncoder(Encoder& encoder) override { Device::setupEncoder(encoder); encoder.supportCANFD = true; encoder.supportEthPhy = true; } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } bool requiresVehiclePower() const override { return false; } }; diff --git a/include/icsneo/device/tree/radpluto/radplutousb.h b/include/icsneo/device/tree/radpluto/radplutousb.h deleted file mode 100644 index fdb6042..0000000 --- a/include/icsneo/device/tree/radpluto/radplutousb.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __RADPLUTOUSB_H_ -#define __RADPLUTOUSB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radpluto/radpluto.h" -#include "icsneo/platform/cdcacm.h" - -namespace icsneo { - -class RADPlutoUSB : public RADPluto { -public: - // Serial numbers start with RP - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADPlutoUSB(neodevice)); - - return found; - } - -private: - RADPlutoUSB(neodevice_t neodevice) : RADPluto(neodevice) { - initialize(); - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radstar2/radstar2.h b/include/icsneo/device/tree/radstar2/radstar2.h index df740c1..173c58d 100644 --- a/include/icsneo/device/tree/radstar2/radstar2.h +++ b/include/icsneo/device/tree/radstar2/radstar2.h @@ -12,9 +12,9 @@ namespace icsneo { class RADStar2 : public Device { public: // Serial numbers start with RS - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADStar2; - static constexpr const uint16_t PRODUCT_ID = 0x0005; - static constexpr const char* SERIAL_START = "RS"; + // USB PID is 0x0005, standard driver is FTDI + // Ethernet MAC allocation is 0x05, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(RADStar2, DeviceType::RADStar2, "RS"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -30,6 +30,10 @@ public: } protected: + RADStar2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); + } + virtual void setupPacketizer(Packetizer& packetizer) override { Device::setupPacketizer(packetizer); packetizer.disableChecksum = true; @@ -46,18 +50,13 @@ protected: decoder.timestampResolution = 10; // Timestamps are in 10ns increments instead of the usual 25ns } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } - - RADStar2(neodevice_t neodevice) : Device(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; - } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/radstar2/radstar2eth.h b/include/icsneo/device/tree/radstar2/radstar2eth.h deleted file mode 100644 index 3e0c056..0000000 --- a/include/icsneo/device/tree/radstar2/radstar2eth.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __RADSTAR2ETH_H_ -#define __RADSTAR2ETH_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radstar2/radstar2.h" -#include "icsneo/communication/network.h" -#include "icsneo/communication/message/serialnumbermessage.h" -#include "icsneo/platform/pcap.h" - -namespace icsneo { - -class RADStar2ETH : public RADStar2 { -public: - // Serial numbers start with RS - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new RADStar2ETH({})); - for(auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for(auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if(!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a RADStar2 - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.push_back(std::make_shared(device)); - break; - } - } - - return found; - } - - RADStar2ETH(neodevice_t neodevice) : RADStar2(neodevice) { - initialize(); - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radstar2/radstar2usb.h b/include/icsneo/device/tree/radstar2/radstar2usb.h deleted file mode 100644 index 555ec3d..0000000 --- a/include/icsneo/device/tree/radstar2/radstar2usb.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __RADSTAR2USB_H_ -#define __RADSTAR2USB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/radstar2/radstar2.h" -#include "icsneo/platform/ftdi.h" - -namespace icsneo { - -class RADStar2USB : public RADStar2 { -public: - // Serial numbers start with RS - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADStar2USB(neodevice)); - - return found; - } - -private: - RADStar2USB(neodevice_t neodevice) : RADStar2(neodevice) { - initialize(); - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/radsupermoon/radsupermoon.h b/include/icsneo/device/tree/radsupermoon/radsupermoon.h index ce1bd45..f85e55e 100644 --- a/include/icsneo/device/tree/radsupermoon/radsupermoon.h +++ b/include/icsneo/device/tree/radsupermoon/radsupermoon.h @@ -6,30 +6,20 @@ #include "icsneo/device/device.h" #include "icsneo/device/devicetype.h" #include "icsneo/device/tree/radsupermoon/radsupermoonsettings.h" -#include "icsneo/platform/ftdi3.h" namespace icsneo { class RADSupermoon : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADSupermoon; - static constexpr const uint16_t PRODUCT_ID = 0x1201; - static constexpr const char* SERIAL_START = "SM"; + // Serial numbers start with SM + // USB PID is 0x1201, standard driver is FTDI3 + ICSNEO_FINDABLE_DEVICE(RADSupermoon, DeviceType::RADSupermoon, "SM"); enum class SKU { Standard, APM1000ET, // Keysight Branding }; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI3::FindByProduct(PRODUCT_ID)) - found.emplace_back(new RADSupermoon(neodevice)); - - return found; - } - static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { Network::NetID::Ethernet, @@ -60,10 +50,8 @@ public: bool getEthPhyRegControlSupported() const override { return true; } protected: - RADSupermoon(neodevice_t neodevice) : Device(neodevice) { - initialize(); - productId = PRODUCT_ID; - getWritableNeoDevice().type = DEVICE_TYPE; + RADSupermoon(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } void setupPacketizer(Packetizer& packetizer) override { diff --git a/include/icsneo/device/tree/valuecan3/valuecan3.h b/include/icsneo/device/tree/valuecan3/valuecan3.h index 7b673cd..3d58fbd 100644 --- a/include/icsneo/device/tree/valuecan3/valuecan3.h +++ b/include/icsneo/device/tree/valuecan3/valuecan3.h @@ -12,16 +12,8 @@ namespace icsneo { class ValueCAN3 : public Device { public: - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VCAN3; - static constexpr const uint16_t PRODUCT_ID = 0x0601; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID)) - found.emplace_back(new ValueCAN3(neodevice)); - - return found; - } + // USB PID is 0x0601, standard driver is FTDI + ICSNEO_FINDABLE_DEVICE_BY_PID(ValueCAN3, DeviceType::VCAN3, 0x0701); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -32,19 +24,17 @@ public: } private: - ValueCAN3(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + ValueCAN3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } bool requiresVehiclePower() const override { return false; } }; diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-1.h b/include/icsneo/device/tree/valuecan4/valuecan4-1.h index edd950d..8a89b89 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4-1.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4-1.h @@ -5,27 +5,14 @@ #include "icsneo/device/tree/valuecan4/valuecan4.h" #include "icsneo/device/tree/valuecan4/settings/valuecan4-1settings.h" -#include "icsneo/platform/cdcacm.h" -#include namespace icsneo { class ValueCAN4_1 : public ValueCAN4 { public: // Serial numbers start with V1 for 4-1 - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VCAN4_1; - static constexpr const char* SERIAL_START = "V1"; - - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(USB_PRODUCT_ID)) { - if(std::string(neodevice.serial).substr(0, 2) == SERIAL_START) - found.emplace_back(new ValueCAN4_1(neodevice)); - } - - return found; - } + // USB PID is 0x1101 (shared by all ValueCAN 4s), standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(ValueCAN4_1, DeviceType::VCAN4_1, "V1"); static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { @@ -35,25 +22,22 @@ public: } protected: + ValueCAN4_1(neodevice_t neodevice, const driver_factory_t& makeDriver) : ValueCAN4(neodevice) { + initialize(makeDriver); + } + void setupEncoder(Encoder& encoder) override { ValueCAN4::setupEncoder(encoder); encoder.supportCANFD = false; // VCAN 4-1 does not support CAN FD } - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } - -private: - ValueCAN4_1(neodevice_t neodevice) : ValueCAN4(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = USB_PRODUCT_ID; - } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-2.h b/include/icsneo/device/tree/valuecan4/valuecan4-2.h index 4481b02..c2a062e 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4-2.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4-2.h @@ -5,33 +5,20 @@ #include "icsneo/device/tree/valuecan4/valuecan4.h" #include "icsneo/device/tree/valuecan4/settings/valuecan4-2settings.h" -#include "icsneo/platform/cdcacm.h" -#include namespace icsneo { class ValueCAN4_2 : public ValueCAN4 { public: // Serial numbers start with V2 for 4-2 - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VCAN4_2; - static constexpr const char* SERIAL_START = "V2"; + // USB PID is 0x1101 (shared by all ValueCAN 4s), standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(ValueCAN4_2, DeviceType::VCAN4_2, "V2"); enum class SKU { Standard, AP0200A, // USB A and Keysight Branding }; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(USB_PRODUCT_ID)) { - if(std::string(neodevice.serial).substr(0, 2) == SERIAL_START) - found.emplace_back(new ValueCAN4_2(neodevice)); - } - - return found; - } - static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { Network::NetID::HSCAN, @@ -60,20 +47,17 @@ public: } protected: - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + ValueCAN4_2(neodevice_t neodevice, const driver_factory_t& makeDriver) : ValueCAN4(neodevice) { + initialize(makeDriver); + } + + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } - -private: - ValueCAN4_2(neodevice_t neodevice) : ValueCAN4(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = USB_PRODUCT_ID; - } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-2el.h b/include/icsneo/device/tree/valuecan4/valuecan4-2el.h index 995509b..c4eec65 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4-2el.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4-2el.h @@ -5,15 +5,15 @@ #include "icsneo/device/tree/valuecan4/valuecan4.h" #include "icsneo/device/tree/valuecan4/settings/valuecan4-2elsettings.h" -#include namespace icsneo { class ValueCAN4_2EL : public ValueCAN4 { public: // Serial numbers start with VE for 4-2EL - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VCAN4_2EL; - static constexpr const char* SERIAL_START = "VE"; + // USB PID is 0x1101 (shared by all ValueCAN 4s), standard driver is CDCACM + // Ethernet MAC allocation is 0x0B, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(ValueCAN4_2EL, DeviceType::VCAN4_2EL, "VE"); enum class SKU { Standard, @@ -53,14 +53,16 @@ public: Network::NetID::HSCAN, Network::NetID::HSCAN2, - Network::NetID::Ethernet + Network::NetID::Ethernet, + + Network::NetID::LIN }; return supportedNetworks; } protected: - ValueCAN4_2EL(neodevice_t neodevice) : ValueCAN4(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; + ValueCAN4_2EL(neodevice_t neodevice, const driver_factory_t& makeDriver) : ValueCAN4(neodevice) { + initialize(makeDriver); } void setupSupportedRXNetworks(std::vector& rxNetworks) override { @@ -80,6 +82,13 @@ protected: const valuecan4_2el_status_t* status = reinterpret_cast(message->data.data()); ethActivationStatus = status->ethernetActivationLineEnabled; } + + bool currentDriverSupportsDFU() const override { return com->driver->isEthernet(); } + + void setupPacketizer(Packetizer& packetizer) override { + ValueCAN4::setupPacketizer(packetizer); + packetizer.align16bit = !com->driver->isEthernet(); + } }; } diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-2eleth.h b/include/icsneo/device/tree/valuecan4/valuecan4-2eleth.h deleted file mode 100644 index 67af4fc..0000000 --- a/include/icsneo/device/tree/valuecan4/valuecan4-2eleth.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef __VALUECAN4_2EL_ETH_H_ -#define __VALUECAN4_2EL_ETH_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/valuecan4/valuecan4-2el.h" -#include "icsneo/platform/pcap.h" -#include - -namespace icsneo { - -class ValueCAN4_2EL_ETH : public ValueCAN4_2EL { -public: - static constexpr const uint16_t ETH_PRODUCT_ID = 0x000B; - - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new ValueCAN4_2EL_ETH({})); - for (auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for (auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if (!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a ValueCAN4-2EL - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.push_back(std::shared_ptr(new ValueCAN4_2EL_ETH(std::move(device)))); - break; - } - } - - return found; - } - - bool currentDriverSupportsDFU() const override { return false; } - -protected: - void setupPacketizer(Packetizer& packetizer) override { - ValueCAN4_2EL::setupPacketizer(packetizer); - packetizer.align16bit = false; - } - -private: - ValueCAN4_2EL_ETH(neodevice_t neodevice) : ValueCAN4_2EL(neodevice) { - initialize(); - productId = ETH_PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-2elusb.h b/include/icsneo/device/tree/valuecan4/valuecan4-2elusb.h deleted file mode 100644 index ae9756b..0000000 --- a/include/icsneo/device/tree/valuecan4/valuecan4-2elusb.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __VALUECAN4_2EL_USB_H_ -#define __VALUECAN4_2EL_USB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/valuecan4/valuecan4-2el.h" -#include "icsneo/platform/cdcacm.h" -#include - -namespace icsneo { - -class ValueCAN4_2EL_USB : public ValueCAN4_2EL { -public: - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(USB_PRODUCT_ID)) { - if(std::string(neodevice.serial).substr(0, 2) == SERIAL_START) - found.emplace_back(new ValueCAN4_2EL_USB(neodevice)); - } - - return found; - } - -private: - ValueCAN4_2EL_USB(neodevice_t neodevice) : ValueCAN4_2EL(neodevice) { - initialize(); - productId = USB_PRODUCT_ID; - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/valuecan4/valuecan4-4.h b/include/icsneo/device/tree/valuecan4/valuecan4-4.h index 4d147d4..ee0e920 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4-4.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4-4.h @@ -5,16 +5,14 @@ #include "icsneo/device/tree/valuecan4/valuecan4.h" #include "icsneo/device/tree/valuecan4/settings/valuecan4-4settings.h" -#include "icsneo/platform/cdcacm.h" -#include namespace icsneo { class ValueCAN4_4 : public ValueCAN4 { public: // Serial numbers start with V4 for 4-4 - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VCAN4_4; - static constexpr const char* SERIAL_START = "V4"; + // USB PID is 0x1101 (shared by all ValueCAN 4s), standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(ValueCAN4_4, DeviceType::VCAN4_4, "V4"); enum class SKU { Standard, @@ -23,17 +21,6 @@ public: AP0400A_OBD, // OBD, USB A, and Keysight Branding }; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(USB_PRODUCT_ID)) { - if(std::string(neodevice.serial).substr(0, 2) == SERIAL_START) - found.emplace_back(new ValueCAN4_4(neodevice)); - } - - return found; - } - static const std::vector& GetSupportedNetworks() { static std::vector supportedNetworks = { Network::NetID::HSCAN, @@ -71,20 +58,17 @@ public: } protected: - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { + ValueCAN4_4(neodevice_t neodevice, const driver_factory_t& makeDriver) : ValueCAN4(neodevice) { + initialize(makeDriver); + } + + void setupSupportedRXNetworks(std::vector& rxNetworks) override { for(auto& netid : GetSupportedNetworks()) rxNetworks.emplace_back(netid); } // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } - -private: - ValueCAN4_4(neodevice_t neodevice) : ValueCAN4(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = USB_PRODUCT_ID; - } + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } }; } diff --git a/include/icsneo/device/tree/valuecan4/valuecan4.h b/include/icsneo/device/tree/valuecan4/valuecan4.h index f98cb8c..d17520a 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4.h @@ -10,17 +10,16 @@ namespace icsneo { class ValueCAN4 : public Device { public: - // All ValueCAN 4 devices share a USB PID - static constexpr const uint16_t USB_PRODUCT_ID = 0x1101; + // All ValueCAN 4 devices share a USB PID of 0x1101 protected: + using Device::Device; + virtual void setupEncoder(Encoder& encoder) override { Device::setupEncoder(encoder); encoder.supportCANFD = true; } - ValueCAN4(neodevice_t neodevice) : Device(neodevice) {} - bool requiresVehiclePower() const override { return false; } }; diff --git a/include/icsneo/device/tree/valuecan4/valuecan4industrial.h b/include/icsneo/device/tree/valuecan4/valuecan4industrial.h index 6abf963..dc6288b 100644 --- a/include/icsneo/device/tree/valuecan4/valuecan4industrial.h +++ b/include/icsneo/device/tree/valuecan4/valuecan4industrial.h @@ -11,12 +11,40 @@ namespace icsneo { class ValueCAN4Industrial : public ValueCAN4 { public: // Serial numbers start with IV for Industrial - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VCAN4_IND; - static constexpr const char* SERIAL_START = "IV"; + // USB PID is 0x1101 (shared by all ValueCAN 4s), standard driver is CDCACM + // Ethernet MAC allocation is 0x12, standard driver is Raw + ICSNEO_FINDABLE_DEVICE(ValueCAN4Industrial, DeviceType::VCAN4_IND, "IV"); + + static const std::vector& GetSupportedNetworks() { + static std::vector supportedNetworks = { + Network::NetID::HSCAN, + Network::NetID::HSCAN2, + + Network::NetID::Ethernet, + + Network::NetID::LIN + }; + return supportedNetworks; + } protected: - ValueCAN4Industrial(neodevice_t neodevice) : ValueCAN4(neodevice) { - getWritableNeoDevice().type = DEVICE_TYPE; + ValueCAN4Industrial(neodevice_t neodevice, const driver_factory_t& makeDriver) : ValueCAN4(neodevice) { + initialize(makeDriver); + } + + void setupSupportedRXNetworks(std::vector& rxNetworks) override { + for(auto& netid : GetSupportedNetworks()) + rxNetworks.emplace_back(netid); + } + + // The supported TX networks are the same as the supported RX networks for this device + void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } + + bool currentDriverSupportsDFU() const override { return com->driver->isEthernet(); } + + void setupPacketizer(Packetizer& packetizer) override { + ValueCAN4::setupPacketizer(packetizer); + packetizer.align16bit = !com->driver->isEthernet(); } }; diff --git a/include/icsneo/device/tree/valuecan4/valuecan4industrialeth.h b/include/icsneo/device/tree/valuecan4/valuecan4industrialeth.h deleted file mode 100644 index e36458d..0000000 --- a/include/icsneo/device/tree/valuecan4/valuecan4industrialeth.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __VALUECAN4INDUSTRIAL_ETH_H_ -#define __VALUECAN4INDUSTRIAL_ETH_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/valuecan4/valuecan4industrial.h" -#include "icsneo/platform/pcap.h" -#include - -namespace icsneo { - -class ValueCAN4IndustrialETH : public ValueCAN4Industrial { -public: - static constexpr const uint16_t ETH_PRODUCT_ID = 0x0012; - - static std::vector> Find(const std::vector& pcapDevices) { - std::vector> found; - - for(auto& foundDev : pcapDevices) { - auto fakedev = std::shared_ptr(new ValueCAN4IndustrialETH({})); - for (auto& payload : foundDev.discoveryPackets) - fakedev->com->packetizer->input(payload); - for (auto& packet : fakedev->com->packetizer->output()) { - std::shared_ptr msg; - if (!fakedev->com->decoder->decode(msg, packet)) - continue; // We failed to decode this packet - - if(!msg || msg->type != Message::Type::Main51) - continue; // Not a message we care about - auto sn = std::dynamic_pointer_cast(msg); - if(!sn) - continue; // Not a serial number message - - if(sn->deviceSerial.length() < 2) - continue; - if(sn->deviceSerial.substr(0, 2) != SERIAL_START) - continue; // Not a ValueCAN 4 Industrial - - auto device = foundDev.device; - device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0'; - found.push_back(std::shared_ptr(new ValueCAN4IndustrialETH(std::move(device)))); - break; - } - } - - return found; - } - - static const std::vector& GetSupportedNetworks() { - static std::vector supportedNetworks = { - Network::NetID::HSCAN, - Network::NetID::HSCAN2, - - // No Network::NetID::Ethernet, since we're communicating over it instead - }; - return supportedNetworks; - } - - bool currentDriverSupportsDFU() const override { return false; } - -protected: - void setupPacketizer(Packetizer& packetizer) override { - ValueCAN4Industrial::setupPacketizer(packetizer); - packetizer.align16bit = false; - } - - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { - for(auto& netid : GetSupportedNetworks()) - rxNetworks.emplace_back(netid); - } - - // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } - -private: - ValueCAN4IndustrialETH(neodevice_t neodevice) : ValueCAN4Industrial(neodevice) { - initialize(); - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/valuecan4/valuecan4industrialusb.h b/include/icsneo/device/tree/valuecan4/valuecan4industrialusb.h deleted file mode 100644 index 1aeae8b..0000000 --- a/include/icsneo/device/tree/valuecan4/valuecan4industrialusb.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __VALUECAN4INDUSTRIAL_USB_H_ -#define __VALUECAN4INDUSTRIAL_USB_H_ - -#ifdef __cplusplus - -#include "icsneo/device/tree/valuecan4/valuecan4industrial.h" -#include "icsneo/platform/cdcacm.h" -#include - -namespace icsneo { - -class ValueCAN4IndustrialUSB : public ValueCAN4Industrial { -public: - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(USB_PRODUCT_ID)) { - if(std::string(neodevice.serial).substr(0, 2) == SERIAL_START) - found.emplace_back(new ValueCAN4IndustrialUSB(neodevice)); - } - - return found; - } - - static const std::vector& GetSupportedNetworks() { - static std::vector supportedNetworks = { - Network::NetID::HSCAN, - Network::NetID::HSCAN2, - - Network::NetID::Ethernet - }; - return supportedNetworks; - } - -protected: - virtual void setupSupportedRXNetworks(std::vector& rxNetworks) override { - for(auto& netid : GetSupportedNetworks()) - rxNetworks.emplace_back(netid); - } - - // The supported TX networks are the same as the supported RX networks for this device - virtual void setupSupportedTXNetworks(std::vector& txNetworks) override { setupSupportedRXNetworks(txNetworks); } - -private: - ValueCAN4IndustrialUSB(neodevice_t neodevice) : ValueCAN4Industrial(neodevice) { - initialize(); - } -}; - -} - -#endif // __cplusplus - -#endif \ No newline at end of file diff --git a/include/icsneo/device/tree/vividcan/vividcan.h b/include/icsneo/device/tree/vividcan/vividcan.h index 72242c6..9e6a636 100644 --- a/include/icsneo/device/tree/vividcan/vividcan.h +++ b/include/icsneo/device/tree/vividcan/vividcan.h @@ -13,16 +13,8 @@ namespace icsneo { class VividCAN : public Device { public: // Serial numbers start with VV - static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::VividCAN; - static constexpr const uint16_t PRODUCT_ID = 0x1102; - static std::vector> Find() { - std::vector> found; - - for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID)) - found.emplace_back(new VividCAN(neodevice)); - - return found; - } + // USB PID is 0x1102, standard driver is CDCACM + ICSNEO_FINDABLE_DEVICE(VividCAN, DeviceType::VividCAN, "VV"); // VividCAN does not go online, you can only set settings bool goOnline() override { @@ -36,14 +28,11 @@ public: } protected: - bool requiresVehiclePower() const override { return false; } - -private: - VividCAN(neodevice_t neodevice) : Device(neodevice) { - initialize(); - getWritableNeoDevice().type = DEVICE_TYPE; - productId = PRODUCT_ID; + VividCAN(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { + initialize(makeDriver); } + + bool requiresVehiclePower() const override { return false; } }; } diff --git a/include/icsneo/platform/pcap.h b/include/icsneo/platform/pcap.h index d73138d..738ceae 100644 --- a/include/icsneo/platform/pcap.h +++ b/include/icsneo/platform/pcap.h @@ -1,14 +1,12 @@ #ifndef __PCAP_H_ #define __PCAP_H_ -#if defined _WIN32 +#ifdef _WIN32 #include "icsneo/platform/windows/pcap.h" -#elif defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) +#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include "icsneo/platform/posix/pcap.h" #else #warning "This platform is not supported by the PCAP driver" #endif -#define LIBICSNEO_HAVE_PCAP 1 - #endif \ No newline at end of file diff --git a/include/icsneo/platform/posix/cdcacm.h b/include/icsneo/platform/posix/cdcacm.h index a3f8d43..505ca25 100644 --- a/include/icsneo/platform/posix/cdcacm.h +++ b/include/icsneo/platform/posix/cdcacm.h @@ -27,7 +27,7 @@ public: */ CDCACM(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {} ~CDCACM(); - static std::vector FindByProduct(int product); + static void Find(std::vector& found); bool open() override; bool isOpen() override; diff --git a/include/icsneo/platform/posix/devices.h b/include/icsneo/platform/posix/devices.h index 435f157..244cfa9 100644 --- a/include/icsneo/platform/posix/devices.h +++ b/include/icsneo/platform/posix/devices.h @@ -5,31 +5,25 @@ #include "icsneo/device/tree/neoobd2pro/neoobd2pro.h" #include "icsneo/device/tree/neoobd2sim/neoobd2sim.h" #include "icsneo/device/tree/neovifire/neovifire.h" -#include "icsneo/device/tree/neovifire2/neovifire2eth.h" -#include "icsneo/device/tree/neovifire2/neovifire2usb.h" +#include "icsneo/device/tree/neovifire2/neovifire2.h" #include "icsneo/device/tree/neovired2/neovired2.h" #include "icsneo/device/tree/plasion/neoviion.h" #include "icsneo/device/tree/plasion/neoviplasma.h" #include "icsneo/device/tree/radepsilon/radepsilon.h" #include "icsneo/device/tree/radgalaxy/radgalaxy.h" -#include "icsneo/device/tree/radgigastar/radgigastareth.h" -#include "icsneo/device/tree/radgigastar/radgigastarusb.h" -#include "icsneo/device/tree/radmars/radmarseth.h" -#include "icsneo/device/tree/radmars/radmarsusb.h" +#include "icsneo/device/tree/radgigastar/radgigastar.h" +#include "icsneo/device/tree/radmars/radmars.h" #include "icsneo/device/tree/radmoon2/radmoon2.h" #include "icsneo/device/tree/radmoonduo/radmoonduo.h" -#include "icsneo/device/tree/radpluto/radplutousb.h" -#include "icsneo/device/tree/radstar2/radstar2eth.h" -#include "icsneo/device/tree/radstar2/radstar2usb.h" +#include "icsneo/device/tree/radpluto/radpluto.h" +#include "icsneo/device/tree/radstar2/radstar2.h" #include "icsneo/device/tree/radsupermoon/radsupermoon.h" #include "icsneo/device/tree/valuecan3/valuecan3.h" #include "icsneo/device/tree/valuecan4/valuecan4-1.h" #include "icsneo/device/tree/valuecan4/valuecan4-2.h" -#include "icsneo/device/tree/valuecan4/valuecan4-2eleth.h" -#include "icsneo/device/tree/valuecan4/valuecan4-2elusb.h" +#include "icsneo/device/tree/valuecan4/valuecan4-2el.h" #include "icsneo/device/tree/valuecan4/valuecan4-4.h" -#include "icsneo/device/tree/valuecan4/valuecan4industrialeth.h" -#include "icsneo/device/tree/valuecan4/valuecan4industrialusb.h" +#include "icsneo/device/tree/valuecan4/valuecan4industrial.h" #include "icsneo/device/tree/vividcan/vividcan.h" #endif \ No newline at end of file diff --git a/include/icsneo/platform/posix/ftdi.h b/include/icsneo/platform/posix/ftdi.h index d67e6b1..1e1eb54 100644 --- a/include/icsneo/platform/posix/ftdi.h +++ b/include/icsneo/platform/posix/ftdi.h @@ -16,7 +16,7 @@ namespace icsneo { class FTDI : public Driver { public: - static std::vector FindByProduct(int product); + static void Find(std::vector& found); FTDI(const device_eventhandler_t& err, neodevice_t& forDevice); ~FTDI() { if(isOpen()) close(); } @@ -34,7 +34,9 @@ private: context = nullptr; } - std::pair> findDevices(int pid); + // A PID of 0 disables filtering by PID + std::pair > > findDevices(int pid = 0); + int openDevice(int pid, const char* serial); bool closeDevice(); bool isOpen() const { return deviceOpen; } @@ -52,7 +54,7 @@ private: }; FTDIContext ftdi; - static std::vector> handles; + static std::vector handles; static bool ErrorIsDisconnection(int errorCode); void readTask(); diff --git a/include/icsneo/platform/posix/pcap.h b/include/icsneo/platform/posix/pcap.h index 8981fcf..3167578 100644 --- a/include/icsneo/platform/posix/pcap.h +++ b/include/icsneo/platform/posix/pcap.h @@ -4,6 +4,7 @@ #ifdef __cplusplus #include "icsneo/device/neodevice.h" +#include "icsneo/device/founddevice.h" #include "icsneo/communication/driver.h" #include "icsneo/communication/ethernetpacketizer.h" #include "icsneo/api/eventmanager.h" @@ -14,33 +15,28 @@ namespace icsneo { class PCAP : public Driver { public: - class PCAPFoundDevice { - public: - neodevice_t device; - std::vector> discoveryPackets; - }; - - static std::vector FindAll(); + static void Find(std::vector& foundDevices); static std::string GetEthDevSerialFromMacAddress(uint8_t product, uint16_t macSerial); static bool IsHandleValid(neodevice_handle_t handle); PCAP(device_eventhandler_t err, neodevice_t& forDevice); - bool open(); - bool isOpen(); - bool close(); + bool open() override; + bool isOpen() override; + bool close() override; + bool isEthernet() const override { return true; } private: char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; neodevice_t& device; uint8_t deviceMAC[6]; bool openable = true; EthernetPacketizer ethPacketizer; - void readTask(); - void writeTask(); + void readTask() override; + void writeTask() override; class NetworkInterface { public: uint8_t uuid; - uint8_t macAddress[8]; + uint8_t macAddress[6]; std::string nameFromPCAP; std::string descriptionFromPCAP; std::string fullName; diff --git a/include/icsneo/platform/windows/cdcacm.h b/include/icsneo/platform/windows/cdcacm.h index 507191e..26a7ef6 100644 --- a/include/icsneo/platform/windows/cdcacm.h +++ b/include/icsneo/platform/windows/cdcacm.h @@ -10,7 +10,7 @@ namespace icsneo { class CDCACM : public VCP { public: CDCACM(const device_eventhandler_t& err, neodevice_t& forDevice) : VCP(err, forDevice) {} - static std::vector FindByProduct(int product) { return VCP::FindByProduct(product, { L"usbser" }); } + static void Find(std::vector& found) { return VCP::Find(found, { L"usbser" }); } }; } diff --git a/include/icsneo/platform/windows/devices.h b/include/icsneo/platform/windows/devices.h index 35bfd3a..29bf5a1 100644 --- a/include/icsneo/platform/windows/devices.h +++ b/include/icsneo/platform/windows/devices.h @@ -5,31 +5,25 @@ #include "icsneo/device/tree/neoobd2pro/neoobd2pro.h" #include "icsneo/device/tree/neoobd2sim/neoobd2sim.h" #include "icsneo/device/tree/neovifire/neovifire.h" -#include "icsneo/device/tree/neovifire2/neovifire2eth.h" -#include "icsneo/device/tree/neovifire2/neovifire2usb.h" +#include "icsneo/device/tree/neovifire2/neovifire2.h" #include "icsneo/device/tree/neovired2/neovired2.h" #include "icsneo/device/tree/plasion/neoviion.h" #include "icsneo/device/tree/plasion/neoviplasma.h" #include "icsneo/device/tree/radepsilon/radepsilon.h" #include "icsneo/device/tree/radgalaxy/radgalaxy.h" -#include "icsneo/device/tree/radgigastar/radgigastareth.h" -#include "icsneo/device/tree/radgigastar/radgigastarusb.h" -#include "icsneo/device/tree/radmars/radmarseth.h" -#include "icsneo/device/tree/radmars/radmarsusb.h" +#include "icsneo/device/tree/radgigastar/radgigastar.h" +#include "icsneo/device/tree/radmars/radmars.h" #include "icsneo/device/tree/radmoon2/radmoon2.h" #include "icsneo/device/tree/radmoonduo/radmoonduo.h" -#include "icsneo/device/tree/radpluto/radplutousb.h" -#include "icsneo/device/tree/radstar2/radstar2eth.h" -#include "icsneo/device/tree/radstar2/radstar2usb.h" +#include "icsneo/device/tree/radpluto/radpluto.h" +#include "icsneo/device/tree/radstar2/radstar2.h" #include "icsneo/device/tree/radsupermoon/radsupermoon.h" #include "icsneo/device/tree/valuecan3/valuecan3.h" #include "icsneo/device/tree/valuecan4/valuecan4-1.h" #include "icsneo/device/tree/valuecan4/valuecan4-2.h" -#include "icsneo/device/tree/valuecan4/valuecan4-2eleth.h" -#include "icsneo/device/tree/valuecan4/valuecan4-2elusb.h" +#include "icsneo/device/tree/valuecan4/valuecan4-2el.h" #include "icsneo/device/tree/valuecan4/valuecan4-4.h" -#include "icsneo/device/tree/valuecan4/valuecan4industrialeth.h" -#include "icsneo/device/tree/valuecan4/valuecan4industrialusb.h" +#include "icsneo/device/tree/valuecan4/valuecan4industrial.h" #include "icsneo/device/tree/vividcan/vividcan.h" #endif \ No newline at end of file diff --git a/include/icsneo/platform/windows/ftdi.h b/include/icsneo/platform/windows/ftdi.h index f987504..d35b517 100644 --- a/include/icsneo/platform/windows/ftdi.h +++ b/include/icsneo/platform/windows/ftdi.h @@ -10,7 +10,7 @@ namespace icsneo { class FTDI : public VCP { public: FTDI(const device_eventhandler_t& err, neodevice_t& forDevice) : VCP(err, forDevice) {} - static std::vector FindByProduct(int product) { return VCP::FindByProduct(product, { L"serenum" /*, L"ftdibus" */ }); } + static void Find(std::vector& found) { return VCP::Find(found, { L"serenum" /*, L"ftdibus" */ }); } }; } diff --git a/include/icsneo/platform/windows/pcap.h b/include/icsneo/platform/windows/pcap.h index 39ebe7f..f9a3cc8 100644 --- a/include/icsneo/platform/windows/pcap.h +++ b/include/icsneo/platform/windows/pcap.h @@ -6,6 +6,7 @@ #include "icsneo/platform/windows/internal/pcapdll.h" #include "icsneo/device/neodevice.h" #include "icsneo/communication/driver.h" +#include "icsneo/device/founddevice.h" #include "icsneo/api/eventmanager.h" #include "icsneo/communication/ethernetpacketizer.h" #include @@ -14,20 +15,15 @@ namespace icsneo { class PCAP : public Driver { public: - class PCAPFoundDevice { - public: - neodevice_t device; - std::vector> discoveryPackets; - }; - - static std::vector FindAll(); + static void Find(std::vector& foundDevices); static std::string GetEthDevSerialFromMacAddress(uint8_t product, uint16_t macSerial); static bool IsHandleValid(neodevice_handle_t handle); PCAP(const device_eventhandler_t& err, neodevice_t& forDevice); - bool open(); - bool isOpen(); - bool close(); + bool open() override; + bool isOpen() override; + bool close() override; + bool isEthernet() const override { return true; } private: const PCAPDLL& pcap; char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; @@ -48,7 +44,7 @@ private: class NetworkInterface { public: uint8_t uuid; - uint8_t macAddress[8]; + uint8_t macAddress[6]; std::string nameFromWinPCAP; std::string nameFromWin32API; std::string descriptionFromWinPCAP; diff --git a/include/icsneo/platform/windows/vcp.h b/include/icsneo/platform/windows/vcp.h index 3506ad8..e4d7e31 100644 --- a/include/icsneo/platform/windows/vcp.h +++ b/include/icsneo/platform/windows/vcp.h @@ -17,7 +17,7 @@ namespace icsneo { // Virtual COM Port Communication class VCP : public Driver { public: - static std::vector FindByProduct(int product, std::vector driverName); + static void Find(std::vector& found, std::vector driverName); static bool IsHandleValid(neodevice_handle_t handle); typedef void(*fn_boolCallback)(bool success); diff --git a/platform/posix/darwin/cdcacmdarwin.cpp b/platform/posix/darwin/cdcacmdarwin.cpp index 08eb24b..81a1011 100644 --- a/platform/posix/darwin/cdcacmdarwin.cpp +++ b/platform/posix/darwin/cdcacmdarwin.cpp @@ -1,4 +1,5 @@ #include "icsneo/platform/cdcacm.h" +#include "icsneo/device/founddevice.h" #include #include #include @@ -79,22 +80,19 @@ private: io_object_t toRelease; }; -std::vector CDCACM::FindByProduct(int product) { - std::vector found; - +void CDCACM::Find(std::vector& found) { CFMutableDictionaryRef ref = IOServiceMatching(kIOSerialBSDServiceValue); if(ref == nullptr) - return found; + return; io_iterator_t matchingServices = 0; kern_return_t kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, ref, &matchingServices); if(KERN_SUCCESS != kernResult || matchingServices == 0) - return found; + return; IOReleaser matchingServicesReleaser(matchingServices); io_object_t serialPort; while((serialPort = IOIteratorNext(matchingServices))) { IOReleaser serialPortReleaser(serialPort); - neodevice_t device; // First get the parent device // We want to check that it has the right VID/PID @@ -138,10 +136,10 @@ std::vector CDCACM::FindByProduct(int product) { CFReleaser productPropReleaser(productProp); if(CFGetTypeID(productProp) != CFNumberGetTypeID()) continue; - uint16_t pid = 0; - if(!CFNumberGetValue(static_cast(productProp), kCFNumberSInt16Type, &pid)) - continue; - if(pid != product) + + // Read the PID directly into the FoundDevice structure + FoundDevice device; + if(!CFNumberGetValue(static_cast(productProp), kCFNumberSInt16Type, &device.productId)) continue; // Now, let's get the "call-out" device (/dev/cu.*) @@ -173,10 +171,13 @@ std::vector CDCACM::FindByProduct(int product) { continue; device.serial[serial.copy(device.serial, sizeof(device.serial)-1)] = '\0'; + // Add a factory to make the driver + device.makeDriver = [](const device_eventhandler_t& report, neodevice_t& device) { + return std::unique_ptr(new CDCACM(report, device)); + }; + found.push_back(device); } - - return found; } std::string CDCACM::HandleToTTY(neodevice_handle_t handle) { diff --git a/platform/posix/ftdi.cpp b/platform/posix/ftdi.cpp index fac0add..08d6676 100644 --- a/platform/posix/ftdi.cpp +++ b/platform/posix/ftdi.cpp @@ -1,4 +1,5 @@ #include "icsneo/platform/ftdi.h" +#include "icsneo/device/founddevice.h" #include #include #include @@ -9,22 +10,21 @@ using namespace icsneo; -std::vector> FTDI::handles; +std::vector FTDI::handles; -std::vector FTDI::FindByProduct(int product) { +void FTDI::Find(std::vector& found) { constexpr size_t deviceSerialBufferLength = sizeof(device.serial); - std::vector found; static FTDIContext context; - std::pair> result = context.findDevices(product); + const auto result = context.findDevices(); if(result.first < 0) - return found; // TODO Flag an error for the client application, there was an issue with FTDI + return; // TODO Flag an error for the client application, there was an issue with FTDI - for(auto& serial : result.second) { - neodevice_t d; + for(const auto& [serial, pid] : result.second) { + FoundDevice d; strncpy(d.serial, serial.c_str(), deviceSerialBufferLength - 1); d.serial[deviceSerialBufferLength - 1] = '\0'; // strncpy does not write a null terminator if serial is too long - std::tuple devHandle = std::make_tuple(product, serial); + std::string devHandle = serial; auto it = std::find(handles.begin(), handles.end(), devHandle); size_t foundHandle = SIZE_MAX; if(it != handles.end()) { @@ -34,10 +34,14 @@ std::vector FTDI::FindByProduct(int product) { handles.push_back(devHandle); } d.handle = foundHandle; + d.productId = pid; + + d.makeDriver = [](const device_eventhandler_t& report, neodevice_t& device) { + return std::unique_ptr(new FTDI(report, device)); + }; + found.push_back(d); } - - return found; } FTDI::FTDI(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) { @@ -56,8 +60,8 @@ bool FTDI::open() { } // At this point the handle has been checked to be within the bounds of the handles array - std::tuple& handle = handles[device.handle]; - const int openError = ftdi.openDevice(std::get<0>(handle), std::get<1>(handle).c_str()); + auto& handle = handles[device.handle]; + const int openError = ftdi.openDevice(0, handle.c_str()); if(openError == -5) { // Unable to claim device report(APIEvent::Type::DeviceInUse, APIEvent::Severity::Error); return false; @@ -112,17 +116,13 @@ bool FTDI::close() { return ret; } -std::pair> FTDI::FTDIContext::findDevices(int pid) { - std::pair> ret; +std::pair > > FTDI::FTDIContext::findDevices(int pid) { + std::pair > > ret; if(context == nullptr) { ret.first = -1; return ret; } - if(pid == 0) { - ret.first = -2; - return ret; - } struct ftdi_device_list* devlist = nullptr; ret.first = ftdi_usb_find_all(context, &devlist, INTREPID_USB_VENDOR_ID, pid); @@ -138,18 +138,23 @@ std::pair> FTDI::FTDIContext::findDevices(int pid) return ret; } - for (struct ftdi_device_list* curdev = devlist; curdev != NULL;) { - char serial[32]; - memset(serial, 0, sizeof(serial)); - int result = ftdi_usb_get_strings(context, curdev->dev, nullptr, 0, nullptr, 0, serial, 32); - size_t len = strlen(serial); - if(result >= 0 && len > 0) - ret.second.emplace_back(serial); - else if(ret.first > 0) - ret.first--; // We're discarding this device - curdev = curdev->next; + for(struct ftdi_device_list* curdev = devlist; curdev != nullptr; curdev = curdev->next) { + struct libusb_device_descriptor descriptor = {}; + // Check against bDeviceClass here as it will be 0 for FTDI devices + // It will be 2 for CDC ACM devices, which we don't want to handle here + if(libusb_get_device_descriptor(curdev->dev, &descriptor) != 0 || descriptor.bDeviceClass != 0) + continue; + + char serial[16] = {}; + if(ftdi_usb_get_strings(context, curdev->dev, nullptr, 0, nullptr, 0, serial, sizeof(serial)) < 0) + continue; + + const auto len = strnlen(serial, sizeof(serial)); + if(len > 4 && len < 10) + ret.second.emplace_back(serial, descriptor.idProduct); } + ret.first = static_cast(ret.second.size()); ftdi_list_free(&devlist); return ret; } @@ -157,7 +162,7 @@ std::pair> FTDI::FTDIContext::findDevices(int pid) int FTDI::FTDIContext::openDevice(int pid, const char* serial) { if(context == nullptr) return 1; - if(pid == 0 || serial == nullptr) + if(serial == nullptr) return 2; if(serial[0] == '\0') return 3; diff --git a/platform/posix/linux/cdcacmlinux.cpp b/platform/posix/linux/cdcacmlinux.cpp index fd9aec5..ea89f35 100644 --- a/platform/posix/linux/cdcacmlinux.cpp +++ b/platform/posix/linux/cdcacmlinux.cpp @@ -1,4 +1,5 @@ #include "icsneo/platform/cdcacm.h" +#include "icsneo/device/founddevice.h" #include #include #include @@ -80,12 +81,10 @@ private: std::string serial; }; -std::vector CDCACM::FindByProduct(int product) { - std::vector found; - +void CDCACM::Find(std::vector& found) { Directory directory("/sys/bus/usb/drivers/cdc_acm"); // Query the CDCACM driver if(!directory.openedSuccessfully()) - return found; + return; std::vector foundusbs; for(auto& entry : directory.ls()) { @@ -100,8 +99,9 @@ std::vector CDCACM::FindByProduct(int product) { foundusbs.emplace_back(entry.getName()); } - // Pair the USB and TTY if found - std::map foundttys; + // Map the USB directory to the TTY and PID if found + // The PID will be filled later + std::map< std::string, std::pair > foundttys; for(auto& usb : foundusbs) { std::stringstream ss; ss << "/sys/bus/usb/drivers/cdc_acm/" << usb << "/tty"; @@ -113,15 +113,16 @@ std::vector CDCACM::FindByProduct(int product) { if(listing.size() != 1) // We either got no serial ports or multiple, either way no good continue; - foundttys.insert(std::make_pair(usb, listing[0].getName())); + foundttys.insert(std::make_pair(usb, std::make_pair(listing[0].getName(), 0))); } // We're going to remove from the map if this is not the product we're looking for for(auto iter = foundttys.begin(); iter != foundttys.end(); ) { - const auto& dev = *iter; + auto& [_, pair] = *iter; + auto& [tty, ttyPid] = pair; const std::string matchString = "PRODUCT="; std::stringstream ss; - ss << "/sys/class/tty/" << dev.second << "/device/uevent"; // Read the uevent file, which contains should have a line like "PRODUCT=93c/1101/100" + ss << "/sys/class/tty/" << tty << "/device/uevent"; // Read the uevent file, which contains should have a line like "PRODUCT=93c/1101/100" std::ifstream fs(ss.str()); std::string productLine; size_t pos = std::string::npos; @@ -153,32 +154,34 @@ std::vector CDCACM::FindByProduct(int product) { continue; } - if(vid != INTREPID_USB_VENDOR_ID || pid != product) { - iter = foundttys.erase(iter); // Not the right VID or PID, remove + if(vid != INTREPID_USB_VENDOR_ID) { + iter = foundttys.erase(iter); // Not the right VID, remove continue; } + ttyPid = pid; // Set the PID for this TTY iter++; // If the loop ends without erasing the iter from the map, the item is good } // At this point, foundttys contains the the devices we want // Get the serial number, create the neodevice_t - for(auto& dev : foundttys) { - neodevice_t device; + for(auto& [usb, pair] : foundttys) { + auto& [tty, ttyPid] = pair; + FoundDevice device; - USBSerialGetter getter(dev.first); + USBSerialGetter getter(usb); if(!getter.success()) continue; // Failure, could not get serial number // In ttyACM0, we want the i to be the first character of the number size_t i; - for(i = 0; i < dev.second.length(); i++) { - if(isdigit(dev.second[i])) + for(i = 0; i < tty.length(); i++) { + if(isdigit(tty[i])) break; } // Now we try to parse the number so we have a handle for later try { - device.handle = (neodevice_handle_t)std::stoul(dev.second.substr(i)); + device.handle = (neodevice_handle_t)std::stoul(tty.substr(i)); /* The TTY numbering starts at zero, but we want to keep zero for an undefined * handle, so add a constant, and we'll subtract that constant in the open function. */ @@ -186,13 +189,17 @@ std::vector CDCACM::FindByProduct(int product) { } catch(...) { continue; // Somehow this failed, have to toss the device } - + + device.productId = ttyPid; device.serial[getter.getSerial().copy(device.serial, sizeof(device.serial)-1)] = '\0'; + // Add a factory to make the driver + device.makeDriver = [](const device_eventhandler_t& report, neodevice_t& device) { + return std::unique_ptr(new CDCACM(report, device)); + }; + found.push_back(device); // Finally, add device to search results } - - return found; } std::string CDCACM::HandleToTTY(neodevice_handle_t handle) { diff --git a/platform/posix/pcap.cpp b/platform/posix/pcap.cpp index 48925c9..341d503 100644 --- a/platform/posix/pcap.cpp +++ b/platform/posix/pcap.cpp @@ -1,7 +1,9 @@ #include "icsneo/platform/posix/pcap.h" #include "icsneo/communication/network.h" #include "icsneo/communication/communication.h" +#include "icsneo/communication/ethernetpacketizer.h" #include "icsneo/communication/packetizer.h" +#include "icsneo/communication/decoder.h" #include #include #include @@ -15,14 +17,10 @@ using namespace icsneo; -static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -static const uint8_t ICS_UNSET_MAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF }; - std::vector PCAP::knownInterfaces; -std::vector PCAP::FindAll() { +void PCAP::Find(std::vector& found) { static bool warned = false; // Only warn once for failure to open devices - std::vector foundDevices; // First we ask PCAP to give us all of the devices pcap_if_t* alldevs; @@ -39,7 +37,7 @@ std::vector PCAP::FindAll() { if(!success) { EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error); - return std::vector(); + return; } std::vector interfaces; @@ -138,7 +136,7 @@ std::vector PCAP::FindAll() { pcap_sendpacket(iface.fp, bs.data(), (int)bs.size()); auto timeout = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(50); - while(std::chrono::high_resolution_clock::now() <= timeout) { // Wait up to 5ms for the response + while(std::chrono::high_resolution_clock::now() <= timeout) { // Wait up to 50ms for the response struct pcap_pkthdr* header; const uint8_t* data; auto res = pcap_next_ex(iface.fp, &header, &data); @@ -152,48 +150,49 @@ std::vector PCAP::FindAll() { } if(res == 0) continue; // Keep waiting for that packet - - EthernetPacketizer::EthernetPacket packet(data, header->caplen); - // Is this an ICS response packet (0xCAB2) from an ICS MAC, either to broadcast or directly to us? - if(packet.etherType == 0xCAB2 && packet.srcMAC[0] == 0x00 && packet.srcMAC[1] == 0xFC && packet.srcMAC[2] == 0x70 && ( - memcmp(packet.destMAC, iface.macAddress, sizeof(packet.destMAC)) == 0 || - memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) == 0 || - memcmp(packet.destMAC, ICS_UNSET_MAC, sizeof(packet.destMAC)) == 0 - )) { - /* We have received a packet from a device. We don't know if this is the device we're - * looking for, we don't know if it's actually a response to our RequestSerialNumber - * or not, we just know we got something. - * - * Unlike most transport layers, we can't get the serial number here as we actually - * need to parse this message that has been returned. Some devices parse messages - * differently, so we need to use their communication layer. We could technically - * create a communication layer to parse the packet we have in `payload` here, but - * we'd need to be given a packetizer and decoder for the device. I'm intentionally - * avoiding passing that information down here for code quality's sake. Instead, pass - * the packet we received back up so the device can handle it. - */ - neodevice_handle_t handle = (neodevice_handle_t)((i << 24) | (packet.srcMAC[3] << 16) | (packet.srcMAC[4] << 8) | (packet.srcMAC[5])); - PCAPFoundDevice* alreadyExists = nullptr; - for(auto& dev : foundDevices) - if(dev.device.handle == handle) - alreadyExists = &dev; - if(alreadyExists == nullptr) { - PCAPFoundDevice foundDevice; - foundDevice.device.handle = handle; - foundDevice.discoveryPackets.push_back(std::move(packet.payload)); - foundDevices.push_back(foundDevice); - } else { - alreadyExists->discoveryPackets.push_back(std::move(packet.payload)); - } + EthernetPacketizer ethPacketizer([](APIEvent::Type, APIEvent::Severity) {}); + memcpy(ethPacketizer.hostMAC, iface.macAddress, sizeof(ethPacketizer.hostMAC)); + ethPacketizer.allowInPacketsFromAnyMAC = true; + if(!ethPacketizer.inputUp({ data, data + header->caplen })) + continue; // This packet is not for us + + Packetizer packetizer([](APIEvent::Type, APIEvent::Severity) {}); + if(!packetizer.input(ethPacketizer.outputUp())) + continue; // This packet was not well formed + + EthernetPacketizer::EthernetPacket decoded(data, header->caplen); + Decoder decoder([](APIEvent::Type, APIEvent::Severity) {}); + for(const auto& packet : packetizer.output()) { + std::shared_ptr message; + if(!decoder.decode(message, packet)) + continue; + + const neodevice_handle_t handle = (neodevice_handle_t)((i << 24) | (decoded.srcMAC[3] << 16) | (decoded.srcMAC[4] << 8) | (decoded.srcMAC[5])); + if(std::any_of(found.begin(), found.end(), [&handle](const auto& found) { return handle == found.handle; })) + continue; // We already have this device on this interface + + const auto serial = std::dynamic_pointer_cast(message); + if(!serial || serial->deviceSerial.size() != 6) + continue; + + FoundDevice foundDevice; + foundDevice.handle = handle; + foundDevice.productId = decoded.srcMAC[2]; + memcpy(foundDevice.serial, serial->deviceSerial.c_str(), sizeof(foundDevice.serial) - 1); + foundDevice.serial[sizeof(foundDevice.serial) - 1] = '\0'; + + foundDevice.makeDriver = [](const device_eventhandler_t& report, neodevice_t& device) { + return std::unique_ptr(new PCAP(report, device)); + }; + + found.push_back(foundDevice); } } pcap_close(iface.fp); iface.fp = nullptr; } - - return foundDevices; } bool PCAP::IsHandleValid(neodevice_handle_t handle) { diff --git a/platform/windows/pcap.cpp b/platform/windows/pcap.cpp index 662e6ca..fb1a513 100644 --- a/platform/windows/pcap.cpp +++ b/platform/windows/pcap.cpp @@ -4,8 +4,9 @@ #include "icsneo/platform/windows/pcap.h" #include "icsneo/communication/network.h" #include "icsneo/communication/communication.h" -#include "icsneo/communication/packetizer.h" #include "icsneo/communication/ethernetpacketizer.h" +#include "icsneo/communication/packetizer.h" +#include "icsneo/communication/decoder.h" #include #include #pragma comment(lib, "IPHLPAPI.lib") @@ -17,17 +18,14 @@ using namespace icsneo; static std::wstring_convert> converter; -static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -static const uint8_t ICS_UNSET_MAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF }; std::vector PCAP::knownInterfaces; -std::vector PCAP::FindAll() { - std::vector foundDevices; +void PCAP::Find(std::vector& found) { const PCAPDLL& pcap = PCAPDLL::getInstance(); if(!pcap.ok()) { EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotStart, APIEvent::Severity::Error); - return std::vector(); + return; } // First we ask WinPCAP to give us all of the devices @@ -45,7 +43,7 @@ std::vector PCAP::FindAll() { if(!success) { EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error); - return std::vector(); + return; } std::vector interfaces; @@ -62,13 +60,13 @@ std::vector PCAP::FindAll() { ULONG size = 0; if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &size) != ERROR_BUFFER_OVERFLOW) { EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error); - return std::vector(); + return; } std::vector adapterAddressBuffer; adapterAddressBuffer.resize(size); if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, (IP_ADAPTER_ADDRESSES*)adapterAddressBuffer.data(), &size) != ERROR_SUCCESS) { EventManager::GetInstance().add(APIEvent::Type::PCAPCouldNotFindDevices, APIEvent::Severity::Error); - return std::vector(); + return; } // aa->AdapterName constains a unique name of the interface like "{3B1D2791-435A-456F-8A7B-9CB0EEE5DAB3}" @@ -137,46 +135,48 @@ std::vector PCAP::FindAll() { if(res == 0) continue; // Keep waiting for that packet - EthernetPacketizer::EthernetPacket packet(data, header->caplen); - // Is this an ICS response packet (0xCAB2) from an ICS MAC, either to broadcast or directly to us? - if(packet.etherType == 0xCAB2 && packet.srcMAC[0] == 0x00 && packet.srcMAC[1] == 0xFC && packet.srcMAC[2] == 0x70 && ( - memcmp(packet.destMAC, iface.macAddress, sizeof(packet.destMAC)) == 0 || - memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) == 0 - )) { - /* We have received a packet from a device. We don't know if this is the device we're - * looking for, we don't know if it's actually a response to our RequestSerialNumber - * or not, we just know we got something. - * - * Unlike most transport layers, we can't get the serial number here as we actually - * need to parse this message that has been returned. Some devices parse messages - * differently, so we need to use their communication layer. We could technically - * create a communication layer to parse the packet we have in `payload` here, but - * we'd need to be given a packetizer and decoder for the device. I'm intentionally - * avoiding passing that information down here for code quality's sake. Instead, pass - * the packet we received back up so the device can handle it. - */ - neodevice_handle_t handle = (neodevice_handle_t)((i << 24) | (packet.srcMAC[3] << 16) | (packet.srcMAC[4] << 8) | (packet.srcMAC[5])); - PCAPFoundDevice* alreadyExists = nullptr; - for(auto& dev : foundDevices) - if(dev.device.handle == handle) - alreadyExists = &dev; + EthernetPacketizer ethPacketizer([](APIEvent::Type, APIEvent::Severity) {}); + memcpy(ethPacketizer.hostMAC, iface.macAddress, sizeof(ethPacketizer.hostMAC)); + ethPacketizer.allowInPacketsFromAnyMAC = true; + if(!ethPacketizer.inputUp({ data, data + header->caplen })) + continue; // This packet is not for us - if(alreadyExists == nullptr) { - PCAPFoundDevice foundDevice; - foundDevice.device.handle = handle; - foundDevice.discoveryPackets.push_back(std::move(packet.payload)); - foundDevices.push_back(foundDevice); - } else { - alreadyExists->discoveryPackets.push_back(std::move(packet.payload)); - } + Packetizer packetizer([](APIEvent::Type, APIEvent::Severity) {}); + if(!packetizer.input(ethPacketizer.outputUp())) + continue; // This packet was not well formed + + EthernetPacketizer::EthernetPacket decoded(data, header->caplen); + for(const auto& packet : packetizer.output()) { + Decoder decoder([](APIEvent::Type, APIEvent::Severity) {}); + std::shared_ptr message; + if(!decoder.decode(message, packet)) + continue; + + const neodevice_handle_t handle = (neodevice_handle_t)((i << 24) | (decoded.srcMAC[3] << 16) | (decoded.srcMAC[4] << 8) | (decoded.srcMAC[5])); + if(std::any_of(found.begin(), found.end(), [&handle](const auto& found) { return handle == found.handle; })) + continue; // We already have this device on this interface + + const auto serial = std::dynamic_pointer_cast(message); + if(!serial || serial->deviceSerial.size() != 6) + continue; + + FoundDevice foundDevice; + foundDevice.handle = handle; + foundDevice.productId = decoded.srcMAC[2]; + memcpy(foundDevice.serial, serial->deviceSerial.c_str(), sizeof(foundDevice.serial) - 1); + foundDevice.serial[sizeof(foundDevice.serial) - 1] = '\0'; + + foundDevice.makeDriver = [](const device_eventhandler_t& reportFn, neodevice_t& device) { + return std::unique_ptr(new PCAP(reportFn, device)); + }; + + found.push_back(foundDevice); } } pcap.close(iface.fp); iface.fp = nullptr; } - - return foundDevices; } bool PCAP::IsHandleValid(neodevice_handle_t handle) { diff --git a/platform/windows/vcp.cpp b/platform/windows/vcp.cpp index 080a6cb..90784c8 100644 --- a/platform/windows/vcp.cpp +++ b/platform/windows/vcp.cpp @@ -1,6 +1,7 @@ #include "icsneo/platform/windows/ftdi.h" #include "icsneo/platform/ftdi.h" #include "icsneo/platform/registry.h" +#include "icsneo/device/founddevice.h" #include #include #include @@ -19,8 +20,7 @@ static const std::wstring ALL_ENUM_REG_KEY = L"SYSTEM\\CurrentControlSet\\Enum\\ static constexpr unsigned int RETRY_TIMES = 5; static constexpr unsigned int RETRY_DELAY = 50; -struct VCP::Detail -{ +struct VCP::Detail { Detail() { overlappedRead.hEvent = INVALID_HANDLE_VALUE; overlappedWrite.hEvent = INVALID_HANDLE_VALUE; @@ -32,21 +32,22 @@ struct VCP::Detail OVERLAPPED overlappedWait = {}; }; -std::vector VCP::FindByProduct(int product, std::vector driverNames) { - std::vector found; - +void VCP::Find(std::vector& found, std::vector driverNames) { for(auto& driverName : driverNames) { std::wstringstream regss; regss << DRIVER_SERVICES_REG_KEY << driverName << L"\\Enum\\"; std::wstring driverEnumRegKey = regss.str(); uint32_t deviceCount = 0; - if(!Registry::Get(driverEnumRegKey, L"Count", deviceCount)) { - return found; - } + if(!Registry::Get(driverEnumRegKey, L"Count", deviceCount)) + continue; for(uint32_t i = 0; i < deviceCount; i++) { - neodevice_t device = {}; + FoundDevice device; + + device.makeDriver = [](const device_eventhandler_t& reportFn, neodevice_t& device) { + return std::unique_ptr(new VCP(reportFn, device)); + }; // First we want to look at what devices FTDI is enumerating (inside driverEnumRegKey) // The entry for a ValueCAN 3 with SN 138635 looks like "FTDIBUS\VID_093C+PID_0601+138635A\0000" @@ -64,11 +65,10 @@ std::vector VCP::FindByProduct(int product, std::vector VCP::FindByProduct(int product, std::vector VCP::FindByProduct(int product, std::vector VCP::FindByProduct(int product, std::vectorusb_dev) < 0) ftdi_error_return_free_device_list(-4, "usb_open() failed", devs);