603 Commits
Author SHA1 Message Date
David Rebbe 6dd4456f9a API: Added icsneoc2.
Signed-off-by: David Rebbe <drebbe@intrepidcs.com>
2025-02-04 13:48:43 -05:00
Jonathan SchwartzandKyle Schwarz c5ba2d8d32 Communication: Add missing CAN error types 2025-02-04 15:15:44 +00:00
Kyle Schwarz a22791c9e0 CI: Move Windows jobs 2025-02-03 17:16:30 -05:00
Kyle Schwarz dc2a364afb Bindings: Python: Fix API docs since adding stubs 2025-01-29 14:53:18 -05:00
Kyle Schwarz 114b664d78 All: Welcome to 2025 2025-01-15 16:46:07 -05:00
Kyle Schwarz 2acf248583 Bindings: Python: Add stubs 2025-01-09 00:14:46 -05:00
Kyle Schwarz f18aa00322 Communication: Add EthernetStatusMessage 2025-01-06 14:12:19 -05:00
Jonathan SchwartzandKyle Schwarz 87baa97c3f Device: Fix ComponentVersion retrieval 2025-01-06 19:06:11 +00:00
Jonathan SchwartzandKyle Schwarz 8dcbbe0d72 NeoVIConnect: Add ComponentVersions support 2025-01-06 14:51:42 +00:00
Kyle Schwarz b624d06ca0 Driver: FTD3XX: Fix close() 2024-12-30 14:14:23 -05:00
Kyle Schwarz c249df8756 Bindings: Python: Add CANErrorCountMessage 2024-12-23 10:28:19 -05:00
Kyle Schwarz b2161211c5 Bindings: Python: Add Message::Type MessageFilter 2024-12-20 18:28:41 -05:00
Kyle Schwarz 0ee8a990a7 Bindings: Python: Fix get_gptp_status default arg 2024-12-20 18:28:22 -05:00
Yasser YassineandKyle Schwarz dc0f16b1d2 Communication: Add GPTPStatus 2024-12-20 23:22:25 +00:00
Kyle Schwarz c4ce803d62 LINMessage: Fix timestamp scaling 2024-12-19 15:54:27 -05:00
Kyle Schwarz 34cacf4cf2 EthernetMessage: Fix TX receipts
Fixes
- HardwareEthernetPacket packing
- EthernetMessage::fcs
2024-12-13 12:55:57 -05:00
Kyle Schwarz 4157558e84 Bindings: Python: Drop GIL for Device calls
Avoids an ABBA deadlock with the GIL and messageCallbacksLock
2024-12-12 11:12:55 -05:00
Kyle Schwarz 40b85488dc TCP: Add LIBICSNEO_DISABLE_TCP env option 2024-12-11 17:25:36 -05:00
Kyle Schwarz 7584563002 Bindings: Python: Add default MessageFilter constructor 2024-12-11 17:22:09 -05:00
Kyle Schwarz 4f83614037 Bindings: Python: Fix Device RTC functions 2024-12-04 12:31:06 -05:00
Kyle Schwarz 38a4af8062 Device: Fix getRTC response size
Some devices pad to 16-bit.
2024-12-04 12:11:01 -05:00
Kyle Schwarz 3b95b41be4 Bindings: Python: Add LINMessage 2024-12-03 23:41:51 -05:00
Kyle Schwarz 3da31a29b4 Bindings: Python: Add more Network members 2024-12-03 22:35:40 -05:00
Kyle Schwarz d0f3e593df Device: Add RAD-Galaxy 2 2024-12-02 20:02:06 -05:00
Kyle Schwarz 90268a4f04 CI: Update DOCKER_HOST 2024-12-02 19:44:21 -05:00
Kyle Schwarz dbe19a5616 Bindings: Python: Add MDIOMessage 2024-11-08 15:06:45 -05:00
Kyle Schwarz e5d7a38160 CI: Fix push command 2024-11-05 16:00:30 -05:00
Kyle Schwarz d714b620c4 CI: Add GitHub auto-push 2024-11-05 14:58:54 -05:00
Kyle Schwarz 10d2625cb6 Bindings: Python: Add get_tc10_status 2024-11-05 14:30:53 -05:00
Kyle Schwarz b9cfa85009 Docs: Add GitHub link 2024-11-05 12:56:27 -05:00
Kyle Schwarz 776d14bb3e Docs: Fix RTD requirements path 2024-11-04 18:05:24 -05:00
Kyle Schwarz 648fb2502f Docs: Refactor 2024-11-04 18:01:28 -05:00
Kyle Schwarz 008a0e4057 CI: Add needs section 2024-11-01 21:26:45 -04:00
Kyle Schwarz 3787bc27a2 Add Python bindings and the icsneopy package 2024-11-02 01:14:15 +00:00
Bryant JonesandKyle Schwarz e73f61bfcc Device: Add RADGigastar2 2024-10-21 20:00:29 +00:00
Yaroslav StetsykandKyle Schwarz f552df372b Device: Add RADMoonT1S 2024-10-18 18:23:58 +00:00
Vedant NaikandKyle Schwarz 80904dd84c Device: Gigastar: Add TC10 2024-10-03 19:14:33 +00:00
Kyle Schwarz e2bd0b5a3e Device: Fix getHardwareInfo() timeout 2024-10-02 22:19:54 +00:00
Bryant JonesandKyle Schwarz 24f291dc83 Device: Comet: Update settings 2024-09-26 20:42:41 +00:00
Bryant Jones ee7b66625a Network: Add support for new networks on LIN, SPI, and OP Eth 2024-09-25 14:09:38 -04:00
Bryant Jones 99183a89f9 Communication: Add new app errors 2024-08-29 12:28:01 -04:00
Kyle Schwarz 7f30179cc4 Build: Update D3XX libraries 2024-08-29 15:13:38 +00:00
Kyle Johannes 39bcef0230 Communication: warning fix 2024-08-29 15:01:34 +00:00
Bryant JonesandKyle Schwarz ca370a1310 Device: Comet2: Enable TC10 2024-08-22 16:06:13 +00:00
Kyle Schwarz 564933cb41 Device: Add readCoreminiHeader()
- Fixes NeoMemoryDiskDriver::readLogicalDiskAligned() for flash
- Adds FlashMemoryMessage
2024-08-21 10:42:04 -04:00
Kyle JohannesandKyle Schwarz cac8d760b0 Communication: Add AppErrorMessage support
App errors are responses from the device indicating internal runtime errors.
2024-08-15 16:47:35 +00:00
Kurt WachowskiandKyle Schwarz 75af3220b0 Driver: Block between read attempts
Driver:

* Refactored to limit accessibility of member fields;

Communication:

* readTask() now calls for a blocking wait;
2024-08-13 13:55:12 +00:00
Kyle Schwarz f25a0a4a81 Device: Remove const from bool return type 2024-08-02 11:10:20 -04:00
Kyle Schwarz 387c39d3a0 Platform: TCP: Guard against negative duration 2024-07-29 22:50:16 -04:00
Kyle Schwarz 4476bd8b71 Platform: TCP: Add poll function to Socket 2024-07-30 02:09:24 +00:00
Bryant JonesandKyle Schwarz 14588591e5 Device: Comet2/Comet3: Add support for TC10 API 2024-07-08 14:00:24 +00:00
Kyle Johannes cbcbcbdc5d System Test: FIRE 3 and VCAN 4-2EL 2024-06-11 22:04:09 +00:00
Kyle Schwarz cf1b4778a1 Device: RADMoon2ZL: Add TC10 commands 2024-06-03 08:31:17 -04:00
Yasser Yassine 77928dc93d Driver: Add general predicate parameter for waitForRx 2024-05-28 18:21:22 +00:00
Yasser Yassine 659fcf633c Communication: Add pause feature
Removed redirect read
2024-05-23 21:23:45 +00:00
Yasser Yassine 9a1cd1124d Device: Add device hardware info retrieval support 2024-05-14 19:52:00 +00:00
Jonathan SchwartzandKyle Schwarz 3782e12ef6 Device: Add neoVI Connect support 2024-04-30 12:48:31 +00:00
Kyle Schwarz bc6f5eca9c Device: Conditionally retrieve component versions 2024-04-17 14:36:42 -04:00
Kyle Schwarz 53ba297a44 RADComet: Suppress C4201 for nameless struct/union 2024-04-17 14:35:40 -04:00
Kyle Schwarz d9bf4f423e Device: Fix DFU supported check 2024-04-17 14:25:45 -04:00
Kyle Schwarz ba3bceaee0 RADComet: Update settings 2024-04-17 14:24:56 -04:00
Kyle Schwarz 31d47613e7 RADGigastar: Update settings 2024-04-17 14:24:36 -04:00
Bryant Jones 9c830a91a2 Device: Add RAD-Comet3 support 2024-04-11 21:40:38 +00:00
Kyle Johannes 46e244fbab System Test: Hardware test infrastructure 2024-04-05 21:10:49 +00:00
Jonathan Schwartz 63f0516318 Replace concurrentqueue with ringbuffer 2024-04-05 17:24:53 +00:00
Kyle Schwarz 7d2d12c5cd Revert "Communication: Move NetID::Device to Type::CAN" 2024-04-04 21:48:42 +00:00
Yasser Yassine bcf9d62be9 A2B: Fix warnings 2024-04-02 16:02:12 -04:00
Jonathan SchwartzandKyle Schwarz a01aa90740 Communication: Move NetID::Device to Type::CAN
NetID::Device is used as a "virtual" CAN network by the device. All messages on this network are packed identically to CAN messages
2024-04-01 12:28:46 +00:00
Yasser YassineandKyle Schwarz 85178368d7 Build: Add static icsneo40 target 2024-03-19 20:59:33 +00:00
Yasser YassineandKyle Schwarz 16b60d5ca0 A2B: Fix get & set with upstream direction 2024-03-19 20:36:21 +00:00
Yasser YassineandKyle Schwarz cb22e622b3 Device: Refactor A2B APIs
* Removes features in `A2BMessage` class to support API for reading 16, 24, and 32 bit samples from A2B channels
* Re-organizes WAV receiving and transmitting code and API
* Creates API for mapping message channels to WAV channels and vice versa for transmitting and receiving
* Fixes `icsneo::Network::NetID::ExtendedData` VnetID bug for `icsneo::ExtendedDataMessage` decoding
* Creates RAD-A2B sequence chart example
* Fixes coremini uploading for certain devices in EEPROM by introducing `icsneo::Device::supportsEraseMemory`
2024-03-12 12:06:49 +00:00
David RebbeandKyle Schwarz 06f6861130 Legacy: Drop deprecated APIs
Drop icsneoFindNeoDevices() and icsneoOpenNeoDevice() in favor of icsneoFindDevices() and icsneoOpenDevice(), respectively.

Also fixes:
- Failure to re-open a device after it has been closed with the C/legacy APIs
- NumberOfClients not being updated
- FIRE3 settings missing in icsneoGetDeviceSettingsType()
2024-03-07 19:45:46 +00:00
Jonathan Schwartz 219a5edbd8 Fixes Windows build with TCP enabled 2024-02-23 14:16:15 +00:00
Emily Brooks 05888e5c20 Device: Set multiple root directory entry flags at once 2024-02-14 18:06:59 -05:00
Bryant Jones e37d939699 Build: Fix warning on Comet2 missing override keyword 2024-02-14 15:37:09 +00:00
Bryant Jones 2a94b4566b RAD-A2B: Update settings structure 2024-02-14 10:04:14 -05:00
Kyle SchwarzandKyle Johannes 4782e26bed Device: Add isOnlineSupported() 2024-02-13 21:24:51 +00:00
Yasser Yassine 3264a1ecbe RAD-A2B: Fix RADA2BSettings::getChannelSize function 2024-01-23 23:18:01 +00:00
Yasser Yassine 1dfed4c9c4 A2B: Set timestamp field in HardwareA2BPacket::DecodeToMessage 2024-01-22 22:44:06 +00:00
Max Brombach a44952be13 Disk: Update VSA Example and Fix VSA CAN-FD Decode
- Send and validate CAN/CAN-FD/Eth frames in VSA example (two devices)
- Fix failure to decode CAN-FD frames from VSA records
2024-01-16 18:01:10 +00:00
Yasser Yassine 75e9319c32 A2B: Add example for reading/writing A2B board I2C registers 2024-01-12 20:34:11 +00:00
Bryant Jones 9df4aed19f Device: Add RAD-Comet2 support 2024-01-04 14:48:13 +00:00
Kyle Schwarz d56e66afd3 All: Bump copyright to 2024 2024-01-02 08:23:51 -05:00
jschwartz 26b52237e4 Communication: Increase device timeout in overloaded waitForMessageSync 2023-12-07 16:03:31 -05:00
Jonathan Schwartz 28ba94fa25 Remove RTTI dependency, increase default timeout for communication 2023-12-06 22:35:17 +00:00
Kyle Johannes e56c714a0c LIN: update example 2023-12-05 17:30:40 -05:00
Jonathan SchwartzandKyle Johannes 58f53edea8 Update device timeouts 2023-12-01 23:29:42 +00:00
Kyle Schwarz 3d2d3cb43d CI: Add Fedora 38 & 39 jobs 2023-12-01 22:39:46 +00:00
Kyle SchwarzandKyle Johannes bddbcfcf6d CI: Fix warnings 2023-12-01 22:20:41 +00:00
0497b361ef LIN: Settings API (#62)
* Settings: add APIs for LIN configuration

Add getter/setter for LIN configuration:
- baudrate
- commander resistor ON/OFF
- mode (SLEEP, SLOW, NORMAL, FAST)

* Device: add LIN settings getter for devices with LIN
* LIN: add setup to LIN example
* LIN: settings minor tweaks from PR

---------

Co-authored-by: Francesco Valla <francesco.valla@mta.it>
2023-11-30 15:56:18 -05:00
Max Brombach 02f1b4592e Device/Disk: Add VSA read and parse functionality
Implement ability to extract network traffic (CAN, LIN, Ethernet, etc.) from VSA message records on disk. Add a method to Device class that uses the VSAParser and the individual record types to extract messages from the VSA message records and pass them back to the communication system. This routes messages such that it appears as if they were discovered live instead of read from disk. The parse process (in Device) requires determination of metadata about the VSA file system on a device before it can begin extracting messages. This currently only handles data captured from the current coremini script on a device.
2023-11-15 16:02:47 +00:00
Yasser Yassine 4248c1a538 Device: Add CoreMini flashing support 2023-11-08 18:47:03 -05:00
Kyle Schwarz ec51393dfc CMake: Require Threads package 2023-11-06 17:39:11 -05:00
Kurt Wachowski 90e1aa223d Packetizer: 2023-10-12 17:33:05 +00:00
Jonathan Schwartz e0cef880f0 Firmio: Improve exit from Find loop
Device: Null check return from std::dynamic_pointer_cast
2023-10-03 16:24:28 +00:00
Jonathan SchwartzandKyle Schwarz cc7cffe068 Device: FIRE3 Flexray: Add to supported devices for Live Data 2023-09-21 21:28:23 +00:00
Kyle Schwarz e97b307c4d Device: Wait up to 1s for GetAll response
If there's an active disk read in progress the default 50ms timeout is too short.
2023-09-21 16:52:30 +00:00
Kyle Schwarz 0c436621a0 Disk: Refactor ExtExtractorDiskReadDriver
Reading disk data is currently accomplished by redirecting the raw input stream
for the duration of the acquisition, during which no other operation can be
carried out. This change moves disk data reading into the packetizer so the
familiar request/reply with message filters can be used. To accomplish this the
deprecated ISOPIC network type was dropped because the two messages share this
network ID.

Also fixes live data packet lengths which were off-by-one.
2023-09-18 15:44:28 +00:00
Kyle Schwarz 508013baf4 LiveData: Fix unhandled enum warning 2023-08-22 17:55:38 -04:00
Kyle JohannesandKyle Schwarz 8d704b1bbb LiveData: Initial implementation
Add support for live data subscription via Device::subscribeLiveData() and
Device::unsubscribeLiveData(). The live data API can be used to subscribe to
individual "signals", a full list of which can be found in LiveDataValueType.
2023-08-22 16:20:48 -04:00
Max BrombachandKyle Schwarz 018f1fac8e Device: Add disk drivers to RADGigastar, RADMars, and RADGalaxy 2023-08-15 20:21:57 +00:00
Emily Brooks 188a087c51 Device: Wait longer to receive message in heart beat thread 2023-08-15 19:43:08 +00:00
Jonathan SchwartzandKyle Schwarz 53e66b8772 Communication: Fix NetID VNET conflict
There exists a potential conflict with some existing NetIDs and VNET NetIDs in the 200 range. To resolve this there is now an additional optional "expand" argument in various functions that could conflict. In most situations this should be false, and is false for MessageFilters to retain the existing behavior.
2023-08-14 21:47:35 +00:00
Kurt Wachowski 41d6927496 Issue #117 2023-08-02 13:52:52 +00:00
Kyle Schwarz 237bed1b72 Device: Wait for device response in setRTC() 2023-07-18 18:40:41 +00:00
Kyle Schwarz 6c93fc839b FTD3XX: Update library to 1.0.14
Also tweaks FindUSB1.cmake to support a custom prefix libusb.
2023-07-17 19:03:17 +00:00
Kyle Johannes 4cf35acf6c LIN: Fix protected ID not assigned 2023-07-12 00:05:12 +00:00
Kyle Johannes 9ef93eb73e Legacy: SpyMessageToNeoMessage length fix for CAN FD 2023-06-28 17:30:09 -04:00
Kyle Johannes 5b3e21fa7c LIN: C API protected ID automatic calculation 2023-06-22 18:17:00 +00:00
David Rebbe a36d114e1f Updated readme for windows builds 2023-06-21 13:17:05 -04:00
David Rebbe ee9cf26eb2 Updated readme for better linux instructions 2023-06-20 18:29:07 -04:00
Kyle Johannes d7d98855ea Legacy: Update icsnVC40 to support Red 2 settings transactions 2023-06-14 14:39:44 +00:00
Kyle Johannes 245f5089da Network: Add ExtendedData to GetNetIDString 2023-06-05 15:52:29 -04:00
Yasser Yassine d9c12bffe7 Device: Add device binary export support 2023-05-30 21:22:53 +00:00
Joseph Niksa f907d6759f icsneolegacy: implemented getDeviceStatus in C and legacy
-Added missing DLL asserts for getRTC() and setRTC() in icsneoc.h
2023-05-25 16:42:38 +00:00
Jonathan Schwartz 1e773ba9ab Communication: Fix loopLimit when parsing SupportedFeaturesPacket 2023-05-10 23:18:04 +00:00
Bryant Jones f5096b879c MDIO: Network support 2023-05-09 18:14:36 +00:00
Kyle Schwarz 0de23f2817 Driver: FTD3XX: Add Arm support 2023-05-09 16:31:49 +00:00
Jonathan Schwartz 32900ae263 Device: Add GetComponentVersions and GetSupportedFeatures commands
Driver: Fix re-open and failed open cases for TCP

Also enforces even length packets for the RED2, FIRE3, and FIRE3 FlexRay devices.
2023-05-08 21:07:43 +00:00
Kyle Schwarz b6d9ef4c7e EventManager: Add optional debug printing 2023-04-27 18:52:17 +00:00
Kyle Schwarz 2f7c3a2dda Driver: FTD3XX: Use CMake FetchContent for lib 2023-04-25 15:16:15 +00:00
Kyle Schwarz bbf348a6ab Device: Add RADMoon2ZL
Also adds a base class for both Moon2 device types.
2023-04-24 22:39:35 +00:00
Kyle Schwarz 73744bf6d9 Examples: Refactor RTC example 2023-04-21 18:30:13 -04:00
Kyle Schwarz 6b0c588a46 Driver: Add FTD3XX 2023-04-20 20:42:36 +00:00
Joseph Niksa b3bbf91e8c icsneolegacy: Implemented get() and set() RTC functions 2023-04-20 18:37:05 +00:00
Bryant Jones af31aa23ad RAD-Moon3: Add initial support 2023-04-20 17:14:22 +00:00
Joseph Niksa 83f6c611fe Implemented icsneoLoadDefaultSettings to apply the default settings to the device. 2023-04-20 05:00:46 +00:00
Bryant Jones 4fa813ccbc Device: Fix supported device networks for several devices 2023-04-18 13:21:39 +00:00
Yasser Yassine 3ddb832708 A2B: Add additional examples
Device: Add coremini loading example
2023-04-12 16:29:48 +00:00
Kyle Johannes 63c81b1c3d LIN: Legacy API 2023-04-05 15:43:26 +00:00
Kyle Schwarz 0fa7494eab CI: Add Linux platforms 2023-04-04 18:57:42 +00:00
Kyle Schwarz cd7b0b0a7b Driver: PCAP: Properly handle RX timeout
If res == 0 the header and data will not be populated because no message
was RXed.
2023-03-29 00:51:38 -04:00
Bryant Jones d9cdd03618 RAD-Comet: Add initial support 2023-03-28 20:58:12 +00:00
Joseph Niksa 832cf9c84b icsneolegacy: implemented icsneoGetErrorInfo() 2023-03-22 18:39:40 +00:00
Yasser Yassine bf6a059820 Device: Add Coremini script upload function 2023-03-08 18:58:38 +00:00
Kyle Schwarz 9b46d486cb Driver: Add TCP support
Device: Close Driver in heartbeat thread on disconnection
2023-03-08 18:32:26 +00:00
Yasser Yassine ddee1254a0 A2B: Add A2B Tx streaming support
A2B: Add A2BDecoder for streaming wave to A2B device
RADA2B: Add functions to configure settings
2023-03-08 18:22:14 +00:00
Kyle Johannes 539cfa511b LIN: Network support 2023-02-03 18:27:08 +00:00
Emily Brooks 4229d8b66a Device: Update the capture callback to include all of the wivi capture information 2023-01-18 23:17:59 +00:00
jschwartz dc1c4ede9d Device: Add FIRE3 Flexray device type and its settings
Device: Include FIRE3 Flexray in device finder
Device: Correct FIRE3 settings and add additional supported networks
Network: Add additional network enumerations

Communication: Add networks to all switch statements
2023-01-17 09:12:10 -05:00
Kyle Schwarz 9e7d442e83 Update copyright year 2023-01-03 20:57:10 -05:00
Kyle Schwarz 41a569fc2d Device: Consider VSA when calculating logical disk size
When the underlying disk driver has VSA access the total size must be
calculated with respect to the VSA offset.
2022-12-19 14:56:08 +00:00
Kyle Schwarz f4e4a103ad POSIX: PCAP: Check header & data before using 2022-12-19 03:03:12 -05:00
Yasser Yassine 78465e0f20 A2B: Add A2BMessage transmit support 2022-12-02 12:14:44 -05:00
Emily BrooksandKyle Schwarz ed1632c652 DiskWriteDriver: Remove use of atomic buffer 2022-12-02 00:09:49 +00:00
Joe Niksa c97db0f35f icsneolegacy: implemented icsneoGetLastAPIError() 2022-11-25 12:26:41 -05:00
Emily BrooksandKyle Schwarz c9d8a4f0a9 Device: Disk lock the script/wivi commands 2022-11-16 19:55:53 +00:00
Emily BrooksandKyle Schwarz 96fe8895fc Device: Add isEncrypted to script status 2022-11-16 19:55:53 +00:00
Kyle Schwarz e46755f120 Device: RED2: Add missing Ethernet2 2022-11-15 12:37:41 -05:00
Emily Brooks 0619c37a90 Decoder: Add break to end of Internal network switch case 2022-11-08 22:05:01 +00:00
David Rebbe de58b2d639 libicsneoc: Fixed access violation 2022-11-07 20:22:45 +00:00
David Rebbe 5ff1707c47 libicsneoc: Resolve DeviceCurrentlyClosed errors 2022-11-03 23:46:14 +00:00
Jonathan Schwartz 4c0d49f09a Device: Add a mutex against the diskLock to some commands that are on threads 2022-10-24 16:02:53 -04:00
Jonathan Schwartz b32f58da38 Device: Add new method to mark collections as uploaded in CM root directory 2022-10-24 16:02:48 -04:00
Kyle Schwarz 0101467154 Communication: Atomic sync messages
If waitForMessageSync() is called in two threads for the same message
the callback for both will be invoked with the first send.
2022-10-21 14:49:03 +00:00
Emily Brooks 17b3018499 Device: Continue script status loop if no response 2022-10-21 13:23:46 +00:00
Kyle Schwarz 0fc676e576 A2B: Resolve warnings 2022-10-20 19:38:34 -04:00
Yasser Yassine 7b2544864b A2B: Add initial WAV streaming support 2022-10-19 18:44:05 -04:00
Kyle Schwarz 7f22286838 Build: Only search for enabled drivers 2022-10-17 21:01:24 -04:00
Kyle Schwarz 643768fb6a Device: ValueCAN3: Drop ftdi.h include 2022-10-17 21:01:24 -04:00
Kyle Johannes 9817887523 I2C: Network support 2022-10-18 00:12:16 +00:00
Jonathan Schwartz 13ec2bca98 Merge remote-tracking branch 'origin/master' into js-add-fire3-to-finder 2022-10-12 10:55:56 -04:00
Jonathan Schwartz 711976cce0 DeviceFinder: Add serial match for FIRE3 2022-10-12 10:53:19 -04:00
Emily Brooks e02203a974 Device: Creates script status thread, callback for each variable 2022-10-11 14:48:39 -04:00
Emily Brooks 5b14ec7246 Device: Add start/stop/clear script, script status, and preload coremini commands 2022-10-11 14:48:39 -04:00
Yasser Yassine 3b80746fb8 A2B: Add A2B message initial support 2022-10-11 11:20:04 -04:00
Emily Brooks 3b9a31ef51 RAD-A2B: Add netID to string support 2022-10-05 13:50:00 -04:00
Emily Brooks 124bd3b310 WiVICommandPacket: Remove length check 2022-10-05 14:08:39 +00:00
Kyle Schwarz 9871430288 RAD-A2B: Initial support 2022-09-15 11:13:45 -04:00
Kyle Schwarz 2e296dc8d3 ConcurrentQueue: Update to HEAD 2022-09-09 15:46:46 -04:00
Kyle Schwarz b35fab754c Device: ValueCAN3: Fix PID 2022-08-02 14:33:43 -04:00
Kyle Schwarz 9ef01e2d3d Optional: nonstd to std 2022-07-22 01:27:39 -04:00
Kyle Schwarz 1bb33156f7 Device: Use lambda instead of std::bind 2022-07-22 02:47:10 +00:00
Kyle Schwarz a0f73755e8 Build: Bump required C++ to 17 2022-07-21 16:22:52 -04:00
Kyle Schwarz ab54697745 Device: Retain Device objects between FindAll() calls
FindAll() now retains a list of Devices that have already been created
and returns their existing object instead of a new one.
2022-07-15 16:03:54 -04:00
Kyle Schwarz 0d0b7f00bd Merge branch 'master' into v0.3.0-dev 2022-07-15 13:02:26 -04:00
Kyle Schwarz 1a28fbf5ad ThirdParty: FatFs: Enable PIC
Fixes linking with GCC by adding -fPIC
2022-07-15 12:34:07 -04:00
Emily Brooks b50706846c WiVICommandPacket: Add missing cstring header 2022-06-08 16:49:39 -04:00
Paul Hollinsky d6d34eb7bc WiVICommandPacket: Only disable warnings for MSVC
This addresses a warning in GCC and Clang
2022-06-07 13:48:51 +00:00
Paul Hollinsky a928a1d879 Device: Implement Wireless neoVI Stack
This reverts commit cb47065a47.
2022-06-07 13:48:51 +00:00
Paul Hollinsky de3d8bf870 RAD-Jupiter: Add initial support 2022-05-28 14:42:09 -04:00
Paul Hollinsky 407ccccedd Drivers: Ensure serial numbers are uppercase
This prevents mismatches if the device sends a lowercase
serial number, which may happen due to an oversight in
production.
2022-05-28 14:41:41 -04:00
Paul Hollinsky 00024990e9 WiVICommandPacket: Resolve GCC build error 2022-04-26 13:54:03 -04:00
Paul Hollinsky cb47065a47 WiVICommandPacket: Temporarily remove GetAll 2022-04-26 12:58:54 -04:00
Paul Hollinsky 2b819065ad WiVICommandPacket: Disable MSVC struct warnings 2022-04-26 12:48:17 -04:00
Paul Hollinsky 58700afc73 Lifetime: Allow checking for empty lifetimes 2022-04-26 12:48:17 -04:00
Paul Hollinsky 55d7d5bf17 Device: Implement allowSleep for Wireless neoVI support 2022-04-26 12:48:17 -04:00
Jonathan SchwartzandPaul Hollinsky c08c0dd893 Disk: Allow full timeout for each disk read attempt 2022-04-22 17:30:53 +00:00
Jonathan SchwartzandPaul Hollinsky 44ad06d4bb Device: Add mutex for disk info requests to temporarily work around WiVIClient timeout issues 2022-04-22 17:30:53 +00:00
Jonathan SchwartzandPaul Hollinsky c2de1dfdf1 Disk: ExtExtractorDiskReadDriver: Increase timeout for individual read attempts 2022-04-22 17:30:53 +00:00
Paul Hollinsky a2cfc50b7c Message Filter: Fix filtering on NetID or NetType if message doesn't have one 2022-04-15 21:35:40 -04:00
Paul Hollinsky c398afc4e3 Extended Commands: Fix struct packing 2022-04-15 21:35:40 -04:00
Paul Hollinsky 8d495aa916 neoVI FIRE 3: Initial support 2022-04-15 21:35:40 -04:00
Paul Hollinsky 91abf378f8 FirmIO: Use uintptr_t for 64-bit compatibility 2022-04-15 21:35:40 -04:00
Paul Hollinsky 2e3b738e76 Extended Commands: Decode generic responses 2022-04-15 21:35:40 -04:00
Paul Hollinsky 103f938d69 Disk: ReadDriver: Add unified cache
Previously, we had to copy an entire block out of the
old cache every time we wanted to read even a single
byte from it.

This ended up being a fairly significant performance
issue, in addition to the fact that the caching code
was duplicated.
2022-04-14 18:26:44 -04:00
Paul Hollinsky d45d708446 FirmIO: Stable communication 2022-03-27 23:57:44 -04:00
Paul Hollinsky 5d4ed0f4cd Driver: Add optional debug prints 2022-03-27 23:45:47 -04:00
Paul Hollinsky 2dd91325e6 FirmIO: Initial commit 2022-03-27 18:10:24 -04:00
Paul Hollinsky 008a1620c8 Repo: Normalize source files to LF 2022-03-27 14:40:32 -04:00
Paul Hollinsky 781fc2c034 Drivers: Decouple from devices
This allows us to better implement alternative drivers
for devices, such as for device sharing servers or
talking to CoreMini processors within the same device.
2022-03-27 14:30:31 -04:00
Paul Hollinsky 0ff12300f3 RAD-Gigalog: Rename to RAD-Mars 2022-03-11 10:53:05 -05:00
Paul Hollinsky f4e16025c1 Disk: ExtendedExtractor: Implement retries 2022-03-10 18:04:12 -05:00
Paul Hollinsky fef6f363f1 ThirdParty: FatFs: Use standard C++ for MSVC 2017+
This prevents unicode issues with TCHAR, because we
don't want to import windows.h.
2022-03-07 12:49:03 -05:00
Paul Hollinsky f367fcecca Disk: NeoMemory: Implement writing 2022-03-03 20:34:46 -05:00
Paul Hollinsky f05fd5e201 EthernetPacketizer: Correct reassembly for RAD devices
The RAD devices will give us a packet size larger than the packet,
as they specify the size of the entire reassembly.
2022-03-03 20:34:46 -05:00
Paul Hollinsky adad9b3761 Disk: ExtendedExtractor: Better header parsing 2022-03-03 20:34:46 -05:00
Paul Hollinsky 0a15adbe91 Disk: Allow mismatched access for Read and Write drivers
This will cause the driver to fall back to the least common
denominator.
2022-03-03 20:29:13 -05:00
Paul Hollinsky 1118428250 Device: Only allow one disk transaction at a time
Most drivers will not gracefully handle more than one transaction
2022-03-03 16:20:51 -05:00
Paul Hollinsky 8c774228bc Disk: FAT: Fix Windows UNICODE compilation 2022-03-03 15:13:04 -05:00
Paul Hollinsky 478dfb3cb8 Platform: Windows: Create trampoline header
This way windows.h can be included if needed without a guard,
and we have a place to stub out defines for other platforms if
necessary.
2022-03-03 15:01:32 -05:00
Paul Hollinsky 8aa5bef7dc Disk: Implement Extended Extractor Driver
This is the high speed driver used for RED 2, FIRE 3, and many
of the RAD-family devices.
2022-03-03 00:03:37 -05:00
Paul Hollinsky 453d3366af Platform: Windows: Avoid windows.h
This way Windows.h doesn't pollute everything with random defines
2022-02-28 19:12:35 -05:00
Paul Hollinsky caf5cca42f Disk: Plasion: Fix bit-width issues 2022-02-28 19:11:39 -05:00
Paul Hollinsky ae1b8d342e Disk: Use std::chrono::seconds for CacheTime
This fixes an issue with MSVC
2022-02-28 19:11:27 -05:00
Paul Hollinsky c314417277 Device: Find the VSA offset for Disk::Access::EntireDisk 2022-02-28 15:55:16 -05:00
Paul Hollinsky 1fadb85206 ThirdParty: Add FatFs
R0.14b
2022-02-28 15:54:38 -05:00
Paul Hollinsky 6bcd8e5637 Disk: Read driver for Plasion 2022-02-28 03:40:44 -05:00
Paul Hollinsky 4c9d6c5ee7 Disk: NeoMemory: Cache last read sector for one second
This prevents constant re-reads if reading in small chunks
2022-02-28 01:55:31 -05:00
Paul Hollinsky 4ef8fe8794 Disk: Predictable behavior for zero length reads 2022-02-28 01:54:21 -05:00
Paul Hollinsky f8a46b7196 Device: Add logical disk size accessor 2022-02-28 01:49:50 -05:00
Paul Hollinsky 0b27e88da1 Disk: WriteDriver: Fix parameter shadowing 2022-02-25 01:14:57 -05:00
Paul Hollinsky 241502c2a2 Disk: Fix improper offset calculation
This would cause an underflow previously
2022-02-25 01:14:57 -05:00
Paul Hollinsky 242c7259ac Disk: Proper error reporting for EOF 2022-02-25 01:14:57 -05:00
Paul Hollinsky 9d2d94d22b Tests: Add disk driver tests 2022-02-25 01:14:57 -05:00
Paul Hollinsky bb49ce039e ThirdParty: Update included gtest 2022-02-25 01:14:57 -05:00
Paul Hollinsky e52073c518 Tests: EthernetPacketizer: Fix typo 2022-02-25 01:14:57 -05:00
Paul Hollinsky 0dcd950092 Device: Add disk write driver framework
At the moment, no drivers are implemented, so all devices have Access::None.
2022-02-25 01:14:57 -05:00
Paul Hollinsky 80cd4ae052 Disk: Fix out of bounds accesses in base ReadDriver 2022-02-25 01:14:57 -05:00
Paul Hollinsky f8bfb243fa Disk: Implement NeoMemoryDiskReadDriver 2022-02-25 01:14:57 -05:00
Paul Hollinsky fe4d5e0c15 Device: Add disk read driver framework
Allow access to the device's logical disk.

At the moment, no drivers are implemented, so all devices have Access::None.
2022-02-25 01:14:57 -05:00
Paul Hollinsky 9e6970fd39 Windows: DynamicLib: Slim down Windows.h
This is important as it ends up being included in icsneoc.h
2022-02-24 16:37:13 -05:00
Paul Hollinsky f1d9be1a81 Build: Don't add libusb include until after libftdi
This fixes GH-46 and a regression caused by 82954d9 where the project
would fail to build until configured a second time on Unix-y platforms.

LibFTDI adds libusb, so we need to make sure that's included first.

Windows does not use libusb so it does not need the include directory.
2022-02-24 16:07:56 -05:00
Paul Hollinsky 6cd821be2c Build: Don't add libusb include until after libftdi
This fixes GH-46 and a regression caused by 82954d9 where the project
would fail to build until configured a second time on Unix-y platforms.

LibFTDI adds libusb, so we need to make sure that's included first.

Windows does not use libusb so it does not need the include directory.
2022-02-24 16:03:02 -05:00
Paul Hollinsky 6cc0f08e2b Settings: The device can report when defaults were applied 2022-02-24 15:50:39 -05:00
Paul Hollinsky 80362e7f81 Event Manager: Refactor 2022-02-24 15:49:21 -05:00
Paul Hollinsky d7d9c15a9f Tests: Resolve MSVC x86 warnings 2022-02-22 10:49:49 -05:00
Paul Hollinsky c326397bea Examples: C Interactive: Resolve warnings 2022-02-22 10:49:49 -05:00
Paul Hollinsky af152fe54a CI: Also set warnings as errors in C code 2022-02-22 10:49:49 -05:00
Paul Hollinsky d051d20db6 CI: Add Windows 32-bit 2022-02-22 10:49:49 -05:00
Paul Hollinsky d0d279fdad Windows: Disable unaligned on x86
Closes GH-44
2022-02-22 10:49:49 -05:00
Paul Hollinsky 2c282fe396 Tests: Resolve MSVC x86 warnings 2022-02-22 10:46:30 -05:00
Paul Hollinsky 95de93aa84 Examples: C Interactive: Resolve warnings 2022-02-22 10:46:27 -05:00
Paul Hollinsky 733312628c CI: Also set warnings as errors in C code 2022-02-22 10:37:37 -05:00
Paul Hollinsky b177617940 CI: Add Windows 32-bit 2022-02-22 10:31:46 -05:00
Paul Hollinsky 28d3730375 Windows: Disable unaligned on x86
Closes GH-44
2022-02-22 10:24:13 -05:00
Paul Hollinsky c32d027b2d MessageCallback: Tolerate being created with nullptr filter
Communication does this in waitForMessageSync if a filter
is not passed in.

This fixes a crash in icsneoWaitForRxMessagesWithTimeOut
for the legacy API.

For good measure, creation with an empty std::function will
immediately throw an std::bad_function_call back at the
caller, rather than letting that happen on the callback thread.

I'm also making the members const here so they are provably
always non-null (and not empty, for the function).
2022-02-21 22:55:49 -05:00
Paul Hollinsky ac7b2d5106 FlexRay: Automatically reconfigure for runtime-added message buffers 2022-02-21 21:40:46 -05:00
Paul Hollinsky 4dbb8f3956 FlexRay: Don't set default key slots to continuous
This way they will come out as NULL frames, which is likely
more appropriate for a default.

This only takes effect if you set a key slot, but then don't
configure a message buffer for it.
2022-02-21 21:40:46 -05:00
Paul Hollinsky eace014494 FlexRay: Don't enforce key slot rules on non-keyslots 2022-02-21 21:40:46 -05:00
Paul Hollinsky 159c54b756 Legacy: Updates for the new neomessage_t API 2022-02-21 21:36:20 -05:00
Paul Hollinsky 416996b31d CI: Warnings are errors 2022-02-21 21:36:20 -05:00
Paul Hollinsky f37669139f MSVC: Resolve warnings 2022-02-21 21:36:20 -05:00
Paul Hollinsky 7aedb673fd Legacy: Fix icsneoGetVnetSimpleNetid
The NetID is written to the out* parameter, not returned.
2022-02-21 21:28:31 -05:00
Paul Hollinsky 52c7b5aaca Legacy: Fix icsneoGetNetidforSlaveVNETs
The NetID is written to the out* parameter, not returned.
2022-02-21 21:28:31 -05:00
Paul Hollinsky 0f9bf83c89 Legacy: Formatting 2022-02-21 21:28:31 -05:00
Paul Hollinsky dfd8768bbf Legacy: Correct Ethernet message translation
* Fixes NetIDs over 255
* Fixes data lengths over 255
* Avoids writing unexpected messages to client
2022-02-21 21:28:31 -05:00
Paul Hollinsky 94e0ea1fe0 Legacy: Prevent incorrect access to NetID maps 2022-02-21 21:28:30 -05:00
Paul Hollinsky 58944a2523 Tests: Spaces to Tabs 2022-02-21 21:28:30 -05:00
Paul Hollinsky be666e810d CI: Add Windows 2022-02-21 21:28:30 -05:00
Paul Hollinsky c451fc2b7c CI: Warnings are errors 2022-02-21 21:23:58 -05:00
Paul Hollinsky c620b2ee8b MSVC: Resolve warnings 2022-02-21 21:16:15 -05:00
Paul Hollinsky 111d377d4a Legacy: Fix icsneoGetVnetSimpleNetid
The NetID is written to the out* parameter, not returned.
2022-02-21 21:16:12 -05:00
Paul Hollinsky c3469f5fb6 Legacy: Fix icsneoGetNetidforSlaveVNETs
The NetID is written to the out* parameter, not returned.
2022-02-21 21:16:07 -05:00
Paul Hollinsky 0219eccc94 Legacy: Formatting 2022-02-21 21:14:31 -05:00
Paul Hollinsky e22f70a35a Legacy: Correct Ethernet message translation
* Fixes NetIDs over 255
* Fixes data lengths over 255
* Avoids writing unexpected messages to client
2022-02-21 21:14:31 -05:00
Paul Hollinsky b019c20ad0 Legacy: Prevent incorrect access to NetID maps 2022-02-21 21:14:31 -05:00
Paul Hollinsky 6fa469de5f Tests: Spaces to Tabs 2022-02-21 20:26:57 -05:00
Paul Hollinsky be219288dc CI: Add Windows 2022-02-21 20:13:28 -05:00
Paul Hollinsky d35653e3d0 Windows: PCAP: Fix WinPCAP loading
Used when LIBICSNEO_NPCAP_INCLUDE_DIR is not defined
2022-02-14 19:37:41 -05:00
Paul Hollinsky 0ce7326b83 Windows: PCAP: Fix a race which could cause transmit delays
If you had a chain of packets being sent all at once, the latter
section of packets could be delayed, theoretically infinitely.

If queue1 was filled and enqueued for transmit, then queue2
had packets enqueued in it while queue1 was still transmitting,
we'd try to fill queue2 further rather than waiting for queue1's
transmit to finish.

However, in that case, we wouldn't check if we could transmit
queue2 again until the next packet. If the user application
was waiting for the response from something in queue2
before pushing more packets, it could hang indefinitely.

This also fixes a subtle bug where hitting the "not safe to try
to fit any more packets in this queue" limit would cause a
packet to drop, as it would be dequeued and then tossed.

Closes GH-42
2022-02-14 19:37:41 -05:00
Paul Hollinsky 44e48182bf Device: Don't try to deduce lock_guard template parameters
This improves compatibility with older C++ standards
2022-02-14 19:32:12 -05:00
Paul Hollinsky 4fd65d85c8 Windows: PCAP: Fix WinPCAP loading
Used when LIBICSNEO_NPCAP_INCLUDE_DIR is not defined
2022-02-14 19:24:46 -05:00
Paul Hollinsky 0ded5508c1 Windows: Fix build issues with EthPhyRegPacket 2022-02-14 19:20:50 -05:00
Paul Hollinsky 6d92b7a03a Windows: PCAP: Fix a race which could cause transmit delays
If you had a chain of packets being sent all at once, the latter
section of packets could be delayed, theoretically infinitely.

If queue1 was filled and enqueued for transmit, then queue2
had packets enqueued in it while queue1 was still transmitting,
we'd try to fill queue2 further rather than waiting for queue1's
transmit to finish.

However, in that case, we wouldn't check if we could transmit
queue2 again until the next packet. If the user application
was waiting for the response from something in queue2
before pushing more packets, it could hang indefinitely.

This also fixes a subtle bug where hitting the "not safe to try
to fit any more packets in this queue" limit would cause a
packet to drop, as it would be dequeued and then tossed.

Closes GH-42
2022-02-04 01:14:08 -05:00
Kyle JohannesandPaul Hollinsky 2d1bb381f6 Device: Implement Ethernet PHY MDIO Communication
The following fixups were added during the squash/merge:

Fix formatting in EthPhyMessage and EthPhyRegPacket
Device: Use std::make_shared when creating the EthPHYControl filter
Network: Create NetID String for EthPHYControl
EthPhyRegPacket: Constants in PascalCase
2021-12-08 19:07:07 -05:00
Paul Hollinsky 890eb1e1bc RAD-Galaxy: Update settings structure with new entries 2021-12-08 14:30:54 -05:00
Paul Hollinsky 96f18dcfd6 PCAP: Don't use pthread_cancel on Linux
It is not necessary and can cause a crash in libunwind
2021-12-08 14:30:02 -05:00
Paul Hollinsky d5087c1ba5 Communication: Remove extra accidentally added logging 2021-12-06 05:41:27 -05:00
Paul Hollinsky f8b5710a6c Communication: Avoid MessageFilter type punning in waitForMessageSync 2021-12-02 15:00:13 -05:00
Paul Hollinsky 78747aa899 CMake: Set CXX_STANDARD to C++11 if not set elsewhere
We need at least C++11.

If we're statically compiling into an application, we want to be using the same
CXX_STANDARD as it for ABI compatibility (particularly with icsneo::optional),
hence having the check around it.
2021-11-16 20:04:12 -05:00
Paul Hollinsky 2d6004bed1 CANPacket: Remove unused byte from datastream 2021-11-16 20:04:12 -05:00
Paul Hollinsky 574530978c Encoder: Add 1 to host-to-device long format packets
Vehicle Spy 3 does this, it's a long-standing firmware idiosyncrasy.

Due to the way the device handles packets, this didn't cause a loss of
communication, only a "host to device byte" app error under certain
circumstances.
2021-11-16 20:03:41 -05:00
Paul Hollinsky 988289afc1 ValueCAN 4 Industrial: Disable 16-bit alignment over Ethernet
This is a continuation of a1a544045b
2021-11-16 20:03:02 -05:00
Paul Hollinsky 714db03a05 CMake: Set CXX_STANDARD to C++11 if not set elsewhere
We need at least C++11.

If we're statically compiling into an application, we want to be using the same
CXX_STANDARD as it for ABI compatibility (particularly with icsneo::optional),
hence having the check around it.
2021-11-16 19:49:08 -05:00
Paul Hollinsky d097fb9a74 CANPacket: Remove unused byte from datastream 2021-11-16 19:48:55 -05:00
Paul Hollinsky 9d5bad94d4 Encoder: Add 1 to host-to-device long format packets
Vehicle Spy 3 does this, it's a long-standing firmware idiosyncrasy.

Due to the way the device handles packets, this didn't cause a loss of
communication, only a "host to device byte" app error under certain
circumstances.
2021-11-16 19:35:20 -05:00
Paul Hollinsky 181223375a ValueCAN 4 Industrial: Disable 16-bit alignment over Ethernet
This is a continuation of a1a544045b
2021-11-16 19:27:38 -05:00
Paul Hollinsky 51626b9e63 POSIX: PCAP: Use EthernetPacketizer 2021-11-16 18:00:04 -05:00
Paul Hollinsky a1a544045b Ethernet Comm Devices: Disable unnecessary align16bit 2021-11-16 18:00:04 -05:00
Paul Hollinsky 719dbcefc8 EthernetPacketizer: Coalesce small PC-to-device packets 2021-11-16 18:00:04 -05:00
Paul Hollinsky ac77fe2b56 POSIX: PCAP: Use EthernetPacketizer 2021-09-23 21:31:59 -04:00
Paul Hollinsky 1aa3828688 Ethernet Comm Devices: Disable unnecessary align16bit 2021-09-23 21:30:48 -04:00
Paul Hollinsky 0656cb568e EthernetPacketizer: Coalesce small PC-to-device packets 2021-09-23 21:29:15 -04:00
Paul Hollinsky 6b37acf471 Encoder: Remove unused function
This is instead handled by an overloaded function in Communication
2021-09-21 00:23:32 -04:00
Paul Hollinsky df9827fb2c Device: Don't allow suppressDisconnects during a heartbeat request
See the comment block for an explanation
2021-09-20 23:39:45 -04:00
Paul Hollinsky f129be34b5 C API: Resolve compilation against new icsneo::Messasge API 2021-09-20 23:24:19 -04:00
Paul Hollinsky 38f0022bb6 Communication: Support extended commands 2021-09-20 23:07:49 -04:00
Kyle Schwarz 67c8e6a952 Build: Associate pcap include dir with icsneocpp
If an external project links to the icsneocpp target and pcap has
been installed in a non-standard location, the build will fail to find
pcap.h because PCAP_INCLUDE_DIR is not associated with the
target.

Closes #58
2021-09-20 21:55:56 -04:00
Kyle Schwarz 80c6816a54 Build: Associate libusb include dir with icsneocpp
If an external project links to the icsneocpp target and libusb has
been installed in a non-standard location, the build will fail to find
libusb.h because LIBUSB_INCLUDE_DIR is not associated with the
target.

Closes #57
2021-09-20 21:55:56 -04:00
Kyle Schwarz c5314884ce Build: Associate pcap include dir with icsneocpp
If an external project links to the icsneocpp target and pcap has
been installed in a non-standard location, the build will fail to find
pcap.h because PCAP_INCLUDE_DIR is not associated with the
target.

Closes #58
2021-09-20 21:38:34 -04:00
Kyle Schwarz 82954d9190 Build: Associate libusb include dir with icsneocpp
If an external project links to the icsneocpp target and libusb has
been installed in a non-standard location, the build will fail to find
libusb.h because LIBUSB_INCLUDE_DIR is not associated with the
target.

Closes #57
2021-09-20 21:31:13 -04:00
Paul Hollinsky 1b13e2d6a4 MessageFilter: Ensure non-frames can be filtered by network type and ID 2021-09-20 19:38:00 -04:00
Paul Hollinsky c847d68f3c POSIX FTDI: Count LIBUSB_ERROR_IO as a disconnection 2021-09-20 19:30:59 -04:00
Paul Hollinsky 3764a2e814 Device: Wider tolerance for disconnections 2021-09-20 19:29:57 -04:00
Paul Hollinsky 5f44986c1b Merge branch 'master' into v0.3.0-dev 2021-08-22 13:15:54 -04:00
Paul Hollinsky 68715d515d Decoder: Allow older ResetStatus packets without voltage or temperature 2021-08-22 13:12:36 -04:00
Paul Hollinsky 27184a203f Legacy: Use new layout for SDeviceSettings
This fixes issues where the settings values would be shifted.
2021-08-20 10:36:55 -04:00
Paul Hollinsky c7e7222140 Legacy: Ensure stddef.h is present for size_t
Many compilers won't need this, but better to
have it so it's correct.
2021-08-05 15:07:02 -07:00
Paul Hollinsky 6241996a58 RAD-Star 2: Fix invalid serial numbers being reported 2021-07-06 19:38:41 -04:00
Paul Hollinsky 84c6b202c7 RAD-Star 2: Fix invalid serial numbers being reported 2021-07-06 19:31:44 -04:00
Paul Hollinsky 16b88b7787 macOS: PCAP: Fix typo 2021-07-05 23:55:22 -04:00
Paul Hollinsky 0c67cdf078 macOS: PCAP: Fix typo 2021-07-05 23:54:15 -04:00
Paul Hollinsky bb65e37841 Merge branch 'master' into v0.3.0-dev 2021-06-17 21:07:50 -04:00
Paul Hollinsky 02c14aeb35 macOS: PCAP: Add code necessary for device discovery
You will still need chmod_bpf or similar to find devices
2021-06-17 21:07:22 -04:00
Tomasz ZiobrowskiandPaul Hollinsky ca83d7c4f2 Fixed ValueCan4 Industrial settings interpretation.
Description:
Possibly was an type - casting was done different structure.
Was not possible to determine or setup settings for ValueCan4 Industrial.

Whitespace fixed from the original commit
Co-authored-by: Paul Hollinsky <phollinsky@intrepidcs.com>
2021-06-16 21:02:42 -04:00
sbo79andPaul Hollinsky 4da5f63e57 Update README.md
Just experienced list filters got introduced to cmake in 3.6.... still failed run trough in ubuntu 18.04. works above 3.12.
2021-06-15 19:19:47 -04:00
Paul Hollinsky 37d06807e4 POSIX: PCAP: Update inferface name to match Windows implementation 2021-06-15 19:09:13 -04:00
Paul Hollinsky b13a33f0be Windows: PCAP: Less verbose name for the interface
Fixing some tabs/spaces formatting here as well
2021-06-15 19:09:05 -04:00
Tomasz Ziobrowski af2c30885b Added support for MinGW32 - to be working with qticsneo 2021-06-15 20:15:08 +02:00
Paul Hollinsky 3cff831c6b Examples: C++: Correct compilation in a C++20 project
Otherwise nonstd::optional doesn't match std::optional
2021-06-14 14:42:37 -04:00
Paul Hollinsky a8562aca60 API: Legacy: Make icsneoFindDevices edge cases match icsneo40 2021-06-14 14:41:54 -04:00
Paul Hollinsky e5bf87ba7d Merge branch 'master' into v0.3.0-dev 2021-06-11 18:54:36 -04:00
Paul Hollinsky da4ab6ef62 API: Legacy: Fix MSVC build issues 2021-06-11 18:44:33 -04:00
Paul Hollinsky a9840028ff Windows: DynamicLib: DLLExport before _stdcall for Legacy 2021-06-11 18:43:33 -04:00
Paul Hollinsky 4b7cb28bdf API: Legacy: Disable octal mappings for non-stubbed functions 2021-06-11 18:42:33 -04:00
Paul Hollinsky c888aad5ae VersionPacket: Use C++11 function signature 2021-06-11 18:40:50 -04:00
Paul Hollinsky 8c9d3a5e6a Merge branch 'master' into v0.3.0-dev 2021-06-11 15:40:42 -04:00
Paul Hollinsky 4588cb55fa POSIX: DynamicLib: Force visibility of exports in case of -fvisibility=hidden 2021-06-11 15:20:41 -04:00
Paul Hollinsky 9b2eae4a6c API: Legacy: Fix icsneoFindDevices 2021-06-11 15:19:40 -04:00
Paul Hollinsky 45c879c2b6 API: Legacy: Update def file with the correct ordinals 2021-06-11 13:52:09 -04:00
Paul Hollinsky a43c0117d6 API: C: Check nullptr in icsneo_serialStringToNum
Otherwise it will implicitly call the std::string constructor
and that constructor does not check nullptr.
2021-06-11 13:06:47 -04:00
Paul Hollinsky f3e456e7ea API: Legacy: Fix build issues caused by the merge 2021-06-11 13:05:39 -04:00
Paul Hollinsky 843fa92564 API: Legacy: Add standard DLLExport to LegacyDLLExport 2021-06-11 12:39:20 -04:00
Paul Hollinsky 34f7bfabd2 API: Legacy: Remove unused variable 2021-06-11 12:36:37 -04:00
David RebbeandPaul Hollinsky d82a069842 API: Legacy: Add icsneoOpenDevice
Needed for compatibility with the latest python-ics
2021-06-11 12:35:28 -04:00
Sangeetha HariharasudhanandPaul Hollinsky 9e70a9d51f API: Legacy: Implement functions necessary for J2534
icsneoEnableNetworkComEx
icsneoGetDeviceSettingsType
icsneoGetDeviceSettings
icsneoSetDeviceSettings
icsneoGetMiniportAdapterInfo
icsneoEnableDOIPLine
icsneoGetVnetSimpleNetid
icsneoGetNetidforSlaveVNETs
icsneoSetBitRateEx
icsneoSetFDBitRate
icsneoSerialNumberFromString
icsneoJ2534Cmd

_stdcall convention added with .def file (octal support)

use NumberBytesHeader instead of NodeID in txmessagesEx
2021-06-10 16:58:11 -04:00
Paul Hollinsky 4095f23ded Settings: Make getBaudrateFor work for SWCAN and LSFTCAN 2021-06-10 15:18:31 -04:00
Paul Hollinsky 1b7db51a45 Windows: PCAP: Fix Npcap loading for _UNICODE 2021-06-10 15:18:23 -04:00
Paul Hollinsky 165eb0f8a2 Windows: Correct dynamic load helper when _UNICODE is defined 2021-06-10 15:18:13 -04:00
Paul Hollinsky ed94012046 Examples: Interactive C: Fix initializers 2021-06-10 15:18:05 -04:00
Paul Hollinsky 7b7320bc27 Support the RAD-Epsilon 2021-06-10 15:17:57 -04:00
Paul Hollinsky 19aabdfacf POSIX: PCAP: Cancel after pcap_breakloop() to EINTR out of poll()
This is necessary as pcap_breakloop() does not actually wake the
thread from blocking operations, such as poll.
2021-06-10 15:17:43 -04:00
Paul Hollinsky b340d167dc Support the neoVI RED 2 2021-06-10 15:17:34 -04:00
Paul Hollinsky d4f6c12394 CANPacket: Fix invalid length check
This case is already checked above, and further
was invalid since the length had already been
translated to the numeric (0-64) value.
2021-06-10 15:03:34 -04:00
David Rebbe 4e901676d2 Added icsneoOpenDevice. 2021-06-07 17:03:56 -04:00
Paul Hollinsky ffe2d34799 Settings: Make getBaudrateFor work for SWCAN and LSFTCAN 2021-06-01 22:40:26 -04:00
Paul Hollinsky 71fc039689 Windows: PCAP: Fix Npcap loading for _UNICODE 2021-05-30 03:02:41 -07:00
Paul Hollinsky 496a007da3 Windows: Correct dynamic load helper when _UNICODE is defined 2021-05-30 02:57:18 -07:00
Paul Hollinsky cf8bcd1d63 Examples: Interactive C: Fix initializers 2021-05-30 02:55:00 -07:00
Paul Hollinsky bda37e31f3 Support the RAD-Epsilon 2021-05-28 18:10:16 -04:00
Paul Hollinsky c12330eec4 POSIX: PCAP: Cancel after pcap_breakloop() to EINTR out of poll()
This is necessary as pcap_breakloop() does not actually wake the
thread from blocking operations, such as poll.
2021-05-27 22:47:44 -04:00
Paul Hollinsky 04e7bfd1af Support the neoVI RED 2 2021-05-27 22:47:36 -04:00
Paul Hollinsky ed5132e852 CANPacket: Ensure correct padding when padding by the DLC 2021-05-25 22:19:03 -04:00
Paul Hollinsky 76b6ecbf04 CANPacket: Fix invalid length check
This case is already checked above, and further
was invalid since the length had already been
translated to the numeric (0-64) value.
2021-05-25 17:23:41 -04:00
Paul Hollinsky ad07af160c MSVC: Variable shadowing 2021-05-22 11:31:19 -04:00
Paul Hollinsky 21bc4eeff2 Message: Create a type system so non-frame data can be represented
This change breaks existing code, hence the version bump, but it's
going to be much less error prone going forward.
2021-05-22 01:58:36 -04:00
Paul Hollinsky 21e93d1f73 CAN: Honor the specified dlcOnWire for transmit 2021-05-21 17:38:00 -04:00
Paul Hollinsky b97f358a0f Settings: Extra Ethernet settings on ValueCAN 4 and RAD-Pluto 2021-05-10 21:17:31 -04:00
Paul Hollinsky 6f8e073fd1 MultiChannelCommunication: Resolve MSVC constexpr warning 2021-05-10 21:16:21 -04:00
Paul Hollinsky 07afbebc6d Settings: Resolve MSVC structure warnings 2021-05-10 21:15:54 -04:00
Paul Hollinsky 9ba7320fd3 MSVC: Fix build warnings 2021-05-05 12:51:52 -04:00
Paul Hollinsky f752924a36 Unaligned: Use correct MSVC define 2021-05-05 12:32:29 -04:00
Paul Hollinsky 295ba490aa Settings: Mark termination enables as an unaligned ptr
Unfortunately, the termination enables are not always at an aligned
boundary, and MSVC needs to taint the ptr type with __unaligned
in that case.
2021-05-05 03:38:58 -04:00
Paul Hollinsky 1bb114004e Remove unused parameters
These can cause warnings (which we treat as errors) on MSVC
2021-05-05 02:40:00 -04:00
Paul Hollinsky e99107c1bc Device: Allow different Question options for OpenStatus 2021-05-05 02:21:15 -04:00
Paul Hollinsky 82113f1a67 Settings: Better handling of the checksum 2021-05-05 02:20:36 -04:00
Paul Hollinsky 0006f31844 Network: Mark Main51, OldFormat, and ReadSettings as Internal 2021-05-05 02:18:22 -04:00
Paul Hollinsky 595cc36545 Device: Implement version handling 2021-05-05 02:17:38 -04:00
Paul Hollinsky 8be3bbaee5 CMake: Use CMAKE_CXX_STANDARD_REQUIRED 2021-05-05 02:16:01 -04:00
Paul Hollinsky 72bc5914a6 EthernetPacket: Allow 1 extra byte at the end of the packet
ValueCAN 4-2EL sends an extra byte to pad the message
to an even byte count.
2021-05-04 23:25:36 -04:00
Paul Hollinsky eca1110305 ValueCAN 4-2EL: Allow the Ethernet network while communicating over it
All frames except for the CAB1/CAB2 communication are reported
2021-05-04 23:08:34 -04:00
Paul Hollinsky b104b34919 Device: Report whether the current driver supports DFU 2021-05-04 22:53:28 -04:00
Paul Hollinsky 805ff4f549 ValueCAN 4-2EL: Device reqires PCAP to enumerate over Ethernet 2021-05-04 22:39:33 -04:00
Paul Hollinsky 78e3eb18df Drivers: Rename STM32 to CDC ACM
This is much more descriptive of what the driver actually is
2021-05-04 22:37:16 -04:00
Paul Hollinsky 6d22b1e001 POSIX: STM32: Check re-enumeration by inode
This is much more stable than waiting for a set amount of time
We still timeout at 5s, if we see that being hit it can be increased
2021-05-04 22:22:30 -04:00
Paul Hollinsky b7c7d4349a Device: Extend open() API for long-running tasks 2021-04-29 19:08:31 -04:00
Paul Hollinsky 3d4e0a27e3 Decoder: Pass on short Device messages 2021-04-29 19:07:38 -04:00
Paul Hollinsky 0ce52f064b Event: Better error message for USB powered devices 2021-04-29 18:15:56 -04:00
Paul Hollinsky f629125e67 Build: Allow inheritance of the C++ standard
This fixes symbol name incompatibilities when linking with icsneo::optional
between C++ standards.
2021-04-29 18:08:01 -04:00
Paul Hollinsky a63d701839 Event: More user-friendly message for the packet decoding error 2021-04-29 18:07:08 -04:00
Paul Hollinsky 622c5ee57a POSIX: STM32: Handle re-enumeration when changing modes 2021-04-27 21:12:59 -04:00
Paul Hollinsky 5733300de6 Extensions: Auto-add linked extensions 2021-04-27 21:12:24 -04:00
Paul Hollinsky 65a6fadd1d Device: Pull out communication close on open error
We don't want to close before calling the extension hooks.
2021-04-27 21:07:36 -04:00
Paul Hollinsky 8e2883bca9 MultiChannelCommunication: Use generic handleInput
This way redirection, and any other changes we
make to the packetizer/dispatch flow, apply to
MultiChannelCommunication as well.
2021-04-23 22:34:32 -04:00
Paul Hollinsky f8355df770 Communication: Block destruction while inside redirectionFn 2021-04-23 22:33:32 -04:00
Paul Hollinsky 218648ae5a Extensions: Offer an opportunity to communicate with a dead device 2021-04-23 22:32:42 -04:00
Paul Hollinsky 4cd7bafca7 Device: Allow the suppression of disconnects from extensions 2021-04-23 20:04:02 -04:00
Paul Hollinsky 6c1cbc9db8 Optional: Move optional-lite to the include/third-party directory
This fixes the use case of adding the include folder
manually to an outside project.
2021-04-23 20:01:53 -04:00
Paul Hollinsky b7ce9819bd POSIX STM32: Handle large write payloads failing with O_NONBLOCK 2021-04-23 17:06:16 -04:00
Paul Hollinsky 55ca6adee6 Communication: Allow redirection of reads 2021-04-23 17:00:37 -04:00
Paul Hollinsky bb7719d185 POSIX Drivers: Clear disconnected status when closing
This allows us to properly re-open if we were
previously disconnected.
2021-04-23 16:59:48 -04:00
Paul Hollinsky 4b12d3aa4d EventCallback: Convert indentation to tabs 2021-04-22 13:29:56 -04:00
Paul Hollinsky bb322ad190 neoVI FIRE 2: MiscIO and EMiscIO Support 2021-04-21 10:40:35 -04:00
Paul Hollinsky 92589c2ce7 Device: Make IO system thread-safe 2021-04-21 10:04:25 -04:00
Paul Hollinsky 3b6b4f0541 C API: Expose icsneo_getNetworkByNumber 2021-04-12 20:20:48 -04:00
Paul Hollinsky 40be68e744 C API: Add typedefs for neonetid_t and neonettype_t 2021-04-12 20:20:07 -04:00
Paul Hollinsky e29d63b08c Add Keysight branding where applicable
Because there is now more than one "product name" per device
type, we have a concept of a "generic product name" which
singularly maps onto a device type.

This change comes with a few small breaking changes within
the C++ API:

DeviceType::GetDeviceTypeString has been renamed to
DeviceType::GetGenericProductName to denote that
the returned value is not device specific and
device->getProductName() is preferable.

The member function DeviceType::toString has been renamed
to DeviceType::getGenericProductName for the same reason.

The DeviceType std::ostream& operator<< has been removed
to avoid accidental use of the generic product name.
2021-04-12 19:01:43 -04:00
Paul Hollinsky d79f735df8 Settings: Fix an issue where read errors were not properly reported
Since we were not failing the open for a settings read failure,
any errors would go unnoticed.
2021-04-11 22:37:44 -04:00
Paul Hollinsky e82b5d15e0 Support software controllable termination 2021-04-11 22:13:51 -04:00
Paul Hollinsky c8bf1f26da Examples: C Interactive: Initialize product description to empty string
This is a guard in case the icsneo_describeDevice call were to
fail for some reason, and is just good practice regardless.
2021-04-11 22:00:12 -04:00
Paul Hollinsky 9ba21d5dc7 C API: Digital IO function use stdbool.h
This requirement is already in place and makes the API more consistent
2021-04-11 20:54:59 -04:00
Paul Hollinsky eb5a84132a EtherBADGE: Device only has one CAN channel 2021-04-08 15:51:56 -04:00
Paul Hollinsky 66b0c91cea Settings: Add missing early return on error to getFDBaudrateFor 2021-04-08 15:05:39 -04:00
Paul Hollinsky 7fdae15aed Network: Update DeviceStatus define to match the standard style 2021-04-07 00:38:49 -04:00
Paul Hollinsky adb972b1f7 Network: Fix defines for C API 2021-04-07 00:35:08 -04:00
Paul Hollinsky 441b16e9a1 Network: Add CoreMini Mappings
These are used for network and termination enables
2021-04-07 00:30:54 -04:00
Paul Hollinsky cf8c5a31c7 I2C: Add as type and fix network definitions
The first I2C was mysteriously missing, it is here now.

In addition, I2C support will soon be requested so it has been
given its own type.
2021-04-07 00:23:29 -04:00
Paul Hollinsky a6c8acd8e9 Ethernet (DoIP) Activation Line support 2021-04-06 22:50:25 -04:00
Paul Hollinsky 4e245db94e ValueCAN 4-2EL: Fix wrong structure used in settings
The old structure lined up with the correct one, so the wrong
way did work, but it was just by sheer luck.
2021-04-06 18:03:41 -04:00
Paul Hollinsky 4a1d0382f2 ThirdParty: Add optional-lite polyfill
Thanks to all who have made contributions to
https://github.com/martinmoene/optional-lite
2021-04-06 18:01:26 -04:00
Paul Hollinsky 18394d0cfb Add transmit support for ISO 9141-2 2021-03-23 17:23:55 -04:00
Paul Hollinsky 4bca43028c EthernetPacketizer: Resolve warnings 2021-03-23 14:36:10 -04:00
Paul Hollinsky 92790330f1 macOS: STM32: Fix device finding for newer versions of the OS 2021-03-22 16:07:51 -04:00
Jeffrey Quesnelle 7f27b30954 Make icsneo::Plasion::GetSupportedNetworks public 2021-02-26 10:38:38 -05:00
Paul Hollinsky f63c187ed3 Add receive support for ISO 9141-2 2021-02-18 23:19:33 -05:00
Paul Hollinsky 4d655da69d Decoder: 64-bit shift to avoid UB
Shifting a value by more than the size of its type is UB.

This was actually causing mangled serial numbers with
optimization on using Clang 12 on Linux.
2021-01-29 17:32:07 -05:00
Paul Hollinsky 09a02ff420 Platform: Windows: Unicode safe
Compile and run correctly whether UNICODE and _UNICODE are defined or not
2021-01-28 15:51:35 -05:00
Kyle SchwarzandPaul Hollinsky 33a84bf8ce PCAP: Switch to pcap_dispatch() 2020-11-17 15:05:14 -05:00
Paul Hollinsky 7c1d44bc4f C Example: Show transmit receipts 2020-11-17 11:47:09 -05:00
Paul Hollinsky cfaf677263 C Example: Fix improper allocation size 2020-11-17 11:47:05 -05:00
Kyle Schwarz ffbb5e20c5 Add description field for messages
Closes https://github.com/intrepidcs/libicsneo/issues/28
2020-11-13 16:15:04 -05:00
Paul Hollinsky e5920417ff POSIX: FTDI: Use libusb include directory
This allows for the same include to be used on macOS
2020-10-08 21:09:45 -04:00
Kyle SchwarzandPaul Hollinsky a5b27a15b0 Allow disconnections to be signaled by drivers
This allows for disconnections to be detected quickly
where possible.

It also makes sure other driver errors aren't thrown
in the event of a disconnection.
2020-10-08 17:38:10 -04:00
Paul HollinskyandGitHub dfe2d23d85 Merge pull request #27 from pierreluctg/icsneolegacy-ExtraDataPrtEnabled
Setting ExtraDataPtrEnabled when ExtraDataPtr is use
2020-09-23 12:40:56 -04:00
Paul HollinskyandGitHub 66d7c2f390 Merge pull request #25 from pierreluctg/icsneolegacy-setFDBitRate
Adding icsneoSetFDBitRate api to the icsneolocacy
2020-09-23 12:36:23 -04:00
Paul Hollinsky 7e714abfd1 EthernetPacketizer: Add missing include for GCC 2020-09-23 10:23:05 -04:00
Pierre-Luc Tessier Gagne 2cd074cf13 Setting ExtraDataPtrEnabled when ExtraDataPtr is use 2020-09-23 08:40:57 -04:00
Pierre-Luc Tessier Gagne 90b04f4578 Adding icsneoSetFDBitRate api to the icsneolocacy 2020-09-23 07:23:17 -04:00
Paul Hollinsky 6f0654c336 Windows: PCAP: Rework for Ethernet Packetizer and Performance 2020-09-22 19:22:40 -04:00
Paul Hollinsky 76619e2496 RAD-Galaxy: RJ45 Ethernet Support
The "Ethernet" network must be enabled in neoVI Explorer.
It is disabled by default.

This network corresponds with the port labeled DAQ on
the Galaxy.
2020-09-22 19:20:56 -04:00
Paul Hollinsky 2c55584962 Ethernet: Encode preemption enabled flag 2020-09-22 19:19:22 -04:00
Paul Hollinsky 1f4358af4b Packetizer: Correct packet length check
AA(1) + Old format(1)  + New Length(2) + New NetID(2) = 6
2020-09-22 19:17:12 -04:00
Paul Hollinsky 28b35a8243 Communication: Create EthernetPacketizer
This code previously was separately maintained in each of the
PCAP driver layers.

While adding complexity for reassembly, I decided it was
time to pull it out into a common implementation.

As of this commit, the old implementations have not been
removed from the PCAP drivers yet.
2020-09-22 19:15:24 -04:00
Paul Hollinsky 5c18bedf70 RAD-Gigalog: Fix serial number prefix 2020-09-18 16:38:09 -04:00
Paul Hollinsky eda4a30dcd Add ValueCAN 4 Industrial 2020-09-14 12:45:32 -04:00
Paul Hollinsky 211f844f77 ValueCAN 4-2EL: Fix device agnostic CAN settings 2020-09-14 12:36:19 -04:00
Paul Hollinsky 8843ace87e ValueCAN 4-2EL: Add communication over Ethernet
The device can communicate with the PC over its Ethernet if the
enablePcEthernetComm setting is set within the structure.

This stops the Ethernet port from being used for vehicle data.
2020-09-14 12:35:43 -04:00
Paul Hollinsky d2676afa11 Update device names for consistency 2020-09-14 11:58:34 -04:00
Paul Hollinsky c48efe8e5b Add Gigalog, Gigastar, Moon 2, Moon Duo, and Supermoon
The USB drivers for these devices are currently stubbed, it will find them
but not connect.

The Ethernet drivers work though, where applicable.
2020-09-14 11:57:01 -04:00
Paul Hollinsky 9dc4b302ef POSIX: PCAP: Enable if permissions are set, with a warning otherwise
On Linux, raw packet capture requires CAP_NET_RAW (or root).

If we can't capture raw packets, we will not be able to find/connect to
devices over ethernet.
2020-09-14 11:51:15 -04:00
Paul Hollinsky a460e27657 Add RADGigalog for Windows
Ethernet communication with device only
2020-09-08 17:55:52 -04:00
Paul Hollinsky eaa1409af0 Update/add settings structures for several devices 2020-09-08 17:41:47 -04:00
Paul Hollinsky de0c16a461 VividCAN: Better "Online Not Supported" Error 2020-09-08 17:39:47 -04:00
Paul Hollinsky 3f8ed840ba Start callback IDs at 1 so 0 is reserved 2020-09-08 17:38:38 -04:00
Kyle Schwarz 12463ea2f4 Remove globs from CMake 2020-09-02 12:19:17 -04:00
Paul Hollinsky 8e999a0fb8 Heartbeat: Break from loop rather than returning
This makes sure we run the cleanup code at the bottom of the thread
2020-09-01 16:32:54 -04:00
Paul Hollinsky a325d8a12b PCAP: Send initial requests from the interface MAC
This allows the device to respond directly to us
2020-09-01 15:53:45 -04:00
Paul Hollinsky 046e2bae9d Ensure proper closure of the heartbeat thread on reopen 2020-09-01 15:52:41 -04:00
Paul Hollinsky c48995520f POSIX: FTDI: Report warnings and retry on libftdi errors 2020-09-01 15:15:36 -04:00
Paul Hollinsky aceea6dc5b libftdi: Don't discard data on LIBUSB_ERROR_TIMEOUT
libusb may have transferred some data, don't want to lose it
2020-09-01 15:14:37 -04:00
Kyle Schwarz 1bb1ab7a82 Add CoreFoundation and IOKit frameworks for macOS 2020-08-28 13:34:28 -04:00
Kyle Schwarz 044c2bb86f Detect device disconnects
When a device is sending any traffic, the device is considered to be connected. If no traffic if being received from the device, a status is requested. If the device fails to report the status back in a timely manner, it is considered to be disconnected.

If the device fails to reply to the status request, it is important to confirm that the device is not applying settings. While the device is applying settings, it will not be sending heartbeats or able to process a status request.
2020-08-27 13:20:48 -04:00
Paul Hollinsky 5db07102aa PCAP: Listen for ICS_UNSET_MAC
On newer firmware, the device will address the PC directly after
EnableNetworkComm. Before this, it will set the destination MAC to
00:FC:70:FF:FF:FF.
2020-08-27 12:24:35 -04:00
Paul Hollinsky b5c9443fc8 POSIX: PCAP: Ensure packets get captured
No packets were being captured with a timeout of 0
2020-08-27 12:24:35 -04:00
Kyle Schwarz 4c2cd918de Revert "Add FindLibUSB.cmake for libftdi"
This reverts commit dfe5845b3c.
2020-08-27 12:22:24 -04:00
Kyle SchwarzandPaul Hollinsky 7cd008a003 Switch to non-blocking I/O for STM32
STM32 can latency is not as good as it could be when it is synchronous due to read() timeouts,
so switch to asynchronous reading with select().
2020-08-25 16:14:47 -04:00
Kyle Schwarz dfe5845b3c Add FindLibUSB.cmake for libftdi 2020-08-20 12:44:05 -04:00
Kyle SchwarzandPaul Hollinsky b6692d3762 Add missing C++ guards 2020-08-18 16:01:51 -04:00
Kyle Schwarz 3e4b595fe4 Resolve signedness warnings on GCC 2020-08-18 15:37:05 -04:00
Kyle Schwarz 4cd897badd Fix deadlock with Driver::write
Use a spin lock to recheck the queue size until it has room to push.
2020-08-14 16:57:52 -04:00
Kyle Schwarz afda617894 Remove trailing white-space 2020-08-11 13:42:13 -04:00
Kyle Schwarz 1d286be1e4 Switch PLUTO_MAX_MAC_CONFIG_ENTRIES to C API define 2020-08-10 15:50:29 -04:00
Kyle Schwarz 6638cf05ae Use C++11 constexpr instead of define 2020-08-10 15:21:16 -04:00
Kyle Schwarz d58202dfc0 Add RADPlutoSettings to initializer template call 2020-08-10 15:07:12 -04:00
Kyle Schwarz 08928c36e3 RADPluto uses HSCAN2 instead of MSCAN 2020-08-10 14:31:59 -04:00
Kyle Schwarz 4b218b3f9a Merge branch 'master' of Lustra:InfiniteWalrus/libicsneo into radpluto 2020-08-10 13:06:14 -04:00
Paul Hollinsky 07e99515fa Always send the ReadSettings command in short format
This is needed for FIRE
2020-08-10 12:30:30 -04:00
Kyle Schwarz 3123cbb54b Merge branch 'master' of Lustra:InfiniteWalrus/libicsneo into radpluto 2020-08-10 11:11:38 -04:00
Kyle Schwarz 17ebba3c57 Fix line-endings and include guard 2020-08-10 10:40:40 -04:00
Kyle Schwarz 7b3782cbe7 Update concurrentqueue to 1.0.2
1.0.2 resolves compiler warnings for MSVC 2019 with C++17 support (https://github.com/cameron314/concurrentqueue/commit/9cfda6cc61065d016ae3f51f486ce0fae563ea87)
2020-08-10 10:20:00 -04:00
Kyle Schwarz f9ff4049f2 Add initial support for RADPluto settings 2020-08-07 17:13:08 -04:00
Paul Hollinsky 154eab4b1b Direct to the examples folder 2020-08-06 16:26:46 -04:00
Paul Hollinsky b09f85693f v0.2.0
This update has breaking changes for the event/error subsystem, see
Usage within the documentation for details on the workings of the new
system.
2020-08-06 16:17:28 -04:00
Paul Hollinsky 6218a5cc7e Fix documentation building 2020-08-06 16:09:29 -04:00
Paul Hollinsky 8566f9d57d Update copyright date 2020-08-06 16:06:31 -04:00
Paul Hollinsky f49f65c3ed Move examples into tree
See history at https://github.com/intrepidcs/libicsneo-examples/tree/v0.2.0-dev
2020-08-06 15:41:48 -04:00
Paul Hollinsky 2079037ae4 POSIX FTDI: Nicer error message for when device is in use
Commonly, the device is being used by another libicsneo program
(icsscand, maybe) or passed through to a VM.
2020-06-24 22:15:22 -04:00
Paul Hollinsky a759c1faa9 Communication: Fix issue where driver failing to open leaves dangling thread 2020-06-24 22:03:31 -04:00
Paul Hollinsky 67bd1e616a MultiChannelCommunication: Fix issue where initial open fails 2020-06-24 21:38:57 -04:00
Paul Hollinsky 25f079b5c6 POSIX FTDI: Fix a bug where closing device successfully returned an error 2020-06-24 20:59:53 -04:00
Paul Hollinsky dcc44d99ea Fix an issue where the FIRE could not be opened 2020-06-17 15:11:57 -04:00
Jeffrey Quesnelle 7a71a35848 add option to build with Npcap on Windows 2020-06-16 12:14:46 -04:00
Jeffrey Quesnelle 8f6ff86448 Load pcap_sendqueue functions on Windows 2020-06-12 13:55:47 -04:00
Paul Hollinsky 8260149cb8 Add bridging between neomessage_eth_t and EthernetMessage
This allows transmitting Ethernet from the C API
2020-05-18 17:23:40 -04:00
Jeffrey Quesnelle d2019c24df reuse discovered pcap interfaces in DeviceFinder::FindAll() 2020-05-11 16:17:56 -04:00
Jeffrey Quesnelle 99879c9021 turn PCAPDLL into a singleton 2020-03-24 13:15:26 -04:00
Paul Hollinsky 38e24d7641 Refactor ICommunication/Transport => Driver 2020-03-09 14:09:27 -04:00
Paul Hollinsky d8798acaa7 Communication: MultiChannel: Properly mask out communication from non-main VNETs
This also makes it possible for Communication to create more instances of Packetizer
This is necessary because Packetizer is not thread safe,
so when we support more VNETs we will need to create more Packetizers.
2020-03-09 13:56:18 -04:00
Paul Hollinsky 42780dc610 Add ReaderWriterQueue and update ConcurrentQueue 2020-03-09 13:38:14 -04:00
Paul Hollinsky 9ac3fd56bd FlexRay: Don't check for POCReady when writing configuration
It is not needed and this gives a good speedup to configuration
2020-02-28 20:10:31 -05:00
Paul Hollinsky 8ae3317930 FlexRay: Rework controller register reading for reliability 2020-02-28 20:09:33 -05:00
Paul Hollinsky 1cd817a16b Fix race conditions with Communication::waitForMessageSync 2020-02-28 20:00:08 -05:00
Paul Hollinsky 9fcba2eb13 Notify extensions we're going offline before we actually do 2020-02-28 19:57:43 -05:00
Paul Hollinsky 0c330f734b Fix typo 2020-02-28 19:57:16 -05:00
Paul Hollinsky a2fecb7621 Support for EtherBADGE 2020-02-20 14:43:10 -05:00
Jeffrey Quesnelle 98bd7e9c55 add decoding of transmitted, error, and description fields for CAN packets 2020-02-19 09:36:28 -05:00
Paul Hollinsky ef34959c91 STM32 device finder for Darwin 2020-02-14 23:18:34 -05:00
Jeffrey Quesnelle 57fb55b686 fix uninitialized memory which may cause Windows to not properly enumerate devices 2020-01-24 13:32:35 -05:00
Paul Hollinsky 724cc428d9 Properly specify the FlexRay CC registers 2019-11-20 16:24:20 +01:00
Paul Hollinsky 52b0b4c586 Properly set up transmit buffers 2019-11-19 17:07:48 +01:00
Paul Hollinsky fe7c50f8a3 Correctly shift received data 2019-11-19 17:07:26 +01:00
Paul Hollinsky 4821a957dd Properly decode incoming FlexRayPackets 2019-11-18 06:09:25 +01:00
Paul Hollinsky 31062dd928 For now, assume VNET Z is in coldstart mode 2019-11-12 20:48:30 -05:00
Paul Hollinsky 37778d7891 Implement FlexRay transmit, configuration, and cold start 2019-11-12 20:38:47 -05:00
Paul Hollinsky 3396f5dcce Refining the FlexRay API 2019-11-09 15:34:58 -05:00
Paul Hollinsky f0582697a6 Clarify FlexRay Slot ID 2019-11-01 14:48:14 -04:00
Jeffrey Quesnelle b990e03343 add CMake options to disable certain targets and fix a few compiler warnings 2019-10-17 09:43:50 -04:00
Jeffrey Quesnelle 423f854682 fix MSVC build errors and warnings 2019-10-16 23:56:49 -04:00
Paul Hollinsky eb856dffec Quiet down warnings on Windows 2019-10-16 17:43:11 -04:00
Paul Hollinsky debaf8f0cb Merge branch 'v0.2.0-dev' of github.com:intrepidcs/libicsneo into v0.2.0-dev 2019-10-16 16:44:16 -04:00
Paul Hollinsky 2f9844df92 Begin work on FlexRay support 2019-10-16 16:43:31 -04:00
Paul Hollinsky 5795efbde8 Merge changes from v0.1.2
Dropping the updateLEDState fix as the one on this branch is nicer
2019-09-04 13:40:42 -04:00
Paul Hollinsky 0607986114 Resolve merge conflicts 2019-08-12 11:17:28 -04:00
EricLiu2000 ef16e60025 Added more mutexes in eventmanager, fixed exiting destruction bug 2019-08-07 13:12:16 -04:00
EricLiu2000 9629864f1b Fixed wait check in device online/offline 2019-08-07 10:06:33 -04:00
Jeffrey Quesnelle 781b23c0e7 std::chrono::seconds::duration should just be std::chrono::seconds 2019-08-06 17:35:44 -04:00
Jeffrey Quesnelle 5112e1d2f9 fix building for macos 2019-08-06 17:14:12 -04:00
EricLiu2000 3358241abe Reordered error downgrading, order of going offline, and renamed locks 2019-08-06 10:32:19 -04:00
EricLiu2000 01c62b6445 Replaced formal parameter filter in addmessagecallback and addeventcallback 2019-08-06 10:31:08 -04:00
EricLiu2000 4a81b9443a Changed getpollingmessagelimit to return an int 2019-08-05 17:25:09 -04:00
EricLiu2000 71176137ca Added waits to ensure going online and offline succeed before returning 2019-08-05 15:35:44 -04:00
EricLiu2000 451f0a9ac1 Added documentation for event callbacks 2019-08-05 11:41:01 -04:00
EricLiu2000 1aeee082ae Testing successful removal of events from within event callbacks 2019-08-05 11:40:47 -04:00
EricLiu2000 9b3d36c8c1 Moved calling of event callbacks to after the event is added. Now using unique_locks on the list of events to allow event callbacks to safely modify the list of events 2019-08-05 11:40:17 -04:00
EricLiu2000 bf77b7ac3b Added event callbacks multithreaded test and added documentation 2019-08-05 10:57:48 -04:00
EricLiu2000 2108d6223c Fixed runtime error casting placeholder void* to void in message and event callbacks 2019-08-05 10:32:23 -04:00
EricLiu2000 9040edc25d Added event callback functionality in icsneoc 2019-08-02 16:32:15 -04:00
EricLiu2000 4f735a651c Added event callback functionality. EventManager now uses multiple mutexes to lock events, errors, callbacks, and downgradedThreads separately. Wrote single-threaded test for event callbacks. 2019-08-02 15:00:31 -04:00
EricLiu2000 f9712a4bcd Added error flag when packetizer and multichannelcommunication fail to read 2019-08-01 16:21:29 -04:00
EricLiu2000 453f098cdb Added check to see if message polling is enabled before disabling it in device destructor 2019-08-01 14:08:12 -04:00
EricLiu2000 f41b5c4a79 Removed cancellation of error downgrading after closing, was causing read access violations. 2019-08-01 14:07:42 -04:00
EricLiu2000 055cae1232 Removed radpluto override of setupDecoder() in order to fix timestamp 2019-08-01 13:40:38 -04:00
EricLiu2000 8516a9c8bd Added placeholder void* filter parameter to icsneo_addMessageCallback and added more documentation for message callback functions 2019-07-30 14:02:34 -04:00
EricLiu2000 655a483aee Cleaned up icsneolegacy returns that use icsneo_settingsReadStructure 2019-07-30 10:29:42 -04:00
EricLiu2000 c10224002a Added message callback functionality in c and canceled error downgrading on user callbacks in communication as well 2019-07-30 10:22:27 -04:00
EricLiu2000 5a98bac8a6 Standardized int-returning functions in icsneoc library to return -1 on failure. Updated icsneolegacy accordingly, and added headers for message callback functionality in c 2019-07-29 16:08:54 -04:00
EricLiu2000 54b98ec9b4 Error downgrading now uses a map<threadid, bool>, and error downgrading is canceled during message callbacks 2019-07-29 15:16:35 -04:00
EricLiu2000 ff1e65b292 Added flag BUILD_DOCS for documentation in CMakeLists.txt 2019-07-29 14:30:50 -04:00
EricLiu2000 f1632aada5 Added overview section for API concepts and added more detailed explanation of message callbacks and polling 2019-07-29 12:57:00 -04:00
EricLiu2000 c62ea4d05f Ignoring _build 2019-07-29 12:57:00 -04:00
Paul Hollinsky 511a724252 POSIX FTDI: Improve performance by setting the latency timer 2019-07-26 17:46:24 -04:00
EricLiu2000 f30b2ef11c Added official documentation for device concepts in usage 2019-07-26 15:12:17 -04:00
EricLiu2000 f009d8cac5 Wrote official documentation for the events and error system 2019-07-26 13:34:35 -04:00
EricLiu2000 b75536c4a2 Updated some documentation in eventmanager to reflect chronological pruning of events 2019-07-26 13:34:03 -04:00
EricLiu2000 4654742046 Updated copyrights from 2018 to 2019 2019-07-25 16:49:07 -04:00
EricLiu2000 80999251ef Updated library version numbers to 0.2.0 2019-07-25 16:45:54 -04:00
EricLiu2000 16205d29b6 Added initial documentation files for c#, java, and usage 2019-07-25 16:43:33 -04:00
EricLiu2000 8c186f00cd Added functionality to set blocking behavior of write 2019-07-24 14:57:06 -04:00
EricLiu2000 69b7e5b45a Device::GetMessages now returns a pair of {vector, bool} instead of vector 2019-07-24 13:40:54 -04:00
EricLiu2000 66126b2b61 Downgraded non-user thread errors to warnings 2019-07-24 13:22:17 -04:00
EricLiu2000 6f8d307850 Implemented thread specific error-downgrading to events and wrote corresponding unit test 2019-07-24 12:52:15 -04:00
EricLiu2000 42a5d525ce Renamed test suite in CMakeLists.txt 2019-07-23 17:20:25 -04:00
EricLiu2000 199bd2b144 Reverted refactor changes to icsneolegacy.h 2019-07-23 17:16:27 -04:00
Paul Hollinsky 21c3fead4a Error checking for Encoder::encode UpdateLEDState 2019-07-23 15:04:50 -04:00
Paul Hollinsky 77eed8f58d Revise documentation for icsneo_getLastError 2019-07-23 15:03:43 -04:00
EricLiu2000 69a7b9bc2d Removed casts in network.h constants for SWIG compatibility 2019-07-17 16:36:40 -04:00
EricLiu2000 65cd6ff8c8 Cleaned up some formatting 2019-07-17 15:22:13 -04:00
EricLiu2000 42690d1f9a Updated documentation, added multithreaded test with both events and errors for eventmanager 2019-06-28 11:11:58 -04:00
EricLiu2000 e3517767cb Events are now removed purely in chronological order if overflowing 2019-06-27 18:04:59 -04:00
EricLiu2000 70d5b4f5b5 Reordered tests 2019-06-27 17:28:54 -04:00
EricLiu2000 a4ddd24a50 Added functionality for filtering by both type and severity. Wrote tests for eventmanager::get 2019-06-27 17:04:07 -04:00
EricLiu2000 baa9404432 Went back to normal mutex because I forgot I reverted those 2019-06-27 16:02:31 -04:00
EricLiu2000 1d3b3359ca Wrote more tests, fixed bug with eventmanager::get(size), optimized eventmanager adding and shrinking, prevented trying to add TooManyEvents 2019-06-27 15:50:22 -04:00
EricLiu2000 d0c6aba0fc Revert "Changed list of events to vector, switched back to using lock_guard instead of shared/unique_locks"
This reverts commit 2dac03b3e5.
2019-06-27 14:16:36 -04:00
EricLiu2000 2dac03b3e5 Changed list of events to vector, switched back to using lock_guard instead of shared/unique_locks 2019-06-27 13:42:02 -04:00
EricLiu2000 a9a2a978b8 Fixed multithreading issue with eventmanager 2019-06-27 13:20:13 -04:00
EricLiu2000 ec95f0f7c3 Wrote more tests and fixed locking bug in eventmanager 2019-06-26 15:08:41 -04:00
EricLiu2000 975c7f422f CMake properly uses -DBUILD_TESTS flag, added CmakeSettings.json to gitignore 2019-06-26 11:53:06 -04:00
EricLiu2000 4923218d35 Separated tests into different files, added ResetInstance() method to EventManager 2019-06-26 11:30:24 -04:00
EricLiu2000 1dd68eb0d0 Test framework tentatively working on windows 2019-06-25 18:01:32 -04:00
EricLiu2000 bb2d7c1265 Reversed nullptr device check 2019-06-25 17:46:59 -04:00
EricLiu2000 150c7d2b07 Added gtest folder and building doesn't throw errors 2019-06-25 16:56:04 -04:00
EricLiu2000 f45bd6772f Builds and runs on both windows and ubuntu 2019-06-25 13:20:49 -04:00
EricLiu2000 92dc23fa4b Updated README for refactor 2019-06-25 12:48:58 -04:00
EricLiu2000 2f971d7565 Runs on windows 2019-06-25 11:35:40 -04:00
EricLiu2000 50dba62a89 Event refactor builds on Windows 2019-06-24 17:59:45 -04:00
EricLiu2000 878d9e6dde Implemented threaded error handling in errormanager and fixed compile error 2019-06-21 16:14:52 -04:00
EricLiu2000 f9d88b4743 Upgraded the severity of some warnings to errors and cleaned up internal API error adding 2019-06-21 15:08:08 -04:00
EricLiu2000 cb6f88c6bb Initial rework of internal management for overflowing errors 2019-06-21 11:18:24 -04:00
EricLiu2000 33ad0c1967 C++ error descriptions now distinguish between severity levels 2019-06-19 11:00:41 -04:00
EricLiu2000 12cb4c227a icsneolegacy icsneoOpenNeoDevice return now checks success for setting polling message limit and enabling message polling too 2019-06-18 11:40:18 -04:00
EricLiu2000 92368f70a5 Added error checking for polling 2019-06-18 11:38:12 -04:00
EricLiu2000 2b34c82382 Added error checking to Device::getMessages() 2019-06-18 10:34:50 -04:00
EricLiu2000 04a2402925 Added additional documentation 2019-06-14 17:44:01 -04:00
EricLiu2000 a4a42c8704 Reworked updating LEDState to use sendCommand() instead of transmit() 2019-06-14 16:09:19 -04:00
EricLiu2000 28fc98c475 Added icsneo_isMessagePollingEnabled(), removed polling check from transmitting, and disabled error reporting on device destruction 2019-06-14 15:13:22 -04:00
Paul HollinskyandEricLiu2000 a608d21304 Fix for error at pcap and vcp level on Windows causes crash 2019-06-14 09:41:47 -04:00
EricLiu2000 44ca4d4db1 Removed extraneous error checking 2019-06-13 16:04:20 -04:00
EricLiu2000 b7288edd9a Finished adding error checking 2019-06-13 16:01:35 -04:00
EricLiu2000 255e1e2b90 Added more error logging 2019-06-13 16:01:35 -04:00
EricLiu2000 dc4f96affb Commands can now only be sent when the device is open 2019-06-13 16:01:35 -04:00
EricLiu2000 8a6073a9cf Transmit and receiving messages now fails properly when the device is closed. Device closes when serial number initialization fails after open. 2019-06-13 16:01:35 -04:00
EricLiu2000 519e64fb17 Added error checking to functions called from Communication 2019-06-13 16:01:35 -04:00
EricLiu2000 a16f2843d8 Added error reporting to idevicesettings 2019-06-13 16:01:35 -04:00
EricLiu2000 965679c370 Added error checking and removed some redundancy from device isOpen() 2019-06-13 16:01:35 -04:00
EricLiu2000 2806c935f1 Added errors for DeviceCurrentlyOpen and DeviceCurrentlyClosed 2019-06-13 16:01:35 -04:00
EricLiu2000 8862a06c3d Added .vs to gitignore 2019-06-13 16:01:35 -04:00
EricLiu2000 903615dadd Added icsneo_isOpen() functionality 2019-06-13 16:01:35 -04:00
EricLiu2000 f1e0625429 Fixed typo in documentation of icsneo_getLastError 2019-06-13 16:01:35 -04:00
EricLiu2000 0644234859 Removed hard coded .dll filepaths 2019-06-13 16:01:35 -04:00
EricLiu2000 9b21c153c7 Fixed icsneoc.h to work with c 2019-06-13 16:01:35 -04:00
Paul Hollinsky b7dbeccaef Lock before adding or removing message callbacks 2019-06-13 15:47:23 -04:00
2700 changed files with 568097 additions and 8281 deletions
+9 -1
View File
@@ -1,9 +1,17 @@
_build/
build/ build/
build*/ build*/
.DS_Store .DS_Store
Thumbs.db Thumbs.db
CMakeSettings.json
.vscode .vscode
third-party/concurrentqueue/benchmarks third-party/concurrentqueue/benchmarks
third-party/concurrentqueue/tests third-party/concurrentqueue/tests
*.bak *.bak
.vs .vs
.cache
*.wav
*.orig
examples/csharp/bin
examples/csharp/obj
test/system
+531
View File
@@ -0,0 +1,531 @@
variables:
DEBIAN_FRONTEND: noninteractive
stages:
- build
- unit_test
- hardware_test
- deploy
#-------------------------------------------------------------------------------
# Windows
#-------------------------------------------------------------------------------
build windows/x64:
stage: build
script:
- CMD.EXE /C ci\build-windows64.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- libicsneo-win-x64
unit_test windows/x64:
stage: unit_test
script:
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x64
needs:
- build windows/x64
tags:
- libicsneo-win-x64
timeout: 5m
build windows/x86:
stage: build
script:
- CMD.EXE /C ci\build-windows32.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- libicsneo-win-x64
unit_test windows/x86:
stage: unit_test
script:
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x86
needs:
- build windows/x86
tags:
- libicsneo-win-x64
timeout: 5m
#-------------------------------------------------------------------------------
# Ubuntu
#-------------------------------------------------------------------------------
.build_linux_ubuntu_gcc: &build_linux_ubuntu_gcc
stage: build
script:
- apt update -y
- apt upgrade -y
- apt install -y g++ ninja-build cmake libusb-1.0-0-dev libpcap-dev git
- sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_ubuntu_gcc: &test_linux_ubuntu_gcc
stage: unit_test
script:
- apt update -y
- apt upgrade -y
- apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
.build_linux_ubuntu_clang: &build_linux_ubuntu_clang
stage: build
script:
- apt update -y
- apt upgrade -y
- apt install -y clang lld ninja-build cmake libusb-1.0-0-dev libpcap-dev git
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_ubuntu_clang: &test_linux_ubuntu_clang
stage: unit_test
script:
- apt update -y
- apt upgrade -y
- apt install -y libusb-1.0-0-dev libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/ubuntu/2004/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:20.04
unit_test linux/ubuntu/2004/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:20.04
dependencies:
- build linux/ubuntu/2004/amd64/gcc
needs:
- build linux/ubuntu/2004/amd64/gcc
build linux/ubuntu/2004/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:20.04
unit_test linux/ubuntu/2004/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:20.04
dependencies:
- build linux/ubuntu/2004/amd64/clang
needs:
- build linux/ubuntu/2004/amd64/clang
build linux/ubuntu/2204/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/gcc
needs:
- build linux/ubuntu/2204/amd64/gcc
build linux/ubuntu/2204/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:22.04
unit_test linux/ubuntu/2204/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:22.04
dependencies:
- build linux/ubuntu/2204/amd64/clang
needs:
- build linux/ubuntu/2204/amd64/clang
#-------------------------------------------------------------------------------
# Fedora
#-------------------------------------------------------------------------------
.build_linux_fedora_gcc: &build_linux_fedora_gcc
stage: build
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y g++ libpcap-devel cmake ninja-build libusb1-devel git
- sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_fedora_gcc: &test_linux_fedora_gcc
stage: unit_test
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
.build_linux_fedora_clang: &build_linux_fedora_clang
stage: build
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y clang lld libpcap-devel cmake ninja-build libusb1-devel git
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- linux-build
.test_linux_fedora_clang: &test_linux_fedora_clang
stage: unit_test
cache:
paths:
- /var/cache/dnf
script:
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
- echo fastestmirror=True >>/etc/dnf/dnf.conf
- dnf upgrade -y
- dnf install -y libpcap-devel libusb1-devel
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/fedora/37/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:37
unit_test linux/fedora/37/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:37
dependencies:
- build linux/fedora/37/amd64/gcc
needs:
- build linux/fedora/37/amd64/gcc
build linux/fedora/37/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:37
unit_test linux/fedora/37/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:37
dependencies:
- build linux/fedora/37/amd64/clang
needs:
- build linux/fedora/37/amd64/clang
build linux/fedora/38/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:38
unit_test linux/fedora/38/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:38
dependencies:
- build linux/fedora/38/amd64/gcc
needs:
- build linux/fedora/38/amd64/gcc
build linux/fedora/38/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:38
unit_test linux/fedora/38/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:38
dependencies:
- build linux/fedora/38/amd64/clang
needs:
- build linux/fedora/38/amd64/clang
build linux/fedora/39/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:39
unit_test linux/fedora/39/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:39
dependencies:
- build linux/fedora/39/amd64/gcc
needs:
- build linux/fedora/39/amd64/gcc
build linux/fedora/39/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:39
unit_test linux/fedora/39/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:39
dependencies:
- build linux/fedora/39/amd64/clang
needs:
- build linux/fedora/39/amd64/clang
.hw_test: &hw_test
stage: hardware_test
tags:
- libicsneo_hil
timeout: 5m
script:
- echo $GUEST_OS_TAG
- echo $DEVICE_PORT
- /opt/libvirt-driver/prepare.sh
- /opt/libvirt-driver/run.sh
after_script:
- /opt/libvirt-driver/cleanup.sh
allow_failure: true
.fedora38_needs: &fedora38_needs
needs:
- job: build linux/fedora/38/amd64/clang
artifacts: true
hardware_test fedora38-red2:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_A
hardware_test fedora38-vcan42:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_D
hardware_test fedora38-fire3:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_B
hardware_test fedora38-vcan42-EL:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_C
.ubuntu2204_needs: &ubuntu2204_needs
needs:
- job: build linux/ubuntu/2204/amd64/clang
artifacts: true
hardware_test ubuntu2204-red2:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_A
hardware_test ubuntu2204-vcan42:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_D
hardware_test ubuntu2204-fire3:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_B
hardware_test ubuntu2204-vcan42-EL:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_C
.win10_needs: &win10_needs
needs:
- job: build windows/x64
artifacts: true
hardware_test win10-red2:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_A
hardware_test win10-vcan42:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_D
hardware_test win10-fire3:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_B
hardware_test win10-vcan42-EL:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_C
#-------------------------------------------------------------------------------
# Python Module
#-------------------------------------------------------------------------------
build python/linux/amd64:
stage: build
tags:
- linux-build
image: python:3.12
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64
DOCKER_HOST: unix:///var/run/docker.sock
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- curl -sSL https://get.docker.com/ | sh
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/linux/arm64:
stage: build
tags:
- arm64-linux-build
variables:
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install:/project/libusb/install
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/macos:
stage: build
tags:
- macos-arm64
variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh && sh ci/bootstrap-libusb.sh
CIBW_ARCHS: arm64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/install:$CI_PROJECT_DIR/libusb/install
MACOSX_DEPLOYMENT_TARGET: 10.14
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/windows:
stage: build
tags:
- libicsneo-win-x64
variables:
CIBW_ARCHS: AMD64
CIBW_ENVIRONMENT: CMAKE_GENERATOR=Ninja
script:
- cmd /c ci\build-wheel-windows.bat
artifacts:
paths:
- wheelhouse
deploy python/pypi:
stage: deploy
variables:
TWINE_USERNAME: __token__
TWINE_PASSWORD: $PYPI_TOKEN
tags:
- linux-build
image: python:3.12
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- python3 -m pip install -U twine
- twine upload wheelhouse/*
dependencies:
- build python/linux/amd64
- build python/linux/arm64
- build python/macos
- build python/windows
needs:
- build python/linux/amd64
- build python/linux/arm64
- build python/macos
- build python/windows
push github:
stage: deploy
tags:
- linux-build
image: alpine:latest
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
dependencies:
- deploy python/pypi
needs:
- deploy python/pypi
script:
- apk add git
- git push https://$LIBICSNEO_GITHUB_USERNAME:$LIBICSNEO_GITHUB_TOKEN@github.com/intrepidcs/libicsneo.git HEAD:master
+15
View File
@@ -0,0 +1,15 @@
version: 2
build:
os: "ubuntu-24.04"
tools:
python: "3.12"
apt_packages:
- doxygen
python:
install:
- requirements: docs/requirements.txt
sphinx:
configuration: docs/conf.py
+1 -1
View File
@@ -4,7 +4,7 @@ KERNEL=="ttyUSB?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
KERNEL=="ttyACM?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666" KERNEL=="ttyACM?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
# neoVI ION/PLASMA PIDs are not in the latest ftdi_sio driver so lets make a # neoVI ION/PLASMA PIDs are not in the latest ftdi_sio driver so lets make a
# rule to add it when we see a new unclaimed device. # rule to add it when we see a new unclaimed device.
# PLASMA = 0x0801, ION = 0x0901 # PLASMA = 0x0801, ION = 0x0901
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", \ ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", \
ATTRS{idVendor}=="093c", ATTRS{idProduct}=="0801", \ ATTRS{idVendor}=="093c", ATTRS{idProduct}=="0801", \
+505 -123
View File
@@ -1,17 +1,45 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.12)
project(libicsneo VERSION 0.1.2) project(libicsneo VERSION 0.3.0)
set(CMAKE_CXX_STANDARD 11) cmake_policy(SET CMP0074 NEW)
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
option(LIBICSNEO_BUILD_UNIT_TESTS "Build unit tests." OFF)
option(LIBICSNEO_BUILD_SYSTEM_TESTS "Build system tests." OFF)
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC2 "Build dynamic C2 library" ON)
option(LIBICSNEO_BUILD_ICSNEOC2_STATIC "Build static C2 library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
# Device Drivers
# You almost certainly don't want firmio for your build,
# it is only relevant for communication between Linux and
# CoreMini from the onboard processor of the device.
option(LIBICSNEO_ENABLE_FIRMIO "Enable communication between Linux and CoreMini within the same device" OFF)
option(LIBICSNEO_ENABLE_RAW_ETHERNET "Enable devices which communicate over raw ethernet" ON)
option(LIBICSNEO_ENABLE_CDCACM "Enable devices which communicate over USB CDC ACM" ON)
option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX" ON)
option(LIBICSNEO_ENABLE_TCP "Enable devices which communicate over TCP" OFF)
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
option(LIBICSNEO_ENABLE_BINDINGS_RUST "Enable Rust library" OFF)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
include(GNUInstallDirs) include(GNUInstallDirs)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# macOS Homebrew Boost Fix
if(NOT MSVC)
include_directories(AFTER /usr/local/include)
endif()
# Enable Warnings # Enable Warnings
if(MSVC) if(MSVC)
# Force to always compile with W4 # Force to always compile with W4
@@ -20,88 +48,268 @@ if(MSVC)
else() else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif() endif()
# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html
# Still supported until a suitable replacement is standardized
add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-nested-anon-types -Wno-gnu-anonymous-struct -Wno-unknown-pragmas -Wno-zero-length-array") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
endif() endif()
find_package(Threads REQUIRED)
# doxygen # doxygen
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
set(DOXYGEN_OUT ${CMAKE_CURRENT_SOURCE_DIR}/generated/Doxyfile) set(DOXYGEN_OUT ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile)
set(ICSNEO_DOCS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/docs) set(ICSNEO_DOCS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/docs)
if(NOT EXISTS "${DOXYGEN_OUT}") if(NOT EXISTS "${DOXYGEN_OUT}")
set(DOXYGEN_FOUND FALSE) set(DOXYGEN_FOUND FALSE)
endif() endif()
endif() endif()
if(DOXYGEN_FOUND) if(LIBICSNEO_BUILD_DOCS)
message("Will build Doxygen based documentation") if(DOXYGEN_FOUND)
message("Will build Doxygen based documentation")
add_custom_target(libicsneo_doxygen ALL add_custom_target(libicsneo_doxygen
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen" COMMENT "Generating API documentation with Doxygen"
VERBATIM VERBATIM
DEPENDS icsneocpp icsneoc icsneolegacy)
# sphinx
find_package(Sphinx)
if(SPHINX_EXECUTABLE)
message("Will build Sphinx based documentation")
set(SPHINX_OUT ${ICSNEO_DOCS_DIR}/build/sphinx)
# configured documentation tools and intermediate build results
set(SPHINX_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_build)
# Sphinx cache with pickled ReST documents
set(SPHINX_CACHE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_doctrees)
# HTML output directory
set(SPHINX_HTML_DIR ${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx)
configure_file(
"${ICSNEO_DOCS_DIR}/conf.py.template"
"${ICSNEO_DOCS_DIR}/conf.py"
@ONLY)
add_custom_target(libicsneo_sphinx ALL
${SPHINX_EXECUTABLE}
-q -b html
-c "${ICSNEO_DOCS_DIR}"
-d "${SPHINX_CACHE_DIR}"
"${ICSNEO_DOCS_DIR}"
"${SPHINX_HTML_DIR}"
COMMENT "Building HTML documentation with Sphinx"
DEPENDS icsneocpp icsneoc icsneolegacy) DEPENDS icsneocpp icsneoc icsneolegacy)
# sphinx
find_package(Sphinx)
if(SPHINX_EXECUTABLE)
message("Will build Sphinx based documentation")
set(SPHINX_OUT ${ICSNEO_DOCS_DIR}/build/sphinx)
# configured documentation tools and intermediate build results
set(SPHINX_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_build)
# Sphinx cache with pickled ReST documents
set(SPHINX_CACHE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_doctrees)
# HTML output directory
set(SPHINX_HTML_DIR ${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx)
configure_file(
"${ICSNEO_DOCS_DIR}/conf.py.template"
"${ICSNEO_DOCS_DIR}/conf.py"
@ONLY)
add_custom_target(libicsneo_sphinx ALL
${SPHINX_EXECUTABLE}
-q -b html
-c "${ICSNEO_DOCS_DIR}"
-d "${SPHINX_CACHE_DIR}"
"${ICSNEO_DOCS_DIR}"
"${SPHINX_HTML_DIR}"
COMMENT "Building HTML documentation with Sphinx"
DEPENDS icsneocpp icsneoc icsneolegacy)
endif()
endif() endif()
endif() endif()
if(WIN32) if(WIN32)
file(GLOB PLATFORM_SRC_EXTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/*.cpp) set(PLATFORM_SRC
file(GLOB PLATFORM_SRC_INTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/internal/*.cpp) platform/windows/registry.cpp
set(PLATFORM_SRC ${PLATFORM_SRC_EXTERNAL} ${PLATFORM_SRC_INTERNAL}) )
else()
file(GLOB PLATFORM_SRC ${CMAKE_CURRENT_SOURCE_DIR}/platform/posix/*.cpp) if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/windows/pcap.cpp
platform/windows/internal/pcapdll.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/windows/vcp.cpp
)
endif()
else() # Darwin or Linux
set(PLATFORM_SRC)
if(LIBICSNEO_ENABLE_FIRMIO)
list(APPEND PLATFORM_SRC
platform/posix/firmio.cpp
)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/posix/pcap.cpp
)
endif()
if(LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/posix/ftdi.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC
platform/posix/cdcacm.cpp
)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
list(APPEND PLATFORM_SRC
platform/posix/darwin/cdcacmdarwin.cpp
)
else() # Linux or other
list(APPEND PLATFORM_SRC
platform/posix/linux/cdcacmlinux.cpp
)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
message(WARNING
"There is no CDCACM platform port defined for ${CMAKE_SYSTEM_NAME}!\n"
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly."
)
endif()
endif()
endif()
endif() endif()
set(COMMON_SRC if(LIBICSNEO_ENABLE_FTD3XX)
if(NOT FTD3XX_ROOT) # allow system override
include(FetchContent)
if(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.3.0.10-win-x64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=459e635496ab47d6069c9d3515fdd6d82cba3d95e7ae34f794d66ffdf336e9d1")
elseif(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.3.0.10-win-i686.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=ce4259ae11772d6ede7d217172156fa392f329b29d9455131f4126a2fb89dad1")
elseif(APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-macos-universal2.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=0904ac5eda8e1dc4b5aac3714383bcc7792b42dfeb585dce6cbfb8b67b8c0c51")
elseif(UNIX)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-x64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cf66bf299fc722f050cdd3c36998a670f1df69f7c0df18afa73707277067114b")
endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-aarch64.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=66341b5112b9841e959e81400b51711be96fec91894477c5cbfc29b10a0c00a6")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LIBICSNEO_FTD3XX_URL "https://github.com/intrepidcs/libftd3xx-repack/releases/download/24.34.0/libftd3xx-1.0.16-linux-armhf.zip")
set(LIBICSNEO_FTD3XX_URL_HASH "SHA256=cec1f959b48a11eb6b829ed43c81b6ba1c0bcf3e797bafcc84a6376e5ffc3c47")
endif()
endif()
endif()
if(NOT LIBICSNEO_FTD3XX_URL)
message(FATAL_ERROR "Unsupported platform for FTD3XX driver")
endif()
FetchContent_Declare(
ftdi3xx
URL ${LIBICSNEO_FTD3XX_URL}
URL_HASH ${LIBICSNEO_FTD3XX_URL_HASH}
)
FetchContent_GetProperties(ftdi3xx)
if(NOT ftdi3xx_POPULATED)
FetchContent_Populate(ftdi3xx)
endif()
set(FTD3XX_ROOT "${ftdi3xx_SOURCE_DIR}")
endif()
find_package(FTD3XX REQUIRED)
list(APPEND PLATFORM_SRC
platform/ftd3xx.cpp
)
endif()
if(LIBICSNEO_ENABLE_TCP)
list(APPEND PLATFORM_SRC
platform/tcp.cpp
)
endif()
if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# Extensions
set(LIBICSNEO_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
foreach(EXT_PATH ${LIBICSNEO_EXTENSION_DIRS})
get_filename_component(EXT_DIR ${EXT_PATH} NAME)
message("Adding extension " ${EXT_DIR})
add_subdirectory(${EXT_PATH} ${CMAKE_CURRENT_BINARY_DIR}/${EXT_DIR})
endforeach()
set(SRC_FILES
communication/message/flexray/control/flexraycontrolmessage.cpp
communication/message/callback/streamoutput/a2bwavoutput.cpp
communication/message/a2bmessage.cpp
communication/message/apperrormessage.cpp
communication/message/neomessage.cpp communication/message/neomessage.cpp
communication/message/ethphymessage.cpp
communication/message/linmessage.cpp
communication/message/livedatamessage.cpp
communication/message/tc10statusmessage.cpp
communication/message/gptpstatusmessage.cpp
communication/message/ethernetstatusmessage.cpp
communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp
communication/packet/ethernetpacket.cpp communication/packet/ethernetpacket.cpp
communication/packet/versionpacket.cpp
communication/packet/iso9141packet.cpp
communication/packet/ethphyregpacket.cpp
communication/packet/livedatapacket.cpp
communication/packet/logicaldiskinfopacket.cpp
communication/packet/wivicommandpacket.cpp
communication/packet/i2cpacket.cpp
communication/packet/linpacket.cpp
communication/packet/mdiopacket.cpp
communication/packet/scriptstatuspacket.cpp
communication/packet/componentversionpacket.cpp
communication/packet/supportedfeaturespacket.cpp
communication/packet/genericbinarystatuspacket.cpp
communication/packet/hardwareinfopacket.cpp
communication/decoder.cpp communication/decoder.cpp
communication/encoder.cpp communication/encoder.cpp
communication/ethernetpacketizer.cpp
communication/packetizer.cpp communication/packetizer.cpp
communication/multichannelcommunication.cpp communication/multichannelcommunication.cpp
communication/communication.cpp communication/communication.cpp
communication/icommunication.cpp communication/driver.cpp
communication/livedata.cpp
communication/ringbuffer.cpp
device/extensions/flexray/extension.cpp
device/extensions/flexray/controller.cpp
device/idevicesettings.cpp device/idevicesettings.cpp
device/devicefinder.cpp device/devicefinder.cpp
device/device.cpp device/device.cpp
device/neodevice.cpp
disk/diskreaddriver.cpp
disk/diskwritedriver.cpp
disk/nulldiskdriver.cpp
disk/neomemorydiskdriver.cpp
disk/plasiondiskreaddriver.cpp
disk/extextractordiskreaddriver.cpp
disk/fat.cpp
disk/vsa/vsa.cpp
disk/vsa/vsa02.cpp
disk/vsa/vsa03.cpp
disk/vsa/vsa04.cpp
disk/vsa/vsa05.cpp
disk/vsa/vsa06.cpp
disk/vsa/vsa07.cpp
disk/vsa/vsa08.cpp
disk/vsa/vsa09.cpp
disk/vsa/vsa0b.cpp
disk/vsa/vsa0c.cpp
disk/vsa/vsa0d.cpp
disk/vsa/vsa0e.cpp
disk/vsa/vsa0f.cpp
disk/vsa/vsa6a.cpp
disk/vsa/vsaparser.cpp
${PLATFORM_SRC}
) )
set(SRC_FILES ${COMMON_SRC} ${PLATFORM_SRC})
# Generate build info header # Generate build info header
execute_process( execute_process(
COMMAND git rev-parse --abbrev-ref HEAD COMMAND git rev-parse --abbrev-ref HEAD
@@ -129,90 +337,264 @@ endif()
configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h) configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h)
configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc) configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
configure_file(api/icsneoc2/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES})
message("Including " ${EXTINC})
list(APPEND LIBICSNEO_EXT_CODE_INCS_LIST "#include \"${EXTINC}\"")
endforeach()
list(JOIN LIBICSNEO_EXT_CODE_INCS_LIST "\n" LIBICSNEO_EXT_CODE_INCS)
foreach(EXTCLASS ${LIBICSNEO_EXTENSION_CLASSES})
list(APPEND LIBICSNEO_EXT_CODE_LIST "device->addExtension(std::make_shared<${EXTCLASS}>(*device))\;")
endforeach()
list(JOIN LIBICSNEO_EXT_CODE_LIST "\n\t" LIBICSNEO_EXT_CODE)
configure_file(include/icsneo/device/extensions/builtin.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/extensions/builtin.h)
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
add_library(icsneocpp add_library(icsneocpp
api/icsneocpp/icsneocpp.cpp api/icsneocpp/icsneocpp.cpp
api/icsneocpp/error.cpp api/icsneocpp/event.cpp
api/icsneocpp/errormanager.cpp api/icsneocpp/eventmanager.cpp
api/icsneocpp/version.cpp api/icsneocpp/version.cpp
${SRC_FILES} ${SRC_FILES}
) )
message("Include paths " ${LIBICSNEO_EXTENSION_INCLUDE_PATHS})
target_include_directories(icsneocpp target_include_directories(icsneocpp
PUBLIC PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:> $<INSTALL_INTERFACE:>
PRIVATE PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include
${LIBICSNEO_EXTENSION_INCLUDE_PATHS}
) )
target_link_libraries(icsneocpp PUBLIC Threads::Threads)
set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
# libftdi
if(NOT WIN32)
target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
set(LIBFTDI_LINK_PYTHON_LIBRARY OFF CACHE INTERNAL "")
set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi)
endif(NOT WIN32)
# winpcap
if(WIN32)
target_include_directories(icsneocpp PUBLIC AFTER third-party/winpcap/include)
add_definitions(-DWPCAP -DHAVE_REMOTE -DWIN32_LEAN_AND_MEAN)
endif(WIN32)
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
target_include_directories(icsneoc
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc PRIVATE icsneocpp)
add_library(icsneoc-static STATIC api/icsneoc/icsneoc.cpp)
target_include_directories(icsneoc-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
)
target_include_directories(icsneolegacy
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneolegacy PRIVATE icsneocpp)
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) 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)
target_compile_features(icsneoc PRIVATE 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_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums) target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
target_compile_features(icsneolegacy PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums) if(LIBICSNEO_ENABLE_FIRMIO)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FIRMIO)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_RAW_ETHERNET)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
endif()
if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
endif()
if(LIBICSNEO_ENABLE_FTD3XX)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTD3XX)
target_link_libraries(icsneocpp PRIVATE FTD3XX::FTD3XX)
endif()
if(LIBICSNEO_ENABLE_TCP)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_TCP)
if(WIN32)
target_link_libraries(icsneocpp PRIVATE ws2_32 iphlpapi)
endif()
endif()
# fatfs
add_subdirectory(third-party/fatfs)
set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PRIVATE fatfs)
# libftdi # libftdi
if(NOT WIN32) if(LIBICSNEO_ENABLE_FTDI)
find_package(Threads) if(NOT WIN32)
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
target_link_libraries(icsneocpp PUBLIC ftdi1-static) set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT}) set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
find_package(PCAP REQUIRED) set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY}) set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
set(LIBFTDI_LINK_PYTHON_LIBRARY OFF CACHE INTERNAL "")
set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi)
target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
endif(NOT WIN32)
endif(LIBICSNEO_ENABLE_FTDI)
# pcap
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
if(WIN32)
if(LIBICSNEO_NPCAP_INCLUDE_DIR STREQUAL "")
target_include_directories(icsneocpp PUBLIC AFTER third-party/winpcap/include)
add_definitions(-DWPCAP -DHAVE_REMOTE -DWIN32_LEAN_AND_MEAN)
else()
target_include_directories(icsneocpp PUBLIC AFTER ${LIBICSNEO_NPCAP_INCLUDE_DIR})
add_definitions(-DNPCAP -DWIN32_LEAN_AND_MEAN)
endif()
else()
find_package(PCAP REQUIRED)
target_include_directories(icsneocpp PUBLIC ${PCAP_INCLUDE_DIR})
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
endif(WIN32)
endif(LIBICSNEO_ENABLE_RAW_ETHERNET)
if(LIBICSNEO_BUILD_ICSNEOC)
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
target_include_directories(icsneoc
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc PRIVATE icsneocpp)
target_compile_features(icsneoc PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
add_library(icsneoc-static STATIC api/icsneoc/icsneoc.cpp)
target_include_directories(icsneoc-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
target_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOC2)
add_library(icsneoc2 SHARED api/icsneoc2/icsneoc2.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
target_include_directories(icsneoc2
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc2 PRIVATE icsneocpp)
target_compile_definitions(icsneoc2
PRIVATE
ICSNEO_EXPORTS _CRT_SECURE_NO_WARNINGS
PUBLIC
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
INTERFACE
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
)
target_compile_features(icsneoc2 PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc2 PUBLIC ICSNEOC2_BUILD_DYNAMIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOC2_STATIC)
add_library(icsneoc2-static STATIC api/icsneoc2/icsneoc2.cpp)
target_include_directories(icsneoc2-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc2-static PUBLIC icsneocpp)
target_compile_features(icsneoc2-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc2-static PUBLIC ICSNEOC2_BUILD_STATIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
platform/windows/icsneolegacy.def
)
target_include_directories(icsneolegacy
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneolegacy PRIVATE icsneocpp)
target_compile_features(icsneolegacy PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC)
add_library(icsneolegacy-static STATIC
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
)
target_include_directories(icsneolegacy-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneolegacy-static PUBLIC icsneocpp)
target_compile_features(icsneolegacy-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneolegacy-static PUBLIC ICSNEOC_BUILD_STATIC)
endif()
add_subdirectory(bindings)
# googletest
if(LIBICSNEO_BUILD_UNIT_TESTS)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
if (NOT TARGET gtest)
add_subdirectory(third-party/googletest-master)
endif()
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
add_executable(libicsneo-unit-tests
test/unit/main.cpp
test/unit/diskdriverreadtest.cpp
test/unit/diskdriverwritetest.cpp
test/unit/eventmanagertest.cpp
test/unit/ethernetpacketizertest.cpp
test/unit/i2cencoderdecodertest.cpp
test/unit/linencoderdecodertest.cpp
test/unit/a2bencoderdecodertest.cpp
test/unit/mdioencoderdecodertest.cpp
test/unit/livedataencoderdecodertest.cpp
test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp
test/unit/icsneoc2.cpp
)
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
target_link_libraries(libicsneo-unit-tests icsneocpp)
target_link_libraries(libicsneo-unit-tests icsneoc2-static)
target_include_directories(libicsneo-unit-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
enable_testing()
add_test(NAME libicsneo-unit-test-suite COMMAND libicsneo-unit-tests)
endif()
if(LIBICSNEO_BUILD_SYSTEM_TESTS)
if(DEFINED ENV{LIBICSNEO_SYSTEM_TESTS})
include(FetchContent)
file(MAKE_DIRECTORY test/system)
FetchContent_Declare(
SystemTests
GIT_REPOSITORY $ENV{LIBICSNEO_SYSTEM_TESTS}
GIT_TAG main
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test/system
)
FetchContent_MakeAvailable(SystemTests)
else()
message("System test repo not defined!")
endif()
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
-39
View File
@@ -1,39 +0,0 @@
# Hardware Support
- Connecting over Ethernet
- neoVI FIRE 2
- CAN works
- CAN FD works
- ValueCAN 4-2EL
- CAN works
- CAN FD works
- Ethernet works
- RADGalaxy
- CAN works
- Ethernet works
- RADStar 2
- CAN works
- Ethernet works
- Connecting over USB
- ValueCAN 4 series
- CAN works
- CAN FD works
- Ethernet works (on 4-2EL)
- neoOBD2 PRO
- CAN works
- neoVI FIRE
- CAN works
- neoVI FIRE 2
- CAN works
- CAN FD works
- Ethernet works
- ValueCAN 3
- CAN works
- RADStar 2
- CAN works
- Ethernet works
- neoVI PLASMA
- CAN works
- neoVI ION
- CAN works
+23 -7
View File
@@ -1,13 +1,29 @@
Copyright 2018-2019 Intrepid Control Systems, Inc. Copyright (c) 2018-2025 Intrepid Control Systems, Inc.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
4. It is forbidden to use this library or derivatives to interface with vehicle networking hardware not produced by Intrepid Control Systems, Inc. 4. It is forbidden to use this library or derivatives to interface with vehicle
networking hardware not produced by Intrepid Control Systems, Inc.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+35 -122
View File
@@ -1,130 +1,43 @@
# libicsneo # libicsneo
### The Intrepid Control Systems Open Cross-Platform Device Communication API
An open source solution to integrate Intrepid Control Systems vehicle networking hardware with your application. libicsneo is the [Intrepid Control Systems](https://intrepidcs.com/) device
communication library. Installation and usage documentation can be found within
each of the respective APIs.
[Read the Full Documentation](https://libicsneo.readthedocs.io/) ## Documentation
## Getting Started - [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/)
There are two major ways to write a new application using libicsneo. You can use the C++ interface, which will be compiled with your project and statically linked, or you can use the C interface, which can be either statically or dynamically linked. - [Python](https://libicsneo.readthedocs.io/en/latest/icsneopy/)
### Integration with CMake (Static Linking) - [C](https://libicsneo.readthedocs.io/en/latest/icsneoc/)
Integrating the library with your current CMake project is extremely easy.
1. Checkout the library (or add as a submodule) into a subdirectory of your project.
2. Within your `CMakeLists.txt` you can add the line `add_subdirectory("third-party/libicsneo")` to bring in the libicsneo targets. Replace `third-party` with any subdirectory you choose.
3. The libicsneo library include paths should automatically be added to your include path.
4. Link the library with your target by adding `target_link_libraries(libicsneocpp-example icsneocpp)` after your target, substituting `libicsneocpp-example` with your target application.
You can now include either the C++ API with `#include <icsneo/icsneocpp.h>` or the C API with `#include <icsneo/icsneoc.h>` ## Hardware Support
### DLL / SO / DYLIB Releases (Dynamic Linking) - EtherBADGE
It is also possible to use the precompiled binaries with runtime linking. It is not recommended or supported to attempt to use the C++ interface with dynamic linking due to the complexities of C++ compilers. - neoVI Connect
1. Add this repository's `/include` to your include path - neoVI FIRE
2. Add `#define ICSNEOC_DYNAMICLOAD` to the top of your source file - neoVI FIRE 2
2. Add `#import <icsneo/icsneoc.h>` below that line - neoVI FIRE 3
3. Call `icsneo_init();` to import the library before using any other libicsneo functions. - neoVI ION
4. Use the library as normal. - neoVI PLASMA
5. Call `icsneo_close();` to unload the library. - neoVI RED 2
- RAD-A2B
- RAD-Comet 2
- RAD-Comet 3
- RAD-Galaxy
- RAD-Galaxy 2
- RAD-Gigastar
- RAD-Gigastar 2
- RAD-Moon 2
- RAD-Moon 3
- RAD-Moon T1S
- RAD-Pluto
- RAD-Star 2
- RAD-SuperMoon
- RADComet
- ValueCAN 3
- ValueCAN 4
## Usage ## License
### Using the C++ API
The C++ API is designed to be modern and easy to use. All library functions and classes are in the namespace `icsneo`. Most applications will start by calling `icsneo::FindAllDevices()`. This will return an `std::vector` of `std::shared_ptr<icsneo::Device>` objects. You will want to keep a copy of the `shared_ptr` to any devices you want to use, as allowing it to go out of scope will automatically close the device and free all memory associated with it.
Any time you get bus traffic from the API, you will receive it as an `std::shared_ptr<icsneo::Message>`. The message will be valid as long as the `shared_ptr` stays in scope. Checking the type of the message allows you to cast it accordingly and access extra data for certain protocols. For instance, casting an `icsneo::Message` to an `icsneo::CANMessage` allows you to access the arbitration ID. libicsneo is licensed as BSD-3 with an extra clause, see [LICENSE](LICENSE)
for more details.
A barebones example is provided. For a more complete example, check [intrepidcs/libicsneo-examples](https://github.com/intrepidcs/libicsneo-examples).
``` c++
std::vector<std::shared_ptr<icsneo::Device>> devices = icsneo::FindAllDevices();
std::cout << devices.size() << " found!" << std::endl;
for(auto& device : devices)
std::cout << "Found " << device->describe() << std::endl; // "Found neoVI FIRE 2 CY2345"
std::shared_ptr<icsneo::Device> myDevice = devices[0];
if(!myDevice->open()) {
// There was an error while attempting to open the device, print the error details
for(auto& error : icsneo::getErrors())
std::cout << error << std::endl;
}
myDevice->goOnline(); // Start receiving messages
myDevice->enableMessagePolling(); // Allow the use of myDevice->getMessages() later
// Alternatively, assign a callback for new messages
std::this_thread::wait_for(std::chrono::seconds(5));
std::vector<std::shared_ptr<icsneo::Message>> messages = myDevice->getMessages();
std::cout << "We got " << messages.size() << " messages!" << std::endl;
for(auto& msg : messages) {
switch(msg->network.getType()) {
case icsneo::Network::Type::CAN:
case icsneo::Network::Type::SWCAN:
case icsneo::Network::Type::LSFTCAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canmsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
// canmsg->arbid is valid here
// canmsg->data is an std::vector<uint8_t>, you can check .size() for the DLC of the message
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
default:
// Handle others
}
}
myDevice->close();
```
### Using the C API
The C API is designed to be a robust and fault tolerant interface which allows easy integration with other languages as well as existing C applications. When calling `icsneo_findAllDevices()` you will provide a buffer of `neodevice_t` structures, which will be written with the found devices. These `neodevice_t` structures can be uses to interface with the API from then on. Once you call `icsneo_close()` with a device, that device and all associated memory will be freed. You will need to run `icsneo_findAllDevices()` again to reconnect.
Messages are passed in the form of `neomessage_t` structures when calling `icsneo_getMessages()`. These structures contain a `uint8_t*` to the payload data, and this pointer will be valid until the next call to `icsneo_getMessages()` or the device is closed.
A barebones example is provided. For a more complete example, check [intrepidcs/libicsneo-examples](https://github.com/intrepidcs/libicsneo-examples).
``` c
size_t deviceCount = 10; // Pre-set to the size of your buffer before the icsneo_findAllDevices() call
neodevice_t devices[10];
icsneo_findAllDevices(devices, &deviceCount);
printf("We found %ull devices\n", deviceCount);
for(size_t i = 0; i < deviceCount; i++) {
neodevice_t* myDevice = &devices[i];
char desc[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION];
size_t sz = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
icsneo_describeDevice(myDevice, desc, &sz);
printf("Found %s\n", desc); // "Found neoVI FIRE 2 CY2345"
}
neodevice_t* myDevice = &devices[0];
if(!icsneo_openDevice(myDevice)) {
neoerror_t error;
if(icsneo_getLastError(&error))
printf("Error! %s\n", error.description);
}
icsneo_goOnline(myDevice); // Start receiving messages
icsneo_enableMessagePolling(myDevice); // Allow the use of icsneo_getMessages() later
sleep(5);
neomessage_t messages[50];
size_t messageCount = 50;
icsneo_getMessages(myDevice, messages, &messageCount, 0 /* non-blocking */);
printf("We got %ull messages!\n", messageCount);
for(size_t i = 0; i < messageCount; i++) {
if(messages[i].type == ICSNEO_NETWORK_TYPE_CAN) {
// A message of type CAN should be interperated a neomessage_can_t, so we can cast safely
neomessage_can_t* canmsg = (neomessage_can_t*)&messages[i];
// canmsg->arbid is valid here
// canmsg->data is an uint8_t*, you can check canmsg->length for the length of the payload
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
}
icsneo_closeDevice(myDevice);
```
## Building from Source
### Windows
Building will require Microsoft Visual Studio 2017 and CMake to be installed.
### macOS
Getting the dependencies is easiest with the Homebrew package manager. You will also need XCode installed. You can then install CMake, an up-to-date version of GCC or Clang, and `libusb-1.0`.
### Linux
The dependencies are as follows
- CMake 3.2 or above
- GCC 4.7 or above, 4.8+ recommended
- `libusb-1.0-0-dev`
- `build-essential` is recommended
If you'd like to be able to run programs that use this library without being root, consider using the included udev rules
```
$ sudo cp 99-intrepidcs.rules /etc/udev/rules.d/
```
+54
View File
@@ -0,0 +1,54 @@
#include "icsneo/icsneo.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h"
#include <string>
#include <algorithm>
using namespace icsneo;
struct icsneoOpenOptions_t {
/** Open the device in online mode on open. */
bool goOnlineOnOpen = true;
/** Enable message polling on open. */
bool enablePollingOnOpen = true;
/** Synchronize the device RTC on open.
* Useful for devices that don't have an RTC battery like ValueCAN4 */
bool syncRTCOnOpen = true;
};
typedef struct icsneo_device_t {
// This is the actual device handle, when its not open it will be NULL.
std::shared_ptr<Device> device;
icsneoOpenOptions_t openOptions;
} *icsneo_device_ptr_t;
icsneo_result_t icsneo_find(icsneo_device_ptr_t* devices, uint32_t* devices_count, void* reserved) {
static std::deque<icsneo_device_t> found_icsneo_devices;
if (!devices || !devices_count) {
return icsneo_error_invalid_parameter;
}
// Find all devices and get the minimum size to process
auto found_devices = DeviceFinder::FindAll();
auto min_size = std::minmax(found_devices.size(), static_cast<size_t>(*devices_count)).first;
// lets resize the array to the minimum size
for (auto i = 0; i < min_size; i++) {
const auto* dev = devices[i];
dev = new icsneo_device_t {};
dev->device = found_devices[i];
}
return icsneo_error_success;
}
icsneo_result_t icsneo_open(icsneo_device_ptr_t* device) {
if (!device) {
return icsneo_error_invalid_parameter;
}
return icsneo_error_success;
}
+51
View File
@@ -0,0 +1,51 @@
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@
#define VER_FILEVERSION_STR "v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@BUILD_METADATA_PLUS@ @BUILD_GIT_INFO@"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK (VS_FF_DEBUG)
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Intrepid Control Systems, Inc."
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneo.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "OriginalFilename", "icsneo.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END
+759 -616
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -29,7 +29,7 @@ BEGIN
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API" VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneoc.dll" VALUE "InternalName", "icsneoc.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2019" VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2025"
VALUE "OriginalFilename", "icsneoc.dll" VALUE "OriginalFilename", "icsneoc.dll"
VALUE "ProductName", "libicsneo" VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR VALUE "ProductVersion", VER_PRODUCTVERSION_STR
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@
#define VER_FILEVERSION_STR "v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@BUILD_METADATA_PLUS@ @BUILD_GIT_INFO@"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK (VS_FF_DEBUG)
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Intrepid Control Systems, Inc."
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneo.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "OriginalFilename", "icsneo.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END
-183
View File
@@ -1,183 +0,0 @@
#include "icsneo/api/error.h"
#include "icsneo/device/device.h"
#include <sstream>
using namespace icsneo;
APIError::APIError(ErrorType error) : errorStruct({}) {
init(error);
}
APIError::APIError(ErrorType error, const Device* forDevice) : errorStruct({}) {
device = forDevice;
serial = device->getSerial();
errorStruct.serial[serial.copy(errorStruct.serial, sizeof(errorStruct.serial))] = '\0';
init(error);
}
void APIError::init(ErrorType error) {
timepoint = ErrorClock::now();
errorStruct.description = DescriptionForType(error);
errorStruct.errorNumber = (uint32_t)error;
errorStruct.severity = (uint8_t)SeverityForType(error);
errorStruct.timestamp = ErrorClock::to_time_t(timepoint);
}
std::string APIError::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
ss << " Error: ";
ss << getDescription();
return ss.str();
}
bool APIError::isForDevice(std::string filterSerial) const noexcept {
if(!device || filterSerial.length() == 0)
return false;
return device->getSerial() == filterSerial;
}
// API Errors
static constexpr const char* ERROR_INVALID_NEODEVICE = "The provided neodevice_t object was invalid.";
static constexpr const char* ERROR_REQUIRED_PARAMETER_NULL = "A required parameter was NULL.";
static constexpr const char* ERROR_BUFFER_INSUFFICIENT = "The provided buffer was insufficient. No data was written.";
static constexpr const char* ERROR_OUTPUT_TRUNCATED = "The output was too large for the provided buffer and has been truncated.";
static constexpr const char* ERROR_PARAMETER_OUT_OF_RANGE = "A parameter was out of range.";
// Device Errors
static constexpr const char* ERROR_POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
static constexpr const char* ERROR_NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered with 12 volts?";
static constexpr const char* ERROR_INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* ERROR_SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* ERROR_SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* ERROR_SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* ERROR_SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* ERROR_SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
// Transport Errors
static constexpr const char* ERROR_FAILED_TO_READ = "A read operation failed.";
static constexpr const char* ERROR_FAILED_TO_WRITE = "A write operation failed.";
static constexpr const char* ERROR_DRIVER_FAILED_TO_OPEN = "The device driver encountered a low-level error while opening the device.";
static constexpr const char* ERROR_PACKET_CHECKSUM_ERROR = "There was a checksum error while decoding a packet. The packet was dropped.";
static constexpr const char* ERROR_TRANSMIT_BUFFER_FULL = "The transmit buffer is full and the device is set to non-blocking.";
static constexpr const char* ERROR_PCAP_COULD_NOT_START = "The PCAP driver could not be started. Ethernet devices will not be found.";
static constexpr const char* ERROR_PCAP_COULD_NOT_FIND_DEVICES = "The PCAP driver failed to find devices. Ethernet devices will not be found.";
static constexpr const char* ERROR_TOO_MANY_ERRORS = "Too many errors have occurred. The list has been truncated.";
static constexpr const char* ERROR_UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* ERROR_INVALID = "An invalid internal error occurred.";
const char* APIError::DescriptionForType(ErrorType type) {
switch(type) {
// API Errors
case InvalidNeoDevice:
return ERROR_INVALID_NEODEVICE;
case RequiredParameterNull:
return ERROR_REQUIRED_PARAMETER_NULL;
case BufferInsufficient:
return ERROR_BUFFER_INSUFFICIENT;
case OutputTruncated:
return ERROR_OUTPUT_TRUNCATED;
case ParameterOutOfRange:
return ERROR_PARAMETER_OUT_OF_RANGE;
// Device Errors
case PollingMessageOverflow:
return ERROR_POLLING_MESSAGE_OVERFLOW;
case NoSerialNumber:
return ERROR_NO_SERIAL_NUMBER;
case IncorrectSerialNumber:
return ERROR_INCORRECT_SERIAL_NUMBER;
case SettingsReadError:
return ERROR_SETTINGS_READ;
case SettingsVersionError:
return ERROR_SETTINGS_VERSION;
case SettingsLengthError:
return ERROR_SETTINGS_LENGTH;
case SettingsChecksumError:
return ERROR_SETTINGS_CHECKSUM;
case SettingsNotAvailable:
return ERROR_SETTINGS_NOT_AVAILABLE;
// Transport Errors
case FailedToRead:
return ERROR_FAILED_TO_READ;
case FailedToWrite:
return ERROR_FAILED_TO_WRITE;
case DriverFailedToOpen:
return ERROR_DRIVER_FAILED_TO_OPEN;
case PacketChecksumError:
return ERROR_PACKET_CHECKSUM_ERROR;
case TransmitBufferFull:
return ERROR_TRANSMIT_BUFFER_FULL;
case PCAPCouldNotStart:
return ERROR_PCAP_COULD_NOT_START;
case PCAPCouldNotFindDevices:
return ERROR_PCAP_COULD_NOT_FIND_DEVICES;
// Other Errors
case TooManyErrors:
return ERROR_TOO_MANY_ERRORS;
case Unknown:
return ERROR_UNKNOWN;
default:
return ERROR_INVALID;
}
}
APIError::Severity APIError::SeverityForType(ErrorType type) {
switch(type) {
// API Warnings
case OutputTruncated:
// Device Warnings
case PollingMessageOverflow:
// Transport Warnings
case PCAPCouldNotStart:
case PCAPCouldNotFindDevices:
return Severity::Warning;
// API Errors
case InvalidNeoDevice:
case RequiredParameterNull:
case BufferInsufficient:
case ParameterOutOfRange:
// Device Errors
case NoSerialNumber:
case IncorrectSerialNumber:
case SettingsReadError:
case SettingsVersionError:
case SettingsLengthError:
case SettingsChecksumError:
case SettingsNotAvailable:
// Transport Errors
case FailedToRead:
case FailedToWrite:
case DriverFailedToOpen:
case PacketChecksumError:
case TransmitBufferFull:
// Other Errors
case TooManyErrors:
case Unknown:
default:
return Severity::Error;
}
}
bool ErrorFilter::match(const APIError& error) const noexcept {
if(type != APIError::Any && type != error.getType())
return false;
if(matchOnDevicePtr && !error.isForDevice(device))
return false;
if(severity != APIError::Severity::Any && severity != error.getSeverity())
return false;
if(serial.length() != 0 && !error.isForDevice(serial))
return false;
return true;
}
-146
View File
@@ -1,146 +0,0 @@
#include "icsneo/api/errormanager.h"
#include <memory>
using namespace icsneo;
static std::unique_ptr<ErrorManager> singleton;
ErrorManager& ErrorManager::GetInstance() {
if(!singleton)
singleton = std::unique_ptr<ErrorManager>(new ErrorManager());
return *singleton.get();
}
void ErrorManager::get(std::vector<APIError>& errorOutput, size_t max, ErrorFilter filter) {
std::lock_guard<std::mutex> lk(mutex);
if(max == 0) // A limit of 0 indicates no limit
max = (size_t)-1;
size_t count = 0;
errorOutput.clear();
auto it = errors.begin();
while(it != errors.end()) {
if(filter.match(*it)) {
errorOutput.push_back(*it);
errors.erase(it++);
if(count++ >= max)
break; // We now have as many written to output as we can
} else {
std::advance(it, 1);
}
}
}
bool ErrorManager::getLastError(APIError& errorOutput, ErrorFilter filter) {
std::lock_guard<std::mutex> lk(mutex);
auto it = errors.rbegin();
while(it != errors.rend()) {
if(filter.match(*it)) {
errorOutput = *it;
errors.erase(std::next(it).base());
return true;
}
std::advance(it, 1);
}
return false;
}
void ErrorManager::discard(ErrorFilter filter) {
std::lock_guard<std::mutex> lk(mutex);
errors.remove_if([&filter](const APIError& error) {
return filter.match(error);
});
}
size_t ErrorManager::count_internal(ErrorFilter filter) const {
size_t ret = 0;
for(auto& error : errors)
if(filter.match(error))
ret++;
return ret;
}
bool ErrorManager::beforeAddCheck(APIError::ErrorType type) {
if(enforceLimit()) { // The enforceLimit will add the "TooManyErrors" error for us if necessary
// We need to decide whether to add this error or drop it
// We would have to remove something if we added this error
if(APIError::SeverityForType(type) < lowestCurrentSeverity())
return false; // Don't add this one, we are already full of higher priority items
}
return true;
}
bool ErrorManager::enforceLimit() {
if(errors.size() + 1 < errorLimit)
return false;
bool hasTooManyWarningAlready = count_internal(ErrorFilter(APIError::TooManyErrors)) != 0;
size_t amountToRemove = (errors.size() + (hasTooManyWarningAlready ? 1 : 2)) - errorLimit;
discardLeastSevere(amountToRemove);
if(!hasTooManyWarningAlready)
errors.emplace_back(APIError::TooManyErrors);
return true;
}
APIError::Severity ErrorManager::lowestCurrentSeverity() {
if(errors.empty())
return APIError::Severity(0);
APIError::Severity lowest = APIError::Severity::Error;
auto it = errors.begin();
while(it != errors.end()) {
if((*it).getSeverity() < lowest)
lowest = (*it).getSeverity();
it++;
}
return lowest;
}
void ErrorManager::discardLeastSevere(size_t count) {
if(count == 0)
return;
ErrorFilter infoFilter(APIError::Severity::Info);
auto it = errors.begin();
while(it != errors.end()) {
if(infoFilter.match(*it)) {
errors.erase(it++);
if(--count == 0)
break;
} else {
it++;
}
}
if(count != 0) {
ErrorFilter warningFilter(APIError::Severity::Warning);
it = errors.begin();
while(it != errors.end()) {
if(warningFilter.match(*it)) {
errors.erase(it++);
if(--count == 0)
break;
} else {
it++;
}
}
}
if(count != 0) {
ErrorFilter errorFilter(APIError::Severity::Error);
it = errors.begin();
while(it != errors.end()) {
if(errorFilter.match(*it)) {
errors.erase(it++);
if(--count == 0)
break;
} else {
it++;
}
}
}
}
+461
View File
@@ -0,0 +1,461 @@
#include "icsneo/api/event.h"
#include "icsneo/device/device.h"
#include <sstream>
using namespace icsneo;
APIEvent::APIEvent(Type type, APIEvent::Severity severity, const Device* device) : eventStruct({}) {
this->device = device;
if(device) {
serial = device->getSerial();
eventStruct.serial[serial.copy(eventStruct.serial, sizeof(eventStruct.serial))] = '\0';
}
init(type, severity);
}
void APIEvent::init(Type event, APIEvent::Severity severity) {
timepoint = EventClock::now();
eventStruct.description = DescriptionForType(event);
eventStruct.eventNumber = (uint32_t)event;
eventStruct.severity = (uint8_t) severity;
eventStruct.timestamp = EventClock::to_time_t(timepoint);
}
std::string APIEvent::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
} else if(severity == Severity::EventWarning) {
ss << " Warning: ";
} else if(severity == Severity::Error) {
ss << " Error: ";
} else {
// Should never get here, since Severity::Any should only be used for filtering
ss << " Any: ";
}
ss << getDescription();
return ss.str();
}
void APIEvent::downgradeFromError() noexcept {
eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning;
}
bool APIEvent::isForDevice(std::string filterSerial) const noexcept {
if(!device || filterSerial.length() == 0)
return false;
return device->getSerial() == filterSerial;
}
// API Errors
static constexpr const char* INVALID_NEODEVICE = "The provided neodevice_t object was invalid.";
static constexpr const char* REQUIRED_PARAMETER_NULL = "A required parameter was NULL.";
static constexpr const char* OUTPUT_TRUNCATED = "The output was too large for the provided buffer and has been truncated.";
static constexpr const char* BUFFER_INSUFFICIENT = "The provided buffer was insufficient. No data was written.";
static constexpr const char* PARAMETER_OUT_OF_RANGE = "A parameter was out of range.";
static constexpr const char* DEVICE_CURRENTLY_OPEN = "The device is currently open.";
static constexpr const char* DEVICE_CURRENTLY_CLOSED = "The device is currently closed.";
static constexpr const char* DEVICE_CURRENTLY_ONLINE = "The device is currently online.";
static constexpr const char* DEVICE_CURRENTLY_OFFLINE = "The device is currently offline.";
static constexpr const char* DEVICE_CURRENTLY_POLLING = "The device is currently polling for messages.";
static constexpr const char* DEVICE_NOT_CURRENTLY_POLLING = "The device is not currently polling for messages.";
static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network.";
static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long.";
static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present.";
static constexpr const char* TIMEOUT = "The timeout was reached.";
static constexpr const char* WIVI_NOT_SUPPORTED = "Wireless neoVI functions are not supported on this device.";
static constexpr const char* RESTRICTED_ENTRY_FLAG = "Attempted to set a restricted flag in a Root Directory entry.";
static constexpr const char* NOT_SUPPORTED = "The requested feature is not supported.";
// Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
static constexpr const char* NO_SERIAL_NUMBER_FW_12V = "Communication could not be established with the device. Perhaps it is not powered with 12 volts?";
static constexpr const char* NO_SERIAL_NUMBER_FW = "Communication could not be established with the device. Perhaps it is not powered?";
static constexpr const char* NO_SERIAL_NUMBER_12V = "Communication could not be established with the device. Perhaps it is not powered with 12 volts or requires a firmware update using Vehicle Spy.";
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy.";
static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device.";
static constexpr const char* CAN_SETTINGS_NOT_AVAILABLE = "CAN settings are not available for this device.";
static constexpr const char* CANFD_SETTINGS_NOT_AVAILABLE = "CANFD settings are not available for this device.";
static constexpr const char* LSFTCAN_SETTINGS_NOT_AVAILABLE = "LSFTCAN settings are not available for this device.";
static constexpr const char* SWCAN_SETTINGS_NOT_AVAILABLE = "SWCAN settings are not available for this device.";
static constexpr const char* BAUDRATE_NOT_FOUND = "The baudrate was not found.";
static constexpr const char* UNEXPECTED_NETWORK_TYPE = "The network type was not found.";
static constexpr const char* DEVICE_FIRMWARE_OUT_OF_DATE = "The device firmware is out of date. New API functionality may not be supported.";
static constexpr const char* SETTINGS_STRUCTURE_MISMATCH = "Unexpected settings structure for this device.";
static constexpr const char* SETTINGS_STRUCTURE_TRUNCATED = "Settings structure is longer than the device supports and will be truncated.";
static constexpr const char* NO_DEVICE_RESPONSE = "Expected a response from the device but none were found.";
static constexpr const char* MESSAGE_FORMATTING = "The message was not properly formed.";
static constexpr const char* CANFD_NOT_SUPPORTED = "This device does not support CANFD.";
static constexpr const char* RTR_NOT_SUPPORTED = "RTR is not supported with CANFD.";
static constexpr const char* DEVICE_DISCONNECTED = "The device was disconnected.";
static constexpr const char* ONLINE_NOT_SUPPORTED = "This device does not support going online.";
static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination.";
static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device.";
static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled.";
static constexpr const char* ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE = "Ethernet PHY register control is not available for this device.";
static constexpr const char* DISK_NOT_SUPPORTED = "This device does not support accessing the specified disk.";
static constexpr const char* EOF_REACHED = "The requested length exceeds the available data from this disk.";
static constexpr const char* SETTINGS_DEFAULTS_USED = "The device settings could not be loaded, the default settings have been applied.";
static constexpr const char* ATOMIC_OPERATION_RETRIED = "An operation failed to be atomically completed, but will be retried.";
static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An ideally-atomic operation was completed nonatomically.";
static constexpr const char* WIVI_STACK_REFRESH_FAILED = "The Wireless neoVI stack encountered a communication error.";
static constexpr const char* WIVI_UPLOAD_STACK_OVERFLOW = "The Wireless neoVI upload stack has encountered an overflow condition.";
static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the frames of the A2B message does not contain samples for each channel and stream.";
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device.";
static constexpr const char* MODE_NOT_FOUND = "The mode was not found.";
static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device.";
// Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
static constexpr const char* FAILED_TO_WRITE = "A write operation failed.";
static constexpr const char* DRIVER_FAILED_TO_OPEN = "The device driver encountered a low-level error while opening the device.";
static constexpr const char* DRIVER_FAILED_TO_CLOSE = "The device driver encountered a low-level error while closing the device.";
static constexpr const char* PACKET_CHECKSUM_ERROR = "There was a checksum error while decoding a packet. The packet was dropped.";
static constexpr const char* TRANSMIT_BUFFER_FULL = "The transmit buffer is full and the device is set to non-blocking.";
static constexpr const char* DEVICE_IN_USE = "The device is currently in use by another program.";
static constexpr const char* PCAP_COULD_NOT_START = "The PCAP driver could not be started. Ethernet devices will not be found.";
static constexpr const char* PCAP_COULD_NOT_FIND_DEVICES = "The PCAP driver failed to find devices. Ethernet devices will not be found.";
static constexpr const char* PACKET_DECODING = "There was an error decoding a packet from the device.";
static constexpr const char* SOCKET_FAILED_TO_OPEN = "Unable to open new socket.";
static constexpr const char* FAILED_TO_BIND = "Unable to bind socket.";
static constexpr const char* ERROR_SETTING_SOCKET_OPTION = "A call to setsockopt() failed.";
static constexpr const char* GETIFADDRS_ERROR = "A call to getifaddrs() failed.";
static constexpr const char* SEND_TO_ERROR = "A call to sendto() failed.";
// FTD3XX
static constexpr const char* FT_OK = "FTD3XX success.";
static constexpr const char* FT_INVALID_HANDLE = "Invalid FTD3XX handle.";
static constexpr const char* FT_DEVICE_NOT_FOUND = "FTD3XX device not found.";
static constexpr const char* FT_DEVICE_NOT_OPENED = "FTD3XX device not opened.";
static constexpr const char* FT_IO_ERROR = "FTD3XX IO error.";
static constexpr const char* FT_INSUFFICIENT_RESOURCES = "Insufficient resources for FTD3XX.";
static constexpr const char* FT_INVALID_PARAMETER = "Invalid FTD3XX parameter.";
static constexpr const char* FT_INVALID_BAUD_RATE = "Invalid FTD3XX baud rate.";
static constexpr const char* FT_DEVICE_NOT_OPENED_FOR_ERASE = "FTD3XX device not opened for erase.";
static constexpr const char* FT_DEVICE_NOT_OPENED_FOR_WRITE = "FTD3XX not opened for write.";
static constexpr const char* FT_FAILED_TO_WRITE_DEVICE = "FTD3XX failed to write device.";
static constexpr const char* FT_EEPROM_READ_FAILED = "FTD3XX EEPROM read failed.";
static constexpr const char* FT_EEPROM_WRITE_FAILED = "FTD3XX EEPROM write failed.";
static constexpr const char* FT_EEPROM_ERASE_FAILED = "FTD3XX EEPROM erase failed.";
static constexpr const char* FT_EEPROM_NOT_PRESENT = "FTD3XX EEPROM not present.";
static constexpr const char* FT_EEPROM_NOT_PROGRAMMED = "FTD3XX EEPROM not programmed.";
static constexpr const char* FT_INVALID_ARGS = "Invalid FTD3XX arguments.";
static constexpr const char* FT_NOT_SUPPORTED = "FTD3XX not supported.";
static constexpr const char* FT_NO_MORE_ITEMS = "No more FTD3XX items.";
static constexpr const char* FT_TIMEOUT = "FTD3XX timeout.";
static constexpr const char* FT_OPERATION_ABORTED = "FTD3XX operation aborted.";
static constexpr const char* FT_RESERVED_PIPE = "Reserved FTD3XX pipe.";
static constexpr const char* FT_INVALID_CONTROL_REQUEST_DIRECTION = "Invalid FTD3XX control request direction.";
static constexpr const char* FT_INVALID_CONTROL_REQUEST_TYPE = "Invalid FTD3XX control request type.";
static constexpr const char* FT_IO_PENDING = "FTD3XX IO pending.";
static constexpr const char* FT_IO_INCOMPLETE = "FTD3XX IO incomplete.";
static constexpr const char* FT_HANDLE_EOF = "Handle FTD3XX EOF.";
static constexpr const char* FT_BUSY = "FTD3XX busy.";
static constexpr const char* FT_NO_SYSTEM_RESOURCES = "No FTD3XX system resources.";
static constexpr const char* FT_DEVICE_LIST_NOT_READY = "FTD3XX device list not ready.";
static constexpr const char* FT_DEVICE_NOT_CONNECTED = "FTD3XX device not connected.";
static constexpr const char* FT_INCORRECT_DEVICE_PATH = "Incorrect FTD3XX device path.";
static constexpr const char* FT_OTHER_ERROR = "Other FTD3XX error.";
// VSA
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted.";
static constexpr const char* VSA_TIMESTAMP_NOT_FOUND = "Unable to find a VSA record with a valid timestamp.";
static constexpr const char* VSA_BUFFER_FORMAT_ERROR = "VSA record buffer is formatted incorrectly.";
static constexpr const char* VSA_MAX_READ_ATTEMPTS_REACHED = "Reached max attempts to read VSA records before exit.";
static constexpr const char* VSA_BYTE_PARSE_FAILURE = "Failure to parse record bytes from VSA buffer.";
static constexpr const char* VSA_EXTENDED_MESSAGE_ERROR = "Failure to parse extended message record sequence";
static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API.";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* INVALID = "An invalid internal error occurred.";
const char* APIEvent::DescriptionForType(Type type) {
switch(type) {
// API Errors
case Type::InvalidNeoDevice:
return INVALID_NEODEVICE;
case Type::RequiredParameterNull:
return REQUIRED_PARAMETER_NULL;
case Type::BufferInsufficient:
return BUFFER_INSUFFICIENT;
case Type::OutputTruncated:
return OUTPUT_TRUNCATED;
case Type::ParameterOutOfRange:
return PARAMETER_OUT_OF_RANGE;
case Type::DeviceCurrentlyOpen:
return DEVICE_CURRENTLY_OPEN;
case Type::DeviceCurrentlyClosed:
return DEVICE_CURRENTLY_CLOSED;
case Type::DeviceCurrentlyOnline:
return DEVICE_CURRENTLY_ONLINE;
case Type::DeviceCurrentlyOffline:
return DEVICE_CURRENTLY_OFFLINE;
case Type::DeviceCurrentlyPolling:
return DEVICE_CURRENTLY_POLLING;
case Type::DeviceNotCurrentlyPolling:
return DEVICE_NOT_CURRENTLY_POLLING;
case Type::UnsupportedTXNetwork:
return UNSUPPORTED_TX_NETWORK;
case Type::MessageMaxLengthExceeded:
return MESSAGE_MAX_LENGTH_EXCEEDED;
case Type::ValueNotYetPresent:
return VALUE_NOT_YET_PRESENT;
case Type::Timeout:
return TIMEOUT;
case Type::WiVINotSupported:
return WIVI_NOT_SUPPORTED;
case Type::RestrictedEntryFlag:
return RESTRICTED_ENTRY_FLAG;
case Type::NotSupported:
return NOT_SUPPORTED;
// Device Errors
case Type::PollingMessageOverflow:
return POLLING_MESSAGE_OVERFLOW;
case Type::NoSerialNumber:
return NO_SERIAL_NUMBER;
case Type::IncorrectSerialNumber:
return INCORRECT_SERIAL_NUMBER;
case Type::SettingsReadError:
return SETTINGS_READ;
case Type::SettingsVersionError:
return SETTINGS_VERSION;
case Type::SettingsLengthError:
return SETTINGS_LENGTH;
case Type::SettingsChecksumError:
return SETTINGS_CHECKSUM;
case Type::SettingsNotAvailable:
return SETTINGS_NOT_AVAILABLE;
case Type::SettingsReadOnly:
return SETTINGS_READONLY;
case Type::CANSettingsNotAvailable:
return CAN_SETTINGS_NOT_AVAILABLE;
case Type::CANFDSettingsNotAvailable:
return CANFD_SETTINGS_NOT_AVAILABLE;
case Type::LSFTCANSettingsNotAvailable:
return LSFTCAN_SETTINGS_NOT_AVAILABLE;
case Type::SWCANSettingsNotAvailable:
return SWCAN_SETTINGS_NOT_AVAILABLE;
case Type::BaudrateNotFound:
return BAUDRATE_NOT_FOUND;
case Type::UnexpectedNetworkType:
return UNEXPECTED_NETWORK_TYPE;
case Type::DeviceFirmwareOutOfDate:
return DEVICE_FIRMWARE_OUT_OF_DATE;
case Type::SettingsStructureMismatch:
return SETTINGS_STRUCTURE_MISMATCH;
case Type::SettingsStructureTruncated:
return SETTINGS_STRUCTURE_TRUNCATED;
case Type::NoDeviceResponse:
return NO_DEVICE_RESPONSE;
case Type::MessageFormattingError:
return MESSAGE_FORMATTING;
case Type::CANFDNotSupported:
return CANFD_NOT_SUPPORTED;
case Type::RTRNotSupported:
return RTR_NOT_SUPPORTED;
case Type::DeviceDisconnected:
return DEVICE_DISCONNECTED;
case Type::OnlineNotSupported:
return ONLINE_NOT_SUPPORTED;
case Type::TerminationNotSupportedDevice:
return TERMINATION_NOT_SUPPORTED_DEVICE;
case Type::TerminationNotSupportedNetwork:
return TERMINATION_NOT_SUPPORTED_NETWORK;
case Type::AnotherInTerminationGroupEnabled:
return ANOTHER_IN_TERMINATION_GROUP_ENABLED;
case Type::NoSerialNumberFW:
return NO_SERIAL_NUMBER_FW;
case Type::NoSerialNumber12V:
return NO_SERIAL_NUMBER_12V;
case Type::NoSerialNumberFW12V:
return NO_SERIAL_NUMBER_FW_12V;
case Type::EthPhyRegisterControlNotAvailable:
return ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE;
case Type::DiskNotSupported:
return DISK_NOT_SUPPORTED;
case Type::EOFReached:
return EOF_REACHED;
case Type::SettingsDefaultsUsed:
return SETTINGS_DEFAULTS_USED;
case Type::AtomicOperationRetried:
return ATOMIC_OPERATION_RETRIED;
case Type::AtomicOperationCompletedNonatomically:
return ATOMIC_OPERATION_COMPLETED_NONATOMICALLY;
case Type::WiVIStackRefreshFailed:
return WIVI_STACK_REFRESH_FAILED;
case Type::WiVIUploadStackOverflow:
return WIVI_UPLOAD_STACK_OVERFLOW;
case Type::A2BMessageIncompleteFrame:
return A2B_MESSAGE_INCOMPLETE_FRAME;
case Type::CoreminiUploadVersionMismatch:
return COREMINI_UPLOAD_VERSION_MISMATCH;
case Type::DiskNotConnected:
return DISK_NOT_CONNECTED;
case Type::UnexpectedResponse:
return UNEXPECTED_RESPONSE;
case Type::LINSettingsNotAvailable:
return LIN_SETTINGS_NOT_AVAILABLE;
case Type::ModeNotFound:
return MODE_NOT_FOUND;
// Transport Errors
case Type::FailedToRead:
return FAILED_TO_READ;
case Type::FailedToWrite:
return FAILED_TO_WRITE;
case Type::DriverFailedToOpen:
return DRIVER_FAILED_TO_OPEN;
case Type::DriverFailedToClose:
return DRIVER_FAILED_TO_CLOSE;
case Type::PacketChecksumError:
return PACKET_CHECKSUM_ERROR;
case Type::TransmitBufferFull:
return TRANSMIT_BUFFER_FULL;
case Type::DeviceInUse:
return DEVICE_IN_USE;
case Type::PCAPCouldNotStart:
return PCAP_COULD_NOT_START;
case Type::PCAPCouldNotFindDevices:
return PCAP_COULD_NOT_FIND_DEVICES;
case Type::PacketDecodingError:
return PACKET_DECODING;
case Type::SocketFailedToOpen:
return SOCKET_FAILED_TO_OPEN;
case Type::FailedToBind:
return FAILED_TO_BIND;
case Type::ErrorSettingSocketOption:
return ERROR_SETTING_SOCKET_OPTION;
case Type::GetIfAddrsError:
return GETIFADDRS_ERROR;
case Type::SendToError:
return SEND_TO_ERROR;
case Type::GPTPNotSupported:
return GPTP_NOT_SUPPORTED;
// FTD3XX
case Type::FTOK:
return FT_OK;
case Type::FTInvalidHandle:
return FT_INVALID_HANDLE;
case Type::FTDeviceNotFound:
return FT_DEVICE_NOT_FOUND;
case Type::FTDeviceNotOpened:
return FT_DEVICE_NOT_OPENED;
case Type::FTIOError:
return FT_IO_ERROR;
case Type::FTInsufficientResources:
return FT_INSUFFICIENT_RESOURCES;
case Type::FTInvalidParameter:
return FT_INVALID_PARAMETER;
case Type::FTInvalidBaudRate:
return FT_INVALID_BAUD_RATE;
case Type::FTDeviceNotOpenedForErase:
return FT_DEVICE_NOT_OPENED_FOR_ERASE;
case Type::FTDeviceNotOpenedForWrite:
return FT_DEVICE_NOT_OPENED_FOR_WRITE;
case Type::FTFailedToWriteDevice:
return FT_FAILED_TO_WRITE_DEVICE;
case Type::FTEEPROMReadFailed:
return FT_EEPROM_READ_FAILED;
case Type::FTEEPROMWriteFailed:
return FT_EEPROM_WRITE_FAILED;
case Type::FTEEPROMEraseFailed:
return FT_EEPROM_ERASE_FAILED;
case Type::FTEEPROMNotPresent:
return FT_EEPROM_NOT_PRESENT;
case Type::FTEEPROMNotProgrammed:
return FT_EEPROM_NOT_PROGRAMMED;
case Type::FTInvalidArgs:
return FT_INVALID_ARGS;
case Type::FTNotSupported:
return FT_NOT_SUPPORTED;
case Type::FTNoMoreItems:
return FT_NO_MORE_ITEMS;
case Type::FTTimeout:
return FT_TIMEOUT;
case Type::FTOperationAborted:
return FT_OPERATION_ABORTED;
case Type::FTReservedPipe:
return FT_RESERVED_PIPE;
case Type::FTInvalidControlRequestDirection:
return FT_INVALID_CONTROL_REQUEST_DIRECTION;
case Type::FTInvalidControlRequestType:
return FT_INVALID_CONTROL_REQUEST_TYPE;
case Type::FTIOPending:
return FT_IO_PENDING;
case Type::FTIOIncomplete:
return FT_IO_INCOMPLETE;
case Type::FTHandleEOF:
return FT_HANDLE_EOF;
case Type::FTBusy:
return FT_BUSY;
case Type::FTNoSystemResources:
return FT_NO_SYSTEM_RESOURCES;
case Type::FTDeviceListNotReady:
return FT_DEVICE_LIST_NOT_READY;
case Type::FTDeviceNotConnected:
return FT_DEVICE_NOT_CONNECTED;
case Type::FTIncorrectDevicePath:
return FT_INCORRECT_DEVICE_PATH;
case Type::FTOtherError:
return FT_OTHER_ERROR;
// VSA
case Type::VSABufferCorrupted:
return VSA_BUFFER_CORRUPTED;
case Type::VSATimestampNotFound:
return VSA_TIMESTAMP_NOT_FOUND;
case Type::VSABufferFormatError:
return VSA_BUFFER_FORMAT_ERROR;
case Type::VSAMaxReadAttemptsReached:
return VSA_MAX_READ_ATTEMPTS_REACHED;
case Type::VSAByteParseFailure:
return VSA_BYTE_PARSE_FAILURE;
case Type::VSAExtendedMessageError:
return VSA_EXTENDED_MESSAGE_ERROR;
case Type::VSAOtherError:
return VSA_OTHER_ERROR;
// Other Errors
case Type::TooManyEvents:
return TOO_MANY_EVENTS;
case Type::Unknown:
return UNKNOWN;
default:
return INVALID;
}
}
bool EventFilter::match(const APIEvent& event) const noexcept {
if(type != APIEvent::Type::Any && type != event.getType())
return false;
if(matchOnDevicePtr && !event.isForDevice(device))
return false;
if(severity != APIEvent::Severity::Any && severity != event.getSeverity())
return false;
if(serial.length() != 0 && !event.isForDevice(serial))
return false;
return true;
}
+257
View File
@@ -0,0 +1,257 @@
#include "icsneo/api/eventmanager.h"
#include <memory>
#include <optional>
#include <iostream>
#include <cstdlib>
using namespace icsneo;
EventManager& EventManager::GetInstance() {
static EventManager inst;
return inst;
}
void EventManager::downgradeErrorsOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = true;
} else {
downgradedThreads.insert({std::this_thread::get_id(), true});
}
}
void EventManager::cancelErrorDowngradingOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = false;
}
}
void EventManager::add(APIEvent event) {
if(destructing)
return;
static const auto printLevel = []() -> std::optional<uint8_t> {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const auto level = std::getenv("LIBICSNEO_PRINT_EVENTS");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
if(!level)
return std::nullopt;
try {
return (uint8_t)std::stoi(level);
} catch (std::invalid_argument const&) {
return std::nullopt;
}
}();
if(printLevel && (uint8_t)event.getSeverity() >= *printLevel)
std::cerr << event.describe() << std::endl;
if(event.getSeverity() == APIEvent::Severity::Error) {
// if the error was added on a thread that downgrades errors (non-user thread)
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end() && i->second) {
event.downgradeFromError();
{
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
} else {
std::lock_guard<std::mutex> errorsLock(errorsMutex);
lastUserErrors[std::this_thread::get_id()] = event;
}
} else {
{
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
}
}
void EventManager::addEventInternal(APIEvent event) {
// Ensure the event list is at most exactly full (size of eventLimit - 1, leaving room for a potential APIEvent::TooManyEvents)
// Removes any events of type TooManyEvents from the end before checking to avoid duplicates.
enforceLimit();
// We are exactly full, either because the list was truncated or because we were simply full before
if(events.size() == eventLimit - 1) {
// If the event is worth adding
if(event.getType() != APIEvent::Type::TooManyEvents) {
discardOldest(1);
events.push_back(event);
}
events.push_back(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
} else {
if (event.getType() != APIEvent::Type::TooManyEvents)
events.push_back(event);
}
}
void EventManager::runCallbacks(APIEvent event) {
std::lock_guard<std::mutex> lk(callbacksMutex);
for(auto& i : callbacks)
i.second.callIfMatch(std::make_shared<APIEvent>(event));
}
void EventManager::setEventLimit(size_t newLimit) {
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
if(newLimit == eventLimit)
return;
if(newLimit < 10) {
add(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return;
}
eventLimit = newLimit;
std::lock_guard<std::mutex> eventsLock(eventsMutex);
if(enforceLimit())
addEventInternal(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
}
void EventManager::ResetInstance() {
std::lock_guard<std::mutex> eventsLock(eventsMutex);
std::lock_guard<std::mutex> errorsLock(errorsMutex);
std::lock_guard<std::mutex> downgradedThreadsLock(downgradedThreadsMutex);
std::lock_guard<std::mutex> callbacksLock(callbacksMutex);
std::lock_guard<std::mutex> callbackIDLock(callbackIDMutex);
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
events.clear();
lastUserErrors.clear();
downgradedThreads.clear();
callbacks.clear();
callbackID = 0;
eventLimit = 10000;
}
int EventManager::addEventCallback(const EventCallback &cb) {
std::lock_guard<std::mutex> callbacksLock(callbacksMutex);
std::lock_guard<std::mutex> callbackIDLock(callbackIDMutex);
callbacks.insert({callbackID, cb});
return callbackID++;
}
bool EventManager::removeEventCallback(int id) {
std::lock_guard<std::mutex> lk(callbacksMutex);
auto iter = callbacks.find(id);
if(iter != callbacks.end()) {
callbacks.erase(iter);
return true;
} else
return false;
}
bool EventManager::isDowngradingErrorsOnCurrentThread() const {
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
return i->second;
}
return false;
}
void EventManager::get(std::vector<APIEvent>& eventOutput, size_t max, EventFilter filter) {
std::lock_guard<std::mutex> lk(eventsMutex);
if(max == 0) // A limit of 0 indicates no limit
max = (size_t)-1;
size_t count = 0;
eventOutput.clear();
auto it = events.begin();
while(it != events.end()) {
if(filter.match(*it)) {
eventOutput.push_back(*it);
it = events.erase(it);
if(++count >= max)
break; // We now have as many written to output as we can
} else {
it++;
}
}
}
/**
* Removes the returned error from the map
* If no error was found, return a NoErrorFound Info event
*/
APIEvent EventManager::getLastError() {
std::lock_guard<std::mutex> lk(errorsMutex);
auto it = lastUserErrors.find(std::this_thread::get_id());
if(it == lastUserErrors.end()) {
return APIEvent(APIEvent::Type::NoErrorFound, APIEvent::Severity::EventInfo);
} else {
APIEvent ret = it->second;
it = lastUserErrors.erase(it);
return ret;
}
}
void EventManager::discard(EventFilter filter) {
std::lock_guard<std::mutex> lk(eventsMutex);
events.remove_if([&filter](const APIEvent& event) {
return filter.match(event);
});
}
size_t EventManager::countInternal(EventFilter filter) const {
size_t ret = 0;
for(auto& event : events)
if(filter.match(event))
ret++;
return ret;
}
/**
* Ensures events is always at most eventLimit - 1 in size.
* Returns true if any events were removed in the process of doing so.
*/
bool EventManager::enforceLimit() {
// Remove all TooManyEvents from the end before checking
auto filter = EventFilter(APIEvent::Type::TooManyEvents);
auto it = events.rbegin();
while(it != events.rend() && filter.match(*it)) {
it = decltype(it){events.erase( std::next(it).base() )};
}
// We are not overflowing
if(events.size() < eventLimit)
return false;
size_t amountToRemove = events.size() + 1 - eventLimit;
discardOldest(amountToRemove);
return true;
}
void EventManager::discardOldest(size_t count) {
if(count == 0)
return;
auto it = events.begin();
while(it != events.end()) {
it = events.erase(it);
if(--count == 0)
break;
}
}
+47 -47
View File
@@ -1,48 +1,48 @@
#include "icsneo/icsneocpp.h" #include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h" #include "icsneo/device/devicefinder.h"
using namespace icsneo; using namespace icsneo;
std::vector<std::shared_ptr<Device>> icsneo::FindAllDevices() { std::vector<std::shared_ptr<Device>> icsneo::FindAllDevices() {
return DeviceFinder::FindAll(); return DeviceFinder::FindAll();
} }
std::vector<DeviceType> icsneo::GetSupportedDevices() { std::vector<DeviceType> icsneo::GetSupportedDevices() {
return DeviceFinder::GetSupportedDevices(); return DeviceFinder::GetSupportedDevices();
} }
size_t icsneo::ErrorCount(ErrorFilter filter) { size_t icsneo::EventCount(EventFilter filter) {
return ErrorManager::GetInstance().count(filter); return EventManager::GetInstance().eventCount(filter);
} }
std::vector<APIError> icsneo::GetErrors(ErrorFilter filter, size_t max) { std::vector<APIEvent> icsneo::GetEvents(EventFilter filter, size_t max) {
return ErrorManager::GetInstance().get(filter, max); return EventManager::GetInstance().get(filter, max);
} }
std::vector<APIError> icsneo::GetErrors(size_t max, ErrorFilter filter) { std::vector<APIEvent> icsneo::GetEvents(size_t max, EventFilter filter) {
return ErrorManager::GetInstance().get(max, filter); return EventManager::GetInstance().get(max, filter);
} }
void icsneo::GetErrors(std::vector<APIError>& errors, ErrorFilter filter, size_t max) { void icsneo::GetEvents(std::vector<APIEvent>& events, EventFilter filter, size_t max) {
ErrorManager::GetInstance().get(errors, filter, max); EventManager::GetInstance().get(events, filter, max);
} }
void icsneo::GetErrors(std::vector<APIError>& errors, size_t max, ErrorFilter filter) { void icsneo::GetEvents(std::vector<APIEvent>& events, size_t max, EventFilter filter) {
ErrorManager::GetInstance().get(errors, max, filter); EventManager::GetInstance().get(events, max, filter);
} }
bool icsneo::GetLastError(APIError& error, ErrorFilter filter) { APIEvent icsneo::GetLastError() {
return ErrorManager::GetInstance().getLastError(error, filter); return EventManager::GetInstance().getLastError();
} }
void icsneo::DiscardErrors(ErrorFilter filter) { void icsneo::DiscardEvents(EventFilter filter) {
ErrorManager::GetInstance().discard(filter); EventManager::GetInstance().discard(filter);
} }
void icsneo::SetErrorLimit(size_t newLimit) { void icsneo::SetEventLimit(size_t newLimit) {
ErrorManager::GetInstance().setErrorLimit(newLimit); EventManager::GetInstance().setEventLimit(newLimit);
} }
size_t icsneo::GetErrorLimit() { size_t icsneo::GetEventLimit() {
return ErrorManager::GetInstance().getErrorLimit(); return EventManager::GetInstance().getEventLimit();
} }
+19 -22
View File
@@ -3,8 +3,7 @@
#include <Tchar.h> #include <Tchar.h>
//Basic Functions //Basic Functions
FINDNEODEVICES icsneoFindNeoDevices; OPENDEVICE icsneoOpenDevice;
OPENNEODEVICE icsneoOpenNeoDevice;
CLOSEPORT icsneoClosePort; CLOSEPORT icsneoClosePort;
FREEOBJECT icsneoFreeObject; FREEOBJECT icsneoFreeObject;
////OPENPORTEX icsneoOpenPortEx; ////OPENPORTEX icsneoOpenPortEx;
@@ -45,6 +44,7 @@ SETVCAN412SETTINGS icsneoSetVCAN412Settings;
SETBITRATE icsneoSetBitRate; SETBITRATE icsneoSetBitRate;
GETDEVICEPARMS icsneoGetDeviceParameters; GETDEVICEPARMS icsneoGetDeviceParameters;
SETDEVICEPARMS icsneoSetDeviceParameters; SETDEVICEPARMS icsneoSetDeviceParameters;
ENABLEDOIPACTIVATIONLINE icsneoEnableDOIPLine;
//Error Functions //Error Functions
GETLASTAPIERROR icsneoGetLastAPIError; GETLASTAPIERROR icsneoGetLastAPIError;
@@ -81,17 +81,17 @@ SCRIPTWRITEAPPSIGNAL icsneoScriptWriteAppSignal;
//SCRIPTWRITETXMESSAGE icsneoScriptWriteTxMessage; //SCRIPTWRITETXMESSAGE icsneoScriptWriteTxMessage;
//The following are valid strings for setting parameters on devices //The following are valid strings for setting parameters on devices
//using the icsneoGetDeviceParameters() and icsneoSetDeviceParameters() functions //using the icsneoGetDeviceParameters() and icsneoSetDeviceParameters() functions
char *FireParameters[] = char *FireParameters[] =
{ {
"can1", "can2", "can3", "can4", "swcan", "lsftcan", "lin1", "lin2", "can1", "can2", "can3", "can4", "swcan", "lsftcan", "lin1", "lin2",
"lin3", "lin4", "cgi_baud", "cgi_tx_ifs_bit_times", "lin3", "lin4", "cgi_baud", "cgi_tx_ifs_bit_times",
"cgi_rx_ifs_bit_times", "cgi_chksum_enable", "network_enables", "cgi_rx_ifs_bit_times", "cgi_chksum_enable", "network_enables",
"network_enabled_on_boot", "pwm_man_timeout", "pwr_man_enable", "network_enabled_on_boot", "pwm_man_timeout", "pwr_man_enable",
"misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_analog_enable", "misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_analog_enable",
"misc_io_report_period", "misc_io_on_report_events", "ain_sample_period", "misc_io_report_period", "misc_io_on_report_events", "ain_sample_period",
"ain_threshold", "iso15765_separation_time_offset", "iso9141_kwp_settings", "ain_threshold", "iso15765_separation_time_offset", "iso9141_kwp_settings",
"perf_en", "iso_parity", "iso_msg_termination", "network_enables_2" "perf_en", "iso_parity", "iso_msg_termination", "network_enables_2"
}; };
@@ -99,30 +99,30 @@ char *FireParameters[] =
char *VCAN3Parameters[] = char *VCAN3Parameters[] =
{ {
"can1", "can2", "network_enables", "network_enabled_on_boot", "iso15765_separation_time_offset", "can1", "can2", "network_enables", "network_enabled_on_boot", "iso15765_separation_time_offset",
"perf_en", "misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_report_period", "perf_en", "misc_io_initial_ddr", "misc_io_initial_latch", "misc_io_report_period",
"misc_io_on_report_events" "misc_io_on_report_events"
}; };
char *CANParameters[] = char *CANParameters[] =
{ {
"Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1", "Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1",
"TqSeg2", "TqProp", "TqSync", "BRP", "auto_baud" "TqSeg2", "TqProp", "TqSync", "BRP", "auto_baud"
}; };
char *SWCANParameters[] = char *SWCANParameters[] =
{ {
"Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1", "TqSeg2", "Mode", "SetBaudrate", "Baudrate", "NetworkType", "TqSeg1", "TqSeg2",
"TqProp", "TqSync", "BRP", "high_speed_auto_switch", "auto_baud" "TqProp", "TqSync", "BRP", "high_speed_auto_switch", "auto_baud"
}; };
char *LINParameters[] = char *LINParameters[] =
{ {
"Baudrate", "spbrg", "brgh", "MasterResistor", "Mode" "Baudrate", "spbrg", "brgh", "MasterResistor", "Mode"
}; };
char *ISOKWPParms[] = char *ISOKWPParms[] =
{ {
"Baudrate", "spbrg", "brgh", "init_steps", "init_step_count", "Baudrate", "spbrg", "brgh", "init_steps", "init_step_count",
"p2_500us", "p3_500us", "p4_500us", "chksum_enabled" "p2_500us", "p3_500us", "p4_500us", "chksum_enabled"
}; };
@@ -132,10 +132,7 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
if((hAPIDLL = LoadLibrary(_T("icsneo40.dll"))) == NULL) if((hAPIDLL = LoadLibrary(_T("icsneo40.dll"))) == NULL)
return false; return false;
icsneoOpenDevice = (OPENDEVICE) GetProcAddress(hAPIDLL, "icsneoOpenDevice");
icsneoFindNeoDevices = (FINDNEODEVICES) GetProcAddress(hAPIDLL, "icsneoFindNeoDevices");
icsneoOpenNeoDevice = (OPENNEODEVICE) GetProcAddress(hAPIDLL, "icsneoOpenNeoDevice");
icsneoClosePort = (CLOSEPORT) GetProcAddress(hAPIDLL, "icsneoClosePort"); icsneoClosePort = (CLOSEPORT) GetProcAddress(hAPIDLL, "icsneoClosePort");
icsneoFreeObject = (FREEOBJECT) GetProcAddress(hAPIDLL, "icsneoFreeObject"); icsneoFreeObject = (FREEOBJECT) GetProcAddress(hAPIDLL, "icsneoFreeObject");
//// icsneoOpenPortEx = (OPENPORTEX) GetProcAddress(hAPIDLL, "icsneoOpenPortEx"); //// icsneoOpenPortEx = (OPENPORTEX) GetProcAddress(hAPIDLL, "icsneoOpenPortEx");
@@ -201,22 +198,22 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
icsneoScriptReadAppSignal = (SCRIPTREADAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptReadAppSignal"); icsneoScriptReadAppSignal = (SCRIPTREADAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptReadAppSignal");
icsneoScriptWriteAppSignal = (SCRIPTWRITEAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptWriteAppSignal"); icsneoScriptWriteAppSignal = (SCRIPTWRITEAPPSIGNAL) GetProcAddress(hAPIDLL, "icsneoScriptWriteAppSignal");
icsneoEnableDOIPLine = (ENABLEDOIPACTIVATIONLINE)GetProcAddress(hAPIDLL, "icsneoEnableDOIPLine");
if(!icsneoFindNeoDevices || !icsneoOpenNeoDevice || !icsneoClosePort || !icsneoFreeObject || if(!icsneoOpenDevice || !icsneoClosePort || !icsneoFreeObject ||
!icsneoTxMessages || !icsneoGetMessages || !icsneoWaitForRxMessagesWithTimeOut || !icsneoTxMessages || !icsneoGetMessages || !icsneoWaitForRxMessagesWithTimeOut ||
!icsneoGetTimeStampForMsg || !icsneoEnableNetworkRXQueue || !icsneoGetISO15765Status || !icsneoTxMessagesEx || !icsneoGetTimeStampForMsg || !icsneoEnableNetworkRXQueue || !icsneoGetISO15765Status || !icsneoTxMessagesEx ||
!icsneoSetISO15765RxParameters || !icsneoGetConfiguration || !icsneoSendConfiguration || !icsneoSetISO15765RxParameters || !icsneoGetConfiguration || !icsneoSendConfiguration ||
!icsneoGetFireSettings || !icsneoSetFireSettings || !icsneoGetVCAN3Settings || !icsneoGetFireSettings || !icsneoSetFireSettings || !icsneoGetVCAN3Settings ||
!icsneoSetVCAN3Settings || !icsneoGetVCANRFSettings || !icsneoSetVCANRFSettings || !icsneoGetFire2Settings || !icsneoSetVCAN3Settings || !icsneoGetVCANRFSettings || !icsneoSetVCANRFSettings || !icsneoGetFire2Settings ||
!icsneoGetVCAN412Settings || !icsneoSetVCAN412Settings || !icsneoGetVCAN412Settings || !icsneoSetVCAN412Settings ||
!icsneoSetFire2Settings || !icsneoGetRADGalaxySettings || !icsneoSetRADGalaxySettings || !icsneoSetFire2Settings || !icsneoGetRADGalaxySettings || !icsneoSetRADGalaxySettings ||
!icsneoSetBitRate || !icsneoGetDeviceParameters || !icsneoSerialNumberToString || !icsneoSetBitRate || !icsneoGetDeviceParameters || !icsneoSerialNumberToString ||
!icsneoSetDeviceParameters || !icsneoGetLastAPIError || !icsneoGetErrorMessages || !icsneoSetDeviceParameters || !icsneoGetLastAPIError || !icsneoGetErrorMessages ||
!icsneoGetErrorInfo || !icsneoScriptLoad || !icsneoScriptStart || !icsneoScriptStop || !icsneoGetErrorInfo || !icsneoScriptLoad || !icsneoScriptStart || !icsneoScriptStop ||
!icsneoScriptClear || !icsneoScriptStartFBlock || !icsneoScriptStopFBlock || !icsneoScriptClear || !icsneoScriptStartFBlock || !icsneoScriptStopFBlock ||
!icsneoScriptGetFBlockStatus || !icsneoScriptGetScriptStatus || !icsneoScriptReadAppSignal || !icsneoScriptGetFBlockStatus || !icsneoScriptGetScriptStatus || !icsneoScriptReadAppSignal ||
!icsneoScriptWriteAppSignal || !icsneoGetDLLVersion) !icsneoScriptWriteAppSignal || !icsneoGetDLLVersion || !icsneoEnableDOIPLine)
{ {
FreeLibrary(hAPIDLL); FreeLibrary(hAPIDLL);
return false; return false;
+19 -17
View File
@@ -11,23 +11,24 @@ void UnloadDLLAPI(HINSTANCE &hAPIDLL);
//Basic Functions //Basic Functions
typedef int (__stdcall *FINDNEODEVICES)(unsigned long DeviceTypes, NeoDevice *pNeoDevice, int *pNumDevices); typedef int (__stdcall *FINDNEODEVICES)(unsigned long DeviceTypes, NeoDevice *pNeoDevice, int *pNumDevices);
typedef int (__stdcall *OPENNEODEVICE)(NeoDevice *pNeoDevice, void * hObject, unsigned char *bNetworkIDs, int bConfigRead, int bSyncToPC); typedef int (__stdcall *OPENNEODEVICE)(NeoDevice *pNeoDevice, void * hObject, unsigned char *bNetworkIDs, int bConfigRead, int bSyncToPC);
typedef int (__stdcall *CLOSEPORT)(void * hObject, int *pNumberOfErrors); typedef int (__stdcall *OPENDEVICE)(NeoDeviceEx* pNeoDeviceEx, void** hObject, unsigned char* bNetworkIDs, int bConfigRead, int iOptions, OptionsOpenNeoEx* stOptionsOpenNeoEx, unsigned long reserved);
typedef int (__stdcall *CLOSEPORT)(void * hObject, int *pNumberOfErrors);
typedef void (__stdcall *FREEOBJECT)(void * hObject); typedef void (__stdcall *FREEOBJECT)(void * hObject);
typedef int (__stdcall *OPENPORTEX)(void * lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB, int lIPAddressLSBOrBaudRate, typedef int (__stdcall *OPENPORTEX)(void * lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB, int lIPAddressLSBOrBaudRate,
int bConfigRead, unsigned char *bNetworkID, int * hObject); int bConfigRead, unsigned char *bNetworkID, int * hObject);
typedef int (__stdcall *SERIALNUMBERTOSTRING) (unsigned long serial, char *data,unsigned long data_size); typedef int (__stdcall *SERIALNUMBERTOSTRING) (unsigned long serial, char *data,unsigned long data_size);
//Message Functions //Message Functions
typedef int (__stdcall *GETMESSAGES)(void * hObject, icsSpyMessage *pMsg, int * pNumberOfMessages, int * pNumberOfErrors); typedef int (__stdcall *GETMESSAGES)(void * hObject, icsSpyMessage *pMsg, int * pNumberOfMessages, int * pNumberOfErrors);
typedef int (__stdcall *TXMESSAGES)(void * hObject, icsSpyMessage *pMsg, int lNetworkID, int lNumMessages); typedef int (__stdcall *TXMESSAGES)(void * hObject, icsSpyMessage *pMsg, int lNetworkID, int lNumMessages);
typedef int (__stdcall *TXMESSAGESEX)(void * hObject,icsSpyMessage *pMsg, unsigned int lNetworkID,unsigned int lNumMessages,unsigned int *NumTxed, unsigned int zero2); typedef int (__stdcall *TXMESSAGESEX)(void * hObject,icsSpyMessage *pMsg, unsigned int lNetworkID,unsigned int lNumMessages,unsigned int *NumTxed, unsigned int zero2);
typedef int (__stdcall *WAITFORRXMSGS)(void * hObject, unsigned int iTimeOut); typedef int (__stdcall *WAITFORRXMSGS)(void * hObject, unsigned int iTimeOut);
typedef int (__stdcall *ENABLERXQUEUE)(void * hObject, int iEnable); typedef int (__stdcall *ENABLERXQUEUE)(void * hObject, int iEnable);
typedef int (__stdcall *GETTSFORMSG)(void * hObject, icsSpyMessage *pMsg, double *pTimeStamp); typedef int (__stdcall *GETTSFORMSG)(void * hObject, icsSpyMessage *pMsg, double *pTimeStamp);
typedef void (__stdcall *GETISO15765STATUS)(void * hObject, int lNetwork, int lClearTxStatus, typedef void (__stdcall *GETISO15765STATUS)(void * hObject, int lNetwork, int lClearTxStatus,
int lClearRxStatus, int *lTxStatus, int *lRxStatus); int lClearRxStatus, int *lTxStatus, int *lRxStatus);
typedef void (__stdcall *SETISO15765RXPARMS)(void * hObject, int lNetwork, int lEnable, typedef void (__stdcall *SETISO15765RXPARMS)(void * hObject, int lNetwork, int lEnable,
spyFilterLong *pFF_CFMsgFilter, icsSpyMessage *pTxMsg, spyFilterLong *pFF_CFMsgFilter, icsSpyMessage *pTxMsg,
int lCFTimeOutMs, int lFlowCBlockSize, int lCFTimeOutMs, int lFlowCBlockSize,
int lUsesExtendedAddressing, int lUseHardwareIfPresent); int lUsesExtendedAddressing, int lUseHardwareIfPresent);
typedef int (__stdcall *DOWNLOADISO15765_2_TXSCRIPT)(void * hObject, unsigned int NetworkID); typedef int (__stdcall *DOWNLOADISO15765_2_TXSCRIPT)(void * hObject, unsigned int NetworkID);
@@ -36,7 +37,7 @@ typedef int (__stdcall *TXISO15765_2_MESSAGE)(void * hObject, stCM_ISO157652_TxM
//Device Functions //Device Functions
typedef int (__stdcall *GETCONFIG)(void * hObject, unsigned char * pData, int * lNumBytes); typedef int (__stdcall *GETCONFIG)(void * hObject, unsigned char * pData, int * lNumBytes);
typedef int (__stdcall *SENDCONFIG)(void * hObject, unsigned char * pData, int lNumBytes); typedef int (__stdcall *SENDCONFIG)(void * hObject, unsigned char * pData, int lNumBytes);
typedef int (__stdcall *GETFIRESETTINGS)(void * hObject, SFireSettings *pSettings, int iNumBytes); typedef int (__stdcall *GETFIRESETTINGS)(void * hObject, SFireSettings *pSettings, int iNumBytes);
typedef int (__stdcall *SETFIRESETTINGS)(void * hObject, SFireSettings *pSettings, int iNumBytes, int bSaveToEEPROM); typedef int (__stdcall *SETFIRESETTINGS)(void * hObject, SFireSettings *pSettings, int iNumBytes, int bSaveToEEPROM);
@@ -62,11 +63,12 @@ typedef int (__stdcall *SETRADSTAR2SETTINGS)(void * hObject, SRADStar2Settings *
typedef int (__stdcall *SETBITRATE)(void * hObject, int BitRate, int NetworkID); typedef int (__stdcall *SETBITRATE)(void * hObject, int BitRate, int NetworkID);
typedef int (__stdcall *GETDEVICEPARMS)(void * hObject, char *pParameter, char *pValues, short ValuesLength); typedef int (__stdcall *GETDEVICEPARMS)(void * hObject, char *pParameter, char *pValues, short ValuesLength);
typedef int (__stdcall *SETDEVICEPARMS)(void * hObject, char *pParmValue, int *pErrorIndex, int bSaveToEEPROM); typedef int (__stdcall *SETDEVICEPARMS)(void * hObject, char *pParmValue, int *pErrorIndex, int bSaveToEEPROM);
typedef int(__stdcall *ENABLEDOIPACTIVATIONLINE)(void * hObject, bool Val);
//Error Functions //Error Functions
typedef int (__stdcall *GETLASTAPIERROR)(void * hObject, unsigned long *pErrorNumber); typedef int (__stdcall *GETLASTAPIERROR)(void * hObject, unsigned long *pErrorNumber);
typedef int (__stdcall *GETERRMSGS)(void * hObject, int * pErrorMsgs, int * pNumberOfErrors); typedef int (__stdcall *GETERRMSGS)(void * hObject, int * pErrorMsgs, int * pNumberOfErrors);
typedef int (__stdcall *GETERRORINFO)(int lErrorNumber, TCHAR *szErrorDescriptionShort, typedef int (__stdcall *GETERRORINFO)(int lErrorNumber, TCHAR *szErrorDescriptionShort,
TCHAR *szErrorDescriptionLong, int * lMaxLengthShort, TCHAR *szErrorDescriptionLong, int * lMaxLengthShort,
int * lMaxLengthLong,int * lErrorSeverity,int * lRestartNeeded); int * lMaxLengthLong,int * lErrorSeverity,int * lRestartNeeded);
@@ -84,8 +86,8 @@ typedef int (__stdcall *STARTSOCKSERVER)(void * hObject, int iPort);
typedef int (__stdcall *STOPSOCKSERVER)(void * hObject); typedef int (__stdcall *STOPSOCKSERVER)(void * hObject);
//CoreMini Script functions //CoreMini Script functions
typedef int (__stdcall *SCRIPTSTART)(void * hObject, int iLocation); typedef int (__stdcall *SCRIPTSTART)(void * hObject, int iLocation);
typedef int (__stdcall *SCRIPTSTOP)(void * hObject); typedef int (__stdcall *SCRIPTSTOP)(void * hObject);
typedef int (__stdcall *SCRIPTLOAD)(void * hObject, const unsigned char * bin, unsigned long len_bytes, int iLocation); typedef int (__stdcall *SCRIPTLOAD)(void * hObject, const unsigned char * bin, unsigned long len_bytes, int iLocation);
typedef int (__stdcall *SCRIPTCLEAR)(void * hObject, int iLocation); typedef int (__stdcall *SCRIPTCLEAR)(void * hObject, int iLocation);
typedef int (__stdcall *SCRIPTSTARTFBLOCK)(void * hObject,unsigned int fb_index); typedef int (__stdcall *SCRIPTSTARTFBLOCK)(void * hObject,unsigned int fb_index);
@@ -99,21 +101,20 @@ typedef int (__stdcall *SCRIPTWRITEISO15765TXMESSAGE)(void * hObject, unsigned
//Deprecated (but still suppored in the DLL) //Deprecated (but still suppored in the DLL)
//////typedef int (__stdcall *OPENPORTEX)(int lPortSerialNumber, int lPortType, int lDriverType, //////typedef int (__stdcall *OPENPORTEX)(int lPortSerialNumber, int lPortType, int lDriverType,
////// int lIPAddressMSB, int lIPAddressLSBOrBaudRate,int bConfigRead, ////// int lIPAddressMSB, int lIPAddressLSBOrBaudRate,int bConfigRead,
////// unsigned char * bNetworkID, int * hObject); ////// unsigned char * bNetworkID, int * hObject);
////// //////
//////typedef int (__stdcall *OPENPORT)(int lPortNumber, int lPortType, int lDriverType, //////typedef int (__stdcall *OPENPORT)(int lPortNumber, int lPortType, int lDriverType,
////// unsigned char *bNetworkID, unsigned char *bSCPIDs, int * hObject); ////// unsigned char *bNetworkID, unsigned char *bSCPIDs, int * hObject);
//////typedef int (__stdcall *ENABLENETWORKCOM)(void * hObject, int Enable); //////typedef int (__stdcall *ENABLENETWORKCOM)(void * hObject, int Enable);
//////typedef int (__stdcall *FINDCOMDEVICES)(int lDriverType, int lGetSerialNumbers, int lStopAtFirst, int lUSBCommOnly, //////typedef int (__stdcall *FINDCOMDEVICES)(int lDriverType, int lGetSerialNumbers, int lStopAtFirst, int lUSBCommOnly,
////// int *p_lDeviceTypes, int *p_lComPorts, int *p_lSerialNumbers, int *lNumDevices); ////// int *p_lDeviceTypes, int *p_lComPorts, int *p_lSerialNumbers, int *lNumDevices);
//Basic Functions //Basic Functions
extern FINDNEODEVICES icsneoFindNeoDevices; extern OPENDEVICE icsneoOpenDevice;
extern OPENNEODEVICE icsneoOpenNeoDevice;
extern CLOSEPORT icsneoClosePort; extern CLOSEPORT icsneoClosePort;
extern FREEOBJECT icsneoFreeObject; extern FREEOBJECT icsneoFreeObject;
extern SERIALNUMBERTOSTRING icsneoSerialNumberToString; extern SERIALNUMBERTOSTRING icsneoSerialNumberToString;
@@ -157,6 +158,7 @@ extern SETVCAN412SETTINGS icsneoSetVCAN412Settings;
extern SETBITRATE icsneoSetBitRate; extern SETBITRATE icsneoSetBitRate;
extern GETDEVICEPARMS icsneoGetDeviceParameters; extern GETDEVICEPARMS icsneoGetDeviceParameters;
extern SETDEVICEPARMS icsneoSetDeviceParameters; extern SETDEVICEPARMS icsneoSetDeviceParameters;
extern ENABLEDOIPACTIVATIONLINE icsneoEnableDOIPLine;
//Error Functions //Error Functions
extern GETLASTAPIERROR icsneoGetLastAPIError; extern GETLASTAPIERROR icsneoGetLastAPIError;
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -14,15 +14,15 @@
using namespace icsneo; using namespace icsneo;
extern "C" { extern "C" {
extern int DLLExport icsneoValidateHObject(void* hObject); extern int LegacyDLLExport icsneoValidateHObject(void* hObject);
extern int DLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut); extern int LegacyDLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut);
} }
int icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut) { int LegacyDLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned int iTimeOut) {
if(!icsneoValidateHObject(hObject)) if(!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = (neodevice_t*)hObject;
if(device->device->getCurrentMessageCount() != 0) if(device->device->getCurrentMessageCount() != 0)
return true; return true;
return bool(device->device->com->waitForMessageSync(MessageFilter(), std::chrono::milliseconds(iTimeOut))); return bool(device->device->com->waitForMessageSync({}, std::chrono::milliseconds(iTimeOut)));
} }
+18
View File
@@ -0,0 +1,18 @@
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
add_subdirectory(python)
endif()
if(LIBICSNEO_ENABLE_BINDINGS_RUST)
include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
)
FetchContent_MakeAvailable(Corrosion)
corrosion_import_crate(MANIFEST_PATH ${CMAKE_SOURCE_DIR}/bindings/rust/icsneoc2rs/Cargo.toml)
else()
message(STATUS "Not building rust bindings")
endif()
+34
View File
@@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.20)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
pybind11_add_module(icsneopy
icsneopy/api/event.cpp
icsneopy/api/eventcallback.cpp
icsneopy/api/eventmanager.cpp
icsneopy/api/version.cpp
icsneopy/device/devicetype.cpp
icsneopy/communication/network.cpp
icsneopy/communication/message/message.cpp
icsneopy/communication/message/canmessage.cpp
icsneopy/communication/message/canerrormessage.cpp
icsneopy/communication/message/ethernetmessage.cpp
icsneopy/communication/message/linmessage.cpp
icsneopy/communication/message/tc10statusmessage.cpp
icsneopy/communication/message/mdiomessage.cpp
icsneopy/communication/message/gptpstatusmessage.cpp
icsneopy/communication/message/ethernetstatusmessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/device/device.cpp
icsneopy/icsneocpp.cpp
)
target_link_libraries(icsneopy PRIVATE icsneocpp)
install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN stubgen REQUIRED)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND ${STUBGEN} -m icsneopy -o .)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi __init__.py py.typed DESTINATION icsneopy)
+1
View File
@@ -0,0 +1 @@
from .icsneopy import *
+170
View File
@@ -0,0 +1,170 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/event.h"
namespace icsneo {
void init_event(pybind11::module_& m) {
pybind11::class_<APIEvent, std::shared_ptr<APIEvent>> apiEvent(m, "APIEvent");
pybind11::enum_<APIEvent::Type>(apiEvent, "Type")
.value("Any", APIEvent::Type::Any)
.value("InvalidNeoDevice", APIEvent::Type::InvalidNeoDevice)
.value("RequiredParameterNull", APIEvent::Type::RequiredParameterNull)
.value("BufferInsufficient", APIEvent::Type::BufferInsufficient)
.value("OutputTruncated", APIEvent::Type::OutputTruncated)
.value("ParameterOutOfRange", APIEvent::Type::ParameterOutOfRange)
.value("DeviceCurrentlyOpen", APIEvent::Type::DeviceCurrentlyOpen)
.value("DeviceCurrentlyClosed", APIEvent::Type::DeviceCurrentlyClosed)
.value("DeviceCurrentlyOnline", APIEvent::Type::DeviceCurrentlyOnline)
.value("DeviceCurrentlyOffline", APIEvent::Type::DeviceCurrentlyOffline)
.value("DeviceCurrentlyPolling", APIEvent::Type::DeviceCurrentlyPolling)
.value("DeviceNotCurrentlyPolling", APIEvent::Type::DeviceNotCurrentlyPolling)
.value("UnsupportedTXNetwork", APIEvent::Type::UnsupportedTXNetwork)
.value("MessageMaxLengthExceeded", APIEvent::Type::MessageMaxLengthExceeded)
.value("ValueNotYetPresent", APIEvent::Type::ValueNotYetPresent)
.value("Timeout", APIEvent::Type::Timeout)
.value("WiVINotSupported", APIEvent::Type::WiVINotSupported)
.value("RestrictedEntryFlag", APIEvent::Type::RestrictedEntryFlag)
.value("NotSupported", APIEvent::Type::NotSupported)
.value("PollingMessageOverflow", APIEvent::Type::PollingMessageOverflow)
.value("NoSerialNumber", APIEvent::Type::NoSerialNumber)
.value("IncorrectSerialNumber", APIEvent::Type::IncorrectSerialNumber)
.value("SettingsReadError", APIEvent::Type::SettingsReadError)
.value("SettingsVersionError", APIEvent::Type::SettingsVersionError)
.value("SettingsLengthError", APIEvent::Type::SettingsLengthError)
.value("SettingsChecksumError", APIEvent::Type::SettingsChecksumError)
.value("SettingsNotAvailable", APIEvent::Type::SettingsNotAvailable)
.value("SettingsReadOnly", APIEvent::Type::SettingsReadOnly)
.value("CANSettingsNotAvailable", APIEvent::Type::CANSettingsNotAvailable)
.value("CANFDSettingsNotAvailable", APIEvent::Type::CANFDSettingsNotAvailable)
.value("LSFTCANSettingsNotAvailable", APIEvent::Type::LSFTCANSettingsNotAvailable)
.value("SWCANSettingsNotAvailable", APIEvent::Type::SWCANSettingsNotAvailable)
.value("BaudrateNotFound", APIEvent::Type::BaudrateNotFound)
.value("UnexpectedNetworkType", APIEvent::Type::UnexpectedNetworkType)
.value("DeviceFirmwareOutOfDate", APIEvent::Type::DeviceFirmwareOutOfDate)
.value("SettingsStructureMismatch", APIEvent::Type::SettingsStructureMismatch)
.value("SettingsStructureTruncated", APIEvent::Type::SettingsStructureTruncated)
.value("NoDeviceResponse", APIEvent::Type::NoDeviceResponse)
.value("MessageFormattingError", APIEvent::Type::MessageFormattingError)
.value("CANFDNotSupported", APIEvent::Type::CANFDNotSupported)
.value("RTRNotSupported", APIEvent::Type::RTRNotSupported)
.value("DeviceDisconnected", APIEvent::Type::DeviceDisconnected)
.value("OnlineNotSupported", APIEvent::Type::OnlineNotSupported)
.value("TerminationNotSupportedDevice", APIEvent::Type::TerminationNotSupportedDevice)
.value("TerminationNotSupportedNetwork", APIEvent::Type::TerminationNotSupportedNetwork)
.value("AnotherInTerminationGroupEnabled", APIEvent::Type::AnotherInTerminationGroupEnabled)
.value("NoSerialNumberFW", APIEvent::Type::NoSerialNumberFW)
.value("NoSerialNumber12V", APIEvent::Type::NoSerialNumber12V)
.value("NoSerialNumberFW12V", APIEvent::Type::NoSerialNumberFW12V)
.value("EthPhyRegisterControlNotAvailable", APIEvent::Type::EthPhyRegisterControlNotAvailable)
.value("DiskNotSupported", APIEvent::Type::DiskNotSupported)
.value("EOFReached", APIEvent::Type::EOFReached)
.value("SettingsDefaultsUsed", APIEvent::Type::SettingsDefaultsUsed)
.value("AtomicOperationRetried", APIEvent::Type::AtomicOperationRetried)
.value("AtomicOperationCompletedNonatomically", APIEvent::Type::AtomicOperationCompletedNonatomically)
.value("WiVIStackRefreshFailed", APIEvent::Type::WiVIStackRefreshFailed)
.value("WiVIUploadStackOverflow", APIEvent::Type::WiVIUploadStackOverflow)
.value("I2CMessageExceedsMaxLength", APIEvent::Type::I2CMessageExceedsMaxLength)
.value("A2BMessageIncompleteFrame", APIEvent::Type::A2BMessageIncompleteFrame)
.value("CoreminiUploadVersionMismatch", APIEvent::Type::CoreminiUploadVersionMismatch)
.value("DiskNotConnected", APIEvent::Type::DiskNotConnected)
.value("UnexpectedResponse", APIEvent::Type::UnexpectedResponse)
.value("LiveDataInvalidHandle", APIEvent::Type::LiveDataInvalidHandle)
.value("LiveDataInvalidCommand", APIEvent::Type::LiveDataInvalidCommand)
.value("LiveDataInvalidArgument", APIEvent::Type::LiveDataInvalidArgument)
.value("LiveDataVersionMismatch", APIEvent::Type::LiveDataVersionMismatch)
.value("LiveDataNoDeviceResponse", APIEvent::Type::LiveDataNoDeviceResponse)
.value("LiveDataMaxSignalsReached", APIEvent::Type::LiveDataMaxSignalsReached)
.value("LiveDataCommandFailed", APIEvent::Type::LiveDataCommandFailed)
.value("LiveDataEncoderError", APIEvent::Type::LiveDataEncoderError)
.value("LiveDataDecoderError", APIEvent::Type::LiveDataDecoderError)
.value("LiveDataNotSupported", APIEvent::Type::LiveDataNotSupported)
.value("LINSettingsNotAvailable", APIEvent::Type::LINSettingsNotAvailable)
.value("ModeNotFound", APIEvent::Type::ModeNotFound)
.value("AppErrorParsingFailed", APIEvent::Type::AppErrorParsingFailed)
.value("FailedToRead", APIEvent::Type::FailedToRead)
.value("FailedToWrite", APIEvent::Type::FailedToWrite)
.value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen)
.value("DriverFailedToClose", APIEvent::Type::DriverFailedToClose)
.value("PacketChecksumError", APIEvent::Type::PacketChecksumError)
.value("TransmitBufferFull", APIEvent::Type::TransmitBufferFull)
.value("DeviceInUse", APIEvent::Type::DeviceInUse)
.value("PCAPCouldNotStart", APIEvent::Type::PCAPCouldNotStart)
.value("PCAPCouldNotFindDevices", APIEvent::Type::PCAPCouldNotFindDevices)
.value("PacketDecodingError", APIEvent::Type::PacketDecodingError)
.value("SocketFailedToOpen", APIEvent::Type::SocketFailedToOpen)
.value("FailedToBind", APIEvent::Type::FailedToBind)
.value("ErrorSettingSocketOption", APIEvent::Type::ErrorSettingSocketOption)
.value("GetIfAddrsError", APIEvent::Type::GetIfAddrsError)
.value("SendToError", APIEvent::Type::SendToError)
.value("MDIOMessageExceedsMaxLength", APIEvent::Type::MDIOMessageExceedsMaxLength)
.value("FTOK", APIEvent::Type::FTOK)
.value("FTInvalidHandle", APIEvent::Type::FTInvalidHandle)
.value("FTDeviceNotFound", APIEvent::Type::FTDeviceNotFound)
.value("FTDeviceNotOpened", APIEvent::Type::FTDeviceNotOpened)
.value("FTIOError", APIEvent::Type::FTIOError)
.value("FTInsufficientResources", APIEvent::Type::FTInsufficientResources)
.value("FTInvalidParameter", APIEvent::Type::FTInvalidParameter)
.value("FTInvalidBaudRate", APIEvent::Type::FTInvalidBaudRate)
.value("FTDeviceNotOpenedForErase", APIEvent::Type::FTDeviceNotOpenedForErase)
.value("FTDeviceNotOpenedForWrite", APIEvent::Type::FTDeviceNotOpenedForWrite)
.value("FTFailedToWriteDevice", APIEvent::Type::FTFailedToWriteDevice)
.value("FTEEPROMReadFailed", APIEvent::Type::FTEEPROMReadFailed)
.value("FTEEPROMWriteFailed", APIEvent::Type::FTEEPROMWriteFailed)
.value("FTEEPROMEraseFailed", APIEvent::Type::FTEEPROMEraseFailed)
.value("FTEEPROMNotPresent", APIEvent::Type::FTEEPROMNotPresent)
.value("FTEEPROMNotProgrammed", APIEvent::Type::FTEEPROMNotProgrammed)
.value("FTInvalidArgs", APIEvent::Type::FTInvalidArgs)
.value("FTNotSupported", APIEvent::Type::FTNotSupported)
.value("FTNoMoreItems", APIEvent::Type::FTNoMoreItems)
.value("FTTimeout", APIEvent::Type::FTTimeout)
.value("FTOperationAborted", APIEvent::Type::FTOperationAborted)
.value("FTReservedPipe", APIEvent::Type::FTReservedPipe)
.value("FTInvalidControlRequestDirection", APIEvent::Type::FTInvalidControlRequestDirection)
.value("FTInvalidControlRequestType", APIEvent::Type::FTInvalidControlRequestType)
.value("FTIOPending", APIEvent::Type::FTIOPending)
.value("FTIOIncomplete", APIEvent::Type::FTIOIncomplete)
.value("FTHandleEOF", APIEvent::Type::FTHandleEOF)
.value("FTBusy", APIEvent::Type::FTBusy)
.value("FTNoSystemResources", APIEvent::Type::FTNoSystemResources)
.value("FTDeviceListNotReady", APIEvent::Type::FTDeviceListNotReady)
.value("FTDeviceNotConnected", APIEvent::Type::FTDeviceNotConnected)
.value("FTIncorrectDevicePath", APIEvent::Type::FTIncorrectDevicePath)
.value("FTOtherError", APIEvent::Type::FTOtherError)
.value("VSABufferCorrupted", APIEvent::Type::VSABufferCorrupted)
.value("VSATimestampNotFound", APIEvent::Type::VSATimestampNotFound)
.value("VSABufferFormatError", APIEvent::Type::VSABufferFormatError)
.value("VSAMaxReadAttemptsReached", APIEvent::Type::VSAMaxReadAttemptsReached)
.value("VSAByteParseFailure", APIEvent::Type::VSAByteParseFailure)
.value("VSAExtendedMessageError", APIEvent::Type::VSAExtendedMessageError)
.value("VSAOtherError", APIEvent::Type::VSAOtherError)
.value("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown);
pybind11::enum_<APIEvent::Severity>(apiEvent, "Severity")
.value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning)
.value("Error", APIEvent::Severity::Error);
apiEvent
.def("get_type", &APIEvent::getType)
.def("get_severity", &APIEvent::getSeverity)
.def("get_description", &APIEvent::getDescription)
.def("describe", &APIEvent::describe)
.def("__repr__", &APIEvent::describe);
pybind11::class_<EventFilter, std::shared_ptr<EventFilter>>(m, "EventFilter")
.def(pybind11::init())
.def(pybind11::init<APIEvent::Type>())
.def(pybind11::init<APIEvent::Severity>())
.def_readwrite("type", &EventFilter::type)
.def_readwrite("severity", &EventFilter::severity)
.def_readwrite("serial", &EventFilter::serial);
}
} // namespace icsneo
@@ -0,0 +1,16 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/eventcallback.h"
namespace icsneo {
void init_eventcallback(pybind11::module_& m) {
pybind11::class_<EventCallback>(m, "EventCallback")
.def(pybind11::init<EventCallback::fn_eventCallback, EventFilter>())
.def(pybind11::init<EventCallback::fn_eventCallback>());
}
} // namespace icsneo
@@ -0,0 +1,18 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/eventmanager.h"
namespace icsneo {
void init_eventmanager(pybind11::module_& m) {
pybind11::class_<EventManager>(m, "EventManager")
.def_static("get_instance", &EventManager::GetInstance, pybind11::return_value_policy::reference)
.def("add_event_callback", &EventManager::addEventCallback)
.def("remove_event_callback", &EventManager::removeEventCallback)
.def("get_last_error", &EventManager::getLastError);
}
} // namespace icsneo
+28
View File
@@ -0,0 +1,28 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/api/version.h"
#include <sstream>
namespace icsneo {
void init_version(pybind11::module_& m) {
pybind11::class_<neoversion_t>(m, "NeoVersion")
.def_readonly("major", &neoversion_t::major)
.def_readonly("minor", &neoversion_t::minor)
.def_readonly("patch", &neoversion_t::patch)
.def_readonly("metadata", &neoversion_t::metadata)
.def_readonly("buildBranch", &neoversion_t::buildBranch)
.def_readonly("buildTag", &neoversion_t::buildTag)
.def("__repr__", [](const neoversion_t& self) -> std::string {
std::stringstream ss;
ss << self;
return ss.str();
});
m.def("get_version", &GetVersion);
}
} // namespace icsneo
@@ -0,0 +1,15 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/callback/messagecallback.h"
namespace icsneo {
void init_messagecallback(pybind11::module_& m) {
pybind11::class_<MessageCallback, std::shared_ptr<MessageCallback>>(m, "MessageCallback")
.def(pybind11::init<MessageCallback::fn_messageCallback, std::shared_ptr<MessageFilter>>());
}
} // namespace icsneo
@@ -0,0 +1,38 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/canerrormessage.h"
namespace icsneo {
void init_errorcodes(pybind11::module_& m) {
pybind11::enum_<CANErrorCode>(m, "CANErrorCode")
.value("NoError", CANErrorCode::NoError)
.value("StuffError", CANErrorCode::StuffError)
.value("FormError", CANErrorCode::FormError)
.value("AckError", CANErrorCode::AckError)
.value("Bit1Error", CANErrorCode::Bit1Error)
.value("Bit0Error", CANErrorCode::Bit0Error)
.value("CRCError", CANErrorCode::CRCError)
.value("NoChange", CANErrorCode::NoChange);
}
void init_canerrormessage(pybind11::module_& m) {
init_errorcodes(m);
pybind11::class_<CANErrorMessage, std::shared_ptr<CANErrorMessage>, Message>(m, "CANErrorMessage")
.def_readonly("network", &CANErrorMessage::network)
.def_readonly("transmitErrorCount", &CANErrorMessage::transmitErrorCount)
.def_readonly("receiveErrorCount", &CANErrorMessage::receiveErrorCount)
.def_readonly("busOff", &CANErrorMessage::busOff)
.def_readonly("errorPassive", &CANErrorMessage::errorPassive)
.def_readonly("errorWarn", &CANErrorMessage::errorWarn)
.def_readonly("dataErrorCode", &CANErrorMessage::dataErrorCode)
.def_readonly("errorCode", &CANErrorMessage::errorCode);
m.attr("CANErrorCountMessage") = m.attr("CANErrorMessage");
}
} // namespace icsneo
@@ -0,0 +1,22 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/canmessage.h"
namespace icsneo {
void init_canmessage(pybind11::module_& m) {
pybind11::class_<CANMessage, std::shared_ptr<CANMessage>, BusMessage>(m, "CANMessage")
.def(pybind11::init())
.def_readwrite("arbid", &CANMessage::arbid)
.def_readwrite("dlcOnWire", &CANMessage::dlcOnWire)
.def_readwrite("isRemote", &CANMessage::isRemote)
.def_readwrite("isExtended", &CANMessage::isExtended)
.def_readwrite("isCANFD", &CANMessage::isCANFD)
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator);
}
} // namespace icsneo
@@ -0,0 +1,27 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethernetmessage.h"
namespace icsneo {
void init_ethernetmessage(pybind11::module_& m) {
pybind11::class_<MACAddress>(m, "MACAddress")
.def("to_string", &MACAddress::toString)
.def("__repr__", &MACAddress::toString);
pybind11::class_<EthernetMessage, std::shared_ptr<EthernetMessage>, BusMessage>(m, "EthernetMessage")
.def(pybind11::init())
.def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def_readwrite("fcs", &EthernetMessage::fcs)
.def_readwrite("frameTooShort", &EthernetMessage::frameTooShort)
.def_readwrite("noPadding", &EthernetMessage::noPadding)
.def("get_destination_mac", &EthernetMessage::getDestinationMAC, pybind11::return_value_policy::reference)
.def("get_source_mac", &EthernetMessage::getSourceMAC, pybind11::return_value_policy::reference)
.def("get_ether_type", &EthernetMessage::getEtherType);
}
} // namespace icsneo
@@ -0,0 +1,35 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethernetstatusmessage.h"
namespace icsneo {
void init_ethernetstatusmessage(pybind11::module_& m) {
pybind11::class_<EthernetStatusMessage, std::shared_ptr<EthernetStatusMessage>, Message> ethernetStatusMessage(m, "EthernetStatusMessage");
pybind11::enum_<EthernetStatusMessage::LinkSpeed>(ethernetStatusMessage, "LinkSpeed")
.value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto)
.value("LinkSpeed10", EthernetStatusMessage::LinkSpeed::LinkSpeed10)
.value("LinkSpeed100", EthernetStatusMessage::LinkSpeed::LinkSpeed100)
.value("LinkSpeed1000", EthernetStatusMessage::LinkSpeed::LinkSpeed1000)
.value("LinkSpeed2500", EthernetStatusMessage::LinkSpeed::LinkSpeed2500)
.value("LinkSpeed5000", EthernetStatusMessage::LinkSpeed::LinkSpeed5000)
.value("LinkSpeed10000", EthernetStatusMessage::LinkSpeed::LinkSpeed10000);
pybind11::enum_<EthernetStatusMessage::LinkMode>(ethernetStatusMessage, "LinkMode")
.value("LinkModeAuto", EthernetStatusMessage::LinkMode::LinkModeAuto)
.value("LinkModeMaster", EthernetStatusMessage::LinkMode::LinkModeMaster)
.value("LinkModeSlave", EthernetStatusMessage::LinkMode::LinkModeSlave)
.value("LinkModeInvalid", EthernetStatusMessage::LinkMode::LinkModeInvalid);
ethernetStatusMessage
.def_readonly("network", &EthernetStatusMessage::network)
.def_readonly("state", &EthernetStatusMessage::state)
.def_readonly("speed", &EthernetStatusMessage::speed)
.def_readonly("duplex", &EthernetStatusMessage::duplex)
.def_readonly("mode", &EthernetStatusMessage::mode);
}
} // namespace icsneo
@@ -0,0 +1,17 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/filter/messagefilter.h"
namespace icsneo {
void init_messagefilter(pybind11::module_& m) {
pybind11::class_<MessageFilter, std::shared_ptr<MessageFilter>>(m, "MessageFilter")
.def(pybind11::init())
.def(pybind11::init<Message::Type>())
.def(pybind11::init<Network::NetID>());
}
} // namespace icsneo
@@ -0,0 +1,79 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/gptpstatusmessage.h"
namespace icsneo {
void init_gptpstatusmessage(pybind11::module_& m) {
pybind11::class_<GPTPStatus, std::shared_ptr<GPTPStatus>, Message> gptpStatus(m, "GPTPStatus");
pybind11::class_<GPTPStatus::Timestamp>(gptpStatus, "Timestamp")
.def_readonly("seconds", &GPTPStatus::Timestamp::seconds)
.def_readonly("nanoseconds", &GPTPStatus::Timestamp::nanoseconds)
.def("to_seconds", &GPTPStatus::Timestamp::toSeconds, pybind11::call_guard<pybind11::gil_scoped_release>());
pybind11::class_<GPTPStatus::ScaledNanoSeconds>(gptpStatus, "ScaledNanoSeconds")
.def_readonly("nanosecondsMSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB)
.def_readonly("nanosecondsLSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB)
.def_readonly("fractionalNanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds);
pybind11::class_<GPTPStatus::PortID>(gptpStatus, "PortID")
.def_readonly("clockIdentity", &GPTPStatus::PortID::clockIdentity)
.def_readonly("portNumber", &GPTPStatus::PortID::portNumber);
pybind11::class_<GPTPStatus::ClockQuality>(gptpStatus, "ClockQuality")
.def_readonly("clockClass", &GPTPStatus::ClockQuality::clockClass)
.def_readonly("clockAccuracy", &GPTPStatus::ClockQuality::clockAccuracy)
.def_readonly("offsetScaledLogVariance", &GPTPStatus::ClockQuality::offsetScaledLogVariance);
pybind11::class_<GPTPStatus::SystemID>(gptpStatus, "SystemID")
.def_readonly("priority1", &GPTPStatus::SystemID::priority1)
.def_readonly("clockQuality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("priority2", &GPTPStatus::SystemID::priority2)
.def_readonly("clockID", &GPTPStatus::SystemID::clockID);
pybind11::class_<GPTPStatus::PriorityVector>(gptpStatus, "PriorityVector")
.def_readonly("sysID", &GPTPStatus::PriorityVector::sysID)
.def_readonly("stepsRemoved", &GPTPStatus::PriorityVector::stepsRemoved)
.def_readonly("portID", &GPTPStatus::PriorityVector::portID)
.def_readonly("portNumber", &GPTPStatus::PriorityVector::portNumber);
pybind11::class_<GPTPStatus::ParentDS>(gptpStatus, "ParentDS")
.def_readonly("parentPortIdentity", &GPTPStatus::ParentDS::parentPortIdentity)
.def_readonly("cumulativeRateRatio", &GPTPStatus::ParentDS::cumulativeRateRatio)
.def_readonly("grandmasterIdentity", &GPTPStatus::ParentDS::grandmasterIdentity)
.def_readonly("gmClockQualityClockClass", &GPTPStatus::ParentDS::gmClockQualityClockClass)
.def_readonly("gmClockQualityClockAccuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy)
.def_readonly("gmClockQualityOffsetScaledLogVariance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance)
.def_readonly("gmPriority1", &GPTPStatus::ParentDS::gmPriority1)
.def_readonly("gmPriority2", &GPTPStatus::ParentDS::gmPriority2);
pybind11::class_<GPTPStatus::CurrentDS>(gptpStatus, "CurrentDS")
.def_readonly("stepsRemoved", &GPTPStatus::CurrentDS::stepsRemoved)
.def_readonly("offsetFromMaster", &GPTPStatus::CurrentDS::offsetFromMaster)
.def_readonly("lastgmPhaseChange", &GPTPStatus::CurrentDS::lastgmPhaseChange)
.def_readonly("lastgmFreqChange", &GPTPStatus::CurrentDS::lastgmFreqChange)
.def_readonly("gmTimeBaseIndicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator)
.def_readonly("gmChangeCount", &GPTPStatus::CurrentDS::gmChangeCount)
.def_readonly("timeOfLastgmChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent)
.def_readonly("timeOfLastgmPhaseChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent)
.def_readonly("timeOfLastgmFreqChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmFreqChangeEvent);
gptpStatus.def_readonly("currentTime", &GPTPStatus::currentTime)
.def_readonly("gmPriority", &GPTPStatus::gmPriority)
.def_readonly("msOffsetNs", &GPTPStatus::msOffsetNs)
.def_readonly("isSync", &GPTPStatus::isSync)
.def_readonly("linkStatus", &GPTPStatus::linkStatus)
.def_readonly("linkDelayNS", &GPTPStatus::linkDelayNS)
.def_readonly("selectedRole", &GPTPStatus::selectedRole)
.def_readonly("asCapable", &GPTPStatus::asCapable)
.def_readonly("isSyntonized", &GPTPStatus::isSyntonized)
.def_readonly("lastRXSyncTS", &GPTPStatus::lastRXSyncTS)
.def_readonly("currentDS", &GPTPStatus::currentDS)
.def_readonly("parentDS", &GPTPStatus::parentDS);
}
} // namespace icsneo
@@ -0,0 +1,59 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/linmessage.h"
namespace icsneo {
void init_linmessage(pybind11::module_& m) {
pybind11::class_<LINErrorFlags>(m, "LINErrorFlags")
.def_readwrite("ErrRxBreakOnly", &LINErrorFlags::ErrRxBreakOnly)
.def_readwrite("ErrRxBreakSyncOnly", &LINErrorFlags::ErrRxBreakSyncOnly)
.def_readwrite("ErrTxRxMismatch", &LINErrorFlags::ErrTxRxMismatch)
.def_readwrite("ErrRxBreakNotZero", &LINErrorFlags::ErrRxBreakNotZero)
.def_readwrite("ErrRxBreakTooShort", &LINErrorFlags::ErrRxBreakTooShort)
.def_readwrite("ErrRxSyncNot55", &LINErrorFlags::ErrRxSyncNot55)
.def_readwrite("ErrRxDataLenOver8", &LINErrorFlags::ErrRxDataLenOver8)
.def_readwrite("ErrFrameSync", &LINErrorFlags::ErrFrameSync)
.def_readwrite("ErrFrameMessageID", &LINErrorFlags::ErrFrameMessageID)
.def_readwrite("ErrFrameResponderData", &LINErrorFlags::ErrFrameResponderData)
.def_readwrite("ErrChecksumMatch", &LINErrorFlags::ErrChecksumMatch);
pybind11::class_<LINStatusFlags>(m, "LINStatusFlags")
.def_readwrite("TxChecksumEnhanced", &LINStatusFlags::TxChecksumEnhanced)
.def_readwrite("TxCommander", &LINStatusFlags::TxCommander)
.def_readwrite("TxResponder", &LINStatusFlags::TxResponder)
.def_readwrite("TxAborted", &LINStatusFlags::TxAborted)
.def_readwrite("UpdateResponderOnce", &LINStatusFlags::UpdateResponderOnce)
.def_readwrite("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce)
.def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered)
.def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly);
pybind11::class_<LINMessage, std::shared_ptr<LINMessage>, BusMessage> linMessage(m, "LINMessage");
pybind11::enum_<LINMessage::Type>(linMessage, "Type")
.value("NOT_SET", LINMessage::Type::NOT_SET)
.value("LIN_COMMANDER_MSG", LINMessage::Type::LIN_COMMANDER_MSG)
.value("LIN_HEADER_ONLY", LINMessage::Type::LIN_HEADER_ONLY)
.value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY)
.value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY)
.value("LIN_UPDATE_RESPONDER", LINMessage::Type::LIN_UPDATE_RESPONDER)
.value("LIN_ERROR", LINMessage::Type::LIN_ERROR);
linMessage
.def(pybind11::init<>())
.def(pybind11::init<uint8_t>())
.def_static("calc_checksum", &LINMessage::calcChecksum)
.def("calc_protected_id", &LINMessage::calcProtectedID)
.def_readwrite("ID", &LINMessage::ID)
.def_readwrite("protectedID", &LINMessage::protectedID)
.def_readwrite("checksum", &LINMessage::checksum)
.def_readwrite("linMsgType", &LINMessage::linMsgType)
.def_readwrite("isEnhancedChecksum", &LINMessage::isEnhancedChecksum)
.def_readwrite("errFlags", &LINMessage::errFlags)
.def_readwrite("statusFlags", &LINMessage::statusFlags);
}
} // namespace icsneo
@@ -0,0 +1,35 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/mdiomessage.h"
namespace icsneo {
void init_mdiomessage(pybind11::module_& m) {
pybind11::class_<MDIOMessage, std::shared_ptr<MDIOMessage>, BusMessage> mdioMessage(m, "MDIOMessage");
pybind11::enum_<MDIOMessage::Clause>(mdioMessage, "Clause")
.value("Clause45", MDIOMessage::Clause::Clause45)
.value("Clause22", MDIOMessage::Clause::Clause22);
pybind11::enum_<MDIOMessage::Direction>(mdioMessage, "Direction")
.value("Write", MDIOMessage::Direction::Write)
.value("Read", MDIOMessage::Direction::Read);
mdioMessage
.def(pybind11::init())
.def_readwrite("isTXMsg", &MDIOMessage::isTXMsg)
.def_readwrite("txTimeout", &MDIOMessage::txTimeout)
.def_readwrite("txAborted", &MDIOMessage::txAborted)
.def_readwrite("txInvalidBus", &MDIOMessage::txInvalidBus)
.def_readwrite("txInvalidPhyAddr", &MDIOMessage::txInvalidPhyAddr)
.def_readwrite("txInvalidRegAddr", &MDIOMessage::txInvalidRegAddr)
.def_readwrite("txInvalidClause", &MDIOMessage::txInvalidClause)
.def_readwrite("txInvalidOpcode", &MDIOMessage::txInvalidOpcode)
.def_readwrite("phyAddress", &MDIOMessage::phyAddress)
.def_readwrite("devAddress", &MDIOMessage::devAddress)
.def_readwrite("regAddress", &MDIOMessage::regAddress)
.def_readwrite("direction", &MDIOMessage::direction)
.def_readwrite("clause", &MDIOMessage::clause);
}
} // namespace icsneo
@@ -0,0 +1,54 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/message.h"
namespace icsneo {
void init_message(pybind11::module_& m) {
pybind11::class_<Message, std::shared_ptr<Message>> message(m, "Message");
pybind11::enum_<Message::Type>(message, "Type")
.value("BusMessage", Message::Type::BusMessage)
.value("CANErrorCount", Message::Type::CANErrorCount)
.value("CANError", Message::Type::CANError)
.value("LINHeaderOnly", Message::Type::LINHeaderOnly)
.value("LINBreak", Message::Type::LINBreak)
.value("Invalid", Message::Type::Invalid)
.value("InternalMessage", Message::Type::InternalMessage)
.value("ReadSettings", Message::Type::ReadSettings)
.value("ResetStatus", Message::Type::ResetStatus)
.value("DeviceVersion", Message::Type::DeviceVersion)
.value("Main51", Message::Type::Main51)
.value("FlexRayControl", Message::Type::FlexRayControl)
.value("EthernetPhyRegister", Message::Type::EthernetPhyRegister)
.value("LogicalDiskInfo", Message::Type::LogicalDiskInfo)
.value("ExtendedResponse", Message::Type::ExtendedResponse)
.value("WiVICommandResponse", Message::Type::WiVICommandResponse)
.value("ScriptStatus", Message::Type::ScriptStatus)
.value("ComponentVersions", Message::Type::ComponentVersions)
.value("SupportedFeatures", Message::Type::SupportedFeatures)
.value("GenericBinaryStatus", Message::Type::GenericBinaryStatus)
.value("LiveData", Message::Type::LiveData)
.value("HardwareInfo", Message::Type::HardwareInfo)
.value("TC10Status", Message::Type::TC10Status)
.value("AppError", Message::Type::AppError)
.value("GPTPStatus", Message::Type::GPTPStatus)
.value("EthernetStatus", Message::Type::EthernetStatus);
message.def(pybind11::init<Message::Type>());
message.def_readonly("type", &Message::type);
message.def_readwrite("timestamp", &Message::timestamp);
pybind11::class_<InternalMessage, std::shared_ptr<InternalMessage>, Message>(m, "InternalMessage")
.def_readwrite("network", &InternalMessage::network)
.def_readwrite("data", &InternalMessage::data);
pybind11::class_<BusMessage, std::shared_ptr<BusMessage>, InternalMessage>(m, "BusMessage")
.def_readwrite("description", &BusMessage::description)
.def_readwrite("transmitted", &BusMessage::transmitted)
.def_readwrite("error", &BusMessage::error);
}
} // namespace icsneo
@@ -0,0 +1,25 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/tc10statusmessage.h"
namespace icsneo {
void init_tc10statusmessage(pybind11::module_& m) {
pybind11::enum_<TC10WakeStatus>(m, "TC10WakeStatus")
.value("NoWakeReceived", TC10WakeStatus::NoWakeReceived)
.value("WakeReceived", TC10WakeStatus::WakeReceived);
pybind11::enum_<TC10SleepStatus>(m, "TC10SleepStatus")
.value("NoSleepReceived", TC10SleepStatus::NoSleepReceived)
.value("SleepReceived", TC10SleepStatus::SleepReceived)
.value("SleepFailed", TC10SleepStatus::SleepFailed)
.value("SleepAborted", TC10SleepStatus::SleepAborted);
pybind11::class_<TC10StatusMessage, std::shared_ptr<TC10StatusMessage>, Message>(m, "TC10StatusMessage")
.def_readonly("wakeStatus", &TC10StatusMessage::wakeStatus)
.def_readonly("sleepStatus", &TC10StatusMessage::sleepStatus);
}
} // namespace icsneo
@@ -0,0 +1,197 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/network.h"
namespace icsneo {
void init_network(pybind11::module_& m) {
pybind11::class_<Network> network(m, "Network");
pybind11::enum_<Network::NetID>(network, "NetID")
.value("Device", Network::NetID::Device)
.value("HSCAN", Network::NetID::HSCAN)
.value("MSCAN", Network::NetID::MSCAN)
.value("SWCAN", Network::NetID::SWCAN)
.value("LSFTCAN", Network::NetID::LSFTCAN)
.value("FordSCP", Network::NetID::FordSCP)
.value("J1708", Network::NetID::J1708)
.value("Aux", Network::NetID::Aux)
.value("J1850VPW", Network::NetID::J1850VPW)
.value("ISO9141", Network::NetID::ISO9141)
.value("DiskData", Network::NetID::DiskData)
.value("Main51", Network::NetID::Main51)
.value("RED", Network::NetID::RED)
.value("SCI", Network::NetID::SCI)
.value("ISO9141_2", Network::NetID::ISO9141_2)
.value("ISO14230", Network::NetID::ISO14230)
.value("LIN", Network::NetID::LIN)
.value("OP_Ethernet1", Network::NetID::OP_Ethernet1)
.value("OP_Ethernet2", Network::NetID::OP_Ethernet2)
.value("OP_Ethernet3", Network::NetID::OP_Ethernet3)
.value("RED_EXT_MEMORYREAD", Network::NetID::RED_EXT_MEMORYREAD)
.value("RED_INT_MEMORYREAD", Network::NetID::RED_INT_MEMORYREAD)
.value("RED_DFLASH_READ", Network::NetID::RED_DFLASH_READ)
.value("NeoMemorySDRead", Network::NetID::NeoMemorySDRead)
.value("CAN_ERRBITS", Network::NetID::CAN_ERRBITS)
.value("NeoMemoryWriteDone", Network::NetID::NeoMemoryWriteDone)
.value("RED_WAVE_CAN1_LOGICAL", Network::NetID::RED_WAVE_CAN1_LOGICAL)
.value("RED_WAVE_CAN2_LOGICAL", Network::NetID::RED_WAVE_CAN2_LOGICAL)
.value("RED_WAVE_LIN1_LOGICAL", Network::NetID::RED_WAVE_LIN1_LOGICAL)
.value("RED_WAVE_LIN2_LOGICAL", Network::NetID::RED_WAVE_LIN2_LOGICAL)
.value("RED_WAVE_LIN1_ANALOG", Network::NetID::RED_WAVE_LIN1_ANALOG)
.value("RED_WAVE_LIN2_ANALOG", Network::NetID::RED_WAVE_LIN2_ANALOG)
.value("RED_WAVE_MISC_ANALOG", Network::NetID::RED_WAVE_MISC_ANALOG)
.value("RED_WAVE_MISCDIO2_LOGICAL", Network::NetID::RED_WAVE_MISCDIO2_LOGICAL)
.value("RED_NETWORK_COM_ENABLE_EX", Network::NetID::RED_NETWORK_COM_ENABLE_EX)
.value("RED_NEOVI_NETWORK", Network::NetID::RED_NEOVI_NETWORK)
.value("RED_READ_BAUD_SETTINGS", Network::NetID::RED_READ_BAUD_SETTINGS)
.value("RED_OLDFORMAT", Network::NetID::RED_OLDFORMAT)
.value("RED_SCOPE_CAPTURE", Network::NetID::RED_SCOPE_CAPTURE)
.value("RED_HARDWARE_EXCEP", Network::NetID::RED_HARDWARE_EXCEP)
.value("RED_GET_RTC", Network::NetID::RED_GET_RTC)
.value("ISO9141_3", Network::NetID::ISO9141_3)
.value("HSCAN2", Network::NetID::HSCAN2)
.value("HSCAN3", Network::NetID::HSCAN3)
.value("OP_Ethernet4", Network::NetID::OP_Ethernet4)
.value("OP_Ethernet5", Network::NetID::OP_Ethernet5)
.value("ISO9141_4", Network::NetID::ISO9141_4)
.value("LIN2", Network::NetID::LIN2)
.value("LIN3", Network::NetID::LIN3)
.value("LIN4", Network::NetID::LIN4)
.value("RED_App_Error", Network::NetID::RED_App_Error)
.value("CGI", Network::NetID::CGI)
.value("Reset_Status", Network::NetID::Reset_Status)
.value("FB_Status", Network::NetID::FB_Status)
.value("App_Signal_Status", Network::NetID::App_Signal_Status)
.value("Read_Datalink_Cm_Tx_Msg", Network::NetID::Read_Datalink_Cm_Tx_Msg)
.value("Read_Datalink_Cm_Rx_Msg", Network::NetID::Read_Datalink_Cm_Rx_Msg)
.value("Logging_Overflow", Network::NetID::Logging_Overflow)
.value("ReadSettings", Network::NetID::ReadSettings)
.value("HSCAN4", Network::NetID::HSCAN4)
.value("HSCAN5", Network::NetID::HSCAN5)
.value("RS232", Network::NetID::RS232)
.value("UART", Network::NetID::UART)
.value("UART2", Network::NetID::UART2)
.value("UART3", Network::NetID::UART3)
.value("UART4", Network::NetID::UART4)
.value("SWCAN2", Network::NetID::SWCAN2)
.value("Ethernet_DAQ", Network::NetID::Ethernet_DAQ)
.value("Data_To_Host", Network::NetID::Data_To_Host)
.value("TextAPI_To_Host", Network::NetID::TextAPI_To_Host)
.value("SPI1", Network::NetID::SPI1)
.value("OP_Ethernet6", Network::NetID::OP_Ethernet6)
.value("Red_VBat", Network::NetID::Red_VBat)
.value("OP_Ethernet7", Network::NetID::OP_Ethernet7)
.value("OP_Ethernet8", Network::NetID::OP_Ethernet8)
.value("OP_Ethernet9", Network::NetID::OP_Ethernet9)
.value("OP_Ethernet10", Network::NetID::OP_Ethernet10)
.value("OP_Ethernet11", Network::NetID::OP_Ethernet11)
.value("FlexRay1a", Network::NetID::FlexRay1a)
.value("FlexRay1b", Network::NetID::FlexRay1b)
.value("FlexRay2a", Network::NetID::FlexRay2a)
.value("FlexRay2b", Network::NetID::FlexRay2b)
.value("LIN5", Network::NetID::LIN5)
.value("FlexRay", Network::NetID::FlexRay)
.value("FlexRay2", Network::NetID::FlexRay2)
.value("OP_Ethernet12", Network::NetID::OP_Ethernet12)
.value("I2C", Network::NetID::I2C)
.value("MOST25", Network::NetID::MOST25)
.value("MOST50", Network::NetID::MOST50)
.value("MOST150", Network::NetID::MOST150)
.value("Ethernet", Network::NetID::Ethernet)
.value("GMFSA", Network::NetID::GMFSA)
.value("TCP", Network::NetID::TCP)
.value("HSCAN6", Network::NetID::HSCAN6)
.value("HSCAN7", Network::NetID::HSCAN7)
.value("LIN6", Network::NetID::LIN6)
.value("LSFTCAN2", Network::NetID::LSFTCAN2)
.value("LogicalDiskInfo", Network::NetID::LogicalDiskInfo)
.value("WiVICommand", Network::NetID::WiVICommand)
.value("ScriptStatus", Network::NetID::ScriptStatus)
.value("EthPHYControl", Network::NetID::EthPHYControl)
.value("ExtendedCommand", Network::NetID::ExtendedCommand)
.value("ExtendedData", Network::NetID::ExtendedData)
.value("FlexRayControl", Network::NetID::FlexRayControl)
.value("CoreMiniPreLoad", Network::NetID::CoreMiniPreLoad)
.value("HW_COM_Latency_Test", Network::NetID::HW_COM_Latency_Test)
.value("DeviceStatus", Network::NetID::DeviceStatus)
.value("UDP", Network::NetID::UDP)
.value("ForwardedMessage", Network::NetID::ForwardedMessage)
.value("I2C2", Network::NetID::I2C2)
.value("I2C3", Network::NetID::I2C3)
.value("I2C4", Network::NetID::I2C4)
.value("Ethernet2", Network::NetID::Ethernet2)
.value("A2B1", Network::NetID::A2B1)
.value("A2B2", Network::NetID::A2B2)
.value("Ethernet3", Network::NetID::Ethernet3)
.value("WBMS", Network::NetID::WBMS)
.value("DWCAN9", Network::NetID::DWCAN9)
.value("DWCAN10", Network::NetID::DWCAN10)
.value("DWCAN11", Network::NetID::DWCAN11)
.value("DWCAN12", Network::NetID::DWCAN12)
.value("DWCAN13", Network::NetID::DWCAN13)
.value("DWCAN14", Network::NetID::DWCAN14)
.value("DWCAN15", Network::NetID::DWCAN15)
.value("DWCAN16", Network::NetID::DWCAN16)
.value("LIN7", Network::NetID::LIN7)
.value("LIN8", Network::NetID::LIN8)
.value("SPI2", Network::NetID::SPI2)
.value("MDIO1", Network::NetID::MDIO1)
.value("MDIO2", Network::NetID::MDIO2)
.value("MDIO3", Network::NetID::MDIO3)
.value("MDIO4", Network::NetID::MDIO4)
.value("MDIO5", Network::NetID::MDIO5)
.value("MDIO6", Network::NetID::MDIO6)
.value("MDIO7", Network::NetID::MDIO7)
.value("MDIO8", Network::NetID::MDIO8)
.value("OP_Ethernet13", Network::NetID::OP_Ethernet13)
.value("OP_Ethernet14", Network::NetID::OP_Ethernet14)
.value("OP_Ethernet15", Network::NetID::OP_Ethernet15)
.value("OP_Ethernet16", Network::NetID::OP_Ethernet16)
.value("SPI3", Network::NetID::SPI3)
.value("SPI4", Network::NetID::SPI4)
.value("SPI5", Network::NetID::SPI5)
.value("SPI6", Network::NetID::SPI6)
.value("SPI7", Network::NetID::SPI7)
.value("SPI8", Network::NetID::SPI8)
.value("LIN9", Network::NetID::LIN9)
.value("LIN10", Network::NetID::LIN10)
.value("LIN11", Network::NetID::LIN11)
.value("LIN12", Network::NetID::LIN12)
.value("LIN13", Network::NetID::LIN13)
.value("LIN14", Network::NetID::LIN14)
.value("LIN15", Network::NetID::LIN15)
.value("LIN16", Network::NetID::LIN16)
.value("Any", Network::NetID::Any)
.value("Invalid", Network::NetID::Invalid);
pybind11::enum_<Network::Type>(network, "Type")
.value("Invalid", Network::Type::Invalid)
.value("Internal", Network::Type::Internal)
.value("CAN", Network::Type::CAN)
.value("LIN", Network::Type::LIN)
.value("FlexRay", Network::Type::FlexRay)
.value("MOST", Network::Type::MOST)
.value("Ethernet", Network::Type::Ethernet)
.value("LSFTCAN", Network::Type::LSFTCAN)
.value("SWCAN", Network::Type::SWCAN)
.value("ISO9141", Network::Type::ISO9141)
.value("I2C", Network::Type::I2C)
.value("A2B", Network::Type::A2B)
.value("SPI", Network::Type::SPI)
.value("MDIO", Network::Type::MDIO)
.value("Any", Network::Type::Any)
.value("Other", Network::Type::Other);
network
.def(pybind11::init<Network::NetID>())
.def("__repr__", [](Network& self) { return Network::GetNetIDString(self.getNetID()); })
.def_static("get_net_id_string", &Network::GetNetIDString, pybind11::arg("netid"), pybind11::arg("expand") = true)
.def("get_net_id", &Network::getNetID)
.def("get_type", &Network::getType);
}
} // namespace icsneo
@@ -0,0 +1,47 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include "icsneo/device/device.h"
namespace icsneo {
void init_device(pybind11::module_& m) {
pybind11::class_<Device, std::shared_ptr<Device>>(m, "Device")
.def("get_type", &Device::getType)
.def("get_serial", &Device::getSerial)
.def("get_serial_number", &Device::getSerialNumber)
.def("get_product_name", &Device::getProductName)
.def("open", [](Device& device) { return device.open(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("close", &Device::close, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_open", &Device::isOpen)
.def("go_online", &Device::goOnline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("go_offline", &Device::goOffline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_online", &Device::isOnline)
.def("enable_message_polling", &Device::enableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("disable_message_polling", &Device::disableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_message_polling_enabled", &Device::isMessagePollingEnabled)
.def("get_messages", [](Device& device) { return device.getMessages(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_current_message_count", &Device::getCurrentMessageCount)
.def("get_polling_message_limit", &Device::getPollingMessageLimit)
.def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("remove_message_callback", &Device::removeMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<BusMessage>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference)
.def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference)
.def("get_rtc", &Device::getRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("describe", &Device::describe)
.def("is_online_supported", &Device::isOnlineSupported)
.def("supports_tc10", &Device::supportsTC10)
.def("request_tc10_wake", &Device::requestTC10Wake, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_sleep", &Device::requestTC10Sleep, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_gptp_status", &Device::getGPTPStatus, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("__repr__", &Device::describe);
}
} // namespace icsneo
@@ -0,0 +1,72 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/device/devicetype.h"
namespace icsneo {
void init_devicetype(pybind11::module_& m) {
pybind11::class_<DeviceType> deviceType(m, "DeviceType");
pybind11::enum_<DeviceType::Enum>(deviceType, "Enum")
.value("Unknown", DeviceType::Enum::Unknown)
.value("BLUE", DeviceType::Enum::BLUE)
.value("ECU_AVB", DeviceType::Enum::ECU_AVB)
.value("RADSupermoon", DeviceType::Enum::RADSupermoon)
.value("DW_VCAN", DeviceType::Enum::DW_VCAN)
.value("RADMoon2", DeviceType::Enum::RADMoon2)
.value("RADMars", DeviceType::Enum::RADMars)
.value("VCAN4_1", DeviceType::Enum::VCAN4_1)
.value("FIRE", DeviceType::Enum::FIRE)
.value("RADPluto", DeviceType::Enum::RADPluto)
.value("VCAN4_2EL", DeviceType::Enum::VCAN4_2EL)
.value("RADIO_CANHUB", DeviceType::Enum::RADIO_CANHUB)
.value("NEOECU12", DeviceType::Enum::NEOECU12)
.value("OBD2_LCBADGE", DeviceType::Enum::OBD2_LCBADGE)
.value("RADMoonDuo", DeviceType::Enum::RADMoonDuo)
.value("FIRE3", DeviceType::Enum::FIRE3)
.value("VCAN3", DeviceType::Enum::VCAN3)
.value("RADJupiter", DeviceType::Enum::RADJupiter)
.value("VCAN4_IND", DeviceType::Enum::VCAN4_IND)
.value("RADGigastar", DeviceType::Enum::RADGigastar)
.value("RED2", DeviceType::Enum::RED2)
.value("EtherBADGE", DeviceType::Enum::EtherBADGE)
.value("RAD_A2B", DeviceType::Enum::RAD_A2B)
.value("RADEpsilon", DeviceType::Enum::RADEpsilon)
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADComet", DeviceType::Enum::RADComet)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("Connect", DeviceType::Enum::Connect)
.value("RADComet3", DeviceType::Enum::RADComet3)
.value("RADMoonT1S", DeviceType::Enum::RADMoonT1S)
.value("RADGigastar2", DeviceType::Enum::RADGigastar2)
.value("RED", DeviceType::Enum::RED)
.value("ECU", DeviceType::Enum::ECU)
.value("IEVB", DeviceType::Enum::IEVB)
.value("Pendant", DeviceType::Enum::Pendant)
.value("OBD2_PRO", DeviceType::Enum::OBD2_PRO)
.value("ECUChip_UART", DeviceType::Enum::ECUChip_UART)
.value("PLASMA", DeviceType::Enum::PLASMA)
.value("NEOAnalog", DeviceType::Enum::NEOAnalog)
.value("CT_OBD", DeviceType::Enum::CT_OBD)
.value("ION", DeviceType::Enum::ION)
.value("RADStar", DeviceType::Enum::RADStar)
.value("VCAN4_4", DeviceType::Enum::VCAN4_4)
.value("VCAN4_2", DeviceType::Enum::VCAN4_2)
.value("CMProbe", DeviceType::Enum::CMProbe)
.value("EEVB", DeviceType::Enum::EEVB)
.value("VCANrf", DeviceType::Enum::VCANrf)
.value("FIRE2", DeviceType::Enum::FIRE2)
.value("Flex", DeviceType::Enum::Flex)
.value("RADGalaxy", DeviceType::Enum::RADGalaxy)
.value("RADStar2", DeviceType::Enum::RADStar2)
.value("VividCAN", DeviceType::Enum::VividCAN)
.value("OBD2_SIM", DeviceType::Enum::OBD2_SIM);
deviceType.def(pybind11::init<DeviceType::Enum>());
deviceType.def("get_device_type", &DeviceType::getDeviceType);
deviceType.def("get_generic_product_name", &DeviceType::getGenericProductName);
}
} // namespace icsneo
+57
View File
@@ -0,0 +1,57 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/icsneocpp.h"
namespace icsneo {
void init_event(pybind11::module_&);
void init_eventcallback(pybind11::module_&);
void init_eventmanager(pybind11::module_&);
void init_network(pybind11::module_&);
void init_devicetype(pybind11::module_&);
void init_message(pybind11::module_&);
void init_canmessage(pybind11::module_&);
void init_canerrormessage(pybind11::module_&);
void init_ethernetmessage(pybind11::module_&);
void init_linmessage(pybind11::module_&);
void init_tc10statusmessage(pybind11::module_&);
void init_gptpstatusmessage(pybind11::module_&);
void init_mdiomessage(pybind11::module_&);
void init_ethernetstatusmessage(pybind11::module_&);
void init_device(pybind11::module_&);
void init_messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&);
PYBIND11_MODULE(icsneopy, m) {
pybind11::options options;
options.disable_enum_members_docstring();
m.doc() = "libicsneo Python module";
init_event(m);
init_eventcallback(m);
init_eventmanager(m);
init_version(m);
init_devicetype(m);
init_network(m);
init_message(m);
init_canmessage(m);
init_canerrormessage(m);
init_ethernetmessage(m);
init_linmessage(m);
init_tc10statusmessage(m);
init_gptpstatusmessage(m);
init_mdiomessage(m);
init_ethernetstatusmessage(m);
init_messagefilter(m);
init_messagecallback(m);
init_device(m);
m.def("find_all_devices", &FindAllDevices);
m.def("get_supported_devices", &GetSupportedDevices);
m.def("get_last_error", &GetLastError);
}
} // namespace icsneo
View File
+17
View File
@@ -0,0 +1,17 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
+293
View File
@@ -0,0 +1,293 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "icsneoc2rs"
version = "0.1.0"
dependencies = [
"bindgen",
"scopeguard",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "log"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-hash"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+22
View File
@@ -0,0 +1,22 @@
[package]
name = "icsneoc2rs"
version = "0.1.0"
edition = "2021"
[lib]
name = "icsneoc2rs"
crate-type = ["rlib", "staticlib", "cdylib"]
path = "src/lib.rs"
[[example]]
name = "simple"
path = "examples/simple.rs"
[dev-dependencies]
scopeguard = "1.2.0"
[features]
static = []
[build-dependencies]
bindgen = "0.71.1"
+40
View File
@@ -0,0 +1,40 @@
use std::env;
use std::path::PathBuf;
pub fn main() {
// Tell cargo to look for shared libraries in the specified directory
println!("cargo:rustc-link-search=../../../build");
// Tell cargo to tell rustc to link the system
// shared library.
println!("cargo:rustc-link-lib=icsneoc2");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("../../../include/icsneo/icsneoc2.h")
.clang_arg("-I../../../include")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.derive_default(true)
.derive_debug(true)
.derive_partialeq(true)
.derive_copy(true)
.default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true })
.default_alias_style(bindgen::AliasVariation::TypeAlias)
.generate_cstr(true)
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
+333
View File
@@ -0,0 +1,333 @@
use icsneoc2rs::ffi::_icsneoc2_msg_bus_type_t::*;
use icsneoc2rs::ffi::_icsneoc2_msg_type_t::*;
use icsneoc2rs::ffi::_icsneoc2_netid_t;
use icsneoc2rs::ffi::_icsneoc2_netid_t::*;
use icsneoc2rs::ffi::_icsneoc2_open_options_t::*;
use icsneoc2rs::ffi::icsneoc2_message_t;
use icsneoc2rs::ffi::icsneoc2_msg_bus_type_t;
use icsneoc2rs::ffi::icsneoc2_msg_type_t;
use icsneoc2rs::ffi::icsneoc2_netid_t;
use icsneoc2rs::Device;
use icsneoc2rs::Error;
use icsneoc2rs::Result as ICSNeoResult;
use scopeguard::defer;
fn main() -> ICSNeoResult<()> {
print!("Finding devices... ");
let devices = Device::find_all(255)?;
println!(
"OK, {} device{} found...",
devices.len(),
if devices.len() > 1 { "s" } else { "" }
);
for device in devices {
device.device_is_valid()?;
// Get description of the device
let description = match device.device_description_get() {
Ok(description) => description,
Err(err) => {
println!("Failed to get description of device: {err}");
continue;
}
};
println!("{} @ Handle {:?}", description, device.handle);
// Get/Set open options
let mut open_options = match device.device_open_options_get() {
Ok(value) => value,
Err(err) => {
println!("Failed to get open options of device: {err}");
continue;
}
};
// Disable Syncing RTC and going online
open_options &= !(icsneoc2_open_options_sync_rtc as u32);
open_options &= !(icsneoc2_open_options_go_online as u32);
match device.device_open_options_set(open_options) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("\tDevice open options: {open_options:#02x}");
// Open the device
print!("\tOpening device... ");
match device.device_open() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
defer! {
print_device_events(&device, &description).expect("Critical: Failed to print device events");
}
// Get timestamp resolution of the device
print!("\tGetting timestamp resolution... ");
let timestamp_resolution = match device.device_timestamp_resolution_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{timestamp_resolution}ns");
// Get baudrates for HSCAN
print!("\tGetting HSCAN baudrate... ");
let baudrate = match device.device_baudrate_get(icsneoc2_netid_hscan) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{baudrate}mbit/s");
// Get FD baudrates for HSCAN
print!("\tGetting FD HSCAN baudrate... ");
let fd_baudrate = match device.device_canfd_baudrate_get(icsneoc2_netid_hscan) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{fd_baudrate}mbit/s");
// Set baudrates for HSCAN
// saveToDevice: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
print!("\tSetting HSCAN baudrate... ");
let save_to_device = false;
match device.device_baudrate_set(icsneoc2_netid_hscan, baudrate, save_to_device) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Set FD baudrates for HSCAN
print!("\tSetting FD HSCAN baudrate... ");
match device.device_canfd_baudrate_set(icsneoc2_netid_hscan, fd_baudrate, save_to_device) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Get RTC
print!("\tGetting RTC... ");
let current_rtc = match device.device_rtc_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{current_rtc}");
// Set RTC
print!("\tSetting RTC... ");
match device.device_rtc_set(current_rtc) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Get RTC
print!("\tGetting RTC... ");
let rtc = match device.device_rtc_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{rtc}");
// Go online, start acking traffic
print!("\tGoing online... ");
match device.device_go_online(true) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
let is_online = match device.device_is_online() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{}", if is_online { "Online" } else { "Offline" });
// Transmit CAN messages
if transmit_can_messages(&device).is_err() {
continue;
}
println!("\tWaiting 1 second for messages...");
std::thread::sleep(std::time::Duration::from_secs(1));
// Get the messages
let messages = match device.device_messages_get(20000, 3000) {
Ok(messages) => messages,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
// Process the messages
if process_messages(&device, messages).is_err() {
continue;
}
// Close the device
print!("\tClosing device... ");
match device.device_close() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
}
Ok(())
}
fn print_error(device: &Device, device_description: &String, err: Error) {
println!("Failed: {err}");
print_device_events(device, device_description)
.expect("Critical: Failed to print device events");
}
fn transmit_can_messages(device: &Device) -> ICSNeoResult<()> {
const MESSAGE_COUNT: usize = 100;
println!("\tTransmitting {MESSAGE_COUNT} messages...");
for i in 0..MESSAGE_COUNT {
let message = match device.message_can_create(1) {
Ok(messages) => messages[0],
Err(err) => {
println!("Failed to create CAN message #{i}: {err}");
continue;
}
};
device.message_netid_set(message, icsneoc2_netid_hscan)?;
device.message_can_arbid_set(message, 0x10)?;
device.message_can_canfd_set(message, true)?;
device.message_can_extended_set(message, true)?;
device.message_can_baudrate_switch_set(message, true)?;
device.message_data_set(
message,
vec![
(i >> 56 & 0xFF) as u8,
(i >> 48 & 0xFF) as u8,
(i >> 40 & 0xFF) as u8,
(i >> 32 & 0xFF) as u8,
(i >> 24 & 0xFF) as u8,
(i >> 16 & 0xFF) as u8,
(i >> 8 & 0xFF) as u8,
(i & 0xFF) as u8,
],
)?;
device.message_can_dlc_set(message, -1)?;
device.device_messages_transmit(vec![message])?;
}
Ok(())
}
fn process_messages(device: &Device, messages: Vec<*mut icsneoc2_message_t>) -> ICSNeoResult<()> {
let mut tx_count: u32 = 0;
for (i, message) in messages.iter().enumerate() {
// Get the message type
let msg_type = device.message_type_get(*message)?;
// Get the message type name
let msg_type_name = device.message_type_name_get(msg_type)?;
// Check if the message is a bus message, ignore otherwise
if msg_type != icsneoc2_msg_type_bus as icsneoc2_msg_type_t {
println!("\tIgnoring message type : {msg_type} ({msg_type_name})");
continue;
}
// Get the message bus type
let msg_bus_type = device.message_bus_type_get(*message)?;
// Get the message type name
let msg_bus_type_name = device.bus_type_name_get(msg_bus_type)?;
// Check if message is a transmit message
if device.message_is_transmit(*message)? {
tx_count += 1;
continue;
}
println!("\t{i} Message type: {msg_type} bus type: {msg_bus_type_name} ({msg_bus_type})\n");
// Check if the message is a CAN message, ignore otherwise
if msg_bus_type == icsneoc2_msg_bus_type_can as icsneoc2_msg_bus_type_t {
let netid = device.message_netid_get(*message)?;
let netid_name = device.netid_name_get(netid)?;
let arbid = device.message_can_arbid_get(*message)?;
let dlc = device.message_can_dlc_get(*message)?;
let is_remote = device.message_can_is_remote(*message)?;
let is_canfd = device.message_can_is_canfd(*message)?;
let is_extended = device.message_can_is_extended(*message)?;
let data = device.message_data_get(*message, 64)?;
// Finally lets print the RX message
println!("\t NetID: {netid_name} ({:#02x})\tArbID: {arbid:#02x}\t DLC: {dlc}\t Remote: {is_remote}\t \
CANFD: {is_canfd}\t Extended: {is_extended}\t Data length: {}\n", netid as icsneoc2_netid_t,data.len());
println!("\t Data: {data:#02x?}\n");
} else {
println!("\tIgnoring bus message type: {msg_bus_type} ({msg_bus_type_name})\n");
}
}
println!(
"\tReceived {} messages total, {} were TX messages",
messages.len(),
tx_count
);
Ok(())
}
fn print_device_events(device: &Device, device_description: &String) -> ICSNeoResult<()> {
let events = match device.device_events_get(1024) {
Ok(events) => events,
Err(err) => {
println!("Failed to get device events: {err}");
return Err(err);
}
};
for (i, event) in events.iter().enumerate() {
let description = match device.event_description_get(*event) {
Ok(description) => description,
Err(err) => {
println!("Failed to get event description: {err}");
continue;
}
};
println!("\t{device_description}: Event {i}: {description}");
}
// Get global events
let global_events = match device.events_get(1024) {
Ok(events) => events,
Err(err) => {
println!("Failed to get global events: {err}");
return Err(err);
}
};
for (i, event) in global_events.iter().enumerate() {
let description = match device.event_description_get(*event) {
Ok(description) => description,
Err(err) => {
println!("Failed to get event description: {err}");
continue;
}
};
println!("\t{device_description}: Global Event {i}: {description}");
}
println!(
"\t{device_description}: Received {} events and {} global events\n",
events.len(),
global_events.len()
);
Ok(())
}
+5
View File
@@ -0,0 +1,5 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+902
View File
@@ -0,0 +1,902 @@
pub mod ffi;
use ffi::_icsneoc2_error_t::{icsneoc2_error_invalid_device, icsneoc2_error_success};
use ffi::_icsneoc2_open_options_t::*;
use ffi::*;
use std::ffi::CString;
use std::fmt::Display;
#[derive(Debug, Clone)]
pub enum Error {
/// icsneoc2 API error
APIError(icsneoc2_error_t, String),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::APIError(error_code, error_string) => write!(f, "API Error: \"{}\" ({})", error_string, error_code),
}
}
}
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Device {
/// Handle to the device.
pub handle: *mut icsneoc2_device_t,
}
impl Drop for Device {
fn drop(&mut self) {
// Make sure the device is closed before we go out of scope.
self.device_close().expect("Failed to close device!");
}
}
impl Device {
pub fn find_all(device_count: u32) -> Result<Vec<Self>> {
// Find all the devices
const MAX_DEVICE_COUNT: u32 = 255;
let mut devices: [*mut icsneoc2_device_t; MAX_DEVICE_COUNT as usize] =
[std::ptr::null_mut(); 255];
let mut devices_count: u32 = if device_count > MAX_DEVICE_COUNT {
MAX_DEVICE_COUNT
} else {
device_count
};
let res = unsafe {
icsneoc2_device_find_all(
devices.as_mut_ptr(),
&mut devices_count as *mut u32,
std::ptr::null_mut(),
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Return the results
let found_devices: Vec<Self> = devices[..devices_count as usize]
.iter()
.map(|d| Self { handle: *d })
.collect();
Ok(found_devices)
}
pub fn bus_type_name_get(&self, bus_type: icsneoc2_msg_bus_type_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_bus_type_name_get(bus_type, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_baudrate_get(&self, netid: _icsneoc2_netid_t) -> Result<u64> {
let mut value: u64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_baudrate_get(self.handle, netid as icsneoc2_netid_t, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_baudrate_set(
&self,
netid: _icsneoc2_netid_t,
value: u64,
save: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_baudrate_set(self.handle, netid as icsneoc2_netid_t, value, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_canfd_baudrate_get(&self, netid: _icsneoc2_netid_t) -> Result<u64> {
let mut value: u64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_canfd_baudrate_get(self.handle, netid as icsneoc2_netid_t, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_canfd_baudrate_set(
&self,
netid: _icsneoc2_netid_t,
value: u64,
save: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_canfd_baudrate_set(self.handle, netid as icsneoc2_netid_t, value, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_close(&self) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_close(self.handle) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_description_get(&self) -> Result<String> {
// Get the error code
let mut description: Vec<u8> = vec![0; 255];
let mut description_length: u32 = 255;
let res = unsafe {
icsneoc2_device_description_get(
self.handle,
description.as_mut_ptr() as *mut i8,
&mut description_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
description.resize(description_length as usize, 0);
let description_str = {
CString::new(description)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(description_str)
}
pub fn device_events_get(&self, event_count: u32) -> Result<Vec<*mut icsneoc2_event_t>> {
let mut events: Vec<*mut icsneoc2_event_t> =
vec![std::ptr::null_mut(); event_count as usize];
let mut event_count: u32 = event_count;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_events_get(self.handle, events.as_mut_ptr(), &mut event_count)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
events.resize(event_count as usize, std::ptr::null_mut());
Ok(events)
}
pub fn device_go_online(&self, go_online: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_go_online(self.handle, go_online) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_is_online(&self) -> Result<bool> {
let mut is_online: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_online(self.handle, &mut is_online) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_online)
}
pub fn device_is_online_supported(&self) -> Result<bool> {
let mut is_online_supported: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_is_online_supported(self.handle, &mut is_online_supported)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_online_supported)
}
pub fn device_is_valid(&self) -> Result<bool> {
let res: icsneoc2_error_t = unsafe { icsneoc2_device_is_valid(self.handle) };
match res {
res if res == icsneoc2_error_success as icsneoc2_error_t => Ok(true),
res if res == icsneoc2_error_invalid_device as icsneoc2_error_t => Ok(false),
_ => Err(Self::error_code_get(res)),
}
}
pub fn device_is_open(&self) -> Result<bool> {
let mut is_open: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_open(self.handle, &mut is_open) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_open)
}
pub fn device_is_disconnected(&self) -> Result<bool> {
let mut is_disconnected: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_disconnected(self.handle, &mut is_disconnected) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_disconnected)
}
pub fn device_load_default_settings(&self, save: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_load_default_settings(self.handle, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_message_count_get(&self) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_count_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_get(&self) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_limit_get(&self) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_limit_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_set(&self, enable: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_set(self.handle, enable) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_message_polling_set_limit(&self, value: u32) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_set_limit(self.handle, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_messages_get(
&self,
message_count: u32,
timeout_ms: u32,
) -> Result<Vec<*mut icsneoc2_message_t>> {
let mut messages: Vec<*mut icsneoc2_message_t> =
vec![std::ptr::null_mut(); message_count as usize];
let mut message_count: u32 = message_count;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_messages_get(
self.handle,
messages.as_mut_ptr(),
&mut message_count,
timeout_ms,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
messages.resize(message_count as usize, std::ptr::null_mut());
Ok(messages)
}
pub fn device_messages_transmit(&self, messages: Vec<*mut icsneoc2_message_t>) -> Result<u32> {
let mut messages_count: u32 = messages.len() as u32;
let mut messages = messages;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_messages_transmit(
self.handle,
messages.as_mut_ptr(),
&mut messages_count,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(messages_count)
}
pub fn device_open(&self) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_open(self.handle) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_open_options_get(&self) -> Result<ffi::icsneoc2_open_options_t> {
let mut open_options: ffi::icsneoc2_open_options_t =
icsneoc2_open_options_none as ffi::icsneoc2_open_options_t;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_open_options_get(self.handle, &mut open_options) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(open_options)
}
pub fn device_open_options_set(
&self,
open_options: ffi::icsneoc2_open_options_t,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_open_options_set(self.handle, open_options) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_rtc_get(&self) -> Result<i64> {
let mut value: i64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_rtc_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_rtc_set(&self, value: i64) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_rtc_set(self.handle, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_serial_get(&self) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_device_serial_get(self.handle, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_supports_tc10(&self) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_supports_tc10(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_timestamp_resolution_get(&self) -> Result<u32> {
let mut timestamp_resolution: u32 = 0;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_timestamp_resolution_get(self.handle, &mut timestamp_resolution)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(timestamp_resolution)
}
pub fn device_type_from_type(&self, device_type: icsneoc2_devicetype_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_device_type_name_get(
device_type,
str.as_mut_ptr() as *mut i8,
&mut str_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_type_get(&self) -> Result<icsneoc2_devicetype_t> {
let mut value: icsneoc2_devicetype_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_type_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn error_code_get(error_code: icsneoc2_error_t) -> Error {
// Get the error code
let mut error_description: Vec<u8> = vec![0; 255];
let mut error_description_length: u32 = 255;
let res = unsafe {
icsneoc2_error_code_get(
error_code,
error_description.as_mut_ptr() as *mut i8,
&mut error_description_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Error::APIError(res, "icsneoc2_error_code_get() failed.".to_string());
}
// Convert the vec to an String
error_description.resize(error_description_length as usize, 0);
let error_str = CString::new(error_description)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string");
Error::APIError(error_code, error_str)
}
pub fn event_description_get(&self, event: *mut icsneoc2_event_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_event_description_get(event, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn events_get(&self, event_count: u32) -> Result<Vec<*mut icsneoc2_event_t>> {
let mut events: Vec<*mut icsneoc2_event_t> =
vec![std::ptr::null_mut(); event_count as usize];
let mut event_count: u32 = event_count;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_events_get(events.as_mut_ptr(), &mut event_count) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
events.resize(event_count as usize, std::ptr::null_mut());
Ok(events)
}
pub fn message_bus_type_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<icsneoc2_msg_bus_type_t> {
let mut value: icsneoc2_msg_bus_type_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_bus_type_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_arbid_get(&self, message: *mut icsneoc2_message_t) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_arbid_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_arbid_set(
&self,
message: *mut icsneoc2_message_t,
value: u32,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_arbid_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_baudrate_switch_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_baudrate_switch_get(self.handle, message, &mut value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_baudrate_switch_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_baudrate_switch_set(self.handle, message, value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_canfd_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_canfd_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_create(&self, message_count: u32) -> Result<Vec<*mut icsneoc2_message_t>> {
let mut messages: Vec<*mut icsneoc2_message_t> =
vec![std::ptr::null_mut(); message_count as usize];
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_create(self.handle, messages.as_mut_ptr(), message_count)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(messages)
}
pub fn message_can_dlc_get(&self, message: *mut icsneoc2_message_t) -> Result<i32> {
let mut value: i32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_dlc_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_dlc_set(&self, message: *mut icsneoc2_message_t, value: i32) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_dlc_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_error_state_indicator_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_error_state_indicator_get(self.handle, message, &mut value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_extended_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_extended_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_free(&self, message: *mut icsneoc2_message_t) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_message_can_free(self.handle, message) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_is_canfd(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_canfd(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_is_extended(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_extended(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_is_remote(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_remote(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_data_get(
&self,
message: *mut icsneoc2_message_t,
data_length: u32,
) -> Result<Vec<u8>> {
let mut data: Vec<u8> = vec![0; data_length as usize];
let mut data_length = data_length;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_data_get(
self.handle,
message,
data.as_mut_ptr(),
&mut data_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
data.resize(data_length as usize, 0);
Ok(data)
}
pub fn message_data_set(&self, message: *mut icsneoc2_message_t, data: Vec<u8>) -> Result<()> {
let mut data = data;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_data_set(
self.handle,
message,
data.as_mut_ptr(),
data.len() as u32,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_is_transmit(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_is_transmit(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_is_valid(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_is_valid(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_netid_get(&self, message: *mut icsneoc2_message_t) -> Result<_icsneoc2_netid_t> {
let mut value: icsneoc2_netid_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_netid_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// TODO: This is gross, there is probably a better way to do this.
// TryFrom impl would be a lot of work to implement because there are so many values.
// We are relying on the function call to always return a valid value.
let value: _icsneoc2_netid_t = unsafe { std::mem::transmute(value as u32) };
Ok(value)
}
pub fn message_netid_set(
&self,
message: *mut icsneoc2_message_t,
value: _icsneoc2_netid_t,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_netid_set(self.handle, message, value as icsneoc2_netid_t) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_type_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<icsneoc2_msg_type_t> {
let mut value: icsneoc2_msg_type_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_type_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_type_name_get(&self, msg_type: icsneoc2_msg_type_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_message_type_name_get(msg_type, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn netid_name_get(&self, netid: _icsneoc2_netid_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res =
unsafe { icsneoc2_netid_name_get(netid as icsneoc2_netid_t, str.as_mut_ptr() as *mut i8, &mut str_length) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_device_find_all() {
let devices = Device::find_all(0).unwrap();
assert_eq!(devices.len(), 0);
}
}
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
VERSION="1.10.5"
ROOT="$PWD/libpcap"
SOURCE="$ROOT/source"
BUILD="$ROOT/build"
INSTALL="$ROOT/install"
mkdir -p "$ROOT"
cd "$ROOT" || exit 1
curl -LO "https://www.tcpdump.org/release/libpcap-$VERSION.tar.xz" || exit 1
tar -xf "libpcap-$VERSION.tar.xz" || exit 1
mv "libpcap-$VERSION" "$SOURCE" || exit 1
cmake -D CMAKE_POSITION_INDEPENDENT_CODE=ON -D CMAKE_INSTALL_PREFIX="$INSTALL" -D BUILD_SHARED_LIBS=OFF -D BUILD_WITH_LIBNL=OFF -D DISABLE_DBUS=ON -D DISABLE_LINUX_USBMON=ON -D DISABLE_BLUETOOTH=ON -D DISABLE_NETMAP=ON -D DISABLE_DPDK=ON -D DISABLE_RDMA=ON -D DISABLE_DAG=ON -D DISABLE_SEPTEL=ON -D DISABLE_SNF=ON -D DISABLE_TC=ON -B "$BUILD" -S "$SOURCE" || exit 1
cmake --build "$BUILD" || exit 1
cmake --install "$BUILD" || exit 1
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
VERSION="1.0.27"
ROOT="$PWD/libusb"
SOURCE="$ROOT/source"
BUILD="$ROOT/build"
INSTALL="$ROOT/install"
mkdir -p "$ROOT"
cd "$ROOT" || exit 1
curl -LO "https://github.com/libusb/libusb/releases/download/v$VERSION/libusb-$VERSION.tar.bz2" || exit 1
tar -xf "libusb-$VERSION.tar.bz2" || exit 1
mv "libusb-$VERSION" "$SOURCE" || exit 1
mkdir "$BUILD" || exit 1
cd "$BUILD" || exit 1
"$SOURCE/configure" --prefix="$INSTALL" --disable-shared --disable-udev --disable-eventfd --disable-timerfd --with-pic || exit 1
make || exit 1
make install || exit 1
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON \
-DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_BUILD_SYSTEM_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
cmake --build build || exit 1
exit 0
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
python3 -m venv env || exit 1
. env/bin/activate || exit 1
python3 -m pip install cibuildwheel || exit 1
python3 -m cibuildwheel --output-dir wheelhouse || exit 1
+9
View File
@@ -0,0 +1,9 @@
@setlocal
@echo off
call "%VCVARS64_2022%"
python.exe -m venv env || exit /b 1
call env\Scripts\Activate.bat || exit /b 1
python.exe -m pip install cibuildwheel || exit /b 1
python.exe -m cibuildwheel --output-dir wheelhouse --platform windows || exit /b 1
+12
View File
@@ -0,0 +1,12 @@
REM clean intermediate directories
rmdir /s /q build
mkdir build
REM build
cd build
set CFLAGS=/WX
set CXXFLAGS=/WX
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_BUILD_SYSTEM_TESTS=ON -DLIBICSNEO_ENABLE_TCP=ON ..
if %errorlevel% neq 0 exit /b %errorlevel%
cmake --build .
if %errorlevel% neq 0 exit /b %errorlevel%
+2
View File
@@ -0,0 +1,2 @@
call "%VCVARS32_2022%"
call "ci\build-windows.bat"
+2
View File
@@ -0,0 +1,2 @@
call "%VCVARS64_2022%"
call "ci\build-windows.bat"
+22
View File
@@ -0,0 +1,22 @@
find_path(FTD3XX_INCLUDE_DIR
NAMES ftd3xx.h FTD3XX.h
)
find_library(FTD3XX_LIBRARY
NAMES libftd3xx.a libftd3xx-static.a FTD3XX.lib
PATH_SUFFIXES x64/Static
)
mark_as_advanced(FTD3XX_FOUND FTD3XX_INCLUDE_DIR FTD3XX_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FTD3XX
REQUIRED_VARS FTD3XX_INCLUDE_DIR FTD3XX_LIBRARY
)
if(FTD3XX_FOUND AND NOT TARGET D3XX::D3XX)
add_library(FTD3XX::FTD3XX INTERFACE IMPORTED)
set_target_properties(FTD3XX::FTD3XX PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FTD3XX_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${FTD3XX_LIBRARY}"
)
endif()
+209 -46
View File
@@ -12,18 +12,28 @@
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/filter/main51messagefilter.h" #include "icsneo/communication/message/filter/main51messagefilter.h"
#include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/versionmessage.h"
#include "icsneo/communication/message/componentversionsmessage.h"
using namespace icsneo; using namespace icsneo;
int Communication::messageCallbackIDCounter = 1; int Communication::messageCallbackIDCounter = 1;
bool Communication::open() { Communication::~Communication() {
if(isOpen) if(isOpen())
return true; close();
}
bool Communication::open() {
if(isOpen()) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
return false;
}
if(!driver->open())
return false;
spawnThreads(); spawnThreads();
isOpen = true; return true;
return impl->open();
} }
void Communication::spawnThreads() { void Communication::spawnThreads() {
@@ -32,19 +42,33 @@ void Communication::spawnThreads() {
void Communication::joinThreads() { void Communication::joinThreads() {
closing = true; closing = true;
if(pauseReadTask) {
resumeReads();
}
if(readTaskThread.joinable()) if(readTaskThread.joinable())
readTaskThread.join(); readTaskThread.join();
closing = false; closing = false;
} }
bool Communication::close() { bool Communication::close() {
if(!isOpen)
return false;
isOpen = false;
joinThreads(); joinThreads();
return impl->close(); if(!isOpen() && !isDisconnected()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
return driver->close();
}
bool Communication::isOpen() {
return driver->isOpen();
}
bool Communication::isDisconnected() {
return driver->isDisconnected();
} }
bool Communication::sendPacket(std::vector<uint8_t>& bytes) { bool Communication::sendPacket(std::vector<uint8_t>& bytes) {
@@ -54,100 +78,239 @@ bool Communication::sendPacket(std::vector<uint8_t>& bytes) {
bool Communication::sendCommand(Command cmd, std::vector<uint8_t> arguments) { bool Communication::sendCommand(Command cmd, std::vector<uint8_t> arguments) {
std::vector<uint8_t> packet; std::vector<uint8_t> packet;
if(!encoder->encode(packet, cmd, arguments)) if(!encoder->encode(*packetizer, packet, cmd, arguments))
return false; return false;
return sendPacket(packet); return sendPacket(packet);
} }
bool Communication::sendCommand(ExtendedCommand cmd, std::vector<uint8_t> arguments) {
const auto size = arguments.size();
if (size > std::numeric_limits<uint16_t>::max())
return false;
arguments.insert(arguments.begin(), {
uint8_t(uint16_t(cmd) & 0xff),
uint8_t((uint16_t(cmd) >> 8) & 0xff),
uint8_t(size & 0xff),
uint8_t((size >> 8) & 0xff)
});
return sendCommand(Command::Extended, arguments);
}
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) { bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ }); static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings);
std::shared_ptr<Message> msg = waitForMessageSync(MessageFilter(Network::NetID::ReadSettings), timeout); std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ });
}, filter, timeout);
if(!msg) if(!msg)
return false; return false;
std::shared_ptr<ReadSettingsMessage> gsmsg = std::dynamic_pointer_cast<ReadSettingsMessage>(msg); std::shared_ptr<ReadSettingsMessage> gsmsg = std::dynamic_pointer_cast<ReadSettingsMessage>(msg);
if(!gsmsg) if(!gsmsg) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false; return false;
}
if(gsmsg->response != ReadSettingsMessage::Response::OK) if(gsmsg->response == ReadSettingsMessage::Response::OKDefaultsUsed) {
report(APIEvent::Type::SettingsDefaultsUsed, APIEvent::Severity::EventInfo);
} else if(gsmsg->response != ReadSettingsMessage::Response::OK) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false; return false;
}
data = std::move(msg->data);
data = std::move(gsmsg->data);
return true; return true;
} }
std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) { std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) {
sendCommand(Command::RequestSerialNumber); static const std::shared_ptr<MessageFilter> filter = std::make_shared<Main51MessageFilter>(Command::RequestSerialNumber);
std::shared_ptr<Message> msg = waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::RequestSerialNumber), timeout); std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::RequestSerialNumber);
}, filter, timeout);
if(!msg) // Did not receive a message if(!msg) // Did not receive a message
return std::shared_ptr<SerialNumberMessage>(); return std::shared_ptr<SerialNumberMessage>();
auto m51 = std::dynamic_pointer_cast<Main51Message>(msg); auto m51 = std::dynamic_pointer_cast<Main51Message>(msg);
if(!m51) // Could not upcast for some reason if(!m51) // Could not upcast for some reason
return std::shared_ptr<SerialNumberMessage>(); return std::shared_ptr<SerialNumberMessage>();
return std::dynamic_pointer_cast<SerialNumberMessage>(m51); return std::dynamic_pointer_cast<SerialNumberMessage>(m51);
} }
int Communication::addMessageCallback(const MessageCallback& cb) { std::optional< std::vector< std::optional<DeviceAppVersion> > > Communication::getVersionsSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::DeviceVersion);
std::vector< std::optional<DeviceAppVersion> > ret;
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::GetMainVersion);
}, filter, timeout);
if(!msg) // Did not receive a message
return std::nullopt;
auto ver = std::dynamic_pointer_cast<VersionMessage>(msg);
if(!ver) // Could not upcast for some reason
return std::nullopt;
if(ver->ForChip != VersionMessage::MainChip || ver->Versions.size() != 1)
return std::nullopt;
ret.push_back(ver->Versions.front());
msg = waitForMessageSync([this]() {
return sendCommand(Command::GetSecondaryVersions);
}, filter, timeout);
if(msg) { // This one is allowed to fail
ver = std::dynamic_pointer_cast<VersionMessage>(msg);
if(ver && ver->ForChip != VersionMessage::MainChip)
ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end());
}
return ret;
}
std::shared_ptr<LogicalDiskInfoMessage> Communication::getLogicalDiskInfoSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::LogicalDiskInfo);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::GetLogicalDiskInfo);
}, filter, timeout);
if(!msg) // Did not receive a message
return {};
return std::dynamic_pointer_cast<LogicalDiskInfoMessage>(msg);
}
int Communication::addMessageCallback(const std::shared_ptr<MessageCallback>& cb) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb)); messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb));
return messageCallbackIDCounter++; return messageCallbackIDCounter++;
} }
bool Communication::removeMessageCallback(int id) { bool Communication::removeMessageCallback(int id) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
try { try {
messageCallbacks.erase(id); messageCallbacks.erase(id);
return true; return true;
} catch(...) { } catch(...) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false; return false;
} }
} }
std::shared_ptr<Message> Communication::waitForMessageSync(std::shared_ptr<MessageFilter> f, std::chrono::milliseconds timeout) { std::shared_ptr<Message> Communication::waitForMessageSync(std::function<bool(void)> onceWaitingDo,
std::mutex m; const std::shared_ptr<MessageFilter>& f, std::chrono::milliseconds timeout) {
std::mutex cvMutex;
std::condition_variable cv; std::condition_variable cv;
std::shared_ptr<Message> returnedMessage; std::shared_ptr<Message> returnedMessage;
int cb = addMessageCallback(MessageCallback([&m, &returnedMessage, &cv](std::shared_ptr<Message> message) {
std::unique_lock<std::mutex> fnLk(syncMessageMutex); // Only allow for one sync message at a time
std::unique_lock<std::mutex> cvLk(cvMutex); // Don't let the callback fire until we're waiting for it
int cb = addMessageCallback(std::make_shared<MessageCallback>([&cvMutex, &returnedMessage, &cv](std::shared_ptr<Message> message) {
{ {
std::lock_guard<std::mutex> lk(m); std::lock_guard<std::mutex> lk(cvMutex);
returnedMessage = message; returnedMessage = message;
} }
cv.notify_one(); cv.notify_all();
}, f)); }, f));
// We have now added the callback, wait for it to return from the other thread // We have now added the callback, do whatever the caller wanted to do
std::unique_lock<std::mutex> lk(m); bool fail = !onceWaitingDo();
cv.wait_for(lk, timeout, [&returnedMessage]{ return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value if(!fail)
cv.wait_for(cvLk, timeout, [&returnedMessage] { return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value
cvLk.unlock(); // Ensure callbacks can complete even if we didn't wait for them
// We don't actually check that we got a message, because either way we want to remove the callback (since it should only happen once) // We don't actually check that we got a message, because either way we want to remove the callback (since it should only happen once)
removeMessageCallback(cb); removeMessageCallback(cb);
// We are now guaranteed that no more callbacks will happen
if(fail) // The caller's function failed, so don't return a message
returnedMessage.reset();
// Then we either will return the message we got or we will return the empty shared_ptr, caller responsible for checking // Then we either will return the message we got or we will return the empty shared_ptr, caller responsible for checking
return returnedMessage; return returnedMessage;
} }
void Communication::dispatchMessage(const std::shared_ptr<Message>& msg) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
// We want callbacks to be able to access errors
const bool downgrade = EventManager::GetInstance().isDowngradingErrorsOnCurrentThread();
if(downgrade)
EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread();
for(auto& cb : messageCallbacks) {
if(!closing) { // We might have closed while reading or processing
cb.second->callIfMatch(msg);
}
}
if(downgrade)
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
}
void Communication::pauseReads() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
pauseReadTask = true;
}
void Communication::resumeReads() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
if(!pauseReadTask) {
return;
}
pauseReadTask = false;
lk.unlock();
pauseReadTaskCv.notify_one();
}
bool Communication::readsArePaused() {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
return pauseReadTask;
}
void Communication::readTask() { void Communication::readTask() {
std::vector<uint8_t> readBytes; EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) { while(!closing) {
readBytes.clear(); if(pauseReadTask) {
if(impl->readWait(readBytes)) { std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
if(packetizer->input(readBytes)) { pauseReadTaskCv.wait(lk, [this]() { return !pauseReadTask; });
for(auto& packet : packetizer->output()) { }
std::shared_ptr<Message> msg; if(driver->waitForRx(readTaskWakeLimit, readTaskWakeTimeout)) {
if(!decoder->decode(msg, packet)) { if(pauseReadTask) {
err(APIError::Unknown); // TODO Use specific error /**
continue; * Reads could have paused while the driver was not available
} */
continue;
for(auto& cb : messageCallbacks) {
if(!closing) { // We might have closed while reading or processing
cb.second.callIfMatch(msg);
}
}
}
} }
handleInput(*packetizer);
} }
} }
} }
void Communication::handleInput(Packetizer& p) {
if(p.input(driver->getReadBuffer())) {
for(const auto& packet : p.output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue;
dispatchMessage(msg);
}
}
}
std::optional< std::vector<ComponentVersion> > Communication::getComponentVersionsSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::ComponentVersions);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(ExtendedCommand::GetComponentVersions, {});
}, filter, timeout);
if(!msg) // Did not receive a message
return std::nullopt;
auto ver = std::dynamic_pointer_cast<ComponentVersionsMessage>(msg);
if(!ver) // Could not upcast for some reason
return std::nullopt;
return std::make_optional< std::vector<ComponentVersion> >(std::move(ver->versions));
}
+380 -30
View File
@@ -3,62 +3,211 @@
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flashmemorymessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/message/wiviresponsemessage.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
#include "icsneo/communication/message/a2bmessage.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/message/i2cmessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/mdiomessage.h"
#include "icsneo/communication/message/extendeddatamessage.h"
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/diskdatamessage.h"
#include "icsneo/communication/message/hardwareinfo.h"
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/gptpstatusmessage.h"
#include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/a2bpacket.h"
#include "icsneo/communication/packet/ethernetpacket.h" #include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/flexraypacket.h"
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/versionpacket.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
#include "icsneo/communication/packet/wivicommandpacket.h"
#include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/packet/scriptstatuspacket.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/packet/componentversionpacket.h"
#include "icsneo/communication/packet/supportedfeaturespacket.h"
#include "icsneo/communication/packet/mdiopacket.h"
#include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include <iostream> #include <iostream>
using namespace icsneo; using namespace icsneo;
uint64_t Decoder::GetUInt64FromLEBytes(uint8_t* bytes) { uint64_t Decoder::GetUInt64FromLEBytes(const uint8_t* bytes) {
uint64_t ret = 0; uint64_t ret = 0;
for(int i = 0; i < 8; i++) for(int i = 0; i < 8; i++)
ret |= (bytes[i] << (i * 8)); ret |= (uint64_t(bytes[i]) << (i * 8));
return ret; return ret;
} }
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) { bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
switch(packet->network.getType()) { switch(packet->network.getType()) {
case Network::Type::Ethernet: case Network::Type::Ethernet: {
result = HardwareEthernetPacket::DecodeToMessage(packet->data); result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
if(!result) if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode return false; // A nullptr was returned, the packet was not long enough to decode
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; EthernetMessage& eth = *static_cast<EthernetMessage*>(result.get());
result->network = packet->network; eth.timestamp *= timestampResolution;
eth.network = packet->network;
return true; return true;
}
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
if(packet->data.size() < 24) if(packet->data.size() < 24) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; return false;
}
result = HardwareCANPacket::DecodeToMessage(packet->data); result = HardwareCANPacket::DecodeToMessage(packet->data);
if(!result) if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; result->timestamp *= timestampResolution;
result->network = packet->network;
switch(result->type) {
case Message::Type::BusMessage: {
CANMessage& can = *static_cast<CANMessage*>(result.get());
can.network = packet->network;
break;
}
case Message::Type::CANErrorCount: {
CANErrorMessage& can = *static_cast<CANErrorMessage*>(result.get());
can.network = packet->network;
break;
}
default: {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // An unknown type was returned, the packet was malformed
}
}
return true;
}
case Network::Type::FlexRay: {
if(packet->data.size() < 24) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = HardwareFlexRayPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
FlexRayMessage& fr = *static_cast<FlexRayMessage*>(result.get());
fr.timestamp *= timestampResolution;
fr.network = packet->network;
return true;
}
case Network::Type::ISO9141: {
if(packet->data.size() < sizeof(HardwareISO9141Packet)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = iso9141decoder.decodeToMessage(packet->data);
if(!result)
return false; // A nullptr was returned, more data is required to decode this packet
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
ISO9141Message& iso = *static_cast<ISO9141Message*>(result.get());
iso.timestamp *= timestampResolution;
iso.network = packet->network;
return true;
}
case Network::Type::I2C: {
if(packet->data.size() < sizeof(HardwareI2CPacket)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = HardwareI2CPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; //malformed packet indicated by a nullptr return
}
return true;
}
case Network::Type::A2B: {
result = HardwareA2BPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
A2BMessage& msg = *static_cast<A2BMessage*>(result.get());
msg.network = packet->network;
msg.timestamp *= timestampResolution;
return true;
}
case Network::Type::LIN: {
result = HardwareLINPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
LINMessage& msg = *static_cast<LINMessage*>(result.get());
msg.network = packet->network;
msg.timestamp *= timestampResolution;
return true;
}
case Network::Type::MDIO: {
result = HardwareMDIOPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
MDIOMessage& msg = *static_cast<MDIOMessage*>(result.get());
msg.network = packet->network;
return true; return true;
} }
case Network::Type::Internal: { case Network::Type::Internal: {
switch(packet->network.getNetID()) { switch(packet->network.getNetID()) {
case Network::NetID::Reset_Status: { case Network::NetID::Reset_Status: {
if(packet->data.size() < sizeof(HardwareResetStatusPacket)) // We can deal with not having the last two fields (voltage and temperature)
if(packet->data.size() < (sizeof(HardwareResetStatusPacket) - (sizeof(uint16_t) * 2))) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; return false;
}
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data(); HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
auto msg = std::make_shared<ResetStatusMessage>(); auto msg = std::make_shared<ResetStatusMessage>();
msg->network = packet->network;
msg->mainLoopTime = data->main_loop_time_25ns * 25; msg->mainLoopTime = data->main_loop_time_25ns * 25;
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25; msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
msg->busVoltage = data->busVoltage;
msg->deviceTemperature = data->deviceTemperature;
msg->justReset = data->status.just_reset; msg->justReset = data->status.just_reset;
msg->comEnabled = data->status.com_enabled; msg->comEnabled = data->status.com_enabled;
msg->cmRunning = data->status.cm_is_running; msg->cmRunning = data->status.cm_is_running;
@@ -72,20 +221,150 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
msg->cmTooBig = data->status.cm_too_big; msg->cmTooBig = data->status.cm_too_big;
msg->hidUsbState = data->status.hidUsbState; msg->hidUsbState = data->status.hidUsbState;
msg->fpgaUsbState = data->status.fpgaUsbState; msg->fpgaUsbState = data->status.fpgaUsbState;
if(packet->data.size() >= sizeof(HardwareResetStatusPacket)) {
msg->busVoltage = data->busVoltage;
msg->deviceTemperature = data->deviceTemperature;
}
result = msg; result = msg;
return true; return true;
} }
default: case Network::NetID::Device: {
break;//return false; // These are neoVI network messages
} // They come in as CAN but we will handle them in the device rather than
} // passing them onto the user.
default: if(packet->data.size() < 24) {
switch(packet->network.getNetID()) { auto rawmsg = std::make_shared<InternalMessage>(Network::NetID::Device);
result = rawmsg;
rawmsg->data = packet->data;
return true;
}
const auto can = std::dynamic_pointer_cast<CANMessage>(HardwareCANPacket::DecodeToMessage(packet->data));
if(!can) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
if(can->arbid == 0x162) {
result = EthernetStatusMessage::DecodeToMessage(can->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
} else {
// TODO: move more handleNeoVIMessage handling here, the Decoder layer will parse the message and the Device layer can cache the values
can->network = packet->network;
result = can;
}
result->timestamp *= timestampResolution;
return true;
}
case Network::NetID::DeviceStatus: {
// Just pass along the data, the device needs to handle this itself
result = std::make_shared<InternalMessage>(packet->network, packet->data);
return true;
}
case Network::NetID::RED_INT_MEMORYREAD: {
if(packet->data.size() != 512 + sizeof(uint16_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<FlashMemoryMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint16_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 2, packet->data.end());
return true;
}
case Network::NetID::NeoMemorySDRead: {
if(packet->data.size() != 512 + sizeof(uint32_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<NeoReadMemorySDMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint32_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 4, packet->data.end());
return true;
}
case Network::NetID::ExtendedCommand: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
break; // Handle as a raw message, might not be a generic response
const auto& resp = *reinterpret_cast<ExtendedResponseMessage::ResponseHeader*>(packet->data.data());
switch(resp.command) {
case ExtendedCommand::GetComponentVersions:
result = ComponentVersionPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetSupportedFeatures:
result = SupportedFeaturesPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GenericBinaryInfo:
result = GenericBinaryStatusPacket::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GenericReturn: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse))
break;
const auto& packedResp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
result = std::make_shared<ExtendedResponseMessage>(packedResp.command, packedResp.returnCode);
return true;
}
case ExtendedCommand::LiveData:
result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report);
return true;
case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetGPTPStatus: {
result = GPTPStatus::DecodeToMessage(packet->data, report);
return true;
}
default:
// No defined handler, treat this as a InternalMessage
break;
}
break;
}
case Network::NetID::ExtendedData: {
if(packet->data.size() < sizeof(ExtendedDataMessage::ExtendedDataHeader))
break;
const auto& header = *reinterpret_cast<ExtendedDataMessage::ExtendedDataHeader*>(packet->data.data());
switch(header.subCommand) {
case ExtendedDataSubCommand::GenericBinaryRead: {
result = std::make_shared<ExtendedDataMessage>(header);
auto extDataMsg = std::static_pointer_cast<ExtendedDataMessage>(result);
size_t numRead = std::min(ExtendedDataMessage::MaxExtendedDataBufferSize, (size_t)header.length);
extDataMsg->data.resize(numRead);
std::copy(packet->data.begin() + sizeof(header), packet->data.begin() + sizeof(header) + numRead, extDataMsg->data.begin());
extDataMsg->network = Network(static_cast<uint16_t>(Network::NetID::ExtendedData), false);
return true;
}
default:
break;
}
break;
}
case Network::NetID::FlexRayControl: {
auto frResult = std::make_shared<FlexRayControlMessage>(*packet);
if(!frResult->decoded) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = frResult;
return true;
}
case Network::NetID::Main51: { case Network::NetID::Main51: {
switch((Command)packet->data[0]) { switch((Command)packet->data[0]) {
case Command::RequestSerialNumber: { case Command::RequestSerialNumber: {
auto msg = std::make_shared<SerialNumberMessage>(); auto msg = std::make_shared<SerialNumberMessage>();
msg->network = packet->network;
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1); uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
// The device sends 64-bits of serial number, but we never use more than 32-bits. // The device sends 64-bits of serial number, but we never use more than 32-bits.
msg->deviceSerial = Device::SerialNumToString((uint32_t)serial); msg->deviceSerial = Device::SerialNumToString((uint32_t)serial);
@@ -98,9 +377,36 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg; result = msg;
return true; return true;
} }
case Command::GetMainVersion: {
result = HardwareVersionPacket::DecodeMainToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
case Command::GetSecondaryVersions: {
result = HardwareVersionPacket::DecodeSecondaryToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
case Command::GetHardwareInfo: {
result = HardwareInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
default: default:
auto msg = std::make_shared<Main51Message>(); auto msg = std::make_shared<Main51Message>();
msg->network = packet->network;
msg->command = Command(packet->data[0]); msg->command = Command(packet->data[0]);
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end()); msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
result = msg; result = msg;
@@ -111,7 +417,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
/* So-called "old format" messages are a "new style, long format" wrapper around the old short messages. /* So-called "old format" messages are a "new style, long format" wrapper around the old short messages.
* They consist of a 16-bit LE length first, then the 8-bit length and netid combo byte, then the payload * They consist of a 16-bit LE length first, then the 8-bit length and netid combo byte, then the payload
* with no checksum. The upper-nibble length of the combo byte should be ignored completely, using the * with no checksum. The upper-nibble length of the combo byte should be ignored completely, using the
* length from the first two bytes in it's place. Ideally, we never actually send the oldformat messages * length from the first two bytes in its place. Ideally, we never actually send the oldformat messages
* out to the rest of the application as they can recursively get decoded to another message type here. * out to the rest of the application as they can recursively get decoded to another message type here.
* Feed the result back into the decoder in case we do something special with the resultant netid. * Feed the result back into the decoder in case we do something special with the resultant netid.
*/ */
@@ -122,11 +428,18 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
packet->data.resize(length); packet->data.resize(length);
return decode(result, packet); return decode(result, packet);
} }
case Network::NetID::RED_App_Error: {
result = AppErrorMessage::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::ReadSettings: { case Network::NetID::ReadSettings: {
auto msg = std::make_shared<ReadSettingsMessage>(); auto msg = std::make_shared<ReadSettingsMessage>();
msg->network = packet->network;
msg->response = ReadSettingsMessage::Response(packet->data[0]); msg->response = ReadSettingsMessage::Response(packet->data[0]);
if(msg->response == ReadSettingsMessage::Response::OK) { if(msg->response == ReadSettingsMessage::Response::OK) {
// The global settings structure is the payload of the message in this case // The global settings structure is the payload of the message in this case
msg->data.insert(msg->data.begin(), packet->data.begin() + 10, packet->data.end()); msg->data.insert(msg->data.begin(), packet->data.begin() + 10, packet->data.end());
@@ -142,13 +455,50 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg; result = msg;
return true; return true;
} }
case Network::NetID::LogicalDiskInfo: {
result = LogicalDiskInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::WiVICommand: {
result = WiVI::CommandPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::EthPHYControl: {
result = HardwareEthernetPhyRegisterPacket::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::ScriptStatus: {
result = ScriptStatus::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::DiskData: {
result = std::make_shared<DiskDataMessage>(std::move(packet->data));
return true;
}
default:
break;
} }
break;
}
} }
// For the moment other types of messages will automatically be decoded as raw messages // For the moment other types of messages will automatically be decoded as raw messages
auto msg = std::make_shared<Message>(); result = std::make_shared<InternalMessage>(packet->network, packet->data);
msg->network = packet->network;
msg->data = packet->data;
result = msg;
return true; return true;
} }
+97
View File
@@ -0,0 +1,97 @@
#include "icsneo/communication/driver.h"
//#define ICSNEO_DRIVER_DEBUG_PRINTS
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
#include <iostream>
#include <iomanip>
#endif
using namespace icsneo;
bool Driver::pushRx(const uint8_t* buf, size_t numReceived) {
bool ret = readBuffer.write(buf, numReceived);
rxWaitCv.notify_all();
return ret;
}
void Driver::clearBuffers()
{
WriteOperation flushop;
readBuffer.clear();
rxWaitCv.notify_all();
while (writeQueue.try_dequeue(flushop)) {}
}
bool Driver::waitForRx(size_t limit, std::chrono::milliseconds timeout) {
return waitForRx([limit, this]() {
return readBuffer.size() >= limit;
}, timeout);
}
bool Driver::waitForRx(std::function<bool()> predicate, std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> lk(rxWaitMutex);
return rxWaitCv.wait_for(lk, timeout, predicate);
}
bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
if(limit > (readBuffer.size() + 4))
limit = (readBuffer.size() + 4);
// wait until we have enough data, or the timout occurs
waitForRx(limit, timeout);
size_t actuallyRead = std::min(readBuffer.size(), limit);
bytes.resize(actuallyRead);
readBuffer.read(bytes.data(), 0, actuallyRead);
readBuffer.pop(actuallyRead);
bytes.resize(actuallyRead);
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
if(actuallyRead > 0) {
std::cout << "Read data: (" << actuallyRead << ')' << std::hex << std::endl;
for(int i = 0; i < actuallyRead; i += 16) {
for(int j = 0; j < std::min<int>(actuallyRead - i, 16); j++)
std::cout << std::setw(2) << std::setfill('0') << uint32_t(bytes[i+j]) << ' ';
std::cout << std::endl;
}
std::cout << std::dec << std::endl;
}
#endif
return actuallyRead > 0;
}
bool Driver::write(const std::vector<uint8_t>& bytes) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
if(writeBlocks) {
if(writeQueueFull()) {
while(writeQueueAlmostFull()) // Wait until we have some decent amount of space
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
} else {
if(writeQueueFull()) {
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
return false;
}
}
const bool ret = writeInternal(bytes);
if(!ret)
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return ret;
}
+237 -63
View File
@@ -1,104 +1,278 @@
#include "icsneo/communication/encoder.h" #include "icsneo/communication/encoder.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/main51message.h"
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/ethernetpacket.h" #include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/message/i2cmessage.h"
#include "icsneo/communication/packet/a2bpacket.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/packet/mdiopacket.h"
using namespace icsneo; using namespace icsneo;
bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) { bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
bool shortFormat = false; bool shortFormat = false;
bool useResultAsBuffer = false; // Otherwise it's expected that we use message->data std::vector<uint8_t>* buffer = &result;
uint16_t netid = 0;
result.clear(); result.clear();
switch(message->network.getType()) { switch(message->type) {
case Network::Type::Ethernet: { case Message::Type::BusMessage: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message); auto frame = std::dynamic_pointer_cast<BusMessage>(message);
if(!ethmsg)
return false; // The message was not a properly formed EthernetMessage
useResultAsBuffer = true; // Frame uses frame->data as the buffer unless directed otherwise
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result)) buffer = &frame->data;
return false; netid = uint16_t(frame->network.getNetID());
switch(frame->network.getType()) {
case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed EthernetMessage
}
buffer = &result;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
return false;
break;
} // End of Network::Type::Ethernet
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed CANMessage
}
if(!supportCANFD && canmsg->isCANFD) {
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
return false; // This device does not support CAN FD
}
buffer = &result;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
return false; // The CANMessage was malformed
break;
} // End of Network::Type::CAN
case Network::Type::ISO9141: {
auto isomsg = std::dynamic_pointer_cast<ISO9141Message>(message);
if(!isomsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed ISO9141Message
}
// Skip the normal message wrapping at the bottom since we need to send multiple
// packets to the device. This function just encodes them back to back into `result`
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
} // End of Network::Type::ISO9141
case Network::Type::A2B: {
auto a2bmsg = std::dynamic_pointer_cast<A2BMessage>(message);
if(!a2bmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareA2BPacket::EncodeFromMessage(*a2bmsg, result, report)) {
return false;
}
break;
} // End of Network::Type::A2B
case Network::Type::I2C: {
auto i2cmsg = std::dynamic_pointer_cast<I2CMessage>(message);
if(!i2cmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareI2CPacket::EncodeFromMessage(*i2cmsg, result, report)) {
return false;
}
break;
} // End of Network::Type::I2C
case Network::Type::LIN: {
auto linmsg = std::dynamic_pointer_cast<LINMessage>(message);
if(!linmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareLINPacket::EncodeFromMessage(*linmsg, result, report)) {
return false;
}
break;
} // End of Network::Type::LIN
case Network::Type::MDIO: {
auto mdiomsg = std::dynamic_pointer_cast<MDIOMessage>(message);
if(!mdiomsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
buffer = &result;
if(!HardwareMDIOPacket::EncodeFromMessage(*mdiomsg, result, report)) {
return false;
}
break;
} // End of Network::Type::MDIO
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
break; break;
} // End of Network::Type::Ethernet }
case Network::Type::CAN: case Message::Type::InternalMessage: {
case Network::Type::SWCAN: auto raw = std::dynamic_pointer_cast<InternalMessage>(message);
case Network::Type::LSFTCAN: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg)
return false; // The message was not a properly formed CANMessage
if(!supportCANFD && canmsg->isCANFD) // Raw message uses raw->data as the buffer unless directed otherwise
return false; // This device does not support CAN FD buffer = &raw->data;
netid = uint16_t(raw->network.getNetID());
useResultAsBuffer = true; switch(raw->network.getNetID()) {
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result))
return false; // The CANMessage was malformed
break;
} // End of Network::Type::CAN
default:
switch(message->network.getNetID()) {
case Network::NetID::Device: case Network::NetID::Device:
shortFormat = true; shortFormat = true;
break; break;
case Network::NetID::Main51:
if(message->data.size() > 0xF) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(message->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
message->data.insert(message->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8)
});
result = packetizer->packetWrap(message->data, shortFormat);
return true;
} else {
shortFormat = true;
}
break;
case Network::NetID::RED_OLDFORMAT: { case Network::NetID::RED_OLDFORMAT: {
// See the decoder for an explanation // See the decoder for an explanation
// We expect the network byte to be populated already in data, but not the length // We expect the network byte to be populated already in data, but not the length
uint16_t length = uint16_t(message->data.size()) - 1; uint16_t length = uint16_t(raw->data.size()) - 1;
message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)}); raw->data.insert(raw->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
break; break;
} }
default: default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false; return false;
} }
break;
}
case Message::Type::Main51: {
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
if(!m51msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Main51Message
}
buffer = &m51msg->data;
netid = uint16_t(Network::NetID::Main51);
if(!m51msg->forceShortFormat) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(m51msg->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
size += 1; // Main51 Command
m51msg->data.insert(m51msg->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)m51msg->command
});
result = packetizer.packetWrap(m51msg->data, shortFormat);
return true;
} else {
m51msg->data.insert(m51msg->data.begin(), { uint8_t(m51msg->command) });
shortFormat = true;
}
break;
}
case Message::Type::EthernetPhyRegister: {
if(!supportEthPhy) {
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
return false;
}
auto ethPhyMessage = std::dynamic_pointer_cast<EthPhyMessage>(message);
if(!ethPhyMessage) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
if(!HardwareEthernetPhyRegisterPacket::EncodeFromMessage(*ethPhyMessage, result, report))
return false;
break;
}
case Message::Type::LiveData: {
auto liveDataMsg = std::dynamic_pointer_cast<LiveDataMessage>(message);
if(!liveDataMsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed LiveDataMessage
}
if(!HardwareLiveDataPacket::EncodeFromMessage(*liveDataMsg, result, report))
return false;
result = packetizer.packetWrap(result, false);
return true;
}
break;
} }
auto& buffer = useResultAsBuffer ? result : message->data; // Early returns may mean we don't reach this far, check the type you're concerned with
if(shortFormat) { if(shortFormat) {
buffer.insert(buffer.begin(), (uint8_t(buffer.size()) << 4) | uint8_t(message->network.getNetID())); buffer->insert(buffer->begin(), (uint8_t(buffer->size()) << 4) | uint8_t(netid));
} else { } else {
// Size in long format is the size of the entire packet // Size for the host-to-device long format is the size of the entire packet + 1
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID // So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
uint16_t size = uint16_t(buffer.size()) + 1 + 1 + 2 + 2; // Then an extra +1, due to a firmware idiosyncrasy
buffer.insert(buffer.begin(), { uint16_t size = static_cast<uint16_t>(buffer->size()) + 1 + 1 + 2 + 2 + 1;
buffer->insert(buffer->begin(), {
(uint8_t)Network::NetID::RED, // 0x0C for long message (uint8_t)Network::NetID::RED, // 0x0C for long message
(uint8_t)size, // Size, little endian 16-bit (uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8), (uint8_t)(size >> 8),
(uint8_t)message->network.getNetID(), // NetID, little endian 16-bit (uint8_t)netid, // NetID, little endian 16-bit
(uint8_t)(uint16_t(message->network.getNetID()) >> 8) (uint8_t)(netid >> 8)
}); });
} }
result = packetizer->packetWrap(buffer, shortFormat); result = packetizer.packetWrap(*buffer, shortFormat);
return true; return true;
} }
bool Encoder::encode(std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments) { bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments) {
auto msg = std::make_shared<Message>(); std::shared_ptr<Message> msg;
msg->network = Network::NetID::Main51; if(cmd == Command::UpdateLEDState) {
msg->data.reserve(arguments.size() + 1); /* NetID::Device is a super old command type.
msg->data.push_back((uint8_t)cmd); * It has a leading 0x00 byte, a byte for command, and a byte for an argument.
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end())); * In this case, command 0x06 is SetLEDState.
return encode(result, msg); * This old command type is not really used anywhere else.
*/
auto canmsg = std::make_shared<InternalMessage>(Network::NetID::Device);
msg = canmsg;
if(arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
canmsg->data.reserve(3);
canmsg->data.push_back(0x00);
canmsg->data.push_back(0x06); // SetLEDState
canmsg->data.push_back(arguments.at(0)); // See Device::LEDState
} else {
auto m51msg = std::make_shared<Main51Message>();
msg = m51msg;
m51msg->command = cmd;
switch(cmd) {
case Command::ReadSettings:
case Command::RequestSerialNumber:
case Command::EnableNetworkCommunication:
case Command::EnableNetworkCommunicationEx:
case Command::GetMainVersion:
case Command::GetSecondaryVersions:
case Command::NeoReadMemory:
// There is a firmware handling idiosyncrasy with these commands
// They must be encoded in the short format
m51msg->forceShortFormat = true;
default:
break;
}
m51msg->data.insert(m51msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
}
return encode(packetizer, result, msg);
} }
+188
View File
@@ -0,0 +1,188 @@
#include "icsneo/communication/ethernetpacketizer.h"
#include <algorithm>
#include <iterator>
#include <cstring>
#include <cassert>
using namespace icsneo;
const size_t EthernetPacketizer::MaxPacketLength = 1490; // MTU - overhead
static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EthernetPacketizer::EthernetPacket& EthernetPacketizer::newSendPacket(bool first) {
processedDownPackets.emplace_back();
EthernetPacket& ret = processedDownPackets.back();
if(first) {
ret.packetNumber = sequenceDown++;
} else {
ret.firstPiece = false;
if(processedDownPackets.size() > 1)
ret.packetNumber = (processedDownPackets.rbegin() + 1)->packetNumber;
else
assert(false); // This should never be called with !first if there are no packets in the queue
}
std::copy(std::begin(hostMAC), std::end(hostMAC), std::begin(ret.srcMAC));
std::copy(std::begin(deviceMAC), std::end(deviceMAC), std::begin(ret.destMAC));
return ret;
}
void EthernetPacketizer::inputDown(std::vector<uint8_t> bytes, bool first) {
EthernetPacket* sendPacket = nullptr;
if(first && !processedDownPackets.empty()) {
// We have some packets already, let's see if we can add this to the last one
if(processedDownPackets.back().payload.size() + bytes.size() <= MaxPacketLength)
sendPacket = &processedDownPackets.back();
}
if(sendPacket == nullptr)
sendPacket = &newSendPacket(first);
if(sendPacket->payload.empty())
sendPacket->payload = std::move(bytes);
else
sendPacket->payload.insert(sendPacket->payload.end(), bytes.begin(), bytes.end());
// Split packets larger than MTU
std::vector<uint8_t> extraData;
if(sendPacket->payload.size() > MaxPacketLength) {
extraData.insert(extraData.end(), sendPacket->payload.begin() + MaxPacketLength, sendPacket->payload.end());
sendPacket->payload.resize(MaxPacketLength);
sendPacket->lastPiece = false;
inputDown(std::move(extraData), false);
}
}
std::vector< std::vector<uint8_t> > EthernetPacketizer::outputDown() {
std::vector< std::vector<uint8_t> > ret;
ret.reserve(processedDownPackets.size());
for(auto&& packet : std::move(processedDownPackets))
ret.push_back(packet.getBytestream());
processedDownPackets.clear();
return ret;
}
bool EthernetPacketizer::inputUp(std::vector<uint8_t> bytes) {
EthernetPacket packet(bytes);
if(packet.errorWhileDecodingFromBytestream)
return false; // Bad packet
if(packet.etherType != 0xCAB2)
return false; // Not a packet to host
if(memcmp(packet.destMAC, hostMAC, sizeof(packet.destMAC)) != 0 &&
memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0)
return false; // Packet is not addressed to us or broadcast
if(!allowInPacketsFromAnyMAC && memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0)
return false; // Not a packet from the device we're concerned with
// Handle single packets
if(packet.firstPiece && packet.lastPiece) {
// Could ensure no out-of-order reassembly by checking reassembing here,
// not doing that here because it should be harmless if it ever happened.
processedUpBytes.insert(processedUpBytes.end(), std::make_move_iterator(packet.payload.begin()), std::make_move_iterator(packet.payload.end()));
return true;
}
if(packet.firstPiece) {
if(reassembling) {
//report(APIEvent::Type::FailedToRead, APIEvent::Severity::EventWarning);
reassemblingData.clear();
}
reassembling = true;
reassemblingId = packet.packetNumber;
reassemblingData = std::move(packet.payload);
return !processedUpBytes.empty(); // If there are other packets in the pipe
}
if(!reassembling || reassemblingId != packet.packetNumber) {
//report(APIEvent::Type::FailedToRead, APIEvent::Severity::EventWarning);
reassembling = false;
reassemblingData.clear();
return !processedUpBytes.empty(); // If there are other packets in the pipe
}
if(packet.lastPiece) {
processedUpBytes.insert(processedUpBytes.end(), std::make_move_iterator(reassemblingData.begin()), std::make_move_iterator(reassemblingData.end()));
reassemblingData.clear();
reassembling = false;
processedUpBytes.insert(processedUpBytes.end(), std::make_move_iterator(packet.payload.begin()), std::make_move_iterator(packet.payload.end()));
return true;
}
reassemblingData.insert(reassemblingData.end(), std::make_move_iterator(packet.payload.begin()), std::make_move_iterator(packet.payload.end()));
return !processedUpBytes.empty(); // If there are other packets in the pipe
}
std::vector<uint8_t> EthernetPacketizer::outputUp() {
std::vector<uint8_t> ret = std::move(processedUpBytes);
processedUpBytes.clear();
return ret;
}
EthernetPacketizer::EthernetPacket::EthernetPacket(const std::vector<uint8_t>& bytestream) {
loadBytestream(bytestream);
}
EthernetPacketizer::EthernetPacket::EthernetPacket(const uint8_t* data, size_t size) {
std::vector<uint8_t> bs(data, data + size);
loadBytestream(bs);
}
int EthernetPacketizer::EthernetPacket::loadBytestream(const std::vector<uint8_t>& bytestream) {
errorWhileDecodingFromBytestream = 0;
for(size_t i = 0; i < 6; i++)
destMAC[i] = bytestream[i];
for(size_t i = 0; i < 6; i++)
srcMAC[i] = bytestream[i + 6];
etherType = (bytestream[12] << 8) | bytestream[13];
icsEthernetHeader = (bytestream[14] << 24) | (bytestream[15] << 16) | (bytestream[16] << 8) | bytestream[17];
payloadSize = bytestream[18] | (bytestream[19] << 8);
packetNumber = bytestream[20] | (bytestream[21] << 8);
uint16_t packetInfo = bytestream[22] | (bytestream[23] << 8);
firstPiece = packetInfo & 1;
lastPiece = (packetInfo >> 1) & 1;
bufferHalfFull = (packetInfo >> 2) & 2;
payload = std::vector<uint8_t>(bytestream.begin() + 24, bytestream.end());
size_t payloadActualSize = payload.size();
if(payloadActualSize > payloadSize)
payload.resize(payloadSize);
return errorWhileDecodingFromBytestream;
}
std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
uint16_t actualPayloadSize = uint16_t(payload.size());
std::vector<uint8_t> bytestream;
bytestream.reserve(6 + 6 + 2 + 4 + 2 + 2 + 2 + actualPayloadSize);
for(size_t i = 0; i < 6; i++)
bytestream.push_back(destMAC[i]);
for(size_t i = 0; i < 6; i++)
bytestream.push_back(srcMAC[i]);
// EtherType should be put into the bytestream as big endian
bytestream.push_back((uint8_t)(etherType >> 8));
bytestream.push_back((uint8_t)(etherType));
// Our Ethernet header should be put into the bytestream as big endian
bytestream.push_back((uint8_t)(icsEthernetHeader >> 24));
bytestream.push_back((uint8_t)(icsEthernetHeader >> 16));
bytestream.push_back((uint8_t)(icsEthernetHeader >> 8));
bytestream.push_back((uint8_t)(icsEthernetHeader));
uint16_t declaredPayloadSize = payloadSize ? payloadSize : actualPayloadSize;
// The payload size comes next, it's little endian
bytestream.push_back((uint8_t)(declaredPayloadSize));
bytestream.push_back((uint8_t)(declaredPayloadSize >> 8));
// Packet number is little endian
bytestream.push_back((uint8_t)(packetNumber));
bytestream.push_back((uint8_t)(packetNumber >> 8));
// Packet info gets assembled into a bitfield
uint16_t packetInfo = 0;
packetInfo |= firstPiece & 1;
packetInfo |= (lastPiece & 1) << 1;
packetInfo |= (bufferHalfFull & 1) << 2;
packetInfo |= 1 << 8; // Protocol version 1
bytestream.push_back((uint8_t)(packetInfo));
bytestream.push_back((uint8_t)(packetInfo >> 8));
bytestream.insert(bytestream.end(), payload.begin(), payload.end());
return bytestream;
}
-54
View File
@@ -1,54 +0,0 @@
#include "icsneo/communication/icommunication.h"
using namespace icsneo;
bool ICommunication::read(std::vector<uint8_t>& bytes, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
if(limit > (readQueue.size_approx() + 4))
limit = (readQueue.size_approx() + 4);
if(bytes.capacity() < limit)
bytes.resize(limit);
size_t actuallyRead = readQueue.try_dequeue_bulk(bytes.data(), limit);
if(bytes.size() > actuallyRead)
bytes.resize(actuallyRead);
return true;
}
bool ICommunication::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
if(limit > (readQueue.size_approx() + 4))
limit = (readQueue.size_approx() + 4);
bytes.resize(limit);
size_t actuallyRead = readQueue.wait_dequeue_bulk_timed(bytes.data(), limit, timeout);
bytes.resize(actuallyRead);
return actuallyRead > 0;
}
bool ICommunication::write(const std::vector<uint8_t>& bytes) {
if(writeBlocks) {
std::unique_lock<std::mutex> lk(writeMutex);
if(writeQueue.size_approx() > writeQueueSize) {
writeCV.wait(lk);
}
} else {
if(writeQueue.size_approx() > writeQueueSize) {
err(APIError::TransmitBufferFull);
return false;
}
}
return writeQueue.enqueue(WriteOperation(bytes));
}
+22
View File
@@ -0,0 +1,22 @@
#include "icsneo/communication/livedata.h"
namespace icsneo {
namespace LiveDataUtil {
LiveDataHandle getNewHandle() {
static LiveDataHandle currentHandle = 0;
++currentHandle;
if(currentHandle == std::numeric_limits<LiveDataHandle>::max()) {
EventManager::GetInstance().add(APIEvent::Type::LiveDataInvalidHandle, APIEvent::Severity::Error);
currentHandle = 1;
}
return currentHandle;
}
double liveDataValueToDouble(const LiveDataValue& val) {
constexpr double liveDataFixedPointToDouble = 0.00000000023283064365386962890625;
return val.value * liveDataFixedPointToDouble;
}
} // namespace LiveDataUtil
} // namespace icsneo
+257
View File
@@ -0,0 +1,257 @@
#include "icsneo/communication/message/a2bmessage.h"
#include "icsneo/communication/message/callback/streamoutput/streamoutput.h"
using namespace icsneo;
// Read a 16 bit sample from the audio buffer, which is stored as little endian
#define SAMPLE_FROM_BYTES_16(audioData) (((audioData)[0]) | ((audioData)[1] << 8))
// Read a 32 bit sample from the audio buffer
#define SAMPLE_FROM_BYTES_32(audioData) (((audioData)[0]) | ((audioData)[1] << 8) | ((audioData)[2] << 16) | ((audioData)[3] << 24))
// Read the most significant bytes of a sample stored in a 32 bit unsigned integer into audioData
#define SAMPLE_TO_BYTES_16(audioData, offset, sample) {\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x00FF0000u) >> 16);\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0xFF000000u) >> 24);\
}
// Read little endian a 32 bit unsigned integer into audioData
#define SAMPLE_TO_BYTES_32(audioData, offset, sample) {\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x000000FFu));\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x0000FF00u) >> 8);\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0x00FF0000u) >> 16);\
(audioData)[(offset)++] = static_cast<uint8_t>(((sample) & 0xFF000000u) >> 24);\
}
uint8_t A2BMessage::tdmToChannelNum(TDMMode tdm) {
switch(tdm) {
case TDMMode::TDM2:
return 4;
case TDMMode::TDM4:
return 8;
case TDMMode::TDM8:
return 16;
case TDMMode::TDM12:
return 24;
case TDMMode::TDM16:
return 32;
case TDMMode::TDM20:
return 40;
case TDMMode::TDM24:
return 48;
case TDMMode::TDM32:
return 64;
}
return 0;
}
uint8_t A2BMessage::getBytesPerChannel() const {
return channelSize16 ? 2u : 4u;
}
size_t A2BMessage::getFrameSize() const {
return static_cast<size_t>(2 * numChannels * getBytesPerChannel());
}
size_t A2BMessage::getSampleOffset(Direction dir, uint8_t channel, size_t frame) const {
size_t frameSize = getFrameSize();
size_t sampleOffset = static_cast<size_t>(frameSize * frame + 2 * channel * getBytesPerChannel());
if(dir == Direction::Upstream) {
sampleOffset += getBytesPerChannel();
}
return sampleOffset;
}
size_t A2BMessage::getNumFrames() const {
size_t frameSize = getFrameSize();
if(frameSize == 0) {
return 0;
}
return data.size() / frameSize;
}
A2BMessage::A2BMessage(size_t numFrames, TDMMode tdm, bool chSize16) : channelSize16(chSize16) {
numChannels = static_cast<uint8_t>(tdmToChannelNum(tdm) / 2);
size_t frameSize = static_cast<size_t>(2 * numChannels * (chSize16 ? 2u : 4u));
size_t audioBufferSize = frameSize * numFrames;
if(audioBufferSize > maxAudioBufferSize) {
size_t maxNumFrames = maxAudioBufferSize / frameSize;
audioBufferSize = maxNumFrames * frameSize;
}
data.resize(std::min<size_t>(maxAudioBufferSize, audioBufferSize), 0);
}
A2BMessage::A2BMessage(TDMMode tdm, bool chSize16) : channelSize16(chSize16) {
numChannels = static_cast<uint8_t>(tdmToChannelNum(tdm) / 2);
size_t frameSize = static_cast<size_t>(2 * numChannels * (chSize16 ? 2u : 4u));
size_t maxNumFrames = maxAudioBufferSize / frameSize;
size_t audioBufferSize = maxNumFrames * frameSize;
data.resize(audioBufferSize, 0);
}
PCMSample A2BMessage::getChannelSample(Direction dir, uint8_t channel, size_t frame, PCMType pcmType) const {
size_t sampleOffset = getSampleOffset(dir, channel, frame);
const uint8_t* audioData = &data[sampleOffset];
PCMSample result = 0;
// Samples coming from the device will either come from a 16 bit channel or 32 bit channel
if(channelSize16) {
int16_t sample16 = 0;
uint16_t& uSample16 = *reinterpret_cast<uint16_t*>(&sample16);
// Read little endian from the audio buffer
uSample16 = SAMPLE_FROM_BYTES_16(audioData);
// Scale the sample up according to the desired PCM size by
// multiplying using logical shifting
switch(pcmType) {
case PCMType::L16:
result = static_cast<PCMSample>(sample16);
break;
case PCMType::L24:
result = static_cast<PCMSample>(sample16) << 8;
break;
case PCMType::L32:
result = static_cast<PCMSample>(sample16) << 16;
break;
}
} else {
PCMSample sample32 = 0;
uint32_t& uSample32 = *reinterpret_cast<uint32_t*>(&sample32);
// Read little endian
uSample32 = SAMPLE_FROM_BYTES_32(audioData);
// Scale the sample down according to the desired PCM size by dividing using
// logical shifting, if the A2B network was set up with the desired pcmType
// there should be a clean division and no loss in PCM resolution.
switch(pcmType) {
case PCMType::L16:
result = sample32 >> 16;
break;
case PCMType::L24:
result = sample32 >> 8;
break;
case PCMType::L32:
result = sample32;
break;
}
}
return result;
}
void A2BMessage::setChannelSample(Direction dir, uint8_t channel, size_t frame, PCMSample sampleToSet, PCMType pcmType) {
size_t sampleOffset = getSampleOffset(dir, channel, frame);
uint32_t& uSample = *reinterpret_cast<uint32_t*>(&sampleToSet);
// Align the bytes towards the most significant bit by multiplying using
// left shifts
switch(pcmType) {
case PCMType::L16:
sampleToSet = sampleToSet << 16;
break;
case PCMType::L24:
sampleToSet = sampleToSet << 8;
break;
}
if(channelSize16) {
// Read the 2 most significant bytes of the sample
SAMPLE_TO_BYTES_16(data, sampleOffset, uSample)
} else {
// Read the entire sample
SAMPLE_TO_BYTES_32(data, sampleOffset, uSample);
}
}
bool A2BMessage::loadAudioBuffer(IWAVStream& wavStream, const ChannelMap& channelMap) {
if(!wavStream) {
return false;
}
size_t totalMessageChannels = numChannels * 2; // Multiply by two inorder to include both down and upstream channels
size_t bytesPerChannel = static_cast<size_t>(getBytesPerChannel()); // Number of bytes per message channel
size_t frameSize = getFrameSize();
size_t numFrames = getNumFrames();
size_t bytesPerSampleWAV = static_cast<size_t>(wavStream.header.bitsPerSample / 8); // Number of bytes per sample in the WAV data-stream
size_t numWAVChannels = static_cast<size_t>(wavStream.header.numChannels);
size_t wavFrameSize = numWAVChannels * bytesPerSampleWAV;
if(bytesPerSampleWAV != 2 && bytesPerSampleWAV != 3 && bytesPerSampleWAV != 4) {
return false;
}
if(numFrames == 0) {
return false;
}
uint8_t* audioBuffer = data.data();
std::vector<uint8_t> wavFrame(wavFrameSize, 0);
for(size_t frame = 0; frame < numFrames; frame++) {
// Read one frame of data from the input stream
if(!wavStream.read(reinterpret_cast<char*>(wavFrame.data()), wavFrame.size())) {
break;
}
// Iterate through each mapping and set a message channel to a channel in the WAV frame above
for(const auto& [messageChannel, wavChannel] : channelMap) {
if(messageChannel >= totalMessageChannels || wavChannel >= numWAVChannels) {
return false;
}
size_t frameOffset = wavChannel * bytesPerSampleWAV; // Offset in the read WAV frame
size_t audioBufferOffset = frame * frameSize + messageChannel * bytesPerChannel; // Offset in the message audio buffer
if(bytesPerChannel < bytesPerSampleWAV) {
// In this case, the message channels are smaller than the samples in the input WAV
// samples in both the message channel and WAV are little endian, so we write only the
// most significant bytes of the WAV
// Align to most significant bytes of wav frame
size_t align = bytesPerSampleWAV - bytesPerChannel;
for(
size_t frameByte = frameOffset + align;
frameByte < frameOffset + bytesPerSampleWAV;
frameByte++,
audioBufferOffset++
) {
audioBuffer[audioBufferOffset] = wavFrame[frameByte];
}
} else {
// The message channel is greater than or equal to the sample in the WAV
// I2S specifies that the sample in this case is right aligned to the most significant
// byte of the message channel
// Align to most significant byte of audio buffer channel
size_t align = bytesPerChannel - bytesPerSampleWAV;
for(
size_t audioByte = audioBufferOffset + align;
audioByte < audioBufferOffset + bytesPerChannel;
audioByte++,
frameOffset++
) {
audioBuffer[audioByte] = wavFrame[frameOffset];
}
}
}
}
return true;
}
+148
View File
@@ -0,0 +1,148 @@
#include <icsneo/communication/message/apperrormessage.h>
namespace icsneo {
#pragma pack(push, 2)
typedef struct {
uint16_t error_type;
uint16_t network_id;
uint32_t uiTimeStamp10uS;
uint32_t uiTimeStamp10uSMSB;
} AppErrorData;
#pragma pack(pop)
std::shared_ptr<Message> AppErrorMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
const AppErrorData* data = reinterpret_cast<const AppErrorData*>(bytestream.data());
if(!data) {
report(APIEvent::Type::AppErrorParsingFailed, APIEvent::Severity::Error);
return nullptr;
}
auto appErr = std::make_shared<AppErrorMessage>();
appErr->errorType = data->error_type;
appErr->errorNetID = static_cast<Network::NetID>(data->network_id);
appErr->timestamp10us = data->uiTimeStamp10uS;
appErr->timestamp10usMSB = data->uiTimeStamp10uSMSB;
appErr->network = Network::NetID::RED_App_Error;
return appErr;
}
AppErrorType AppErrorMessage::getAppErrorType() {
AppErrorType errType = static_cast<AppErrorType>(errorType);
if(errType > AppErrorType::AppNoError) {
return AppErrorType::AppNoError;
}
return errType;
}
std::string AppErrorMessage::getAppErrorString() {
auto netIDString = Network::GetNetIDString(errorNetID);
AppErrorType errType = static_cast<AppErrorType>(errorType);
switch (errType) {
case AppErrorType::AppErrorRxMessagesFull:
return std::string(netIDString) + ": RX message buffer full";
case AppErrorType::AppErrorTxMessagesFull:
return std::string(netIDString) + ": TX message buffer full";
case AppErrorType::AppErrorTxReportMessagesFull:
return std::string(netIDString) + ": TX report buffer full";
case AppErrorType::AppErrorBadCommWithDspIC:
return "Received bad packet from DSP IC";
case AppErrorType::AppErrorDriverOverflow:
return std::string(netIDString) + ": Driver overflow";
case AppErrorType::AppErrorPCBuffOverflow:
return "PC buffer overflow";
case AppErrorType::AppErrorPCChksumError:
return "PC checksum error";
case AppErrorType::AppErrorPCMissedByte:
return "PC missed byte";
case AppErrorType::AppErrorPCOverrunError:
return "PC overrun error";
case AppErrorType::AppErrorSettingFailure:
return std::string(netIDString) + ": Settings incorrectly set";
case AppErrorType::AppErrorTooManySelectedNetworks:
return "Too many selected networks";
case AppErrorType::AppErrorNetworkNotEnabled:
return std::string(netIDString) + ": Network not enabled";
case AppErrorType::AppErrorRtcNotCorrect:
return "RTC not correct";
case AppErrorType::AppErrorLoadedDefaultSettings:
return "Loaded default settings";
case AppErrorType::AppErrorFeatureNotUnlocked:
return "Feature not unlocked";
case AppErrorType::AppErrorFeatureRtcCmdDropped:
return "RTC command dropped";
case AppErrorType::AppErrorTxMessagesFlushed:
return "TX message buffer flushed";
case AppErrorType::AppErrorTxMessagesHalfFull:
return "TX message buffer half full";
case AppErrorType::AppErrorNetworkNotValid:
return "Network is not valid";
case AppErrorType::AppErrorTxInterfaceNotImplemented:
return "TX interface is not implemented";
case AppErrorType::AppErrorTxMessagesCommEnableIsOff:
return "TX message communication is disabled";
case AppErrorType::AppErrorRxFilterMatchCountExceeded:
return "RX filter match count exceeded";
case AppErrorType::AppErrorEthPreemptionNotEnabled:
return std::string(netIDString) + ": Ethernet preemption not enabled";
case AppErrorType::AppErrorTxNotSupportedInMode:
return std::string(netIDString) + ": Transmit is not supported in this mode";
case AppErrorType::AppErrorJumboFramesNotSupported:
return std::string(netIDString) + ": Jumbo frames not supported";
case AppErrorType::AppErrorEthernetIpFragment:
return "Ethernet IP fragment received";
case AppErrorType::AppErrorTxMessagesUnderrun:
return std::string(netIDString) + ": Transmit buffer underrun";
case AppErrorType::AppErrorDeviceFanFailure:
return "Device fan failure";
case AppErrorType::AppErrorDeviceOvertemperature:
return "Device overtemperature";
case AppErrorType::AppErrorTxMessageIndexOutOfRange:
return "Transmit message index out of range";
case AppErrorType::AppErrorUndersizedFrameDropped:
return std::string(netIDString) + ": Undersized frame dropped";
case AppErrorType::AppErrorOversizedFrameDropped:
return std::string(netIDString) + ": Oversized frame dropped";
case AppErrorType::AppErrorWatchdogEvent:
return "Watchdog event occured";
case AppErrorType::AppErrorSystemClockFailure:
return "Device clock failed";
case AppErrorType::AppErrorSystemClockRecovered:
return "Device clock recovered";
case AppErrorType::AppErrorSystemPeripheralReset:
return "Device peripheral reset";
case AppErrorType::AppErrorSystemCommunicationFailure:
return "Device communication failure";
case AppErrorType::AppErrorTxMessagesUnsupportedSourceOrPacketId:
return std::string(netIDString) + ": Transmit unsupported source or packet ID";
case AppErrorType::AppErrorWbmsManagerConnectFailed:
return std::string(netIDString) + ": Failed to connect to managers with settings";
case AppErrorType::AppErrorWbmsManagerConnectBadState:
return std::string(netIDString) + ": Connected to managers in a invalid state";
case AppErrorType::AppErrorWbmsManagerConnectTimeout:
return std::string(netIDString) + ": Timeout while attempting to connect to managers";
case AppErrorType::AppErrorFailedToInitializeLoggerDisk:
return "Device failed to initialize storage disk";
case AppErrorType::AppErrorInvalidSetting:
return std::string(netIDString) + ": Invalid settings";
case AppErrorType::AppErrorSystemFailureRequestedReset:
return "Device rebooted to recover from an unexpected error condition";
case AppErrorType::AppErrorPortKeyMistmatch:
return std::string(netIDString) + ": Mismatch between key in manager and stored key";
case AppErrorType::AppErrorBusFailure:
return std::string(netIDString) + ": Bus failure";
case AppErrorType::AppErrorTapOverflow:
return std::string(netIDString) + ": Tap overflow";
case AppErrorType::AppErrorEthTxNoLink:
return std::string(netIDString) + ": Attempted Ethernet transmit without link";
case AppErrorType::AppErrorErrorBufferOverflow:
return "Device error buffer overflow";
case AppErrorType::AppNoError:
return "No error";
default:
return "Unknown error";
}
}
} // namespace icsneo
@@ -0,0 +1,234 @@
#include "icsneo/communication/message/callback/streamoutput/a2bwavoutput.h"
#include "icsneo/device/tree/rada2b/rada2b.h"
#include "icsneo/icsneocpp.h"
namespace icsneo {
A2BWAVOutput::A2BWAVOutput(
const char* filename,
const ChannelMap& channelMap,
PCMType bitDepth,
size_t numWAVChannels,
uint32_t sampleRate
)
: StreamOutput(filename), wavSampleRate(sampleRate), numChannelsWAV(numWAVChannels), chMap(channelMap) {
switch(bitDepth) {
case PCMType::L16:
bytesPerSampleWAV = 2;
break;
case PCMType::L24:
bytesPerSampleWAV = 3;
break;
case PCMType::L32:
bytesPerSampleWAV = 4;
break;
}
if(initialize()) {
initialized = true;
}
}
A2BWAVOutput::A2BWAVOutput(
std::ostream& os,
const ChannelMap& channelMap,
PCMType bitDepth,
size_t numWAVChannels,
uint32_t sampleRate
)
: StreamOutput(os), wavSampleRate(sampleRate), numChannelsWAV(numWAVChannels), chMap(channelMap) {
switch(bitDepth) {
case PCMType::L16:
bytesPerSampleWAV = 2;
break;
case PCMType::L24:
bytesPerSampleWAV = 3;
break;
case PCMType::L32:
bytesPerSampleWAV = 4;
break;
}
if(initialize()) {
initialized = true;
}
}
A2BWAVOutput::~A2BWAVOutput() {
if(!closed) {
close();
}
}
bool A2BWAVOutput::initialize() {
static constexpr size_t maxWAVChannels = 256;
if(numChannelsWAV > maxWAVChannels) {
return false;
}
maxMessageChannel = 0;
// Check if the inputted channel map has invalid mappings and compute maxMessageChannel
for(auto [wavChannel, messageChannel] : chMap) {
maxMessageChannel = std::max<size_t>(maxMessageChannel, messageChannel);
if(wavChannel >= numChannelsWAV) {
return false;
}
}
WAVHeader header = WAVHeader(
static_cast<uint16_t>(chMap.size()),
wavSampleRate,
static_cast<uint16_t>(bytesPerSampleWAV * 8)
);
if(!stream->write(reinterpret_cast<const char*>(&header), sizeof(WAVHeader))) {
return false;
}
streamStartPos = static_cast<uint32_t>(stream->tellp());
wavBuffer = std::vector<uint8_t>(wavBufferSize, 0);
wavBufferOffset = 0;
return true;
}
bool A2BWAVOutput::callIfMatch(const std::shared_ptr<Message>& message) const {
if(!initialized) {
return false;
}
if(closed) {
return false;
}
if(message->type != Message::Type::BusMessage) {
return false;
}
const auto& frameMsg = std::dynamic_pointer_cast<BusMessage>(message);
if(!frameMsg) {
return false;
}
if(frameMsg->network.getType() != Network::Type::A2B)
return false;
const auto& a2bMsg = std::dynamic_pointer_cast<A2BMessage>(frameMsg);
if(!a2bMsg) {
return false;
}
size_t frameSize = a2bMsg->getFrameSize();
size_t wavFrameSize = numChannelsWAV * bytesPerSampleWAV;
size_t bytesPerChannel = static_cast<size_t>(a2bMsg->getBytesPerChannel());
size_t numMessageChannels = 2 * a2bMsg->numChannels;
size_t numFrames = a2bMsg->getNumFrames();
const uint8_t* audioBuffer = a2bMsg->data.data();
if(maxMessageChannel >= numMessageChannels) {
// The max message channel in our channel map is larger than the number of channels in this message
// this is likely due to the user inputting incorrect settings
return false;
}
for(size_t frame = 0; frame < numFrames; frame++) {
// Check to see if we can read another frame in wavBuffer, otherwise write and clear the buffer
if(wavBufferOffset + wavFrameSize >= wavBufferSize) {
if(!writeCurrentBuffer()) {
return false;
}
}
for(size_t wavChannel = 0; wavChannel < numChannelsWAV; wavChannel++) {
if(auto iter = chMap.find(static_cast<uint8_t>(wavChannel)); iter != chMap.end()) {
auto messageChannel = iter->second;
size_t messageChannelOffset = messageChannel * bytesPerChannel + frameSize* frame;
// Samples in the WAV are little endian signed integers
// Samples in the message channels are little endian signed integers that are
// most significant bit aligned
if(a2bMsg->channelSize16) {
// In this case, the channel size will be less than or equal to the sample we are writing
// so we zero out any of the least significant bytes which won't be occupied by a sample byte
for(size_t zeroByte = 0; zeroByte < bytesPerSampleWAV - bytesPerChannel; zeroByte++) {
wavBuffer[wavBufferOffset++] = 0;
}
// Write the channel data in the most signifant bytes of the wav sample, this effectively
// writes a sample which is scaled up.
for(size_t channelByte = 0; channelByte < bytesPerChannel; channelByte++) {
wavBuffer[wavBufferOffset++] = audioBuffer[messageChannelOffset + channelByte];
}
} else {
// In this case, the channel size will be greater than or equal to the sample we are reading
// Align the wav sample with the most significant bytes of the channel
size_t channelByte = messageChannelOffset + (bytesPerChannel - bytesPerSampleWAV);
// Read the most significant bytes of the channel into the wavBuffer
for(size_t sampleByte = 0; sampleByte < bytesPerSampleWAV; sampleByte++, channelByte++) {
wavBuffer[wavBufferOffset++] = audioBuffer[channelByte];
}
}
} else {
// If this channel wasn't specified in the channel map, set a zero sample
for(
size_t sampleByte = 0;
sampleByte < bytesPerSampleWAV;
sampleByte++
) {
wavBuffer[wavBufferOffset++] = 0;
}
}
}
}
return true;
}
void A2BWAVOutput::close() const {
if(closed) {
return;
}
if(!initialized) {
return;
}
// Write any left over data in the buffer
if(wavBufferOffset > 0) {
writeCurrentBuffer();
}
// Seek back in the output stream and write the WAV chunk sizes
uint32_t streamEndPos = static_cast<uint32_t>(stream->tellp());
uint32_t subChunk2Size = streamEndPos - streamStartPos;
uint32_t chunkSize = streamEndPos - 8;
stream->seekp(streamStartPos - 4);
stream->write(reinterpret_cast<const char*>(&subChunk2Size), 4);
stream->seekp(4, std::ios::beg);
stream->write(reinterpret_cast<const char*>(&chunkSize), 4);
closed = true;
}
bool A2BWAVOutput::writeCurrentBuffer() const {
if(!stream->write(reinterpret_cast<const char*>(wavBuffer.data()), wavBufferOffset)) {
return false;
}
wavBufferOffset = 0;
return true;
}
}
@@ -0,0 +1,57 @@
#include "icsneo/communication/message/ethernetstatusmessage.h"
using namespace icsneo;
#pragma pack(push, 1)
enum LinkSpeed {
ethSpeed10,
ethSpeed100,
ethSpeed1000,
ethSpeedAutoNeg,
ethSpeed2500,
ethSpeed5000,
ethSpeed10000,
};
enum LinkMode {
OPETH_LINK_AUTO,
OPETH_LINK_MASTER,
OPETH_LINK_SLAVE,
OPETH_LINK_INVALID = 255,
};
struct Packet {
uint8_t state;
uint8_t speed;
uint8_t duplex;
uint16_t network;
uint8_t mode;
};
#pragma pack(pop)
std::shared_ptr<Message> EthernetStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) {
return nullptr;
}
Packet* packet = (Packet*)bytestream.data();
LinkSpeed speed;
switch(packet->speed) {
case ethSpeed10: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed10; break;
case ethSpeed100: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed100; break;
case ethSpeed1000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed1000; break;
case ethSpeedAutoNeg: speed = EthernetStatusMessage::LinkSpeed::LinkSpeedAuto; break;
case ethSpeed2500: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed2500; break;
case ethSpeed5000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed5000; break;
case ethSpeed10000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed10000; break;
default: return nullptr;
}
LinkMode mode;
switch(packet->mode) {
case OPETH_LINK_INVALID: mode = EthernetStatusMessage::LinkMode::LinkModeInvalid; break;
case OPETH_LINK_AUTO: mode = EthernetStatusMessage::LinkMode::LinkModeAuto; break;
case OPETH_LINK_MASTER: mode = EthernetStatusMessage::LinkMode::LinkModeMaster; break;
case OPETH_LINK_SLAVE: mode = EthernetStatusMessage::LinkMode::LinkModeSlave; break;
default: return nullptr;
}
return std::make_shared<EthernetStatusMessage>(packet->network, packet->state, speed, packet->duplex, mode);
}
+50
View File
@@ -0,0 +1,50 @@
#include "icsneo/communication/message/ethphymessage.h"
namespace icsneo
{
bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t phyAddrOrPort, uint8_t pageOrDevice, uint16_t regAddr, uint16_t regVal, bool enabled)
{
auto msg = std::make_shared<PhyMessage>();
msg->Clause45Enable = clause45;
msg->Enabled = enabled;
msg->WriteEnable = writeEnable;
msg->version = 1u;
if( (FiveBits < phyAddrOrPort) ||
(clause45 && (FiveBits < pageOrDevice)) ||
(!clause45 && (FiveBits < regAddr)) )
{
return false;
}
if(clause45)
{
msg->clause45.port = phyAddrOrPort;
msg->clause45.device = pageOrDevice;
msg->clause45.regAddr = regAddr;
msg->clause45.regVal = regVal;
}
else
{
msg->clause22.phyAddr = phyAddrOrPort;
msg->clause22.page = pageOrDevice;
msg->clause22.regAddr = regAddr;
msg->clause22.regVal = regVal;
}
return appendPhyMessage(msg);
}
bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message)
{
if(message != nullptr)
{
messages.push_back(message);
return true;
}
return false;
}
size_t EthPhyMessage::getMessageCount() const
{
return messages.size();
}
}
@@ -0,0 +1,98 @@
#include <icsneo/communication/message/flexray/control/flexraycontrolmessage.h>
#include <cstring> // memcpy
#include <limits>
#include <algorithm>
#include <iostream>
using namespace icsneo;
std::vector<uint8_t> FlexRayControlMessage::BuildBaseControlArgs(uint8_t controller, FlexRay::Opcode op, const std::vector<uint8_t>& args) {
std::vector<uint8_t> ret;
ret.reserve(args.size() + 4);
ret.push_back(controller);
const uint16_t size = uint16_t((std::min)(args.size() + 1, size_t(std::numeric_limits<uint16_t>::max()))); // Add 1 for the opcode
ret.push_back(uint8_t(size));
ret.push_back(uint8_t(size >> 8));
ret.push_back(uint8_t(op));
ret.insert(ret.end(), args.begin(), args.end());
return ret;
}
std::vector<uint8_t> FlexRayControlMessage::BuildReadCCRegsArgs(uint8_t controller, uint16_t startAddress, uint8_t numRegisters) {
startAddress /= 4;
return BuildBaseControlArgs(controller, FlexRay::Opcode::ReadCCRegs, {
uint8_t(startAddress),
uint8_t(startAddress >> 8),
numRegisters
});
}
std::vector<uint8_t> FlexRayControlMessage::BuildWriteCCRegArgs(uint8_t controller, uint16_t address, uint32_t value) {
address /= 4;
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteCCReg, {
uint8_t(address),
uint8_t(address >> 8),
uint8_t(value),
uint8_t(value >> 8),
uint8_t(value >> 16),
uint8_t(value >> 24)
});
}
std::vector<uint8_t> FlexRayControlMessage::BuildAddConfiguredTxMessageArgs(
uint8_t controller, uint16_t descriptionId, uint16_t slotId, uint8_t baseCycle, uint8_t cycleReps, FlexRay::Channel channel) {
return BuildBaseControlArgs(controller, FlexRay::Opcode::AddConfiguredTxMessage, {
uint8_t(descriptionId),
uint8_t(descriptionId >> 8),
uint8_t(slotId),
uint8_t(slotId >> 8),
uint8_t(baseCycle + cycleReps),
uint8_t(channel)
});
}
std::vector<uint8_t> FlexRayControlMessage::BuildWriteMessageBufferArgs(
uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize) {
desiredSize += desiredSize % 4; // Must be a multiple of 4
std::vector<uint8_t> args = {
uint8_t(bufferId),
uint8_t(desiredSize / 4)
};
args.insert(args.end(), data.begin(), data.end());
if((int)args.size() != desiredSize + 2)
args.resize(desiredSize + 2);
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
}
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message(Message::Type::FlexRayControl) {
if(packet.data.size() < 2)
return; // huh?
controller = packet.data[0];
if(controller >= 2)
return; // Invalid controller
// Opcode is only ReadCCStatus or ReadCCRegs for the moment
opcode = FlexRay::Opcode(packet.data[1]);
if(opcode != FlexRay::Opcode::ReadCCRegs && opcode != FlexRay::Opcode::ReadCCStatus)
return;
// Read out registers
size_t bytes = packet.data.size() - 2;
const size_t count = bytes / sizeof(uint32_t);
bytes -= bytes % sizeof(uint32_t); // trim off any trailing bytes
registers.resize(count);
memcpy(registers.data(), packet.data.data() + 2, bytes);
// If it was a status message, we should decode these registers into their components
if(opcode == FlexRay::Opcode::ReadCCStatus) {
if(count < 8)
return;
pocStatus = FlexRay::POCStatus(registers[0] & 0x0000003F);
slotCounterA = registers[4] & 0x0000FFFF;
slotCounterB = (registers[4] & 0xFFFF0000) >> 16;
rateCorrection = registers[6];
offsetCorrection = registers[7];
}
decoded = true;
}
+219
View File
@@ -0,0 +1,219 @@
#include <icsneo/communication/message/gptpstatusmessage.h>
#include <icsneo/communication/message/extendedresponsemessage.h>
#include <cstring>
namespace icsneo {
typedef double float64;
typedef int64_t time_interval;
typedef uint64_t _clock_identity;
#pragma pack(push, 1)
struct port_identity {
_clock_identity clock_identity;
uint16_t port_number;
};
struct _scaled_ns {
int16_t nanoseconds_msb;
int64_t nanoseconds_lsb;
int16_t fractional_nanoseconds;
};
struct _clock_quality {
uint8_t clock_class;
uint8_t clock_accuracy;
uint16_t offset_scaled_log_variance;
};
struct system_identity {
uint8_t priority_1;
struct _clock_quality clock_quality;
uint8_t priority_2;
_clock_identity clock_identity;
};
struct _timestamp {
uint16_t seconds_msb;
uint32_t seconds_lsb;
uint32_t nanoseconds;
};
struct priority_vector {
struct system_identity sysid;
uint16_t steps_removed;
struct port_identity portid;
uint16_t port_number;
};
// IEEE 802.1AS-2020 14.3
// This is a read-only data structure
struct _current_ds {
uint16_t steps_removed;
time_interval offset_from_master;
struct _scaled_ns last_gm_phase_change;
float64 last_gm_freq_change;
uint16_t gm_time_base_indicator;
uint32_t gm_change_count;
uint32_t time_of_last_gm_change_event;
uint32_t time_of_last_gm_phase_change_event;
uint32_t time_of_last_gm_freq_change_event;
};
// IEEE 802.1AS-2020 14.4
// This is a read-only data structure
struct _parent_ds {
struct port_identity parent_port_identity;
int32_t cumulative_rate_ratio;
_clock_identity grandmaster_identity;
uint8_t gm_clock_quality_clock_class;
uint8_t gm_clock_quality_clock_accuracy;
uint16_t gm_clock_quality_offset_scaled_log_variance;
uint8_t gm_priority1;
uint8_t gm_priority2;
};
struct _GPTPStatus
{
struct _timestamp current_time;
struct priority_vector gm_priority;
int64_t ms_offset_ns;
uint8_t is_sync;
uint8_t link_status;
int64_t link_delay_ns;
uint8_t selected_role;
uint8_t as_capable;
uint8_t is_syntonized;
struct _timestamp last_rx_sync_ts; // t2 in IEEE 1588-2019 Figure-16
struct _current_ds current_ds;
struct _parent_ds parent_ds;
};
#pragma pack(pop)
static void SetField(GPTPStatus::Timestamp& output, const _timestamp& input) {
output.seconds = ((uint64_t)(input.seconds_msb) << 32) | ((uint64_t)input.seconds_lsb);
output.nanoseconds = input.nanoseconds;
}
static void SetField(GPTPStatus::PortID& output, const port_identity& input) {
output.clockIdentity = input.clock_identity;
output.portNumber = input.port_number;
}
static void SetField(GPTPStatus::ClockQuality& output, const _clock_quality& input) {
output.clockClass = input.clock_class;
output.clockAccuracy = input.clock_accuracy;
output.offsetScaledLogVariance = input.offset_scaled_log_variance;
}
static void SetField(GPTPStatus::SystemID& output, const system_identity& input) {
output.priority1 = input.priority_1;
SetField(output.clockQuality, input.clock_quality);
output.priority2 = input.priority_2;
output.clockID = input.clock_identity;
}
static void SetField(GPTPStatus::ScaledNanoSeconds& output, const _scaled_ns& input) {
output.nanosecondsMSB = input.nanoseconds_msb;
output.nanosecondsLSB = input.nanoseconds_lsb;
output.fractionalNanoseconds = input.fractional_nanoseconds;
}
static void SetField(GPTPStatus::PriorityVector& output, const priority_vector& input) {
SetField(output.sysID, input.sysid);
output.stepsRemoved = input.steps_removed;
SetField(output.portID, input.portid);
output.portNumber = input.port_number;
}
static void SetField(GPTPStatus::CurrentDS& output, const _current_ds& input) {
output.stepsRemoved = input.steps_removed;
output.offsetFromMaster = input.offset_from_master;
SetField(output.lastgmPhaseChange, input.last_gm_phase_change);
output.lastgmFreqChange = input.last_gm_freq_change;
output.gmTimeBaseIndicator = input.gm_time_base_indicator;
output.gmChangeCount = input.gm_change_count;
output.timeOfLastgmChangeEvent = input.time_of_last_gm_change_event;
output.timeOfLastgmPhaseChangeEvent = input.time_of_last_gm_phase_change_event;
output.timeOfLastgmFreqChangeEvent = input.time_of_last_gm_freq_change_event;
}
static void SetField(GPTPStatus::ParentDS& output, const _parent_ds& input) {
SetField(output.parentPortIdentity, input.parent_port_identity);
output.cumulativeRateRatio = input.cumulative_rate_ratio;
output.grandmasterIdentity = input.grandmaster_identity;
output.gmClockQualityClockClass = input.gm_clock_quality_clock_class;
output.gmClockQualityClockAccuracy = input.gm_clock_quality_clock_accuracy;
output.gmClockQualityOffsetScaledLogVariance = input.gm_clock_quality_offset_scaled_log_variance;
output.gmPriority1 = input.gm_priority1;
output.gmPriority2 = input.gm_priority2;
}
[[maybe_unused]] static void SetField(uint8_t& output, const uint8_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint16_t& output, const uint16_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint32_t& output, const uint32_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint64_t& output, const uint64_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int8_t& output, const int8_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int16_t& output, const int16_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int32_t& output, const int32_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int64_t& output, const int64_t& input) {
output = input;
}
std::shared_ptr<GPTPStatus> GPTPStatus::DecodeToMessage(std::vector<uint8_t>& bytes, const device_eventhandler_t&) {
// The following does not lead to overflow since we only call this function if it has at least ResponseHeader length bytes
std::shared_ptr<GPTPStatus> res = std::make_shared<GPTPStatus>();
auto* header = reinterpret_cast<ExtendedResponseMessage::ResponseHeader*>(bytes.data());
uint16_t length = header->length;
_GPTPStatus* input = reinterpret_cast<_GPTPStatus*>(bytes.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
#define CheckLengthAndSet(output, input) if(length >= sizeof(decltype(input))) { \
SetField(output, input); \
length -= sizeof(decltype(input)); \
} else {\
memset(&output, 0, sizeof(decltype(output))); \
length = 0; \
res->shortFormat = true; \
}
CheckLengthAndSet(res->currentTime, input->current_time);
CheckLengthAndSet(res->gmPriority, input->gm_priority);
CheckLengthAndSet(res->msOffsetNs, input->ms_offset_ns);
CheckLengthAndSet(res->isSync, input->is_sync);
CheckLengthAndSet(res->linkStatus, input->link_status);
CheckLengthAndSet(res->linkDelayNS, input->link_delay_ns);
CheckLengthAndSet(res->selectedRole, input->selected_role);
CheckLengthAndSet(res->asCapable, input->as_capable);
CheckLengthAndSet(res->isSyntonized, input->is_syntonized);
CheckLengthAndSet(res->lastRXSyncTS, input->last_rx_sync_ts);
CheckLengthAndSet(res->currentDS, input->current_ds);
CheckLengthAndSet(res->parentDS, input->parent_ds);
return res;
}
}
+30
View File
@@ -0,0 +1,30 @@
#include "icsneo/communication/message/linmessage.h"
#include <numeric>
namespace icsneo {
void LINMessage::calcChecksum(LINMessage& message) {
uint16_t sum = 0;
auto limitFunc = [](uint16_t x, uint16_t y) -> uint16_t {
if ((x + y) > 0xFFu)
return ((x + y) - 0xFFu);
else
return (x + y);
};
message.checksum = static_cast<uint8_t>(std::accumulate(message.data.begin(), message.data.end(), sum, limitFunc));
if(message.isEnhancedChecksum)
message.checksum = static_cast<uint8_t>(limitFunc(message.checksum, message.protectedID));
message.checksum ^= 0xFFu;
}
uint8_t LINMessage::calcProtectedID(uint8_t& id) {
uint8_t protID = id;
auto bit = [&](uint8_t pos)->uint8_t { return ((protID >> pos) & 0x1u); };
protID |= (~(bit(1) ^ bit(3) ^ bit(4) ^ bit(5)) << 7);
protID |= ((bit(0) ^ bit(1) ^ bit(2) ^ bit(4)) << 6);
return protID;
}
} //namespace icsneo
+15
View File
@@ -0,0 +1,15 @@
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/livedata.h"
namespace icsneo
{
void LiveDataCommandMessage::appendSignalArg(LiveDataValueType valueType) {
auto& arg = args.emplace_back(std::make_shared<LiveDataArgument>());
arg->objectType = LiveDataObjectType::MISC;
arg->objectIndex = 0u;
arg->signalIndex = 0u;
arg->valueType = valueType;
}
} // namespace icsneo
+185 -56
View File
@@ -1,77 +1,206 @@
#include "icsneo/communication/message/neomessage.h" #include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h"
using namespace icsneo; using namespace icsneo;
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) { neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// This function is not responsible for storing the message! // This function is not responsible for storing the message!
// Keep the shared_ptr around for the lifetime of the data access // Keep the shared_ptr around for the lifetime of the data access
const auto type = message->network.getType();
neomessage_t neomsg = {}; // Clear out the memory neomessage_t neomsg = {}; // Clear out the memory
neomsg.netid = (uint32_t)message->network.getNetID(); neomsg.messageType = (neomessagetype_t)message->type;
neomsg.type = (uint8_t)type;
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp; neomsg.timestamp = message->timestamp;
neomsg.status.globalError = message->error; switch (message->type)
neomsg.status.transmitMessage = message->transmitted; {
case Message::Type::BusMessage: {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<BusMessage>(message);
const auto netType = framemsg->network.getType();
switch(type) { frame.netid = (neonetid_t)framemsg->network.getNetID();
case Network::Type::CAN: frame.type = (neonettype_t)netType;
case Network::Type::SWCAN: frame.description = framemsg->description;
case Network::Type::LSFTCAN: { frame.length = framemsg->data.size();
neomessage_can_t& can = *(neomessage_can_t*)&neomsg; frame.data = framemsg->data.data();
auto canmsg = std::static_pointer_cast<CANMessage>(message); frame.timestamp = framemsg->timestamp;
can.arbid = canmsg->arbid; frame.status.globalError = framemsg->error;
can.dlcOnWire = canmsg->dlcOnWire; frame.status.transmitMessage = framemsg->transmitted;
can.status.extendedFrame = canmsg->isExtended;
can.status.remoteFrame = canmsg->isRemote; switch(netType) {
can.status.canfdRTR = canmsg->isRemote; case Network::Type::CAN:
can.status.canfdFDF = canmsg->isCANFD; case Network::Type::SWCAN:
can.status.canfdBRS = canmsg->baudrateSwitch; case Network::Type::LSFTCAN: {
can.status.canfdESI = canmsg->errorStateIndicator; neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
break; auto canmsg = std::static_pointer_cast<CANMessage>(message);
can.arbid = canmsg->arbid;
can.dlcOnWire = canmsg->dlcOnWire;
can.status.extendedFrame = canmsg->isExtended;
can.status.remoteFrame = canmsg->isRemote;
can.status.canfdRTR = canmsg->isRemote;
can.status.canfdFDF = canmsg->isCANFD;
can.status.canfdBRS = canmsg->baudrateSwitch;
can.status.canfdESI = canmsg->errorStateIndicator;
break;
}
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags;
eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcs;
//eth.status.xyz = ethmsg->noPadding;
break;
}
case Network::Type::LIN: {
neomessage_lin_t& lin = *(neomessage_lin_t*)&neomsg;
auto linmsg = std::static_pointer_cast<LINMessage>(message);
if(!linmsg) { break; }
const auto linHdrBytes = std::min(linmsg->data.size(), static_cast<size_t>(2));
lin.header[0] = linmsg->protectedID;
std::copy(linmsg->data.begin(), linmsg->data.begin() + linHdrBytes, lin.header + 1);
linmsg->calcChecksum(*linmsg);
lin.checksum = linmsg->checksum;
lin.data = linmsg->data.data() + linHdrBytes;
if(linmsg->isEnhancedChecksum != linmsg->statusFlags.TxChecksumEnhanced) {
linmsg->isEnhancedChecksum = true;
linmsg->statusFlags.TxChecksumEnhanced = true;
}
if(linmsg->data.size())
lin.length = linmsg->data.size() + 2;
else
lin.length = 1;
lin.linStatus = {
linmsg->statusFlags.TxChecksumEnhanced,
linmsg->statusFlags.TxCommander,
linmsg->statusFlags.TxResponder,
linmsg->statusFlags.UpdateResponderOnce,
linmsg->statusFlags.HasUpdatedResponderOnce,
linmsg->statusFlags.BusRecovered,
linmsg->statusFlags.BreakOnly
};
lin.status.linJustBreakSync = linmsg->errFlags.ErrRxBreakSyncOnly;
lin.status.linErrorTXRXMismatch = linmsg->errFlags.ErrTxRxMismatch;
lin.status.linErrorRXBreakNotZero = linmsg->errFlags.ErrRxBreakNotZero;
lin.status.linErrorRXBreakTooShort = linmsg->errFlags.ErrRxBreakTooShort;
lin.status.linErrorRXSyncNot55 = linmsg->errFlags.ErrRxSyncNot55;
lin.status.linErrorRXDataGreaterEight = linmsg->errFlags.ErrRxDataLenOver8;
lin.status.linSyncFrameError = linmsg->errFlags.ErrFrameSync;
lin.status.linIDFrameError = linmsg->errFlags.ErrFrameMessageID;
lin.status.linSlaveByteError = linmsg->errFlags.ErrFrameResponderData;
lin.status.checksumError = linmsg->errFlags.ErrChecksumMatch;
break;
}
default:
// TODO Implement others
break;
} }
case Network::Type::Ethernet: { break;
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg; }
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message); case Message::Type::CANErrorCount: {
eth.preemptionFlags = ethmsg->preemptionFlags; neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
eth.status.incompleteFrame = ethmsg->frameTooShort; auto canerrormsg = std::static_pointer_cast<CANErrorMessage>(message);
// TODO Fill in extra status bits canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
//eth.status.xyz = ethmsg->preemptionEnabled; canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
//eth.status.xyz = ethmsg->fcsAvailable; canerror.status.canBusOff = canerrormsg->busOff;
//eth.status.xyz = ethmsg->noPadding; canerror.netid = (neonetid_t)canerrormsg->network.getNetID();
break; canerror.type = (neonettype_t)canerrormsg->network.getType();
} break;
default: }
// TODO Implement others default:
break; break;
} }
return neomsg; return neomsg;
} }
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) { std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
const Network network = neomessage->netid; switch((Message::Type)neomessage->messageType) {
switch(network.getType()) { case Message::Type::BusMessage: {
case Network::Type::CAN: const Network network = ((neomessage_frame_t*)neomessage)->netid;
case Network::Type::SWCAN: switch(network.getType()) {
case Network::Type::LSFTCAN: { case Network::Type::CAN:
neomessage_can_t& can = *(neomessage_can_t*)neomessage; case Network::Type::SWCAN:
auto canmsg = std::make_shared<CANMessage>(); case Network::Type::LSFTCAN: {
canmsg->network = network; neomessage_can_t& can = *(neomessage_can_t*)neomessage;
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length); auto canmsg = std::make_shared<CANMessage>();
canmsg->arbid = can.arbid; canmsg->network = network;
canmsg->isExtended = can.status.extendedFrame; canmsg->description = can.description;
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR; canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
canmsg->isCANFD = can.status.canfdFDF; canmsg->arbid = can.arbid;
canmsg->baudrateSwitch = can.status.canfdBRS; canmsg->dlcOnWire = can.dlcOnWire;
canmsg->errorStateIndicator = can.status.canfdESI; canmsg->isExtended = can.status.extendedFrame;
return canmsg; canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
canmsg->isCANFD = can.status.canfdFDF;
canmsg->baudrateSwitch = can.status.canfdBRS;
canmsg->errorStateIndicator = can.status.canfdESI;
return canmsg;
}
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
auto ethmsg = std::make_shared<EthernetMessage>();
ethmsg->network = network;
ethmsg->description = eth.description;
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
return ethmsg;
}
case Network::Type::LIN: {
neomessage_lin_t& lin = *(neomessage_lin_t*)neomessage;
auto linmsg = std::make_shared<LINMessage>();
linmsg->network = network;
linmsg->description = lin.description;
linmsg->protectedID = lin.header[0];
linmsg->ID = linmsg->protectedID & 0x3F;
linmsg->statusFlags = {
static_cast<bool>(lin.linStatus.txChecksumEnhanced),
static_cast<bool>(lin.linStatus.txCommander),
static_cast<bool>(lin.linStatus.txResponder),
static_cast<bool>(lin.linStatus.updateResponderOnce),
static_cast<bool>(lin.linStatus.hasUpdatedResponderOnce),
static_cast<bool>(lin.linStatus.busRecovered),
static_cast<bool>(lin.linStatus.breakOnly)
};
linmsg->isEnhancedChecksum = linmsg->statusFlags.TxChecksumEnhanced;
linmsg->errFlags = {
static_cast<bool>(lin.linStatus.breakOnly),
static_cast<bool>(lin.status.linJustBreakSync),
static_cast<bool>(lin.status.linErrorTXRXMismatch),
static_cast<bool>(lin.status.linErrorRXBreakNotZero),
static_cast<bool>(lin.status.linErrorRXBreakTooShort),
static_cast<bool>(lin.status.linErrorRXSyncNot55),
static_cast<bool>(lin.status.linErrorRXDataGreaterEight),
static_cast<bool>(lin.status.linSyncFrameError),
static_cast<bool>(lin.status.linIDFrameError),
static_cast<bool>(lin.status.linSlaveByteError),
static_cast<bool>(lin.status.checksumError)
};
if(lin.length > 1) {
auto numHeaderBytes = std::min(lin.length, static_cast<size_t>(3));
linmsg->data.insert(linmsg->data.end(), (lin.header + 1), (lin.header + numHeaderBytes));
linmsg->data.insert(linmsg->data.end(), lin.data, (lin.data + (lin.length - numHeaderBytes)));
linmsg->checksum = linmsg->data.back();
linmsg->data.pop_back();
}
if (linmsg->statusFlags.TxCommander) {
if (linmsg->data.size())
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_COMMANDER_MSG;
else
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_HEADER_ONLY;
} else if (linmsg->statusFlags.TxResponder) {
linmsg->linMsgType = icsneo::LINMessage::Type::LIN_UPDATE_RESPONDER;
}
return linmsg;
}
default: break;
}
break;
} }
default: default: break;
// TODO Implement others
return std::shared_ptr<Message>();
} }
return std::shared_ptr<Message>();
} }
@@ -0,0 +1,31 @@
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
#pragma pack(push, 2)
struct Header {
ExtendedCommand command;
uint16_t length;
};
struct Packet {
Header header;
TC10WakeStatus wakeStatus;
TC10SleepStatus sleepStatus;
};
#pragma pack(pop)
std::shared_ptr<TC10StatusMessage> TC10StatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) {
return nullptr;
}
const Packet* packet = (Packet*)bytestream.data();
if (packet->header.command != ExtendedCommand::GetTC10Status) {
return nullptr;
}
if (packet->header.length < sizeof(Packet) - sizeof(Header)) {
return nullptr;
}
return std::make_shared<TC10StatusMessage>(packet->wakeStatus, packet->sleepStatus);
}
+84 -24
View File
@@ -2,19 +2,34 @@
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/communication/decoder.h" #include "icsneo/communication/decoder.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include <iostream> #include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include <iomanip>
using namespace icsneo; using namespace icsneo;
MultiChannelCommunication::MultiChannelCommunication(device_eventhandler_t err, std::unique_ptr<Driver> com,
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer, std::unique_ptr<Encoder> e,
std::unique_ptr<Decoder> md, size_t vnetCount) :
Communication(err, std::move(com), makeConfiguredPacketizer, std::move(e), std::move(md)), numVnets(vnetCount) {
vnetThreads.resize(numVnets);
vnetQueues.resize(numVnets);
}
void MultiChannelCommunication::spawnThreads() { void MultiChannelCommunication::spawnThreads() {
mainChannelReadThread = std::thread(&MultiChannelCommunication::readTask, this); for(size_t i = 0; i < numVnets; i++) {
while(vnetQueues[i].pop()) {} // Ensure the queue is empty
vnetThreads[i] = std::thread(&MultiChannelCommunication::vnetReadTask, this, i);
}
hidReadThread = std::thread(&MultiChannelCommunication::hidReadTask, this);
} }
void MultiChannelCommunication::joinThreads() { void MultiChannelCommunication::joinThreads() {
closing = true; closing = true;
if(mainChannelReadThread.joinable()) if(hidReadThread.joinable())
mainChannelReadThread.join(); hidReadThread.join();
for(auto& thread : vnetThreads) {
if(thread.joinable())
thread.join();
}
closing = false; closing = false;
} }
@@ -23,16 +38,19 @@ bool MultiChannelCommunication::sendPacket(std::vector<uint8_t>& bytes) {
return rawWrite(bytes); return rawWrite(bytes);
} }
void MultiChannelCommunication::readTask() { void MultiChannelCommunication::hidReadTask() {
bool readMore = true; bool readMore = true;
bool gotPacket = false; // Have we got the first valid packet (don't flag errors otherwise)
std::deque<uint8_t> usbReadFifo; std::deque<uint8_t> usbReadFifo;
std::vector<uint8_t> readBytes; std::vector<uint8_t> readBytes;
std::vector<uint8_t> payloadBytes; std::vector<uint8_t> payloadBytes;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) { while(!closing) {
if(readMore) { if(readMore) {
readBytes.clear(); readBytes.clear();
if(impl->readWait(readBytes)) { if(driver->readWait(readBytes)) {
readMore = false; readMore = false;
usbReadFifo.insert(usbReadFifo.end(), std::make_move_iterator(readBytes.begin()), std::make_move_iterator(readBytes.end())); usbReadFifo.insert(usbReadFifo.end(), std::make_move_iterator(readBytes.begin()), std::make_move_iterator(readBytes.end()));
} }
@@ -47,8 +65,9 @@ void MultiChannelCommunication::readTask() {
currentCommandType = (CommandType)usbReadFifo[0]; currentCommandType = (CommandType)usbReadFifo[0];
if(!CommandTypeIsValid(currentCommandType)) { if(!CommandTypeIsValid(currentCommandType)) {
// TODO Flag error? Device to host bytes discarded // Device to host bytes discarded
//std::cout << "cnv" << std::hex << (int)currentCommandType << ' ' << std::dec; if(gotPacket)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
usbReadFifo.pop_front(); usbReadFifo.pop_front();
continue; continue;
} }
@@ -88,7 +107,7 @@ void MultiChannelCommunication::readTask() {
case PreprocessState::GetData: case PreprocessState::GetData:
state = PreprocessState::GetData; // Set state in case we've fallen through, but later need to go around again state = PreprocessState::GetData; // Set state in case we've fallen through, but later need to go around again
if(usbReadFifo.size() <= currentReadIndex + currentCommandLength) { // Come back we have more data if(usbReadFifo.size() < currentReadIndex + currentCommandLength) { // Come back when we have more data
readMore = true; readMore = true;
continue; continue;
} }
@@ -102,26 +121,67 @@ void MultiChannelCommunication::readTask() {
payloadBytes[i] = usbReadFifo[0]; payloadBytes[i] = usbReadFifo[0];
usbReadFifo.pop_front(); usbReadFifo.pop_front();
} }
if(packetizer->input(payloadBytes)) {
for(auto& packet : packetizer->output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet)) {
err(APIError::Unknown); // TODO Use specific error
continue;
}
for(auto& cb : messageCallbacks) { // We might have closed while reading or processing moodycamel::BlockingReaderWriterQueue< std::vector<uint8_t> >* currentQueue = nullptr;
if(!closing) { switch(currentCommandType) {
cb.second.callIfMatch(msg); case CommandType::Vnet1_to_HostPC:
} currentQueue = &vnetQueues[0];
} break;
case CommandType::Vnet2_to_HostPC:
if(numVnets >= 2)
currentQueue = &vnetQueues[1];
break;
case CommandType::Vnet3_to_HostPC:
if(numVnets >= 3)
currentQueue = &vnetQueues[2];
break;
case CommandType::SDCC1_to_HostPC: {
auto msg = std::make_shared<NeoReadMemorySDMessage>();
std::swap(msg->data, payloadBytes);
dispatchMessage(msg);
break;
} }
} }
if(currentQueue == nullptr) {
state = PreprocessState::SearchForCommand;
break;
}
if(!currentQueue->enqueue(std::move(payloadBytes)) && gotPacket)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
payloadBytes.clear();
gotPacket = true;
state = PreprocessState::SearchForCommand; state = PreprocessState::SearchForCommand;
break;
} }
} }
}
}
void MultiChannelCommunication::vnetReadTask(size_t vnetIndex) {
moodycamel::BlockingReaderWriterQueue< std::vector<uint8_t> >& queue = vnetQueues[vnetIndex];
std::vector<uint8_t> payloadBytes;
std::unique_ptr<Packetizer> packetizerLifetime;
Packetizer* vnetPacketizer;
if(vnetIndex == 0)
vnetPacketizer = packetizer.get();
else {
packetizerLifetime = makeConfiguredPacketizer();
vnetPacketizer = packetizerLifetime.get();
}
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
if(queue.wait_dequeue_timed(payloadBytes, std::chrono::milliseconds(250))) {
if(closing)
break;
auto& ringBuffer = driver->getReadBuffer();
ringBuffer.write(payloadBytes);
handleInput(*vnetPacketizer);
}
} }
} }
+60
View File
@@ -0,0 +1,60 @@
#include "icsneo/communication/packet/a2bpacket.h"
#include <cstring>
#include <vector>
namespace icsneo {
const size_t HardwareA2BPacket::a2bMessageMaxLength = sizeof(HardwareA2BPacket) + 1024;
std::shared_ptr<Message> HardwareA2BPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(HardwareA2BPacket))
{
return nullptr;
}
const HardwareA2BPacket* data = (const HardwareA2BPacket*)bytestream.data();
size_t totalPackedLength = static_cast<size_t>(bytestream.size()) - sizeof(HardwareA2BPacket); // First 28 bytes are message header.
if(totalPackedLength == 0) {
return nullptr;
}
std::shared_ptr<A2BMessage> msg = std::make_shared<A2BMessage>();
msg->numChannels = data->header.channelNum;
msg->channelSize16 = data->header.channelSize16;
msg->monitor = data->header.monitor;
msg->txmsg = data->header.txmsg;
msg->errIndicator = data->header.errIndicator;
msg->syncFrame = data->header.syncFrame;
msg->rfu2 = data->header.rfu2;
msg->timestamp = data->timestamp.TS;
msg->data = std::vector(bytestream.begin() + sizeof(HardwareA2BPacket), bytestream.end());
return msg;
}
bool HardwareA2BPacket::EncodeFromMessage(const A2BMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& /*report*/) {
constexpr size_t a2btxMessageHeaderSize = 6;
size_t audioBufferSize = message.data.size();
size_t totalSize = a2btxMessageHeaderSize + audioBufferSize;
bytestream.resize(totalSize, 0);
uint32_t offset = 0;
bytestream[offset++] = 0;
bytestream[offset++] = 0;
bytestream[offset++] = (uint8_t)(audioBufferSize & 0xFF);
bytestream[offset++] = (uint8_t)((audioBufferSize >> 8) & 0xFF);
bytestream[offset++] = (uint8_t)((message.description >> 8) & 0xFF);
bytestream[offset++] = (uint8_t)(message.description & 0xFF);
std::copy(message.data.begin(), message.data.end(), bytestream.begin() + offset);
return true;
}
}
+162 -161
View File
@@ -1,173 +1,171 @@
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrormessage.h"
using namespace icsneo; using namespace icsneo;
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) { std::optional<uint8_t> icsneo::CAN_DLCToLength(uint8_t length, bool fd) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data(); if (length <= 8)
return length;
auto msg = std::make_shared<CANMessage>(); if (fd) {
switch(length) {
// Arb ID case 0x9:
if(data->header.IDE) { // Extended 29-bit ID return uint8_t(12);
msg->arbid = (data->header.SID & 0x7ff) << 18; case 0xa:
msg->arbid |= (data->eid.EID & 0xfff) << 6; return uint8_t(16);
msg->arbid |= (data->dlc.EID2 & 0x3f); case 0xb:
msg->isExtended = true; return uint8_t(20);
} else { // Standard 11-bit ID case 0xc:
msg->arbid = data->header.SID; return uint8_t(24);
} case 0xd:
return uint8_t(32);
// This timestamp is raw off the device (in timestampResolution increments) case 0xe:
// Decoder will fix as it has information about the timestampResolution increments return uint8_t(48);
msg->timestamp = data->timestamp.TS; case 0xf:
return uint8_t(64);
// DLC
uint8_t length = data->dlc.DLC;
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI;
if(length > 8) {
switch(length) { // CAN FD Length Decoding
case 0x9:
length = 12;
break;
case 0xa:
length = 16;
break;
case 0xb:
length = 20;
break;
case 0xc:
length = 24;
break;
case 0xd:
length = 32;
break;
case 0xe:
length = 48;
break;
case 0xf:
length = 64;
break;
default:
return nullptr;
}
}
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
// We don't want to overread our buffer, though, so make sure we cap the length
length = 8;
}
// Data
// The first 8 bytes are always in the standard place
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
msg->data.resize(length); // This data will be all zeros, but the length will be set
msg->isRemote = true;
} else {
msg->data.reserve(length);
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
} }
} }
return msg; return std::nullopt;
} }
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result) { std::optional<uint8_t> icsneo::CAN_LengthToDLC(size_t dataLength, bool fd)
if(message.isCANFD && message.isRemote) {
return false; // RTR frames can not be used with CAN FD if (dataLength <= 8)
return uint8_t(dataLength);
const size_t dataSize = message.data.size(); if (fd) {
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD)) if (dataLength <= 12)
return false; // Too much data for the protocol return uint8_t(0x9);
else if (dataLength <= 16)
uint8_t lengthNibble = uint8_t(message.data.size()); return uint8_t(0xA);
uint8_t paddingBytes = 0; else if (dataLength <= 20)
if(lengthNibble > 8) { return uint8_t(0xB);
switch(lengthNibble) { else if (dataLength <= 24)
case 9: paddingBytes++; return uint8_t(0xC);
case 10: paddingBytes++; else if (dataLength <= 32)
case 11: paddingBytes++; return uint8_t(0xD);
case 12: else if (dataLength <= 48)
lengthNibble = 0x9; return uint8_t(0xE);
break; else if (dataLength <= 64)
case 13: paddingBytes++; return uint8_t(0xF);
case 14: paddingBytes++;
case 15: paddingBytes++;
case 16:
lengthNibble = 0xA;
break;
case 17: paddingBytes++;
case 18: paddingBytes++;
case 19: paddingBytes++;
case 20:
lengthNibble = 0xB;
break;
case 21: paddingBytes++;
case 22: paddingBytes++;
case 23: paddingBytes++;
case 24:
lengthNibble = 0xC;
break;
case 25: paddingBytes++;
case 26: paddingBytes++;
case 27: paddingBytes++;
case 28: paddingBytes++;
case 29: paddingBytes++;
case 30: paddingBytes++;
case 31: paddingBytes++;
case 32:
lengthNibble = 0xD;
break;
case 33: paddingBytes++;
case 34: paddingBytes++;
case 35: paddingBytes++;
case 36: paddingBytes++;
case 37: paddingBytes++;
case 38: paddingBytes++;
case 39: paddingBytes++;
case 40: paddingBytes++;
case 41: paddingBytes++;
case 42: paddingBytes++;
case 43: paddingBytes++;
case 44: paddingBytes++;
case 45: paddingBytes++;
case 46: paddingBytes++;
case 47: paddingBytes++;
case 48:
lengthNibble = 0xE;
break;
case 49: paddingBytes++;
case 50: paddingBytes++;
case 51: paddingBytes++;
case 52: paddingBytes++;
case 53: paddingBytes++;
case 54: paddingBytes++;
case 55: paddingBytes++;
case 56: paddingBytes++;
case 57: paddingBytes++;
case 58: paddingBytes++;
case 59: paddingBytes++;
case 60: paddingBytes++;
case 61: paddingBytes++;
case 62: paddingBytes++;
case 63: paddingBytes++;
case 64:
lengthNibble = 0xF;
break;
default:
return false; // CAN FD frame may have had an incorrect byte count
}
} }
return std::nullopt;
}
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
const HardwareCANErrorPacket* errPacket = (const HardwareCANErrorPacket*)bytestream.data();
if(errPacket->ERROR_INDICATOR) {
auto msg = std::make_shared<CANErrorMessage>();
msg->receiveErrorCount = errPacket->REC;
msg->transmitErrorCount = errPacket->TEC;
msg->errorWarn = HardwareCANErrorPacket::GetErrorWarn(errPacket->flags);
msg->errorPassive = HardwareCANErrorPacket::GetErrorPassive(errPacket->flags);
msg->busOff = HardwareCANErrorPacket::GetBusOff(errPacket->flags);
msg->errorCode = (CANErrorCode)errPacket->error_code;
msg->dataErrorCode = (CANErrorCode)errPacket->brs_data_error_code;
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
return msg;
} else { // CAN Frame
auto msg = std::make_shared<CANMessage>();
// Arb ID
if(data->header.IDE) { // Extended 29-bit ID
msg->arbid = (data->header.SID & 0x7ff) << 18;
msg->arbid |= (data->eid.EID & 0xfff) << 6;
msg->arbid |= (data->dlc.EID2 & 0x3f);
msg->isExtended = true;
} else { // Standard 11-bit ID
msg->arbid = data->header.SID;
}
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// DLC
uint8_t length = data->dlc.DLC;
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI;
const std::optional<uint8_t> lenFromDLC = CAN_DLCToLength(length, true);
if (lenFromDLC)
length = *lenFromDLC;
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
// We don't want to overread our buffer, though, so make sure we cap the length
length = 8;
}
// Data
// The first 8 bytes are always in the standard place
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
msg->data.resize(length); // This data will be all zeros, but the length will be set
msg->isRemote = true;
} else {
msg->data.reserve(length);
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
}
}
msg->transmitted = data->eid.TXMSG;
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
msg->description = data->stats;
return msg;
}
}
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
if(message.isCANFD && message.isRemote) {
report(APIEvent::Type::RTRNotSupported, APIEvent::Severity::Error);
return false; // RTR frames can not be used with CAN FD
}
const size_t dataSize = message.data.size();
std::optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, message.isCANFD);
if (!dlc.has_value()) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol
}
if (message.dlcOnWire != 0) {
if(message.dlcOnWire > 0xf) {
// The DLC is only a nibble
// It is actually possible to transmit a standard CAN frame with a DLC > 8
// While it is invalid, most controllers will still pass along the received
// frame and 8 bytes of data, so it may be desirable to test behavior with
// these frames. We let you do it if you set `message.dlcOnWire` for transmit.
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
if (message.dlcOnWire < *dlc) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
if (message.dlcOnWire > *dlc)
dlc = message.dlcOnWire;
}
// The only way this fails is if we're transmitting a DLC > 8 on standard CAN
const uint8_t paddedLength = CAN_DLCToLength(*dlc, message.isCANFD).value_or(8);
const uint8_t paddingBytes = uint8_t(paddedLength - dataSize);
// Pre-allocate as much memory as we will possibly need for speed // Pre-allocate as much memory as we will possibly need for speed
result.reserve(17 + dataSize + paddingBytes); result.reserve(16 + dataSize + paddingBytes);
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF)); result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
@@ -176,8 +174,10 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
// Next 2-4 bytes are ArbID // Next 2-4 bytes are ArbID
if(message.isExtended) { if(message.isExtended) {
if(message.arbid >= 0x20000000) // Extended messages use 29-bit arb IDs if(message.arbid >= 0x20000000) {// Extended messages use 29-bit arb IDs
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false;
}
result.insert(result.end(), { result.insert(result.end(), {
(uint8_t)(message.arbid >> 21), (uint8_t)(message.arbid >> 21),
@@ -186,8 +186,10 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
(uint8_t)message.arbid (uint8_t)message.arbid
}); });
} else { } else {
if(message.arbid >= 0x800) // Standard messages use 11-bit arb IDs if(message.arbid >= 0x800) {// Standard messages use 11-bit arb IDs
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false;
}
result.insert(result.end(), { result.insert(result.end(), {
(uint8_t)(message.arbid >> 3), (uint8_t)(message.arbid >> 3),
@@ -198,7 +200,7 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
// Status and DLC bits // Status and DLC bits
if(message.isCANFD) { if(message.isCANFD) {
result.push_back(0x0F); // FD Frame result.push_back(0x0F); // FD Frame
uint8_t fdStatusByte = lengthNibble; uint8_t fdStatusByte = *dlc;
if(message.baudrateSwitch) if(message.baudrateSwitch)
fdStatusByte |= 0x80; // BRS status bit fdStatusByte |= 0x80; // BRS status bit
// The firmware does not yet support transmitting ESI // The firmware does not yet support transmitting ESI
@@ -206,13 +208,12 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
} else { } else {
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable // TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0; uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
result.push_back((statusNibble << 4) | lengthNibble); result.push_back((statusNibble << 4) | *dlc);
} }
// Now finally the payload // Now finally the payload
result.insert(result.end(), message.data.begin(), message.data.end()); result.insert(result.end(), message.data.begin(), message.data.end());
result.resize(result.size() + paddingBytes); result.resize(result.size() + paddingBytes);
result.push_back(0);
// Fill in the length byte from earlier // Fill in the length byte from earlier
result[0] |= result.size() << 4; result[0] |= result.size() << 4;
@@ -0,0 +1,45 @@
#include "icsneo/communication/packet/componentversionpacket.h"
#include "icsneo/communication/message/componentversionsmessage.h"
using namespace icsneo;
#pragma pack(push, 2)
struct PackedComponentVersion {
uint8_t valid;
uint8_t expansionSlot;
uint8_t componentInfo; // Component specific data (e.g. Linux: boot device)
uint8_t reserved;
uint32_t identifier;
uint32_t dotVersion; // Represents a.b.c.d, a.b.c, or a.b, depending on leading zeros.
uint32_t commitHash;
};
static constexpr size_t MaxReportedVersions = 16;
struct ComponentVersionsResponse {
ExtendedResponseMessage::ResponseHeader header;
uint16_t numVersions;
PackedComponentVersion versions[MaxReportedVersions];
};
#pragma pack(pop)
std::shared_ptr<ComponentVersionsMessage> ComponentVersionPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
auto msg = std::make_shared<ComponentVersionsMessage>();
// Length checks: At least a header and numVersions field.
if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 2) {
return msg; // Empty
}
// Get a reference to the payload to fully validate the length
const auto& response = *reinterpret_cast<const ComponentVersionsResponse*>(bytes.data());
// Expected size is the header, numVersions field, and numVersions ComponentVersion objects.
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 2 + (response.numVersions * sizeof(ComponentVersion));
// If the response is malformed (too small), return an empty message.
if(bytes.size() < expectedSize) {
return msg; // Empty
}
// Unpack into the portable class
for(unsigned int i = 0; i < response.numVersions; ++i) {
const auto& packedVersion = response.versions[i];
msg->versions.emplace_back(packedVersion.valid, packedVersion.componentInfo, packedVersion.identifier, packedVersion.dotVersion, packedVersion.commitHash);
}
return msg;
}
+30 -17
View File
@@ -4,7 +4,7 @@
using namespace icsneo; using namespace icsneo;
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data()); const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data());
const uint16_t* rawWords = (const uint16_t*)bytestream.data(); const uint16_t* rawWords = (const uint16_t*)bytestream.data();
@@ -16,12 +16,15 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
if(packet->Length < 4) if(packet->Length < 4)
return nullptr; return nullptr;
size_t bytesOnWire = packet->Length - (sizeof(uint16_t) * 2); const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0;
if(bytestream.size() < sizeof(HardwareEthernetPacket) + bytesOnWire) const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + packet->Length;
const size_t bytestreamActualSize = bytestream.size();
if(bytestreamActualSize < bytestreamExpectedSize)
return nullptr; return nullptr;
if(bytestream.size() > sizeof(HardwareEthernetPacket) + bytesOnWire) // Check for oversized packets, noting that some devices will send an extra byte to have an even number of bytes
std::cout << "There is an extra " << (sizeof(HardwareEthernetPacket) + bytesOnWire) << " bytes at the end" << std::endl; if(bytestreamActualSize > bytestreamExpectedSize + 1)
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
auto messagePtr = std::make_shared<EthernetMessage>(); auto messagePtr = std::make_shared<EthernetMessage>();
EthernetMessage& message = *messagePtr; EthernetMessage& message = *messagePtr;
@@ -33,8 +36,6 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED; message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled) if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4); message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.fcsAvailable = packet->header.FCS_AVAIL;
message.frameTooShort = packet->header.RUNT_FRAME; message.frameTooShort = packet->header.RUNT_FRAME;
if(message.frameTooShort) if(message.frameTooShort)
@@ -44,23 +45,36 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
// Decoder will fix as it has information about the timestampResolution increments // Decoder will fix as it has information about the timestampResolution increments
message.timestamp = packet->timestamp.TS; message.timestamp = packet->timestamp.TS;
// Network ID is also not set, this will be fixed in the Decoder as well const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket);
const std::vector<uint8_t>::const_iterator dataend = databegin + packet->Length - fcsSize;
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + (sizeof(HardwareEthernetPacket) - (sizeof(uint16_t) * 2));
const std::vector<uint8_t>::const_iterator dataend = databegin + bytesOnWire;
message.data.insert(message.data.begin(), databegin, dataend); message.data.insert(message.data.begin(), databegin, dataend);
if(fcsSize) {
uint32_t& fcs = message.fcs.emplace();
std::copy(dataend, dataend + fcsSize, (uint8_t*)&fcs);
}
return messagePtr; return messagePtr;
} }
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream) { bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t&) {
const size_t unpaddedSize = message.data.size(); const size_t unpaddedSize = message.data.size();
size_t paddedSize = unpaddedSize; size_t paddedSize = unpaddedSize;
uint16_t description = message.description;
if(!message.noPadding && unpaddedSize < 60) if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60; // Pad out short messages paddedSize = 60; // Pad out short messages
size_t sizeWithHeader = paddedSize + 5; // DescriptionID and Premption Flags size_t sizeWithHeader = paddedSize + 4; // DescriptionID and Padded Count
// Description ID Most Significant bit is used to identify preemption frames
if(description & 0x8000)
return false;
if(message.preemptionEnabled) {
sizeWithHeader++; // Make space for the preemption flags
description |= 0x8000;
}
bytestream.reserve(sizeWithHeader + 8); // Also reserve space for the bytes we'll use later on bytestream.reserve(sizeWithHeader + 8); // Also reserve space for the bytes we'll use later on
bytestream.resize(sizeWithHeader); bytestream.resize(sizeWithHeader);
@@ -71,11 +85,10 @@ bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, s
bytestream[index++] = uint8_t(paddedSize >> 8); bytestream[index++] = uint8_t(paddedSize >> 8);
// Description ID, big endian // Description ID, big endian
bytestream[index++] = uint8_t(message.description >> 8); bytestream[index++] = uint8_t(description >> 8);
bytestream[index++] = uint8_t(message.description); bytestream[index++] = uint8_t(description);
// Yes, we reserved and allocated space for the preemption flags even if we're not putting them there // The header is one byte larger if preemption is enabled, shifting the data
// And yes, the data is intended to move over one byte
if(message.preemptionEnabled) if(message.preemptionEnabled)
bytestream[index++] = message.preemptionFlags; bytestream[index++] = message.preemptionFlags;
+106
View File
@@ -0,0 +1,106 @@
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/packetizer.h"
#include <memory>
#include <cstdint>
#include <iostream>
namespace icsneo
{
std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
if(bytestream.empty() || (bytestream.size() < sizeof(PhyRegisterHeader_t)))
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
auto msg = std::make_shared<EthPhyMessage>();
const PhyRegisterHeader_t* pHeader = reinterpret_cast<const PhyRegisterHeader_t*>(bytestream.data());
const size_t numEntries = static_cast<size_t>(pHeader->numEntries);
if(
(PhyPacketVersion == pHeader->version) &&
(sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) &&
(numEntries <= MaxPhyEntries) &&
((bytestream.size() - sizeof(PhyRegisterHeader_t))
== (sizeof(PhyRegisterPacket_t) * numEntries))
)
{
msg->messages.reserve(numEntries);
const PhyRegisterPacket_t* pFirstEntry = reinterpret_cast<const PhyRegisterPacket_t*>(bytestream.data() + sizeof(PhyRegisterHeader_t));
for(size_t entryIdx{0}; entryIdx < numEntries; ++entryIdx)
{
const PhyRegisterPacket_t* pEntry = (pFirstEntry + entryIdx);
auto phyMessage = std::make_shared<PhyMessage>();
phyMessage->Enabled = (pEntry->Enabled != 0u);
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
phyMessage->Clause45Enable = (pEntry->Clause45Enable != 0u);
phyMessage->version = static_cast<uint8_t>(pEntry->version);
if(phyMessage->Clause45Enable)
phyMessage->clause45 = pEntry->clause45;
else
phyMessage->clause22 = pEntry->clause22;
msg->messages.push_back(phyMessage);
}
}
return msg;
}
bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t messageCount = message.getMessageCount();
if(!messageCount)
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
else if (messageCount > MaxPhyEntries)
{
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
auto byteSize = (messageCount * sizeof(PhyRegisterPacket_t)) + sizeof(PhyRegisterHeader_t);
bytestream.reserve(byteSize);
bytestream.push_back(static_cast<uint8_t>(messageCount & 0xFF));
bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF));
bytestream.push_back(PhyPacketVersion);
bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t)));
for(auto& phyMessage : message.messages)
{
PhyRegisterPacket_t tempPacket;
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
tempPacket.version = (phyMessage->version & 0xF);
if(phyMessage->Clause45Enable)
{
if( (FiveBits < phyMessage->clause45.port) ||
(FiveBits < phyMessage->clause45.device) )
{
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
tempPacket.Clause45Enable = 0x1u;
tempPacket.clause45.port = phyMessage->clause45.port;
tempPacket.clause45.device = phyMessage->clause45.device;
tempPacket.clause45.regAddr = phyMessage->clause45.regAddr;
tempPacket.clause45.regVal = phyMessage->clause45.regVal;
}
else
{
if( (FiveBits < phyMessage->clause22.phyAddr) ||
(FiveBits < phyMessage->clause22.regAddr) )
{
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
tempPacket.Clause45Enable = 0x0u;
tempPacket.clause22.phyAddr = phyMessage->clause22.phyAddr;
tempPacket.clause22.page = phyMessage->clause22.page;
tempPacket.clause22.regAddr = phyMessage->clause22.regAddr;
tempPacket.clause22.regVal = phyMessage->clause22.regVal;
}
uint8_t* pktPtr = reinterpret_cast<uint8_t*>(&tempPacket);
bytestream.insert(bytestream.end(), pktPtr, pktPtr + sizeof(PhyRegisterPacket_t));
}
return true;
}
}
+76
View File
@@ -0,0 +1,76 @@
#include "icsneo/communication/packet/flexraypacket.h"
using namespace icsneo;
std::shared_ptr<FlexRayMessage> HardwareFlexRayPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareFlexRayPacket* data = (const HardwareFlexRayPacket*)bytestream.data();
if(!data->timestamp.IsExtended) // We can only process "extended" frames here
return nullptr;
auto msg = std::make_shared<FlexRayMessage>();
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// Always get the frame length, even for a symbol
msg->framelen = data->frame_length_12_5ns * 12.5e-9;
msg->channel = data->statusBits.bits.chb ? icsneo::FlexRay::Channel::B : icsneo::FlexRay::Channel::A;
if(data->tss_length_12_5ns == 0xffff) {// Flag value meaning this is a symbol
// These values are only for 10Mbit
// That's the only baudrate supported for now
if (data->frame_length_12_5ns > 480)
msg->symbol = FlexRay::Symbol::Wakeup;
else if (data->frame_length_12_5ns > 264)
msg->symbol = FlexRay::Symbol::CAS;
else
msg->symbol = FlexRay::Symbol::Unknown;
} else {
msg->tsslen = data->tss_length_12_5ns * 12.5e-9;
if(data->statusBits.bits.bytesRxed >= 5) {
if(data->statusBits.bits.hcrc_error)
msg->headerCRCStatus = FlexRay::CRCStatus::Error;
} else {
msg->headerCRCStatus = FlexRay::CRCStatus::NoCRC;
}
uint32_t numBytes = data->payload_len * 2;
if(int64_t(numBytes) >= int64_t(data->Length) - 4) {
if(data->statusBits.bits.fcrc_error)
msg->crcStatus = FlexRay::CRCStatus::Error;
} else {
msg->crcStatus = FlexRay::CRCStatus::NoCRC;
}
if(data->statusBits.bits.bytesRxed >= 5) { // Received entire header
msg->headerCRC = (data->hdr_crc_10 << 10) | data->hdr_crc_9_0;
if(msg->headerCRCStatus != FlexRay::CRCStatus::Error) {
msg->reserved0was1 = data->reserved_0;
msg->payloadPreamble = data->payload_preamble;
msg->nullFrame = !data->null_frame;
msg->sync = data->sync;
msg->startup = data->startup;
msg->slotid = data->slotid;
msg->cycle = data->cycle;
msg->dynamic = data->statusBits.bits.dynamic;
if(int64_t(numBytes) != int64_t(data->Length) - 4) {
// This is an error, probably need to flag it
} else {
const uint8_t* dataStart = (const uint8_t*)(data) - 4 + sizeof(HardwareFlexRayPacket);
msg->data = std::vector<uint8_t>(dataStart, dataStart + numBytes);
}
}
}
}
return msg;
}
bool HardwareFlexRayPacket::EncodeFromMessage(const FlexRayMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
(void)message;
(void)bytestream;
(void)report;
return false;
}
@@ -0,0 +1,38 @@
#include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/message/genericbinarystatusmessage.h"
using namespace icsneo;
#pragma pack(push, 2)
struct GenericBinaryStatusResponse {
ExtendedResponseMessage::ResponseHeader header;
size_t size;
uint16_t index;
uint16_t status;
};
#pragma pack(pop)
std::shared_ptr<GenericBinaryStatusMessage> GenericBinaryStatusPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
if(bytes.size() < sizeof(GenericBinaryStatusResponse)) {
return nullptr;
}
auto msg = std::make_shared<GenericBinaryStatusMessage>();
const auto& response = *reinterpret_cast<const GenericBinaryStatusResponse*>(bytes.data());
msg->binarySize = response.size;
msg->binaryIndex = response.index;
msg->binaryStatus = response.status;
return msg;
}
std::vector<uint8_t> GenericBinaryStatusPacket::EncodeArguments(uint16_t binaryIndex) {
std::vector<uint8_t> bytestream(sizeof(GenericBinaryStatusResponse));
auto& parameters = *reinterpret_cast<GenericBinaryStatusResponse*>(bytestream.data());
parameters.index = binaryIndex;
return bytestream;
}
@@ -0,0 +1,50 @@
#include "icsneo/communication/packet/hardwareinfopacket.h"
#include "icsneo/communication/message/hardwareinfo.h"
#include <iostream>
using namespace icsneo;
#pragma pack(push, 1)
typedef struct
{
uint8_t valid;
struct
{
uint8_t day;
uint8_t month;
uint16_t year;
} manufactureDate;
struct
{
uint8_t major;
uint8_t minor;
} hwRev;
uint8_t deviceId;
struct
{
uint8_t major;
uint8_t minor;
} blVersion;
} HardwareInfoFrame;
#pragma pack(pop)
std::shared_ptr<HardwareInfo> HardwareInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
if(bytes.size() < (sizeof(HardwareInfoFrame) + 1)) {
return nullptr;
}
const auto* frame = reinterpret_cast<const HardwareInfoFrame*>(&bytes[1]);
auto msg = std::make_shared<HardwareInfo>();
msg->manufactureDate.day = frame->manufactureDate.day;
msg->manufactureDate.year = frame->manufactureDate.year;
msg->manufactureDate.month = frame->manufactureDate.month;
msg->hardwareRevision.major = frame->hwRev.major;
msg->hardwareRevision.minor = frame->hwRev.minor;
msg->bootloaderVersion.major = frame->blVersion.major;
msg->bootloaderVersion.minor = frame->blVersion.minor;
return msg;
}
+83
View File
@@ -0,0 +1,83 @@
#include "icsneo/communication/packet/i2cpacket.h"
namespace icsneo
{
std::shared_ptr<Message> HardwareI2CPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream)
{
auto msg = std::make_shared<I2CMessage>();
const I2CHeader* packet = reinterpret_cast<const I2CHeader*>(bytestream.data());
const size_t numPayloadBytes = packet->length;
const size_t numControlBytes = packet->CoreMiniBitsI2C.CBLen;
const size_t numDataBytes = numPayloadBytes - numControlBytes;
if( (numPayloadBytes == 0) || (numDataBytes > I2CMaxLength) ||
(sizeof(I2CHeader) != (bytestream.size() - numPayloadBytes)) )
{ return nullptr; }
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->address = (packet->CoreMiniBitsI2C.ID & 0x3FFu);
msg->deviceMode = static_cast<I2CMessage::DeviceMode>(packet->CoreMiniBitsI2C.CT);
msg->direction = static_cast<I2CMessage::Direction>(packet->CoreMiniBitsI2C.DIR);
msg->isExtendedID = static_cast<bool>(packet->CoreMiniBitsI2C.EID & 0x01u);
msg->isTXMsg = static_cast<bool>(packet->CoreMiniBitsI2C.TXMsg & 0x01u);
msg->txTimeout = static_cast<bool>(packet->CoreMiniBitsI2C.TXTimeout & 0x01u);
msg->txNack = static_cast<bool>(packet->CoreMiniBitsI2C.TXNack & 0x01u);
msg->txAborted = static_cast<bool>(packet->CoreMiniBitsI2C.TXAborted & 0x01u);
msg->txLostArb = static_cast<bool>(packet->CoreMiniBitsI2C.TXLostArb & 0x01u);
msg->txError = static_cast<bool>(packet->CoreMiniBitsI2C.TXError & 0x01u);
//We don't care about 0xTRB0Dx in this case...
//copy 0xTRB0STAT even though we likely won't use it either
msg->stats = packet->stats;
msg->timestamp = (packet->timestamp & (0x7FFFFFFFFFFFFFFFull));
//The device will combine the 'control' bytes and data bytes into one payload
//The control bytes will always come before the data
auto cbStart = bytestream.begin() + sizeof(I2CHeader);
auto dataStart = cbStart + numControlBytes;
std::copy(cbStart, dataStart, std::back_inserter(msg->controlBytes));
std::copy(dataStart, bytestream.end(), std::back_inserter(msg->dataBytes));
return msg;
}
bool HardwareI2CPacket::EncodeFromMessage(const I2CMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t numControlBytes = message.controlBytes.size();
const size_t numDataBytes = message.dataBytes.size();
if(I2CMaxLength < numDataBytes)
{
report(APIEvent::Type::I2CMessageExceedsMaxLength, APIEvent::Severity::Error);
return false;
}
if(message.controlBytes.empty() || message.dataBytes.empty())
{
//You'll need to provide a target R/W register in controlBytes
//alternatively, you're expecting to read without providing a dataBytes payload
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
bytestream.push_back(static_cast<uint8_t>(numControlBytes & 0xFFu));
bytestream.push_back(static_cast<uint8_t>((numControlBytes) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>(numDataBytes & 0xFFu));
bytestream.push_back(static_cast<uint8_t>((numDataBytes) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>((message.stats) >> 8) & 0xFFu);
bytestream.push_back(static_cast<uint8_t>(message.stats & 0xFFu));
if(message.isExtendedID)
{
bytestream.push_back(static_cast<uint8_t>(message.address & 0xFFu));
bytestream.push_back(static_cast<uint8_t>(((message.address) >> 8) & 0x03u) | 0x04u);
} else {
bytestream.push_back(static_cast<uint8_t>(message.address & 0xFFu));
bytestream.push_back(static_cast<uint8_t>(0x00u));
}
if(I2CMessage::Direction::Read == message.direction)
{ bytestream.back() |= static_cast<uint8_t>(0x10u); }
std::copy(message.controlBytes.begin(), message.controlBytes.end(), std::back_inserter(bytestream));
std::copy(message.dataBytes.begin(), message.dataBytes.end(), std::back_inserter(bytestream));
return true;
}
}
+135
View File
@@ -0,0 +1,135 @@
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packetizer.h"
#include <algorithm>
using namespace icsneo;
bool HardwareISO9141Packet::EncodeFromMessage(const ISO9141Message& message, std::vector<uint8_t>& bytestream,
const device_eventhandler_t& report, const Packetizer& packetizer)
{
size_t bytesToSend = message.data.size();
if (message.isInit || message.isBreak)
bytesToSend = 0;
if(bytesToSend > 4200) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol
}
bytestream.clear();
std::vector<uint8_t> packet;
packet.reserve(16);
size_t currentStart = 0;
do {
const bool firstPacket = currentStart == 0;
const uint8_t maxSize = (firstPacket ? 9 : 12);
uint8_t currentSize = maxSize;
if(bytesToSend - currentStart < maxSize)
currentSize = (uint8_t)(bytesToSend - currentStart);
packet.insert(packet.begin(), {
(uint8_t)Network::NetID::RED, // 0x0C for long message
(uint8_t)0, // Size, little endian 16-bit, filled later
(uint8_t)0,
(uint8_t)message.network.getNetID(), // NetID, little endian 16-bit
(uint8_t)(uint16_t(message.network.getNetID()) >> 8)
});
packet.push_back(uint8_t(message.network.getNetID()) + uint8_t((currentSize + (firstPacket ? 6 : 3)) << 4));
packet.push_back(uint8_t(currentSize + (firstPacket ? 5 : 2)));
if(bytesToSend - currentStart > maxSize) // More packets are coming
packet.back() |= 0x40;
if(firstPacket) {
if(message.isInit)
packet.back() |= 0x80;
if(message.isBreak)
packet.back() |= 0x20;
}
// Two bytes for Description ID, big endian
packet.insert(packet.end(), { uint8_t(message.description >> 8), uint8_t(message.description) });
// If we're the first packet and not init/break only, we should put the header in
if(firstPacket && !message.isInit && !message.isBreak)
packet.insert(packet.end(), message.header.begin(), message.header.end());
// Now the data
auto dataIt = message.data.begin() + currentStart;
if(currentSize)
packet.insert(packet.end(), dataIt, dataIt + currentSize);
// Advance for the next packet
currentStart += currentSize;
const uint16_t size = uint16_t(packet.size()) + 2;
packet[1] = uint8_t(size & 0xFF);
packet[2] = uint8_t((size >> 8) & 0xFF);
packetizer.packetWrap(packet, false);
bytestream.insert(bytestream.end(), packet.begin(), packet.end());
packet.clear();
} while(currentStart < bytesToSend);
return true;
}
std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareISO9141Packet& packet = *reinterpret_cast<const HardwareISO9141Packet*>(bytestream.data());
if(!mMsg) {
mMsg = std::make_shared<ISO9141Message>();
mGotPackets = 0;
}
mGotPackets++;
const bool morePacketsComing = packet.c3.frm == 0;
const uint8_t bytesInCurrentMessage = packet.c3.len;
if(mMsg->data.size() + bytesInCurrentMessage > 500) {
mMsg.reset();
return std::shared_ptr<ISO9141Message>();
}
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
mMsg->timestamp = packet.timestamp.TS;
auto* dataStart = packet.data;
if(mGotPackets == 1) {
// Header
if(bytesInCurrentMessage < 3) {
mMsg.reset(); // We don't have the header for some reason
return std::shared_ptr<ISO9141Message>();
}
std::copy(packet.data, packet.data + 3, mMsg->header.begin());
dataStart += 3;
}
// Data
mMsg->data.insert(mMsg->data.end(), dataStart, packet.data + (bytesInCurrentMessage > 8 ? 8 : bytesInCurrentMessage));
if(bytesInCurrentMessage > 8)
mMsg->data.push_back(packet.c1.d8);
if(bytesInCurrentMessage > 9)
mMsg->data.push_back(packet.c2.d9);
if(bytesInCurrentMessage > 10)
mMsg->data.push_back(packet.c2.d10);
if(bytesInCurrentMessage > 11)
mMsg->data.push_back(packet.c3.d11);
if(morePacketsComing)
return std::shared_ptr<ISO9141Message>();
mMsg->transmitted = packet.c1.tx;
mMsg->isInit = packet.c3.init;
mMsg->framingError = packet.c1.options & 0x1;
mMsg->overflowError = packet.c1.options & 0x2;
mMsg->parityError = packet.c1.options & 0x4;
mMsg->rxTimeoutError = packet.c1.options & 0x8;
mMsg->description = packet.stats;
auto ret = mMsg;
mMsg.reset();
return ret;
}
+147
View File
@@ -0,0 +1,147 @@
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/packetizer.h"
namespace icsneo {
std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareLINPacket* packet = reinterpret_cast<const HardwareLINPacket*>(bytestream.data());
size_t numDataBytes = packet->CoreMiniBitsLIN.len;
size_t numHeaderBytes = sizeof(HardwareLINPacket::CoreMiniBitsLIN);
if( (sizeof(HardwareLINPacket) != bytestream.size()) ||
((numDataBytes + numHeaderBytes) > bytestream.size()) )
return nullptr;
if(numDataBytes)
--numDataBytes; //If data is present, there will be a checksum included
auto msg = std::make_shared<LINMessage>(static_cast<uint8_t>(packet->CoreMiniBitsLIN.ID));
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->isEnhancedChecksum = static_cast<bool>(packet->CoreMiniBitsLIN.TxChkSumEnhanced);
/* Minimum one responder byte and one checksum byte. */
if(2u > packet->CoreMiniBitsLIN.len)
msg->linMsgType = LINMessage::Type::LIN_ERROR;
auto dataStart = bytestream.begin() + numHeaderBytes;
std::copy(dataStart, (dataStart+numDataBytes), std::back_inserter(msg->data));
/* If OK, validate the checksum*/
auto isChecksumInvalid = [&]() -> bool {
/* messages with no data have no checksum (e.g. header only) */
if(!msg->data.size())
return true;
uint8_t checkSum = (8 > numDataBytes) ? *(dataStart + numDataBytes) : packet->CoreMiniBitsLIN.LINByte9;
LINMessage::calcChecksum(*msg);
if(checkSum != msg->checksum) {
msg->isEnhancedChecksum = true;
LINMessage::calcChecksum(*msg);
if(checkSum != msg->checksum) {
msg->isEnhancedChecksum = false;
msg->checksum = checkSum;
return true;
}
}
return false;
};
/* if any of the status bits are set, then this is
either a failed reception or a bus status update. */
msg->errFlags =
{
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxOnlyBreak),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxOnlyBreakSync),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrTxRxMismatch),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxBreakNotZero),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxBreakTooShort),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxSyncNot55),
static_cast<bool>(packet->CoreMiniBitsLIN.ErrRxDataGreater8),
static_cast<bool>(packet->CoreMiniBitsLIN.SyncFerr),
static_cast<bool>(packet->CoreMiniBitsLIN.MidFerr),
static_cast<bool>(packet->CoreMiniBitsLIN.ResponderByteFerr),
isChecksumInvalid(), /* ErrChecksumMatch */
};
msg->statusFlags =
{
static_cast<bool>(packet->CoreMiniBitsLIN.TxChkSumEnhanced),
static_cast<bool>(packet->CoreMiniBitsLIN.TXCommander),
static_cast<bool>(packet->CoreMiniBitsLIN.TXResponder),
static_cast<bool>(packet->CoreMiniBitsLIN.TxAborted),
static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered),
static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly)
};
if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder)
msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG;
else if(msg->statusFlags.BreakOnly)
msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY;
if( msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly ||
msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero ||
msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 ||
msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync ||
msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch ||
msg->errFlags.ErrFrameResponderData )
{ msg->linMsgType = LINMessage::Type::LIN_ERROR; }
msg->timestamp = packet->timestamp;
return msg;
}
bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
uint8_t size = ((std::min<size_t>(8ul, message.data.size()) + 3ul) & 0xFu);
if(size > 3) { ++size; } // add a checksum byte if there's data
switch(message.linMsgType) {
case LINMessage::Type::LIN_HEADER_ONLY:
case LINMessage::Type::LIN_COMMANDER_MSG:
{
size |= 0x80u;
break;
}
case LINMessage::Type::LIN_BREAK_ONLY:
{
size |= 0x20u;
break;
}
case LINMessage::Type::NOT_SET:
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
default:
break;
}
message.protectedID = message.calcProtectedID(message.ID);
bytestream.insert(bytestream.end(),
{
static_cast<uint8_t>(0x00u),
static_cast<uint8_t>(size),
static_cast<uint8_t>((message.description >> 8) & 0xFF),
static_cast<uint8_t>(message.description & 0xFF),
static_cast<uint8_t>(message.protectedID)
});
switch(message.linMsgType) {
case(LINMessage::Type::LIN_COMMANDER_MSG):
case(LINMessage::Type::LIN_UPDATE_RESPONDER):
{
std::copy(message.data.begin(), message.data.end(), std::back_inserter(bytestream));
LINMessage::calcChecksum(message);
bytestream.push_back(message.checksum);
break;
}
default:
break;
}
if(bytestream.size() % 2)
bytestream.push_back(0x41); //padding
return true;
}
} //namespace icsneo
+125
View File
@@ -0,0 +1,125 @@
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/message/livedatamessage.h"
#include <cstring>
#include <vector>
namespace icsneo {
std::shared_ptr<Message> HardwareLiveDataPacket::DecodeToMessage(const std::vector<uint8_t>& bytes, const device_eventhandler_t& report) {
if(bytes.empty() || (bytes.size() < (sizeof(LiveDataHeader) + sizeof(ExtResponseHeader)))) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
const auto header = reinterpret_cast<const ExtResponseHeader*>(bytes.data());
if(ExtendedCommand::LiveData != static_cast<ExtendedCommand>(header->command)) {
report(APIEvent::Type::LiveDataInvalidCommand, APIEvent::Severity::Error);
return nullptr;
}
const auto ldHeader = reinterpret_cast<const LiveDataHeader*>(bytes.data() + sizeof(ExtResponseHeader));
// Versioning check to avoid bad data interpretation between disparate libicsneo and firmware versions
if(icsneo::LiveDataUtil::LiveDataVersion != ldHeader->version) {
report(APIEvent::Type::LiveDataVersionMismatch, APIEvent::Severity::Error);
return nullptr;
}
switch(LiveDataCommand(ldHeader->cmd)) {
case LiveDataCommand::RESPONSE: {
auto retMsg = std::make_shared<LiveDataValueMessage>();
const auto responseBytes = reinterpret_cast<const LiveDataValueResponse*>(ldHeader);
retMsg->handle = responseBytes->handle;
retMsg->cmd = static_cast<LiveDataCommand>(responseBytes->cmd);
retMsg->numArgs = responseBytes->numArgs;
for(uint32_t i = 0; i < retMsg->numArgs; ++i) {
retMsg->values.emplace_back(std::make_shared<LiveDataValue>(responseBytes->values[i]));
}
return retMsg;
}
case LiveDataCommand::STATUS: {
auto retMsg = std::make_shared<LiveDataStatusMessage>();
const auto responseBytes = reinterpret_cast<const LiveDataStatusResponse*>(ldHeader);
retMsg->handle = responseBytes->handle;
retMsg->cmd = static_cast<LiveDataCommand>(responseBytes->cmd);
retMsg->status = responseBytes->status;
retMsg->requestedCommand = static_cast<LiveDataCommand>(responseBytes->requestedCommand);
return retMsg;
}
default: {
report(APIEvent::Type::LiveDataInvalidCommand, APIEvent::Severity::Error);
break;
}
}
return nullptr;
}
bool HardwareLiveDataPacket::EncodeFromMessage(LiveDataMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
uint16_t payloadSize = 0;
switch(message.cmd) {
case LiveDataCommand::SUBSCRIBE: {
auto commandMsg = reinterpret_cast<LiveDataCommandMessage*>(&message);
const auto numArgs = commandMsg->args.size();
if(numArgs) {
payloadSize = static_cast<uint16_t>(sizeof(LiveDataSubscribe) + (sizeof(LiveDataArgument) * (numArgs-1)));
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
LiveDataSubscribe* out = reinterpret_cast<LiveDataSubscribe*>(bytestream.data() + sizeof(ExtendedCommandHeader));
out->version = icsneo::LiveDataUtil::LiveDataVersion;
out->cmd = static_cast<uint32_t>(commandMsg->cmd);
if(!commandMsg->handle)
commandMsg->handle = LiveDataUtil::getNewHandle();
out->handle = commandMsg->handle;
out->numArgs = static_cast<uint32_t>(commandMsg->args.size());
out->freqMs = static_cast<uint32_t>(commandMsg->updatePeriod.count());
out->expireMs = static_cast<uint32_t>(commandMsg->expirationTime.count());
for(size_t i = 0; i < numArgs; ++i) {
out->args[i].objectType = commandMsg->args[i]->objectType;
out->args[i].objectIndex = commandMsg->args[i]->objectIndex;
out->args[i].signalIndex = commandMsg->args[i]->signalIndex;
out->args[i].valueType = commandMsg->args[i]->valueType;
}
} else {
report(APIEvent::Type::LiveDataInvalidArgument, APIEvent::Severity::Error);
return false;
}
break;
}
case LiveDataCommand::UNSUBSCRIBE: {
payloadSize = sizeof(LiveDataHeader);
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
auto ldUnsubMsg = reinterpret_cast<LiveDataHeader*>(bytestream.data() + sizeof(ExtendedCommandHeader));
ldUnsubMsg->version = static_cast<uint32_t>(icsneo::LiveDataUtil::LiveDataVersion);
ldUnsubMsg->cmd = static_cast<uint32_t>(message.cmd);
ldUnsubMsg->handle = static_cast<uint32_t>(message.handle);
break;
}
case LiveDataCommand::CLEAR_ALL: {
payloadSize = sizeof(LiveDataHeader);
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
auto clearMsg = reinterpret_cast<LiveDataHeader*>(bytestream.data() + sizeof(ExtendedCommandHeader));
clearMsg->version = static_cast<uint32_t>(icsneo::LiveDataUtil::LiveDataVersion);
clearMsg->cmd = static_cast<uint32_t>(message.cmd);
break;
}
default: {
report(APIEvent::Type::LiveDataInvalidCommand, APIEvent::Severity::Error);
return false;
}
}
// +1 for AA, another +1 for firmware nuance
uint16_t fullSize = static_cast<uint16_t>(1 + sizeof(ExtendedCommandHeader) + payloadSize) + 1;
ExtendedCommandHeader* header = reinterpret_cast<ExtendedCommandHeader*>(bytestream.data());
if(!header) {
report(APIEvent::Type::LiveDataEncoderError, APIEvent::Severity::Error);
return false;
}
header->netid = static_cast<uint8_t>(Network::NetID::Main51);
header->fullLength = fullSize;
header->command = static_cast<uint8_t>(Command::Extended);
header->extendedCommand = static_cast<uint16_t>(ExtendedCommand::LiveData);
header->payloadLength = payloadSize;
return true;
}
} // namespace icsneo
@@ -0,0 +1,12 @@
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
using namespace icsneo;
std::shared_ptr<LogicalDiskInfoMessage> LogicalDiskInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
// Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(LogicalDiskInfoPacket))
return {};
const LogicalDiskInfoPacket* packet = reinterpret_cast<const LogicalDiskInfoPacket*>(bytestream.data());
return std::make_shared<LogicalDiskInfoMessage>(packet->isConnected != 0, packet->numSectors, packet->hiddenSectors, packet->bytesPerSector);
}
+79
View File
@@ -0,0 +1,79 @@
#include "icsneo/communication/packet/mdiopacket.h"
namespace icsneo
{
const size_t HardwareMDIOPacket::mdioDataSize = 2;
std::shared_ptr<Message> HardwareMDIOPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream)
{
auto msg = std::make_shared<MDIOMessage>();
const HardwareMDIOPacket* packet = reinterpret_cast<const HardwareMDIOPacket*>(bytestream.data());
if((sizeof(HardwareMDIOPacket) != (bytestream.size())) || (packet->length != 0))
{
return nullptr;
}
msg->network = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(packet->networkID));
msg->clause = static_cast<MDIOMessage::Clause>(packet->header.ST);
msg->direction = static_cast<MDIOMessage::Direction>((packet->header.OP & 0x2) ? 1 : 0);
msg->isTXMsg = static_cast<bool>(packet->header.TRANSMIT & 0x01u);
msg->phyAddress = (packet->header.PHY_ADDR & 0x1Fu);
if (msg->clause == MDIOMessage::Clause::Clause45)
{ // 16-bit register address
msg->devAddress = (packet->header.C45_DEVTYPE & 0x1Fu);
msg->regAddress = (packet->header.REG_ADDR & 0xFFFFu);
}
else
{ // 5-bit register address
msg->devAddress = 0;
msg->regAddress = (packet->header.REG_ADDR & 0x1Fu);
}
msg->isTXMsg = static_cast<bool>(packet->header.TRANSMIT & 0x01u);
msg->txTimeout = static_cast<bool>(packet->header.ERR_TIMEOUT & 0x01u);
msg->txAborted = static_cast<bool>(packet->header.ERR_JOB_CANCELLED & 0x01u);
msg->txInvalidBus = static_cast<bool>(packet->header.ERR_INVALID_BUS & 0x01u);
msg->txInvalidPhyAddr = static_cast<bool>(packet->header.ERR_INVALID_PHYADDR & 0x01u);
msg->txInvalidRegAddr = static_cast<bool>(packet->header.ERR_INVALID_REGADDR & 0x01u);
msg->txInvalidClause = static_cast<bool>(packet->header.ERR_UNSUPPORTED_CLAUSE & 0x01u);
msg->txInvalidOpcode = static_cast<bool>(packet->header.ERR_UNSUPPORTED_OPCODE & 0x01u);
//We don't care about 0xTRB0Dx in this case...
//copy 0xTRB0STAT even though we likely won't use it either
msg->description = packet->stats;
msg->timestamp = (packet->timestamp & (0x7FFFFFFFFFFFFFFFull));
std::copy(packet->data, packet->data + mdioDataSize, std::back_inserter(msg->data));
return msg;
}
bool HardwareMDIOPacket::EncodeFromMessage(const MDIOMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t numDataBytes = message.data.size();
if(mdioDataSize < numDataBytes)
{
report(APIEvent::Type::MDIOMessageExceedsMaxLength, APIEvent::Severity::Error);
return false;
}
uint8_t st = (message.clause == MDIOMessage::Clause::Clause45) ? 0x0 : 0x1;
uint8_t op = (message.direction == MDIOMessage::Direction::Read) ? 0x2 : 0x1;
uint8_t phyAddr = message.phyAddress & 0x1F;
uint16_t regAddr = (message.clause == MDIOMessage::Clause::Clause45) ? message.regAddress : message.regAddress & 0x1F;
uint8_t c45DevType = (message.clause == MDIOMessage::Clause::Clause45) ? message.devAddress & 0x1F : 0;
bytestream.push_back(static_cast<uint8_t>((message.description >> 8) & 0xFF)); // MSB first
bytestream.push_back(static_cast<uint8_t>(message.description & 0xFF)); // LSB
bytestream.push_back(op); // opcode
bytestream.push_back(st); // st (clause)
bytestream.push_back(phyAddr); // st (clause)
bytestream.push_back(c45DevType); // clause 45 device type
bytestream.push_back(regAddr & 0xFF); // reg addr LSB
bytestream.push_back((regAddr >> 8) & 0xFF); // reg addr MSB
std::copy(message.data.begin(), message.data.end(), std::back_inserter(bytestream));
return true;
}
}
@@ -0,0 +1,31 @@
#include <iostream>
#include "icsneo/communication/packet/scriptstatuspacket.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
using namespace icsneo;
std::shared_ptr<ScriptStatusMessage> ScriptStatus::DecodeToMessage(const std::vector<uint8_t>& bytestream){
if(bytestream.size() != sizeof(ScriptStatus))
return {};
auto msg = std::make_shared<ScriptStatusMessage>();
const auto& decoded = *reinterpret_cast<const ScriptStatus*>(bytestream.data());
msg->isCoreminiRunning = decoded.status.isRunning;
msg->isEncrypted = decoded.status.isEncrypted;
msg->sectorOverflows = decoded.sectorOverflows;
msg->numRemainingSectorBuffers = decoded.numRemainingSectorBuffers;
msg->lastSector = decoded.lastSector;
msg->readBinSize = decoded.readBinSize;
msg->minSector = decoded.minSector;
msg->maxSector = decoded.maxSector;
msg->currentSector = decoded.currentSector;
msg->coreminiCreateTime = ((uint64_t)decoded.coreminiCreateTimeMsb << 32) | decoded.coreminiCreateTimeLsb;
msg->fileChecksum = decoded.fileChecksum;
msg->coreminiVersion = decoded.coreminiVersion;
msg->coreminiHeaderSize = decoded.coreminiHeaderSize;
msg->diagnosticErrorCode = decoded.diagErrCode;
msg->diagnosticErrorCodeCount = decoded.diagErrCodeCount;
msg->maxCoreminiSizeKB = decoded.maxCoreminiSizeKB;
return msg;
}
@@ -0,0 +1,44 @@
#include "icsneo/communication/packet/supportedfeaturespacket.h"
#include "icsneo/communication/message/supportedfeaturesmessage.h"
using namespace icsneo;
static constexpr uint16_t SupportedFeaturesCommandVersion = 1;
static constexpr size_t NumSupportedFeaturesFields =
(static_cast<size_t>(SupportedFeature::numSupportedFeatures) + 31) / 32;
#pragma pack(push, 2)
struct SupportedFeaturesResponse {
ExtendedResponseMessage::ResponseHeader header;
uint16_t cmdVersion;
uint16_t numValidBits;
uint32_t featuresFields[NumSupportedFeaturesFields];
};
#pragma pack(pop)
std::shared_ptr<SupportedFeaturesMessage> SupportedFeaturesPacket::DecodeToMessage(const std::vector<uint8_t>& bytes) {
auto msg = std::make_shared<SupportedFeaturesMessage>();
// Length check: At least a header, a 2-byte cmdVersion field, and a 2-byte numValidBits field.
if(bytes.size() < sizeof(ExtendedResponseMessage::ResponseHeader) + 4) {
return msg; // Empty
}
// Get a reference to the payload to fully validate the length
const auto& response = *reinterpret_cast<const SupportedFeaturesResponse*>(bytes.data());
if(response.cmdVersion != SupportedFeaturesCommandVersion) {
return msg;
}
// Expected size is the header, cmdVersion and numValidBits fields, plus the number of 32-bit bitfields in the response based on numValidBits
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 4 + ((response.numValidBits + 31) / 32) * 4;
// If the response is malformed (too small), return an empty message
if(bytes.size() < expectedSize) {
return msg; // Empty
}
unsigned int loopLimit = std::min<unsigned int>(response.numValidBits, static_cast<unsigned int>(SupportedFeature::numSupportedFeatures));
for(unsigned int i = 0; i < loopLimit; ++i) {
uint32_t wordOffset = i / 32;
uint32_t bitOffset = i % 32;
if((response.featuresFields[wordOffset] >> bitOffset) & 1) {
msg->features.insert(static_cast<SupportedFeature>(i));
}
}
return msg;
}
+39
View File
@@ -0,0 +1,39 @@
#include "icsneo/communication/packet/versionpacket.h"
using namespace icsneo;
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < 3) // Not enough bytes to decode
return std::shared_ptr<VersionMessage>();
auto msg = std::make_shared<VersionMessage>(VersionMessage::MainChip);
msg->Versions.emplace_back();
std::optional<DeviceAppVersion>& version = msg->Versions.back();
version.emplace();
version->major = bytestream[1];
version->minor = bytestream[2];
return msg;
}
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) {
auto msg = std::make_shared<VersionMessage>(VersionMessage::SecondaryChips);
size_t bytesLeft = bytestream.size();
if(bytesLeft)
bytesLeft--; // Disregard command byte
while(bytesLeft >= 3) {
const bool versionValid = bytestream[bytestream.size() - bytesLeft + 0];
msg->Versions.emplace_back();
std::optional<DeviceAppVersion>& version = msg->Versions.back();
if(versionValid) {
version.emplace();
version->major = bytestream[bytestream.size() - bytesLeft + 1];
version->minor = bytestream[bytestream.size() - bytesLeft + 2];
}
bytesLeft -= std::min<size_t>(3, bytesLeft);
}
return msg;
}
+100
View File
@@ -0,0 +1,100 @@
#include "icsneo/communication/packet/wivicommandpacket.h"
#include "icsneo/communication/message/wiviresponsemessage.h"
#include <cstring>
using namespace icsneo;
std::shared_ptr<WiVI::ResponseMessage> WiVI::CommandPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(WiVI::CommandPacket::Header))
return {};
auto msg = std::make_shared<WiVI::ResponseMessage>();
const auto& header = *reinterpret_cast<const WiVI::CommandPacket::Header*>(bytestream.data());
switch(header.cmd) {
case WiVI::Command::Result: {
if(bytestream.size() < sizeof(WiVI::CommandPacket::Result))
return {};
const auto& decoded = *reinterpret_cast<const WiVI::CommandPacket::Result*>(bytestream.data());
msg->responseTo = decoded.responseTo;
msg->success = decoded.result != 0;
break;
}
case WiVI::Command::GetSignal: {
// Use the SetSignal structure since it matches the response
if(bytestream.size() < sizeof(WiVI::CommandPacket::SetSignal))
return {};
const auto& setSignal = *reinterpret_cast<const WiVI::CommandPacket::SetSignal*>(bytestream.data());
msg->responseTo = WiVI::Command::GetSignal;
msg->value = setSignal.value.ValueInt32;
break;
}
case WiVI::Command::GetAll: {
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll))
return {};
const auto& getAll = *reinterpret_cast<const WiVI::CommandPacket::GetAll*>(bytestream.data());
msg->responseTo = WiVI::Command::GetAll;
msg->info.emplace();
msg->info->sleepRequest = getAll.sleepRequest;
msg->info->connectionTimeoutMinutes = getAll.connectionTimeoutMinutes;
// Check that we have enough data for the capture infos
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll) + (sizeof(WiVI::CaptureInfo) * getAll.numCaptureInfos))
return {};
msg->info->captures.resize(getAll.numCaptureInfos);
for(uint16_t i = 0; i < getAll.numCaptureInfos; i++)
msg->info->captures[i] = getAll.captureInfos[i];
break;
}
default: // Unknown command response
return {};
}
return msg;
}
std::vector<uint8_t> WiVI::CommandPacket::GetSignal::Encode(WiVI::SignalType type) {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetSignal));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetSignal*>(ret.data());
frame.header.cmd = WiVI::Command::GetSignal;
frame.header.length = sizeof(frame) - sizeof(frame.header);
frame.type = type;
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::SetSignal::Encode(WiVI::SignalType type, CoreMiniFixedPointValue value) {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::SetSignal));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::SetSignal*>(ret.data());
frame.header.cmd = WiVI::Command::SetSignal;
frame.header.length = sizeof(frame) - sizeof(frame.header);
frame.type = type;
frame.value = value;
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::GetAll::Encode() {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetAll));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetAll*>(ret.data());
frame.header.cmd = WiVI::Command::GetAll;
frame.header.length = sizeof(frame) - sizeof(frame.header);
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::ClearUploads::Encode(const std::vector<uint8_t>& bitmask) {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::ClearUploads) + bitmask.size());
auto& frame = *reinterpret_cast<WiVI::CommandPacket::ClearUploads*>(ret.data());
frame.header.cmd = WiVI::Command::ClearUploads;
frame.header.length = uint16_t(ret.size() - sizeof(frame.header));
memcpy(frame.bitmask, bitmask.data(), bitmask.size());
return ret;
}
+87 -34
View File
@@ -1,5 +1,4 @@
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include <iostream>
#include <iomanip> #include <iomanip>
using namespace icsneo; using namespace icsneo;
@@ -13,11 +12,11 @@ uint8_t Packetizer::ICSChecksum(const std::vector<uint8_t>& data) {
return (uint8_t)checksum; return (uint8_t)checksum;
} }
std::vector<uint8_t>& Packetizer::packetWrap(std::vector<uint8_t>& data, bool shortFormat) { std::vector<uint8_t>& Packetizer::packetWrap(std::vector<uint8_t>& data, bool shortFormat) const {
if(shortFormat) { if(shortFormat) {
// Some devices don't use the checksum, so might as well not calculate it if that's the case // Some devices don't use the checksum, so might as well not calculate it if that's the case
// Either way the byte is still expected to be present in the bytestream for short messages // Either way the byte is still expected to be present in the bytestream for short messages
data.push_back(disableChecksum ? 0x00 : ICSChecksum(data)); data.push_back(disableChecksum ? 0x00 : ICSChecksum(data));
} }
data.insert(data.begin(), 0xAA); data.insert(data.begin(), 0xAA);
if(align16bit && data.size() % 2 == 1) // Some devices always expect 16-bit aligned data if(align16bit && data.size() % 2 == 1) // Some devices always expect 16-bit aligned data
@@ -25,9 +24,8 @@ std::vector<uint8_t>& Packetizer::packetWrap(std::vector<uint8_t>& data, bool sh
return data; return data;
} }
bool Packetizer::input(const std::vector<uint8_t>& inputBytes) { bool Packetizer::input(RingBuffer& bytes) {
bool haveEnoughData = true; bool haveEnoughData = true;
bytes.insert(bytes.end(), inputBytes.begin(), inputBytes.end());
while(haveEnoughData) { while(haveEnoughData) {
switch(state) { switch(state) {
@@ -49,44 +47,97 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
haveEnoughData = false; haveEnoughData = false;
break; break;
} }
packetLength = bytes[1] >> 4 & 0xF;
packet.network = Network(bytes[1] & 0xF); // Lower nibble of the second byte is the network ID
packetLength = bytes[1] >> 4 & 0xf; // Upper nibble of the second byte denotes the packet length if(packetLength == 0) {
packet.network = Network(bytes[1] & 0xf); // Lower nibble of the second byte is the network ID
if(packetLength == 0) { // A length of zero denotes a long style packet
state = ReadState::ParseLongStylePacketHeader; state = ReadState::ParseLongStylePacketHeader;
checksum = false; break;
headerSize = 6; } else if(packetLength == 0xA && packet.network == Network::NetID::DiskData) {
} else { state = ReadState::ParseDiskDataHeader;
state = ReadState::GetData; break;
checksum = true; // Even if checksum is not explicitly disallowed, we enable it here, as this goes into length calculation
headerSize = 2;
packetLength += 2; // The packet length given in short packets does not include header
} }
checksum = true; // Even if checksum is not explicitly disallowed, we enable it here, as this goes into length calculation
headerSize = 2;
packetLength += 2; // The packet length given in short packets does not include header
currentIndex++; currentIndex++;
state = ReadState::GetData;
break; break;
case ReadState::ParseLongStylePacketHeader: case ReadState::ParseLongStylePacketHeader:
if(bytes.size() < 6) { if(bytes.size() < 6) {
haveEnoughData = false; haveEnoughData = false;
break; break;
} }
packetLength = bytes[2]; // Long packets have a little endian length on bytes 3 and 4 packetLength = bytes[2]; // Long packets have a little endian length on bytes 3 and 4
packetLength |= bytes[3] << 8; packetLength |= bytes[3] << 8;
packet.network = Network((bytes[5] << 8) | bytes[4]); // Long packets have their netid stored as little endian on bytes 5 and 6 packet.network = Network(((bytes[5] << 8) | bytes[4]), false); // Long packets have their netid stored as little endian on bytes 5 and 6. Devices never send actual VNET IDs so we must not perform ID expansion here.
currentIndex += 4;
/* Long packets can't have a length less than 4, because that would indicate a negative payload size. /* Long packets can't have a length less than 6, because that would indicate a negative payload size.
* Unlike the short packet length, the long packet length encompasses everything from the 0xAA to the * Unlike the short packet length, the long packet length encompasses everything from the 0xAA to the
* end of the payload. The short packet length, for reference, only encompasses the length of the actual * end of the payload. The short packet length, for reference, only encompasses the length of the actual
* payload, and not the header or checksum. * payload, and not the header or checksum.
*/ */
if(packetLength < 4 || packetLength > 4000) { if(packetLength < 6 || packetLength > 4000) {
bytes.pop_front(); bytes.pop_front();
//std::cout << "skipping long packet with length " << packetLength << std::endl; EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
state = ReadState::SearchForHeader; state = ReadState::SearchForHeader;
} else { break;
state = ReadState::GetData;
} }
checksum = false;
headerSize = 6;
currentIndex += 5;
state = ReadState::GetData;
break;
case ReadState::ParseDiskDataHeader:
if(bytes.size() < 3) {
haveEnoughData = false;
break;
}
if(bytes[2] != 0xAA) {
bytes.pop_front();
state = ReadState::SearchForHeader;
break;
}
if(bytes.size() < 4) {
haveEnoughData = false;
break;
}
if(bytes[3] != 0x55) {
bytes.pop_front();
state = ReadState::SearchForHeader;
break;
}
if(bytes.size() < 5) {
haveEnoughData = false;
break;
}
if(bytes[4] != 0x55) {
bytes.pop_front();
state = ReadState::SearchForHeader;
break;
}
if(bytes.size() < 7) {
haveEnoughData = false;
break;
}
packetLength = bytes[5] | (bytes[6] << 8);
checksum = false;
headerSize = 7;
packetLength += headerSize;
currentIndex += 6;
state = ReadState::GetData;
break; break;
case ReadState::GetData: case ReadState::GetData:
// We do not include the checksum in packetLength so it doesn't get copied into the payload buffer // We do not include the checksum in packetLength so it doesn't get copied into the payload buffer
@@ -98,23 +149,25 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
packet.data.clear(); packet.data.clear();
if(packetLength > 0) if(packetLength > 0)
packet.data.resize(packetLength - headerSize); packet.data.resize(packetLength - headerSize);
auto i = 0; bytes.read(packet.data.data(), currentIndex, (packetLength - currentIndex));
while(currentIndex < packetLength) currentIndex = packetLength;
packet.data[i++] = bytes[currentIndex++];
if(disableChecksum || !checksum || bytes[currentIndex] == ICSChecksum(packet.data)) { if(disableChecksum || !checksum || bytes[currentIndex] == ICSChecksum(packet.data)) {
// Got a good packet // Got a good packet
gotGoodPackets = true; gotGoodPackets = true;
processedPackets.push_back(std::make_shared<Packet>(packet)); processedPackets.push_back(std::make_shared<Packet>(packet));
for (auto a = 0; a < packetLength; a++) bytes.pop(packetLength);
if(packet.network == Network::NetID::DiskData && (packetLength - headerSize) % 2 == 0) {
bytes.pop_front(); bytes.pop_front();
}
} else { } else {
if(gotGoodPackets) // Don't complain unless we've already gotten a good packet, in case we started in the middle of a stream if(gotGoodPackets) // Don't complain unless we've already gotten a good packet, in case we started in the middle of a stream
err(APIError::PacketChecksumError); report(APIEvent::Type::PacketChecksumError, APIEvent::Severity::Error);
bytes.pop_front(); // Drop the first byte so it doesn't get picked up again bytes.pop_front(); // Drop the first byte so it doesn't get picked up again
} }
// Reset for the next packet // Reset for the next packet
currentIndex = 0; currentIndex = 0;
state = ReadState::SearchForHeader; state = ReadState::SearchForHeader;

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