Author SHA1 Message Date
Max BrombachandKyle Schwarz 79ff19015a Device: RAD-Gigastar 1 & 2: Add SFP flashing to bootloader pipelines 2026-04-24 16:12:45 -04:00
David RebbeandKyle Schwarz 9c4323987f C2: CAN error message support 2026-04-17 11:39:38 -04:00
David RebbeandKyle Schwarz f5f6d0828b C2: Add LIN message support 2026-04-15 15:50:33 -04:00
David RebbeandKyle Schwarz 6dc005fcea C2: Add PCBSN and MAC Address support 2026-04-14 13:37:27 -04:00
David RebbeandKyle Schwarz 5b553b63d3 C2: Add icsneoc2_device_reconnect 2026-04-08 16:19:31 -04:00
Michael BowersandKyle Schwarz 97a6b4a04f Device: RADGalaxy2: Remove EnterApplicationPhase 2026-04-06 10:57:09 -04:00
Thomas StoddardandKyle Schwarz 67929a19bc Example: Fix type casting for MSVC warnings 2026-04-06 10:17:16 -04:00
Thomas StoddardandKyle Schwarz e7c2c07947 Bindings: Python: Update to pybind11 3.0.3 2026-04-03 16:16:27 -04:00
Thomas StoddardandKyle Schwarz 146ddaf23c Device: Add T1S extended settings 2026-04-03 12:14:17 -04:00
Thomas StoddardandKyle Schwarz 6f2ad54adc Device: Add get_pcb_serial() & get_mac_address() 2026-04-02 15:45:58 -04:00
Max Brombach 87e2a65b71 Device: VividCAN: Add bootloader pipeline and chips 2026-03-30 10:43:41 -04:00
Thomas StoddardandKyle Schwarz 26e8a2c3d9 Device: FIRE3: Add BASE-T settings 2026-03-26 13:56:12 -04:00
David RebbeandKyle Schwarz 0ef26fec63 C2: Fix preprocessor defines for libclang parsing 2026-03-25 09:28:56 -04:00
Thomas StoddardandKyle Schwarz 682299cb8c API: Add icsneoc2 2026-03-24 21:08:40 -04:00
Yaroslav StetsykandKyle Schwarz 294e707924 Device: NeoVIFIRE3T1SLIN: Add bootloader details 2026-03-20 15:54:23 -04:00
Kyle Schwarz 22d2b7c984 Servd: Adjust buffer sizes 2026-03-18 18:21:55 -04:00
Kyle Schwarz 5a4a1489a8 DXX: Update for max packet size 2026-03-18 15:35:31 -04:00
Thomas StoddardandKyle Schwarz b0b7623b4c Core: MACsec: Mirror 128-bit keys 2026-03-16 13:59:40 -04:00
Max BrombachandKyle Schwarz 171422d8e1 Device: RAD-Gemini: Add chip info and fix bootloader pipeline 2026-03-10 15:13:09 -04:00
Kyle Schwarz 81769db025 Device: NeoVIFIRE3: Add CAN networks to settings 2026-03-06 16:08:40 -05:00
Kyle Schwarz 0e60f8f459 Device: RADComet3: Handle AE_LINK_INVALID 2026-03-04 19:37:00 -05:00
Thomas StoddardandKyle Schwarz 0aa7d338fd Bindings: Python: Add formatDisk 2026-03-03 15:38:13 -05:00
Kyle Schwarz 224e840841 Device: Increase DiskFormatProgress timeout 2026-02-17 17:16:49 -05:00
Max Brombach 174c0b80d4 Device: VCAN4-IND: Add chips and bootloader information 2026-02-17 12:00:34 -05:00
Max BrombachandKyle Schwarz 19092bceb6 Device: RAD-MoonT1S: Add bootloader pipeline and chip 2026-02-13 13:17:59 -05:00
Kyle Schwarz 25b673075f All: Copyright 2026 2026-02-13 10:08:09 -05:00
Max BrombachandKyle Schwarz 1a7bc4df47 Device: RADJupiter: Add bootloader pipeline 2026-02-12 17:05:39 -05:00
Max BrombachandKyle Schwarz 20a2474508 Device: Settings: Add missing bit-packed variables to CAN_SETTINGS 2026-02-12 16:25:57 -05:00
Thomas StoddardandKyle Schwarz d18ca9e6eb Device: RAD-Galaxy: Add support for Analog Output 2026-02-11 18:43:30 -05:00
Max BrombachandKyle Schwarz 6cda765fe0 Device: FIRE2: Skip flashing Core chip when chip variant is unknown 2026-02-10 21:20:47 -05:00
Jonathan SchwartzandKyle Schwarz 730aaf5fed Device: FIRE3: Update disk counts 2026-02-06 14:32:31 -05:00
Kyle Schwarz 1f10adb760 ThirdParty: Update icspb & libredxx 2026-01-30 17:12:09 -05:00
Thomas StoddardandKyle Schwarz 6a32823a0f Device: FlexRay: Add additional configuration options for Controller and Cluster 2026-01-30 13:06:39 -05:00
Thomas StoddardandKyle Schwarz 5f16adc103 Device: RADComet3: Add Ethernet settings 2026-01-28 16:00:39 -05:00
Jonathan SchwartzandKyle Schwarz f6926cbb22 Device: Unlock network mutex when going offline 2026-01-27 15:22:12 -05:00
Thomas StoddardandKyle Schwarz 4c7b8e107a Device: RADComet: Add T1S settings 2026-01-23 13:03:39 -05:00
Jonathan SchwartzandKyle Schwarz 0e55101a16 Device: goOnline: Refactor network locking
Only lock known networks.
2026-01-22 16:46:51 -05:00
Max BrombachandKyle Schwarz 68ebb6dae4 Device: Add EnterApplicationPhases step 2026-01-20 14:25:29 -05:00
Jonathan SchwartzandKyle Schwarz 8cb62c2cae Device: Carry bootloader version for potential compatibility checks 2026-01-12 17:45:10 -05:00
Kyle Schwarz d74051f57e Driver: Servd: Refactor to TCP 2026-01-12 13:03:55 -05:00
Thomas Stoddard 530a99d264 Add T1S PLCA and related settings support for Fire3T1S, RadComet3, RadGigaStar2, and RadMoonT1S devices 2026-01-09 18:16:10 +00:00
Thomas StoddardandKyle Schwarz 5ee450353b Bindings: Python: Add T1S members 2026-01-07 23:32:20 -05:00
Thomas StoddardandKyle Schwarz 516bca682c EthernetMessage: Add T1S symbol support 2026-01-07 16:34:34 -05:00
Jonathan SchwartzandKyle Schwarz 3f5150bef3 FirmIO: Fix instability and memory leak issues 2026-01-07 13:35:23 -05:00
Thomas StoddardandKyle Schwarz 2a2d55f20d Bindings: Python : Add baudrate and LIN mode methods 2026-01-07 10:51:25 -05:00
Thomas StoddardandKyle Schwarz 977677e3af Bindings: Add LiveData and LiveDataMessage support in Python bindings 2026-01-05 10:40:14 -05:00
Kyle Schwarz 000036f745 Driver: DXX: Update
Fixes D2XX HANDLE leak.
2025-12-19 22:30:14 -05:00
Kyle Schwarz be6a15c017 Device: Galaxy2: Update supported networks 2025-12-18 12:22:12 -05:00
Nicholas ZamoraandKyle Schwarz 5288385495 Driver: DXX: Update libredxx for FT260 support 2025-12-16 11:05:11 -05:00
Max Brombach d6d9fc16ef Device: Update chips for ValueCAN4_2EL bootloader 2025-12-10 19:47:23 +00:00
Kyle Schwarz dbab92b25c Bindings: Python: Migrate to smart_holder 2025-12-09 14:24:40 -05:00
Max Brombach 579160f6d4 Device: Fix Epsilon-XL bootloader pipeline and chip info 2025-12-08 21:16:14 +00:00
Emily Brooks 737d5ceb3b TransmitMessage: Mark timestamp as extended when using CAN FD 2025-12-05 13:53:26 -05:00
Emily Brooks 95521a5548 TransmitMessage: Add TX support for neoVI network 2025-12-05 10:53:53 -05:00
Emily BrooksandKyle Schwarz 16cd476c01 Network: neoVI: Add TX support 2025-12-03 14:43:35 -05:00
Thomas StoddardandKyle Schwarz d328d314b6 Bindings: Python: Update pybind11
Updates to 3.0.1 and switches to smart_holder & native_enum.
2025-11-24 11:56:09 -05:00
Bryant JonesandKyle Schwarz 7b5b94d980 Docs: Python: Add SPI example 2025-11-20 17:08:30 -05:00
Kyle Schwarz fedb4b88f3 Build: Update icspb 2025-11-10 11:29:42 -05:00
Kyle Schwarz 5cac3a4600 Examples: Remove commented example 2025-11-05 12:01:58 -05:00
Yasser YassineandKyle Schwarz 9ff4bf7d0d MACsec: Refactor API 2025-11-05 12:00:07 -05:00
Kyle Schwarz 30c009fe8f Device: Refactor online keep alive 2025-11-04 16:24:49 -05:00
Max BrombachandKyle Schwarz 51e4fdc6d9 Device: Update tree structs and add size checks to non-deprecated devices 2025-11-04 14:29:37 -05:00
Yasser YassineandKyle Schwarz 39b54d8c4e Device: Fix bootloader phases 2025-11-04 12:37:19 -05:00
Kyle Schwarz 615b7d8d56 Bindings: Python: Document 3.14 support 2025-11-04 11:51:55 -05:00
Kyle Schwarz e3f4bbdc73 Device: sendEthPhyMsg(): Drop online requirement 2025-11-04 11:06:51 -05:00
Nicholas ZamoraandKyle Schwarz 563c444def Device: Add RAD-Gemini 2025-11-03 09:37:50 -05:00
Kyle Schwarz 3f3300d677 Communication: EthernetStatusMessage: Handle BASE-T invalid case 2025-10-31 12:31:03 -04:00
Max BrombachandKyle Schwarz b9e3542bcf Device: Use variant Core chip and fix ZChip flash for FIRE2 2025-10-31 12:02:02 -04:00
Kyle Schwarz 7f192a0cea Network: Use Type::AutomotiveEthernet 2025-10-30 23:40:30 -04:00
Kyle Schwarz 3b60bfc986 CI: Add Fedora 43 & drop 41 2025-10-30 21:21:07 -04:00
Kyle Schwarz d51f88d023 Communication: EthernetStatusMessage: Add BASE-T support 2025-10-30 21:13:20 -04:00
Kyle Schwarz f3cb41d60b Communication: Network: Add Type::AutomotiveEthernet
Also condense switch statements
2025-10-30 21:11:23 -04:00
Yasser YassineandKyle Schwarz 1b00c6a05b Gigastar(2): Fix bootloaders steps 2025-10-30 14:37:12 -04:00
Kyle Schwarz ebf9409c18 Device: Guard mutex usage 2025-10-30 11:18:12 -04:00
Kyle Schwarz 83ab65b062 Device: Fix NeoVI message guard 2025-10-29 15:37:58 -04:00
Kyle Schwarz 7f1668a55b Device: Move network mutex to goOnline 2025-10-29 15:24:03 -04:00
Max Brombach 10ffd756a1 Device: Remove erroneous API error in VSA buffer overlap check 2025-10-29 12:56:46 -04:00
Jonathan SchwartzandKyle Schwarz c2f1022858 Device: Add network mutex support 2025-10-24 12:12:36 -04:00
Kyle Schwarz bf311ebe30 Communication: Add NeoVI timestamps 2025-10-21 15:18:26 -04:00
Max BrombachandKyle Schwarz 5cdaeb1edc Communication: Remove CoreMiniExtendedMsgHdr from HardwareLINPacket struct 2025-10-16 13:31:20 -04:00
Kyle Schwarz deabc2cff4 Linux: Update udev rules
Always unbind ftdi_sio for ICS devices
2025-10-13 09:28:04 -04:00
Yasser YassineandKyle Schwarz b48160286b Device: Add reconnect() 2025-10-11 16:33:22 -04:00
Kyle Schwarz 5d672d48d4 Bindings: Python: Add get_chip_versions 2025-10-09 22:51:18 -04:00
Kyle Schwarz 495632ddb7 Driver: DXX: Add PLASMA 2025-10-09 21:56:48 -04:00
Kyle Schwarz 3668b86f37 Linux: Update udev rules
libredxx doesn't use ftdi_sio
2025-10-09 21:54:57 -04:00
Yasser YassineandKyle Schwarz 0bd733bc5d Device: Add bootloader information & getChipVersions() 2025-10-09 21:21:45 -04:00
Emily BrooksandKyle Schwarz 99a2ca4f0d Device: WiVI: Add VIN support 2025-10-08 15:49:03 -04:00
Kyle Schwarz ec350b522a DeviceSettings: Remove checksum validation 2025-10-06 15:36:55 -04:00
Thomas StoddardandKyle Schwarz 895cd0792c Communication: I2C: Fix invalid packet logic 2025-10-02 10:12:15 -04:00
Max BrombachandKyle Schwarz a5ec9a2d20 VSA: Fix incorrect bytesRead value for end of overlapped buffer 2025-09-30 14:03:21 -04:00
Max BrombachandKyle Schwarz b9d3dde8d5 VSA: Remove packet truncation mechanism 2025-09-30 11:41:40 -04:00
Kyle Schwarz 11643e2281 Bindings: Python: Add EthPhyMessage
Also fixes PhyMessages for RADEpsilon(XL)
2025-09-29 17:17:26 -04:00
Max BrombachandKyle Schwarz f22d666f94 VSA: Discard timestamp top bit 2025-09-24 14:13:29 -04:00
Bryant JonesandKyle Schwarz 58b22da09b Device: Add neoVI FIRE3 T1S/LIN 2025-09-18 17:18:27 -04:00
Yasser YassineandKyle Schwarz 88d32128c9 Communication: Add SPI support 2025-09-17 13:30:12 -04:00
Kyle Schwarz 6d82289864 Driver: DXX: Update libredxx 2025-09-16 11:42:13 -04:00
Kyle Schwarz 674e905340 Driver: CDCACM: Add missing Darwin frameworks 2025-09-15 15:57:16 -04:00
Kyle Schwarz 8b7e2556a0 Driver: DXX: Fix ION, FIRE, ValueCAN3, & VividCAN 2025-09-10 10:11:08 -04:00
Max BrombachandKyle Schwarz fbdab1e998 Communication: Fix MultiChannelCommunication race 2025-09-09 15:52:54 -04:00
Max Brombach f53bc2e920 Fix FlexRay extension bugs and implement FlexRay example 2025-09-04 14:27:32 +00:00
Bryant JonesandKyle Schwarz a9e1f24f67 Device: Comet: Fix networks 2025-09-02 10:26:50 -04:00
Kyle Schwarz b10e29b8f5 Driver: DXX: Update libredxx 2025-08-28 23:24:04 -04:00
Thomas StoddardandKyle Schwarz 3c0c0dd44c Docs: Refactor icsneopy examples 2025-08-28 11:40:57 -04:00
Kyle Schwarz cf2cf3e28b CMake: Disable libredxx install 2025-08-28 10:09:30 -04:00
Kyle Schwarz 6926ca8199 CI: Update Linux images 2025-08-25 11:29:46 -04:00
Kyle Schwarz 29dc7b345f Driver: Switch to libredxx
- no more libFTDI
- no more libusb on Linux and macOS
- no more FTDI repack
- no more binary libs
- faster D2XX on Windows (no longer uses COM)
2025-08-25 11:24:03 -04:00
Kyle Schwarz 17285389e3 Tests: Switch to FetchContent 2025-08-21 20:19:22 -04:00
Bryant JonesandKyle Schwarz 328563b7e6 Docs: Add TC10 .py example 2025-08-12 12:36:16 -04:00
Kyle Schwarz 6b60804174 Device: Add com keepalive 2025-08-06 17:17:36 -04:00
Jonathan SchwartzandKyle Schwarz c5bce795c6 Device: Add MessageFilter to enableMessagePolling() 2025-07-29 13:15:18 -04:00
Yasser YassineandKyle Schwarz 1e5e714f5b Device: Add disk formatting 2025-07-22 20:02:06 +00:00
Kyle Schwarz d70defbf8a All: Address compiler warnings 2025-07-17 15:47:23 -04:00
Thomas StoddardandKyle Schwarz 10efacf91e Communication: EthernetMessage: Switch to TX_WRAP 2025-07-17 01:49:31 +00:00
Kyle Schwarz 6d985ca873 Communication: Fix neotc10sleepstatus_t 2025-07-16 11:54:27 -04:00
Nicholas Zamora 19df557b4a DeviceAppVersion: Add operator== 2025-07-09 20:48:22 +00:00
Kyle Schwarz 7afa41bf2a API: C: Add TC10 2025-07-03 09:30:29 -04:00
Kyle Schwarz c056e8dc2e Driver: Servd: Toggle closing when done 2025-07-02 14:28:59 -04:00
Yasser YassineandKyle Schwarz d5ae1cdb03 Device: RED2: Update settings 2025-07-02 18:10:51 +00:00
Kyle Schwarz 5795791eac Driver: Servd: Fix Address creation 2025-06-19 16:48:15 -04:00
Ben KleinhekselandKyle Schwarz c91db6355c Device: Add setValueLiveData()
* Adds the ability to set a CoreMini signal value via the live data interface
* Adds definition for the Manual Trigger and DAQ Enable signals
2025-06-18 21:51:32 +00:00
Kyle Schwarz f37b88d616 Communication: Fix ScriptStatus sizes 2025-06-12 11:17:59 -04:00
Yasser YassineandKyle Schwarz 33dea748f7 Device: Add supportsCoreminiScript() 2025-06-06 19:29:42 +00:00
Kyle Schwarz 245073f9d5 1.0.0 2025-06-05 21:10:54 -04:00
Kyle Schwarz c4e858d346 Driver: Prefer Npcap
Prefer Npcap over WinPcap and TCP
2025-06-04 22:14:09 -04:00
Keith NashandKyle Schwarz b3d47f2ae5 Communication: Add LogDataMessage 2025-05-16 19:36:27 +00:00
Kyle Schwarz b94ade1ef6 FIRE3: Add Ethernet Activation Lines 2025-05-15 11:11:26 -04:00
Bryant Jones d9ea5e085e Device: Gigastar2: Update networks 2025-05-09 11:51:26 -04:00
Bryant JonesandKyle Schwarz 5125520e76 Device: Gigastar2: Update networks 2025-05-09 15:30:20 +00:00
Kyle Schwarz 4dcb944d35 Driver: Add Servd 2025-05-08 11:22:42 -04:00
Yasser YassineandKyle Schwarz 7eeb1b6c38 Device: Refactor ComponentVersions
Also:
- Add setGenericData()
- Add ExtendedResponseFilter
2025-04-30 18:49:35 +00:00
Kyle Schwarz b1e875980c Communication: Rename Ethernet to Ethernet 01 2025-04-18 09:39:40 -04:00
Kyle Schwarz 8b680f2b64 All: Update network names
Updates all network names, the new format is <id>_<%02d>.
2025-04-17 20:57:46 +00:00
Kyle Schwarz e88cd244c8 Driver: D3XX: Refactor pipe logic 2025-04-15 17:44:58 -04:00
Jonathan SchwartzandKyle Schwarz 70733b3d96 Epsilon: Add PHY settings 2025-04-09 14:08:55 +00:00
Jonathan SchwartzandKyle Schwarz f743f32e63 Bindings: Python: Add FlexRay
Only RX at this time.
2025-04-08 20:47:51 +00:00
Kyle Schwarz 830fe1af59 Build: Add CMake 4.0.0 support 2025-03-31 15:56:14 -04:00
Jonathan SchwartzandKyle Schwarz 2209e348a3 CI: Add warnings & error on warnings 2025-03-28 17:35:26 +00:00
Jonathan SchwartzandKyle Schwarz 52e98af9fd Device: Add RAD-EpsilonXL 2025-03-25 20:43:18 +00:00
Jonathan SchwartzandKyle Schwarz e1a0ca056a Communication: Ignore empty LIN frames for checksum 2025-03-21 18:04:45 +00:00
Kyle Schwarz 538d6ec0c8 Communication: Remove unused parameter 2025-03-17 23:12:25 -04:00
Kyle Schwarz 1ba3eded09 Device: Gracefully handle old firmware without ComponentVersions 2025-03-14 15:38:34 -04:00
Kyle Schwarz 89047447a6 Bindings: Python: Add DoIP Ethernet Activation 2025-03-10 10:50:25 -04:00
Kyle Schwarz f97fd75b8d Docs: icsneopy: Add TC10 example 2025-03-03 17:06:22 -05:00
Yasser YassineandKyle Schwarz ea5f11268c RADMoon2: Enable communication for MDIO 2025-02-26 02:40:01 +00:00
Yasser YassineandKyle Schwarz 759cb2436d Device: RM2 & RM3: Update settings 2025-02-25 22:45:08 +00:00
Kyle Schwarz 771d82826f CI: Delay GitHub push 2025-02-20 15:31:45 -05:00
Yaroslav StetsykandKyle Schwarz b7330a2cea RADMoon3: Add TC10 2025-02-20 19:24:33 +00:00
Kyle Schwarz fb3778f91b Bindings: Python: Rework disk bindings 2025-02-20 12:04:16 -05:00
Kyle Schwarz a0c8cc62df Bindings: Python: Add coremini functions 2025-02-19 17:38:07 +00:00
Kyle Schwarz 77b3564677 Communication: Add missing short format commands 2025-02-19 00:20:49 -05:00
Kyle Schwarz 051063e684 RADGigastar: Add disk support 2025-02-19 00:18:41 -05:00
Kyle Schwarz 7c1cfde6a0 CI: Remove duplicate DOCKER_HOST 2025-02-19 00:16:36 -05:00
Yasser YassineandKyle Schwarz d4995fa2a9 Device: Fix heartbeat thread join location 2025-02-19 05:15:23 +00:00
Kyle Schwarz fb5c4babce CI: Remove hardware tests 2025-02-19 05:12:51 +00:00
Kurt Wachowski 4ba1a1e1dd Resolve "Add MACsec support" 2025-02-17 20:44:58 +00:00
Kyle Schwarz 6b9a687ff9 Bindings: Python: Use static MSVC runtime library 2025-02-11 16:43:00 -05:00
Kyle Schwarz 02b5dafca9 Bindings: Python: Simplify debug process 2025-02-11 12:43:30 -05:00
David RebbeandKyle Schwarz f04cd16bee Platform: Improve Windows wstring support 2025-02-06 18:43:51 +00: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
846 changed files with 51779 additions and 150108 deletions
+6
View File
@@ -10,3 +10,9 @@ third-party/concurrentqueue/tests
*.bak
.vs
.cache
*.wav
*.orig
examples/csharp/bin
examples/csharp/obj
test/system
.env
+359 -15
View File
@@ -1,51 +1,395 @@
variables:
DEBIAN_FRONTEND: noninteractive
LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT}
stages:
- build
- test
- unit_test
- deploy
#-------------------------------------------------------------------------------
# Windows
#-------------------------------------------------------------------------------
build windows/x64:
stage: build
script:
- CMD.EXE /C ci\build-windows64.bat
- cmd /C ci\build-windows64.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- icsneo-windows
- libicsneo-win-x64
test windows/x64:
stage: test
unit_test windows/x64:
stage: unit_test
script:
- build\libicsneo-tests.exe
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x64
needs:
- build windows/x64
tags:
- icsneo-windows
timeout: 3m
- libicsneo-win-x64
timeout: 5m
build windows/x86:
stage: build
script:
- CMD.EXE /C ci\build-windows32.bat
- cmd /C ci\build-windows32.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- icsneo-windows
- libicsneo-win-x64
test windows/x86:
stage: test
unit_test windows/x86:
stage: unit_test
script:
- build\libicsneo-tests.exe
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x86
needs:
- build windows/x86
tags:
- icsneo-windows
timeout: 3m
- 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 libpcap-dev git ca-certificates
- echo "$ICS_IPA_CA_CRT" >/usr/local/share/ca-certificates/ica-ipa-ca.crt
- update-ca-certificates --fresh
- 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 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 libpcap-dev git ca-certificates
- echo "$ICS_IPA_CA_CRT" >/usr/local/share/ca-certificates/ica-ipa-ca.crt
- update-ca-certificates --fresh
- 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 libpcap-dev
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
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
build linux/ubuntu/2404/amd64/gcc:
<<: *build_linux_ubuntu_gcc
image: ubuntu:24.04
unit_test linux/ubuntu/2404/amd64/gcc:
<<: *test_linux_ubuntu_gcc
image: ubuntu:24.04
dependencies:
- build linux/ubuntu/2404/amd64/gcc
needs:
- build linux/ubuntu/2404/amd64/gcc
build linux/ubuntu/2404/amd64/clang:
<<: *build_linux_ubuntu_clang
image: ubuntu:24.04
unit_test linux/ubuntu/2404/amd64/clang:
<<: *test_linux_ubuntu_clang
image: ubuntu:24.04
dependencies:
- build linux/ubuntu/2404/amd64/clang
needs:
- build linux/ubuntu/2404/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 git ca-certificates
- echo "$ICS_IPA_CA_CRT" >/etc/pki/ca-trust/source/anchors/ica-ipa-ca.crt
- update-ca-trust
- 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
- 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 git ca-certificates
- echo "$ICS_IPA_CA_CRT" >/etc/pki/ca-trust/source/anchors/ica-ipa-ca.crt
- update-ca-trust
- 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
- build/libicsneo-unit-tests
tags:
- linux-build
timeout: 5m
build linux/fedora/42/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:42
unit_test linux/fedora/42/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/gcc
needs:
- build linux/fedora/42/amd64/gcc
build linux/fedora/42/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:42
unit_test linux/fedora/42/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:42
dependencies:
- build linux/fedora/42/amd64/clang
needs:
- build linux/fedora/42/amd64/clang
build linux/fedora/43/amd64/gcc:
<<: *build_linux_fedora_gcc
image: fedora:43
unit_test linux/fedora/43/amd64/gcc:
<<: *test_linux_fedora_gcc
image: fedora:43
dependencies:
- build linux/fedora/43/amd64/gcc
needs:
- build linux/fedora/43/amd64/gcc
build linux/fedora/43/amd64/clang:
<<: *build_linux_fedora_clang
image: fedora:43
unit_test linux/fedora/43/amd64/clang:
<<: *test_linux_fedora_clang
image: fedora:43
dependencies:
- build linux/fedora/43/amd64/clang
needs:
- build linux/fedora/43/amd64/clang
#-------------------------------------------------------------------------------
# Python Module
#-------------------------------------------------------------------------------
build python/linux/amd64:
stage: build
tags:
- linux-native-amd64
variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install
script:
- sh ci/build-wheel-posix.sh
artifacts:
paths:
- wheelhouse
build python/linux/arm64:
stage: build
tags:
- arm64-linux-build
variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh
CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/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
CIBW_ARCHS: arm64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/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.13
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
when: delayed
start_in: 10 minutes
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
+5 -21
View File
@@ -3,24 +3,8 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
KERNEL=="ttyUSB?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
KERNEL=="ttyACM?", ATTRS{idVendor}=="093c", GROUP="users", MODE="0666"
# neoVI ION/PLASMA PIDs are not in the latest ftdi_sio driver so lets make a
# rule to add it when we see a new unclaimed device.
# PLASMA = 0x0801, ION = 0x0901
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", \
ATTRS{idVendor}=="093c", ATTRS{idProduct}=="0801", \
DRIVER=="", \
RUN+="/sbin/modprobe -b ftdi_sio"
ACTION=="add", SUBSYSTEM=="drivers", \
ENV{DEVPATH}=="/bus/usb-serial/drivers/ftdi_sio", \
ATTR{new_id}="093c 0801"
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", \
ATTRS{idVendor}=="093c", ATTRS{idProduct}=="0901", \
DRIVER=="", \
RUN+="/sbin/modprobe -b ftdi_sio"
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_interface", \
ATTRS{idVendor}=="093c", ATTRS{idProduct}=="1000", \
DRIVER=="", \
RUN+="/sbin/modprobe -b ftdi_sio"
ACTION=="add", SUBSYSTEM=="drivers", \
ENV{DEVPATH}=="/bus/usb-serial/drivers/ftdi_sio", \
ATTR{new_id}="093c 0901"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="093c", KERNEL=="ttyUSB*", \
RUN+="/bin/sh -c 'echo $id:1.0>/sys/bus/usb/drivers/ftdi_sio/unbind'"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="093c", DRIVER=="usbhid", \
RUN+="/bin/sh -c 'echo $id:1.0>/sys/bus/usb/drivers/usbhid/unbind'"
+211 -75
View File
@@ -1,12 +1,20 @@
cmake_minimum_required(VERSION 3.2)
project(libicsneo VERSION 0.3.0)
cmake_minimum_required(VERSION 3.16)
project(libicsneo VERSION 1.0.0)
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
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_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
@@ -16,11 +24,13 @@ set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to
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_DXX "Enable devices which communicate over D2XX/D3XX via libredxx" ON)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
include(GNUInstallDirs)
@@ -28,19 +38,17 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Enable Warnings
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
set(LIBICSNEO_COMPILER_WARNINGS /W4)
# 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)
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
set(LIBICSNEO_COMPILER_WARNINGS -Wall -Wno-switch -Wno-unknown-pragmas)
endif()
find_package(Threads REQUIRED)
# doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
@@ -98,6 +106,7 @@ endif()
if(WIN32)
set(PLATFORM_SRC
platform/windows/strings.cpp
platform/windows/registry.cpp
)
@@ -108,9 +117,9 @@ if(WIN32)
)
endif()
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC
platform/windows/vcp.cpp
platform/windows/cdcacm.cpp
)
endif()
else() # Darwin or Linux
@@ -128,12 +137,6 @@ else() # Darwin or Linux
)
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
@@ -157,8 +160,16 @@ else() # Darwin or Linux
endif()
endif()
if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples)
if(LIBICSNEO_ENABLE_DXX)
list(APPEND PLATFORM_SRC
platform/dxx.cpp
)
endif()
if(LIBICSNEO_ENABLE_TCP)
list(APPEND PLATFORM_SRC
platform/tcp.cpp
)
endif()
# Extensions
@@ -172,19 +183,38 @@ 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/ethphymessage.cpp
communication/message/linmessage.cpp
communication/message/livedatamessage.cpp
communication/message/logdatamessage.cpp
communication/message/tc10statusmessage.cpp
communication/message/gptpstatusmessage.cpp
communication/message/ethernetstatusmessage.cpp
communication/message/networkmutexmessage.cpp
communication/message/clientidmessage.cpp
communication/message/transmitmessage.cpp
communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp
communication/packet/spipacket.cpp
communication/packet/ethernetpacket.cpp
communication/packet/versionpacket.cpp
communication/packet/iso9141packet.cpp
communication/packet/ethphyregpacket.cpp
communication/packet/livedatapacket.cpp
communication/packet/logicaldiskinfopacket.cpp
communication/packet/wivicommandpacket.cpp
communication/packet/i2cpacket.cpp
communication/packet/linpacket.cpp
communication/packet/mdiopacket.cpp
communication/packet/scriptstatuspacket.cpp
communication/packet/componentversionpacket.cpp
communication/packet/supportedfeaturespacket.cpp
communication/packet/genericbinarystatuspacket.cpp
communication/packet/hardwareinfopacket.cpp
communication/decoder.cpp
communication/encoder.cpp
communication/ethernetpacketizer.cpp
@@ -192,6 +222,10 @@ set(SRC_FILES
communication/multichannelcommunication.cpp
communication/communication.cpp
communication/driver.cpp
communication/livedata.cpp
core/ringbuffer.cpp
core/crc32.cpp
core/macseccfg.cpp
device/extensions/flexray/extension.cpp
device/extensions/flexray/controller.cpp
device/idevicesettings.cpp
@@ -205,6 +239,24 @@ set(SRC_FILES
disk/plasiondiskreaddriver.cpp
disk/extextractordiskreaddriver.cpp
disk/fat.cpp
disk/diskdetails.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/servd.cpp
${PLATFORM_SRC}
)
@@ -235,6 +287,7 @@ endif()
configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h)
configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
configure_file(api/icsneoc2/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES})
message("Including " ${EXTINC})
@@ -265,8 +318,10 @@ target_include_directories(icsneocpp
${CMAKE_CURRENT_SOURCE_DIR}/include
${LIBICSNEO_EXTENSION_INCLUDE_PATHS}
)
target_link_libraries(icsneocpp PUBLIC Threads::Threads $<$<BOOL:${WIN32}>:ws2_32 iphlpapi>)
set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_options(icsneocpp PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
if(LIBICSNEO_ENABLE_FIRMIO)
@@ -277,9 +332,21 @@ if(LIBICSNEO_ENABLE_RAW_ETHERNET)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
if(APPLE)
find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation REQUIRED)
find_library(IO_KIT_FRAMEWORK IOKit REQUIRED)
target_link_libraries(icsneocpp PRIVATE ${CORE_FOUNDATION_FRAMEWORK} ${IO_KIT_FRAMEWORK})
endif()
endif()
if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
if(LIBICSNEO_ENABLE_DXX)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_DXX)
target_link_libraries(icsneocpp PRIVATE libredxx::libredxx)
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
@@ -287,36 +354,25 @@ add_subdirectory(third-party/fatfs)
set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PRIVATE fatfs)
# libftdi
if(LIBICSNEO_ENABLE_FTDI)
if(NOT WIN32)
target_include_directories(icsneocpp PUBLIC third-party/libftdi/src)
set(LIBFTDI_DOCUMENTATION OFF CACHE INTERNAL "")
set(LIBFTDI_BUILD_TESTS OFF CACHE INTERNAL "")
set(LIBFTDI_INSTALL OFF CACHE INTERNAL "")
set(LIBFTDI_PYTHON_BINDINGS OFF CACHE INTERNAL "")
set(LIBFTDI_LINK_PYTHON_LIBRARY OFF CACHE INTERNAL "")
set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi)
target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
find_package(Threads)
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
endif(NOT WIN32)
endif(LIBICSNEO_ENABLE_FTDI)
# dxx
if(LIBICSNEO_ENABLE_DXX)
include(FetchContent)
FetchContent_Declare(libredxx
GIT_REPOSITORY https://github.com/Zeranoe/libredxx.git
GIT_TAG e823a96c39a64ab41b7d1632dbe8f86bb854df83
)
set(LIBREDXX_DISABLE_INSTALL ON)
FetchContent_MakeAvailable(libredxx)
endif()
# 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)
add_definitions(-DWPCAP -DHAVE_REMOTE)
else()
target_include_directories(icsneocpp PUBLIC AFTER ${LIBICSNEO_NPCAP_INCLUDE_DIR})
add_definitions(-DNPCAP -DWIN32_LEAN_AND_MEAN)
endif()
else()
find_package(PCAP REQUIRED)
@@ -325,9 +381,20 @@ if(LIBICSNEO_ENABLE_RAW_ETHERNET)
endif(WIN32)
endif(LIBICSNEO_ENABLE_RAW_ETHERNET)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
target_link_libraries(icsneocpp PUBLIC "-framework CoreFoundation" "-framework IOKit")
# protobuf
if(DEFINED ENV{LIBICSNEO_ICSPB_REPO})
set(LIBICSNEO_ICSPB_REPO "$ENV{LIBICSNEO_ICSPB_REPO}")
endif()
if(NOT LIBICSNEO_ICSPB_REPO)
set(LIBICSNEO_ICSPB_REPO https://github.com/intrepidcs/icspb.git)
endif()
include(FetchContent)
FetchContent_Declare(icspb
GIT_REPOSITORY ${LIBICSNEO_ICSPB_REPO}
GIT_TAG 3339fa6b83a6b3e7704d41f5c2f2175cfc761a1f
)
FetchContent_MakeAvailable(icspb)
target_link_libraries(icsneocpp PRIVATE icspb::icspb)
if(LIBICSNEO_BUILD_ICSNEOC)
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
@@ -340,6 +407,7 @@ if(LIBICSNEO_BUILD_ICSNEOC)
)
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)
target_compile_options(icsneoc PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
endif()
if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
@@ -353,6 +421,40 @@ if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
)
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
target_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC)
target_compile_options(icsneoc-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
endif()
if(LIBICSNEO_BUILD_ICSNEOC2)
add_library(icsneoc2 SHARED api/icsneoc2/icsneoc2.cpp api/icsneoc2/icsneoc2settings.cpp api/icsneoc2/icsneoc2messages.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_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_options(icsneoc2 PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
if(WIN32)
set_target_properties(icsneoc2 PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
endif()
if(LIBICSNEO_BUILD_ICSNEOC2_STATIC)
add_library(icsneoc2-static STATIC api/icsneoc2/icsneoc2.cpp api/icsneoc2/icsneoc2settings.cpp api/icsneoc2/icsneoc2messages.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)
target_compile_options(icsneoc2-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
@@ -371,42 +473,76 @@ if(LIBICSNEO_BUILD_ICSNEOLEGACY)
)
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)
target_compile_options(icsneolegacy PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
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)
target_compile_options(icsneolegacy-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
endif()
add_subdirectory(bindings)
if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# googletest
if(LIBICSNEO_BUILD_TESTS)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
if(LIBICSNEO_BUILD_UNIT_TESTS)
include(FetchContent)
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 6986c2b575f77135401a4e1c65a7a42f20e18fef
)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
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-tests
test/main.cpp
test/diskdriverreadtest.cpp
test/diskdriverwritetest.cpp
test/eventmanagertest.cpp
test/ethernetpacketizertest.cpp
test/i2cencoderdecodertest.cpp
test/a2bencoderdecodertest.cpp
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
test/unit/windowsstrings.cpp
test/unit/periodictest.cpp
)
target_link_libraries(libicsneo-tests gtest gtest_main)
target_link_libraries(libicsneo-tests icsneocpp)
target_compile_options(libicsneo-unit-tests PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
target_include_directories(libicsneo-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
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-test-suite COMMAND libicsneo-tests)
gtest_discover_tests(libicsneo-unit-tests TEST_PREFIX "unit/" PROPERTIES LABELS "unit")
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
include(CPack)
-45
View File
@@ -1,45 +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
- RADA2B
- 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
- RADA2B
- CAN works
- Ethernet works
+23 -7
View File
@@ -1,13 +1,29 @@
Copyright 2018-2020 Intrepid Control Systems, Inc.
Copyright (c) 2018-2026 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.
+39 -122
View File
@@ -1,130 +1,47 @@
# libicsneo
### The Intrepid Control Systems Open Source 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
There are two major ways to write a new application using libicsneo. You can use the C++ interface, which will be compiled with your project and statically linked, or you can use the C interface, which can be either statically or dynamically linked.
### Integration with CMake (Static Linking)
Integrating the library with your current CMake project is extremely easy.
1. Checkout the library (or add as a submodule) into a subdirectory of your project.
2. Within your `CMakeLists.txt` you can add the line `add_subdirectory("third-party/libicsneo")` to bring in the libicsneo targets. Replace `third-party` with any subdirectory you choose.
3. The libicsneo library include paths should automatically be added to your include path.
4. Link the library with your target by adding `target_link_libraries(libicsneocpp-example icsneocpp)` after your target, substituting `libicsneocpp-example` with your target application.
- [C++](https://libicsneo.readthedocs.io/en/latest/icsneocpp/)
- [Python](https://libicsneo.readthedocs.io/en/latest/icsneopy/)
- [C](https://libicsneo.readthedocs.io/en/latest/icsneoc/) (deprecated, use C2)
- [C2](https://libicsneo.readthedocs.io/en/latest/icsneoc2/)
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)
It is also possible to use the precompiled binaries with runtime linking. It is not recommended or supported to attempt to use the C++ interface with dynamic linking due to the complexities of C++ compilers.
1. Add this repository's `/include` to your include path
2. Add `#define ICSNEOC_DYNAMICLOAD` to the top of your source file
2. Add `#import <icsneo/icsneoc.h>` below that line
3. Call `icsneo_init();` to import the library before using any other libicsneo functions.
4. Use the library as normal.
5. Call `icsneo_close();` to unload the library.
- EtherBADGE
- neoVI Connect
- neoVI FIRE
- neoVI FIRE 2
- neoVI FIRE 3
- neoVI ION
- neoVI PLASMA
- neoVI RED 2
- RAD-A2B
- RAD-Comet 2
- RAD-Comet 3
- RAD-Epsilon
- RAD-EpsilonXL
- RAD-Galaxy
- RAD-Galaxy 2
- RAD-Gemini
- 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
### 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.
## License
Any time you get bus traffic from the API, you will receive it as an `std::shared_ptr<icsneo::Message>`. The message will be valid as long as the `shared_ptr` stays in scope. Checking the type of the message allows you to cast it accordingly and access extra data for certain protocols. For instance, casting an `icsneo::Message` to an `icsneo::CANMessage` allows you to access the arbitration ID.
A barebones example is provided. For a more complete example, check the included `examples`.
``` c++
std::vector<std::shared_ptr<icsneo::Device>> devices = icsneo::FindAllDevices();
std::cout << devices.size() << " found!" << std::endl;
for(auto& device : devices)
std::cout << "Found " << device->describe() << std::endl; // "Found neoVI FIRE 2 CY2345"
std::shared_ptr<icsneo::Device> myDevice = devices[0];
if(!myDevice->open()) // Device tried and failed to open, print the last error
std::cout << icsneo::GetLastError() << std::endl;
myDevice->goOnline(); // Start receiving messages
myDevice->enableMessagePolling(); // Allow the use of myDevice->getMessages() later
// Alternatively, assign a callback for new messages
std::this_thread::wait_for(std::chrono::seconds(5));
std::vector<std::shared_ptr<icsneo::Message>> messages = myDevice->getMessages();
std::cout << "We got " << messages.size() << " messages!" << std::endl;
for(auto& msg : messages) {
switch(msg->network.getType()) {
case icsneo::Network::Type::CAN:
case icsneo::Network::Type::SWCAN:
case icsneo::Network::Type::LSFTCAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canmsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
// canmsg->arbid is valid here
// canmsg->data is an std::vector<uint8_t>, you can check .size() for the DLC of the message
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
default:
// Handle others
}
}
myDevice->close();
```
### Using the C API
The C API is designed to be a robust and fault tolerant interface which allows easy integration with other languages as well as existing C applications. When calling `icsneo_findAllDevices()` you will provide a buffer of `neodevice_t` structures, which will be written with the found devices. These `neodevice_t` structures can be uses to interface with the API from then on. Once you call `icsneo_close()` with a device, that device and all associated memory will be freed. You will need to run `icsneo_findAllDevices()` again to reconnect.
Messages are passed in the form of `neomessage_t` structures when calling `icsneo_getMessages()`. These structures contain a `uint8_t*` to the payload data, and this pointer will be valid until the next call to `icsneo_getMessages()` or the device is closed.
A barebones example is provided. For a more complete example, check the included `examples`.
``` c
size_t deviceCount = 10; // Pre-set to the size of your buffer before the icsneo_findAllDevices() call
neodevice_t devices[10];
icsneo_findAllDevices(devices, &deviceCount);
printf("We found %ull devices\n", deviceCount);
for(size_t i = 0; i < deviceCount; i++) {
neodevice_t* myDevice = &devices[i];
char desc[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION];
size_t sz = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
icsneo_describeDevice(myDevice, desc, &sz);
printf("Found %s\n", desc); // "Found neoVI FIRE 2 CY2345"
}
neodevice_t* myDevice = &devices[0];
if(!icsneo_openDevice(myDevice)) {
neoevent_t error;
if(icsneo_getLastError(&error))
printf("Error! %s\n", error.description);
}
icsneo_goOnline(myDevice); // Start receiving messages
icsneo_enableMessagePolling(myDevice); // Allow the use of icsneo_getMessages() later
sleep(5);
neomessage_t messages[50];
size_t messageCount = 50;
icsneo_getMessages(myDevice, messages, &messageCount, 0 /* non-blocking */);
printf("We got %ull messages!\n", messageCount);
for(size_t i = 0; i < messageCount; i++) {
if(messages[i].type == ICSNEO_NETWORK_TYPE_CAN) {
// A message of type CAN should be interperated a neomessage_can_t, so we can cast safely
neomessage_can_t* canmsg = (neomessage_can_t*)&messages[i];
// canmsg->arbid is valid here
// canmsg->data is an uint8_t*, you can check canmsg->length for the length of the payload
// canmsg->timestamp is the time recorded by the hardware in nanoseconds since (1/1/2007 12:00:00 GMT)
}
}
icsneo_closeDevice(myDevice);
```
## Building from Source
### Windows
Building will require MSVC 2017 version 15.7 or newer 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.12 or above
- GCC 7 or above
- `libusb-1.0-0-dev`
- `libpcap0.8-dev`
- `build-essential` is recommended
If you'd like to be able to run programs that use this library without being root, consider using the included udev rules
```
$ sudo cp 99-intrepidcs.rules /etc/udev/rules.d/
```
libicsneo is licensed as BSD-3 with an extra clause, see [LICENSE](LICENSE)
for more details.
+99 -1
View File
@@ -144,8 +144,17 @@ bool icsneo_closeDevice(const neodevice_t* device) {
if((*it).get() == device->device)
itemsToDelete.push_back(it);
}
for(auto it : itemsToDelete)
for(auto it : itemsToDelete) {
// Move it back into connectable devices so we can open it again.
// Without this we will be unable to use/reopen the device due to
// icsneo_isValidNeoDevice / icsneo_openDevice checks against this
// container. Since its closed we are in a connectable state again.
// Notice: When we search again this will be cleaned up by
// icsneo_freeUnconnectedDevices()
connectableFoundDevices.push_back(*it);
// Remove it from the connected devices as we are no longer connected.
connectedDevices.erase(it);
}
return true;
}
@@ -689,3 +698,92 @@ bool icsneo_setTerminationFor(const neodevice_t* device, neonetid_t netid, bool
return device->device->settings->setTerminationFor(Network(netid), enabled);
}
bool icsneo_getRTC(const neodevice_t* device, uint64_t* output)
{
if(!icsneo_isValidNeoDevice(device))
return false;
const std::optional<std::chrono::time_point<std::chrono::system_clock>> rtc = device->device->getRTC();
if(!rtc)
return false;
auto duration = std::chrono::duration_cast<std::chrono::seconds>(rtc->time_since_epoch());
*output = static_cast<uint64_t>(duration.count());
return true;
}
bool icsneo_setRTC(const neodevice_t* device, uint64_t input)
{
if(!icsneo_isValidNeoDevice(device))
return false;
std::chrono::seconds duration(input);
const std::chrono::system_clock::time_point time(duration);
return device->device->setRTC(time);
}
int icsneo_getDeviceStatus(const neodevice_t* device, void* status, size_t* size) {
if(!icsneo_isValidNeoDevice(device))
return false;
if(status == nullptr || size == nullptr)
return false;
std::shared_ptr<Message> msg = device->device->com->waitForMessageSync([&]() {
return device->device->com->sendCommand(Command::RequestStatusUpdate);
}, std::make_shared<MessageFilter>(Network::NetID::DeviceStatus), std::chrono::milliseconds(100));
if(!msg) // Did not receive a message
return false;
auto rawMessage = std::static_pointer_cast<RawMessage>(msg);
if(!rawMessage || (rawMessage->network.getNetID() != Network::NetID::DeviceStatus))
return false;
if(*size < rawMessage->data.size())
return false;
std::copy(rawMessage->data.begin(), rawMessage->data.end(), static_cast<uint8_t*>(status));
*size = rawMessage->data.size();
return true;
}
bool icsneo_isOnlineSupported(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->isOnlineSupported();
}
bool icsneo_requestTC10Wake(const neodevice_t* device, neonetid_t netid) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->requestTC10Wake((Network::NetID)netid);
}
bool icsneo_requestTC10Sleep(const neodevice_t* device, neonetid_t netid) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->requestTC10Sleep((Network::NetID)netid);
}
bool icsneo_getTC10Status(const neodevice_t* device, neonetid_t netid, neotc10status_t* status) {
if(!icsneo_isValidNeoDevice(device))
return false;
const auto statusMsg = device->device->getTC10Status((Network::NetID)netid);
if(!statusMsg)
return false;
status->wakeStatus = (neotc10wakestatus_t)statusMsg->wakeStatus;
status->sleepStatus = (neotc10sleepstatus_t)statusMsg->sleepStatus;
return true;
}
+1 -1
View File
@@ -29,7 +29,7 @@ BEGIN
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneoc.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2019"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2026"
VALUE "OriginalFilename", "icsneoc.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
// This header is for internal icsneoc2 use only, it should not be included by users of the API.
#pragma once
#include "icsneo/icsneoc2.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/scriptstatusmessage.h"
#include "icsneo/api/event.h"
#include "icsneo/disk/diskdetails.h"
#include <memory>
#include <vector>
using namespace icsneo;
typedef struct icsneoc2_message_t {
std::shared_ptr<Message> message;
} icsneoc2_message_t;
typedef struct icsneoc2_event_t {
APIEvent event;
} icsneoc2_event_t;
typedef struct icsneoc2_device_info_t {
std::shared_ptr<Device> device;
icsneoc2_device_info_t* next;
} icsneoc2_device_info_t;
typedef struct icsneoc2_device_t {
std::shared_ptr<Device> device;
} icsneoc2_device_t;
typedef struct icsneoc2_disk_details_t {
std::shared_ptr<DiskDetails> details;
} icsneoc2_disk_details_t;
typedef struct icsneoc2_script_status_t {
std::shared_ptr<ScriptStatusMessage> status;
} icsneoc2_script_status_t;
/**
* Safely copies a std::string to a char array.
*
* @param dest The buffer to copy the string into
* @param dest_size* The size of the buffer. Will be modified to the length of the string without the null terminator.
* @param src The string to copy
*
* @return true if the string was successfully copied, false otherwise
*
* @note This function always null terminates the buffer, even if the string is too long.
* In the case of truncation, dest_size will reflect the truncated length (not including the null terminator).
*/
bool safe_str_copy(char* dest, size_t* dest_size, std::string_view src);
+417
View File
@@ -0,0 +1,417 @@
#include "icsneo/icsneoc2messages.h" // TODO: Remove this after the complete refactor
#include "icsneo/icsneoc2.h"
#include "icsneoc2_internal.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/packet/canpacket.h"
icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_message_t* message, bool* is_valid) {
if(!message || !is_valid) {
return icsneoc2_error_invalid_parameters;
}
*is_valid = (bool)message->message;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_message_t* message, bool* value) {
if(!message || !value) {
return icsneoc2_error_invalid_parameters;
}
// We can static cast here because we are relying on the type being correct at this point
auto frame = std::dynamic_pointer_cast<Frame>(message->message);
if(!frame) {
return icsneoc2_error_invalid_type;
}
*value = frame->transmitted;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_error(icsneoc2_message_t* message, bool* value) {
if(!message || !value) {
return icsneoc2_error_invalid_parameters;
}
auto frame = std::dynamic_pointer_cast<Frame>(message->message);
if(!frame) {
return icsneoc2_error_invalid_type;
}
*value = frame->error;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_message_t* message, icsneoc2_netid_t* netid) {
if(!message || !netid) {
return icsneoc2_error_invalid_parameters;
}
auto raw = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw) {
return icsneoc2_error_invalid_type;
}
*netid = static_cast<icsneoc2_netid_t>(raw->network.getNetID());
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_netid_name_get(icsneoc2_netid_t netid, char* value, size_t* value_length) {
if(!value || !value_length) {
return icsneoc2_error_invalid_parameters;
}
auto netid_str = std::string(Network::GetNetIDString(static_cast<Network::NetID>(netid), true));
// Copy the string into value
return safe_str_copy(value, value_length, netid_str) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
}
icsneoc2_error_t icsneoc2_message_netid_set(icsneoc2_message_t* message, icsneoc2_netid_t netid) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto raw = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw) {
return icsneoc2_error_invalid_type;
}
raw->network = Network(static_cast<neonetid_t>(netid), true);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_data_set(icsneoc2_message_t* message, uint8_t* data, size_t data_length) {
if(!message || !data) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the message has the data field (RawMessage or Frame)
auto raw_message = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw_message) {
return icsneoc2_error_invalid_type;
}
raw_message->data.resize(data_length);
std::copy(data, data + data_length, raw_message->data.begin());
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t* data, size_t* data_length) {
if(!message || !data_length) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the message has the data field (RawMessage or Frame)
auto raw_message = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw_message) {
return icsneoc2_error_invalid_type;
}
if(!data) {
*data_length = raw_message->data.size();
return icsneoc2_error_success;
}
if(*data_length < raw_message->data.size()) {
return icsneoc2_error_invalid_parameters;
}
std::copy(raw_message->data.begin(), raw_message->data.begin() + raw_message->data.size(), data);
*data_length = raw_message->data.size();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_message_t** message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
// Initialize the internal message as a CANMessage so that all icsneoc2_message_can_*_set
// functions work correctly on user-created transmit messages.
(*message)->message = std::make_shared<CANMessage>();
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_free(icsneoc2_message_t* message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
delete message;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_props_set(icsneoc2_message_t* message, const uint64_t* arb_id, const uint64_t* flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_msg = std::dynamic_pointer_cast<CANMessage>(message->message);
if(!can_msg) {
return icsneoc2_error_invalid_type;
}
if(arb_id) {
can_msg->arbid = static_cast<uint32_t>(*arb_id);
}
if(flags) {
can_msg->isRemote = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_RTR);
can_msg->isExtended = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_IDE);
can_msg->isCANFD = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_FDF);
can_msg->baudrateSwitch = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_BRS);
can_msg->errorStateIndicator = (*flags & ICSNEOC2_MESSAGE_CAN_FLAGS_ESI);
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_props_get(icsneoc2_message_t* message, uint64_t* arb_id, uint64_t* flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_msg = std::dynamic_pointer_cast<CANMessage>(message->message);
if(!can_msg) {
return icsneoc2_error_invalid_type;
}
if(arb_id) {
*arb_id = can_msg->arbid;
}
if(flags) {
*flags = 0;
if(can_msg->isRemote) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_RTR;
}
if(can_msg->isExtended) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_IDE;
}
if(can_msg->isCANFD) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_FDF;
}
if(can_msg->baudrateSwitch) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_BRS;
}
if(can_msg->errorStateIndicator) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_ESI;
}
if(can_msg->txAborted) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ABORTED;
}
if(can_msg->txLostArb) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_LOST_ARB;
}
if(can_msg->txError) {
*flags |= ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_network_type_get(icsneoc2_message_t* message, icsneoc2_network_type_t* network_type) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto raw = std::dynamic_pointer_cast<RawMessage>(message->message);
if(!raw) {
return icsneoc2_error_invalid_type;
}
*network_type = (icsneoc2_network_type_t)raw->network.getType();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_raw(icsneoc2_message_t* message, bool* is_raw) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_raw = std::dynamic_pointer_cast<RawMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_frame(icsneoc2_message_t* message, bool* is_frame) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_frame = std::dynamic_pointer_cast<Frame>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_can(icsneoc2_message_t* message, bool* is_can) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
*is_can = std::dynamic_pointer_cast<CANMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_can_error(icsneoc2_message_t* message, bool* is_can_error) {
if(!message || !is_can_error) {
return icsneoc2_error_invalid_parameters;
}
*is_can_error = std::dynamic_pointer_cast<CANErrorMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_error_props_get(
icsneoc2_message_t *message, uint8_t *tx_err_count, uint8_t *rx_err_count,
icsneoc2_can_error_code_t *error_code,
icsneoc2_can_error_code_t *data_error_code,
icsneoc2_message_can_error_flags_t *flags) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto can_err = std::dynamic_pointer_cast<CANErrorMessage>(message->message);
if(!can_err) {
return icsneoc2_error_invalid_type;
}
if(tx_err_count) {
*tx_err_count = can_err->transmitErrorCount;
}
if(rx_err_count) {
*rx_err_count = can_err->receiveErrorCount;
}
if(error_code) {
*error_code = static_cast<icsneoc2_can_error_code_t>(can_err->errorCode);
}
if(data_error_code) {
*data_error_code = static_cast<icsneoc2_can_error_code_t>(can_err->dataErrorCode);
}
if(flags) {
*flags = 0;
if(can_err->busOff) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_BUS_OFF;
}
if(can_err->errorPassive) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_PASSIVE;
}
if(can_err->errorWarn) {
*flags |= ICSNEOC2_MESSAGE_CAN_ERROR_FLAGS_ERROR_WARN;
}
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_is_lin(icsneoc2_message_t* message, bool* is_lin) {
if(!message || !is_lin) {
return icsneoc2_error_invalid_parameters;
}
*is_lin = std::dynamic_pointer_cast<LINMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_create(icsneoc2_message_t** message, uint8_t id) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
try {
*message = new icsneoc2_message_t;
(*message)->message = std::make_shared<LINMessage>(id);
} catch(const std::bad_alloc&) {
return icsneoc2_error_out_of_memory;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_props_get(const icsneoc2_message_t* message,
uint8_t* id, uint8_t* protected_id, uint8_t* checksum,
icsneoc2_lin_msg_type_t* msg_type, bool* is_enhanced_checksum) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
if(id) {
*id = lin_msg->ID;
}
if(protected_id) {
*protected_id = lin_msg->protectedID;
}
if(checksum) {
*checksum = lin_msg->checksum;
}
if(msg_type) {
*msg_type = static_cast<icsneoc2_lin_msg_type_t>(lin_msg->linMsgType);
}
if(is_enhanced_checksum) {
*is_enhanced_checksum = lin_msg->isEnhancedChecksum;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_props_set(icsneoc2_message_t* message,
const uint8_t* id, const uint8_t* checksum,
const icsneoc2_lin_msg_type_t* msg_type, const bool* is_enhanced_checksum) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
if(id) {
lin_msg->ID = *id & 0x3Fu;
lin_msg->protectedID = lin_msg->calcProtectedID(lin_msg->ID);
}
if(checksum) {
lin_msg->checksum = *checksum;
}
if(msg_type) {
lin_msg->linMsgType = static_cast<LINMessage::Type>(*msg_type);
}
if(is_enhanced_checksum) {
lin_msg->isEnhancedChecksum = *is_enhanced_checksum;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_err_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_err_flags_t* err_flags) {
if(!message || !err_flags) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
*err_flags = 0;
if(lin_msg->errFlags.ErrRxBreakOnly) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_ONLY;
if(lin_msg->errFlags.ErrRxBreakSyncOnly) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_SYNC_ONLY;
if(lin_msg->errFlags.ErrTxRxMismatch) *err_flags |= ICSNEOC2_LIN_ERR_TX_RX_MISMATCH;
if(lin_msg->errFlags.ErrRxBreakNotZero) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_NOT_ZERO;
if(lin_msg->errFlags.ErrRxBreakTooShort) *err_flags |= ICSNEOC2_LIN_ERR_RX_BREAK_TOO_SHORT;
if(lin_msg->errFlags.ErrRxSyncNot55) *err_flags |= ICSNEOC2_LIN_ERR_RX_SYNC_NOT_55;
if(lin_msg->errFlags.ErrRxDataLenOver8) *err_flags |= ICSNEOC2_LIN_ERR_RX_DATA_LEN_OVER_8;
if(lin_msg->errFlags.ErrFrameSync) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_SYNC;
if(lin_msg->errFlags.ErrFrameMessageID) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_MESSAGE_ID;
if(lin_msg->errFlags.ErrFrameResponderData) *err_flags |= ICSNEOC2_LIN_ERR_FRAME_RESPONDER_DATA;
if(lin_msg->errFlags.ErrChecksumMatch) *err_flags |= ICSNEOC2_LIN_ERR_CHECKSUM_MATCH;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_status_flags_get(const icsneoc2_message_t* message, icsneoc2_lin_status_flags_t* status_flags) {
if(!message || !status_flags) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
*status_flags = 0;
if(lin_msg->statusFlags.TxChecksumEnhanced) *status_flags |= ICSNEOC2_LIN_STATUS_TX_CHECKSUM_ENHANCED;
if(lin_msg->statusFlags.TxCommander) *status_flags |= ICSNEOC2_LIN_STATUS_TX_COMMANDER;
if(lin_msg->statusFlags.TxResponder) *status_flags |= ICSNEOC2_LIN_STATUS_TX_RESPONDER;
if(lin_msg->statusFlags.TxAborted) *status_flags |= ICSNEOC2_LIN_STATUS_TX_ABORTED;
if(lin_msg->statusFlags.UpdateResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_UPDATE_RESPONDER_ONCE;
if(lin_msg->statusFlags.HasUpdatedResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE;
if(lin_msg->statusFlags.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED;
if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_lin_calc_checksum(icsneoc2_message_t* message) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto lin_msg = std::dynamic_pointer_cast<LINMessage>(message->message);
if(!lin_msg) {
return icsneoc2_error_invalid_type;
}
LINMessage::calcChecksum(*lin_msg);
return icsneoc2_error_success;
}
+684
View File
@@ -0,0 +1,684 @@
#include "icsneo/icsneoc2.h"
#include "icsneo/icsneoc2settings.h"
#include "icsneo/device/device.h"
#include "icsneo/device/devicefinder.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/io.h"
#include <string>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <optional>
#include <sstream>
using namespace icsneo;
#include "icsneoc2_internal.h"
icsneoc2_error_t icsneoc2_settings_apply_defaults(icsneoc2_device_t* device, bool save) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->applyDefaults(!save)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_apply(icsneoc2_device_t* device) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->apply()) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_refresh(icsneoc2_device_t* device) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->refresh()) {
return icsneoc2_error_get_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_baudrate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t* baudrate) {
if(!baudrate) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto baudrate_value = device->device->settings->getBaudrateFor(Network(netid));
if(baudrate_value < 0) {
*baudrate = 0;
return icsneoc2_error_invalid_type;
}
*baudrate = baudrate_value;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_baudrate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t baudrate) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setBaudrateFor(Network(netid), baudrate)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_canfd_baudrate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t* baudrate) {
if(!baudrate) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
*baudrate = device->device->settings->getFDBaudrateFor(Network(netid));
if(*baudrate < 0) {
*baudrate = 0;
return icsneoc2_error_invalid_type;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_canfd_baudrate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, int64_t baudrate) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setFDBaudrateFor(Network(netid), baudrate)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_is_supported(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* supported) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!supported) {
return icsneoc2_error_invalid_parameters;
}
*supported = device->device->settings->isTerminationSupportedFor(Network(static_cast<Network::NetID>(netid)));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_can_enable(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* can_enable) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!can_enable) {
return icsneoc2_error_invalid_parameters;
}
*can_enable = device->device->settings->canTerminationBeEnabledFor(Network(static_cast<Network::NetID>(netid)));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_is_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!enabled) {
return icsneoc2_error_invalid_parameters;
}
*enabled = device->device->settings->isTerminationEnabledFor(Network(static_cast<Network::NetID>(netid))).value_or(false);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool enable) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setTerminationFor(Network(static_cast<Network::NetID>(netid)), enable)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_commander_resistor_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!enabled) {
return icsneoc2_error_invalid_parameters;
}
*enabled = device->device->settings->isCommanderResistorEnabledFor(Network(static_cast<Network::NetID>(netid))).value_or(false);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_commander_resistor_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool enable) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setCommanderResistorFor(Network(static_cast<Network::NetID>(netid)), enable)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_lin_mode_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_lin_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getLINModeFor(network); result.has_value()) {
*value = static_cast<icsneoc2_lin_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_lin_mode_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_lin_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setLINModeFor(network, static_cast<LINMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_lin_commander_response_time_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getLINCommanderResponseTimeFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_lin_commander_response_time_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setLINCommanderResponseTimeFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_enable_get(icsneoc2_device_t* device, uint8_t index, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->getPhyEnable(index); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_enable_set(icsneoc2_device_t* device, uint8_t index, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPhyEnable(index, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_mode_get(icsneoc2_device_t* device, uint8_t index, icsneoc2_ae_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->getPhyMode(index); result.has_value()) {
*value = static_cast<icsneoc2_ae_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_mode_set(icsneoc2_device_t* device, uint8_t index, icsneoc2_ae_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPhyMode(index, static_cast<AELinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_speed_get(icsneoc2_device_t* device, uint8_t index, icsneoc2_eth_phy_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
if(auto result = device->device->settings->getPhySpeed(index); result.has_value()) {
*value = static_cast<icsneoc2_eth_phy_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_speed_set(icsneoc2_device_t* device, uint8_t index, icsneoc2_eth_phy_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setPhySpeed(index, static_cast<EthPhyLinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_role_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_ae_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getPhyRoleFor(network); result.has_value()) {
*value = static_cast<icsneoc2_ae_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_role_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_ae_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setPhyRoleFor(network, static_cast<AELinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_link_mode_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_eth_phy_link_mode_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getPhyLinkModeFor(network); result.has_value()) {
*value = static_cast<icsneoc2_eth_phy_link_mode_t>(result.value());
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_link_mode_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_eth_phy_link_mode_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setPhyLinkModeFor(network, static_cast<EthPhyLinkMode>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_phy_enable_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getPhyEnableFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_phy_enable_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setPhyEnableFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_supported_phy_link_modes_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, icsneoc2_eth_phy_link_mode_t** link_modes, size_t* link_modes_count) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!link_modes || !link_modes_count) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
auto modes = device->device->settings->getSupportedPhyLinkModesFor(network);
*link_modes_count = std::minmax(modes.size(), *link_modes_count).first;
memcpy(*link_modes, modes.data(), *link_modes_count * sizeof(icsneoc2_eth_phy_link_mode_t));
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_is_plca_enabled_for(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->isT1SPLCAEnabledFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_plca_enabled_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SPLCAFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value){
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SLocalIDFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_local_id_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value){
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SLocalIDFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_max_nodes_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMaxNodesFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_max_nodes_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMaxNodesFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1STxOppTimerFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_tx_opp_timer_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1STxOppTimerFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t* value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!value) {
return icsneoc2_error_invalid_parameters;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(auto result = device->device->settings->getT1SMaxBurstFor(network); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = 0;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_t1s_max_burst_timer_for_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto network = Network(static_cast<Network::NetID>(netid));
if(!device->device->settings->setT1SMaxBurstFor(network, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_enabled_set(icsneoc2_device_t* device, uint8_t pin, uint8_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setMiscIOAnalogOutputEnabled(pin, value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_set(icsneoc2_device_t* device, uint8_t pin, icsneoc2_misc_io_analog_voltage_t value) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setMiscIOAnalogOutput(pin, static_cast<MiscIOAnalogVoltage>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_disabled_get(icsneoc2_device_t* device, bool* value) {
if(!value) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
*value = device->device->settings->disabled;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_readonly_get(icsneoc2_device_t* device, bool* value) {
if(!value) {
return icsneoc2_error_invalid_parameters;
}
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
*value = device->device->settings->readonly;
return icsneoc2_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", "icsneoc2.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2026"
VALUE "OriginalFilename", "icsneoc2.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
+174 -5
View File
@@ -28,7 +28,7 @@ std::string APIEvent::describe() const noexcept {
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
@@ -72,6 +72,11 @@ static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too
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.";
static constexpr const char* FIXED_POINT_OVERFLOW = "Value is too large to convert to fixed point.";
static constexpr const char* FIXED_POINT_PRECISION = "Value is too small for fixed point precision.";
static constexpr const char* SYSCALL_ERROR = "Error returned from syscall, check errno/GetLastError().";
// Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
@@ -112,7 +117,18 @@ static constexpr const char* ATOMIC_OPERATION_RETRIED = "An operation failed to
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* 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.";
static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device";
static constexpr const char* DISK_FORMAT_NOT_SUPPORTED = "Disk formatting is not supported on this device.";
static constexpr const char* DISK_FORMAT_INVALID_COUNT = "Disk format config disk count is mismatched with device disk count.";
// Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
@@ -125,10 +141,55 @@ static constexpr const char* DEVICE_IN_USE = "The device is currently in use by
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.";
// 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.";
// MACSEC
static constexpr const char* MACSEC_SECY_LIMIT = "Attempted to exceed the limit of SecY additions to this port";
static constexpr const char* MACSEC_RULE_LIMIT = "Attempted to exceed the limit of rule additions to this port";
static constexpr const char* MACSEC_SA_LIMIT = "Attempted to exceed the limit of SA additions to this port";
static constexpr const char* MACSEC_INVALID_SECY_INDEX = "Attempted to access an invalid SecY index";
static constexpr const char* MACSEC_INVALID_SA_INDEX = "Attempted to access an invalid SA index";
static constexpr const char* MACSEC_INVALID_RULE_INDEX = "Attempted to access an invalid rule index";
static constexpr const char* MACSEC_REKEY_NOT_ENABLED = "Attempted to set rekey SA when rekey was not enabled";
static constexpr const char* MACSEC_NOT_SUPPORTED = "MACsec is not supported on this device";
static constexpr const char* MACSEC_CONFIG_MISMATCH = "Attempted to configure device with a macsec configuration for a different device";
// Servd
static constexpr const char* SERVD_BIND_ERROR = "Error binding socket for Servd communication";
static constexpr const char* SERVD_NONBLOCK_ERROR = "Error setting non-blocking mode for Servd socket";
static constexpr const char* SERVD_TRANSCEIVE_ERROR = "Error while sending to or receiving from Servd";
static constexpr const char* SERVD_OUTDATED_ERROR = "Servd version is lower than client (libicsneo) version, update Servd";
static constexpr const char* SERVD_INVALID_RESPONSE_ERROR = "Unexpected response from Servd";
static constexpr const char* SERVD_LOCK_ERROR = "Error locking Servd mutex";
static constexpr const char* SERVD_SEND_ERROR = "Error sending to Servd";
static constexpr const char* SERVD_RECV_ERROR = "Error receiving from Servd";
static constexpr const char* SERVD_POLL_ERROR = "Error polling on Servd socket";
static constexpr const char* SERVD_NODATA_ERROR = "No data received from Servd";
static constexpr const char* SERVD_JOIN_MULTICAST_ERROR = "Error joining Servd multicast group";
// DXX
static constexpr const char* DXX_ERROR_SYS = "System error, check errno/GetLastError()";
static constexpr const char* DXX_ERROR_INT = "DXX interrupt called";
static constexpr const char* DXX_ERROR_OVERFLOW = "Overflow in DXX";
static constexpr const char* DXX_ERROR_IO = "I/O failure in DXX";
static constexpr const char* DXX_ERROR_ARG = "Invalid arg passed to DXX";
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
@@ -164,6 +225,16 @@ const char* APIEvent::DescriptionForType(Type type) {
return TIMEOUT;
case Type::WiVINotSupported:
return WIVI_NOT_SUPPORTED;
case Type::RestrictedEntryFlag:
return RESTRICTED_ENTRY_FLAG;
case Type::NotSupported:
return NOT_SUPPORTED;
case Type::FixedPointOverflow:
return FIXED_POINT_OVERFLOW;
case Type::FixedPointPrecision:
return FIXED_POINT_PRECISION;
case Type::SyscallError:
return SYSCALL_ERROR;
// Device Errors
case Type::PollingMessageOverflow:
@@ -244,7 +315,18 @@ const char* APIEvent::DescriptionForType(Type type) {
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;
case Type::SettingNotAvaiableDevice:
return SETTING_NOT_AVAILABLE;
// Transport Errors
case Type::FailedToRead:
return FAILED_TO_READ;
@@ -266,7 +348,94 @@ const char* APIEvent::DescriptionForType(Type type) {
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;
case Type::DiskFormatNotSupported:
return DISK_FORMAT_NOT_SUPPORTED;
case Type::DiskFormatInvalidCount:
return DISK_FORMAT_INVALID_COUNT;
// 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;
// MACSEC
case Type::MACsecSecYLimit:
return MACSEC_SECY_LIMIT;
case Type::MACsecSaLimit:
return MACSEC_SA_LIMIT;
case Type::MACsecRuleLimit:
return MACSEC_RULE_LIMIT;
case Type::MACsecInvalidSecYIndex:
return MACSEC_INVALID_SECY_INDEX;
case Type::MACsecInvalidSaIndex:
return MACSEC_INVALID_SA_INDEX;
case Type::MACsecInvalidRuleIndex:
return MACSEC_INVALID_RULE_INDEX;
case Type::MACsecRekeyNotEnabled:
return MACSEC_REKEY_NOT_ENABLED;
case Type::MACsecNotSupported:
return MACSEC_NOT_SUPPORTED;
case Type::MACsecConfigMismatch:
return MACSEC_CONFIG_MISMATCH;
// Servd
case Type::ServdBindError:
return SERVD_BIND_ERROR;
case Type::ServdNonblockError:
return SERVD_NONBLOCK_ERROR;
case Type::ServdTransceiveError:
return SERVD_TRANSCEIVE_ERROR;
case Type::ServdOutdatedError:
return SERVD_OUTDATED_ERROR;
case Type::ServdInvalidResponseError:
return SERVD_INVALID_RESPONSE_ERROR;
case Type::ServdLockError:
return SERVD_LOCK_ERROR;
case Type::ServdSendError:
return SERVD_SEND_ERROR;
case Type::ServdRecvError:
return SERVD_RECV_ERROR;
case Type::ServdPollError:
return SERVD_POLL_ERROR;
case Type::ServdNoDataError:
return SERVD_NODATA_ERROR;
case Type::ServdJoinMulticastError:
return SERVD_JOIN_MULTICAST_ERROR;
// DXX
case Type::DXXErrorSys:
return DXX_ERROR_SYS;
case Type::DXXErrorInt:
return DXX_ERROR_INT;
case Type::DXXErrorOverflow:
return DXX_ERROR_OVERFLOW;
case Type::DXXErrorIO:
return DXX_ERROR_IO;
case Type::DXXErrorArg:
return DXX_ERROR_ARG;
// Other Errors
case Type::TooManyEvents:
return TOO_MANY_EVENTS;
@@ -280,7 +449,7 @@ const char* APIEvent::DescriptionForType(Type type) {
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;
+22
View File
@@ -1,5 +1,8 @@
#include "icsneo/api/eventmanager.h"
#include <memory>
#include <optional>
#include <iostream>
#include <cstdlib>
using namespace icsneo;
@@ -33,6 +36,25 @@ void EventManager::cancelErrorDowngradingOnCurrentThread() {
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);
@@ -3,8 +3,6 @@
#include <Tchar.h>
//Basic Functions
FINDNEODEVICES icsneoFindNeoDevices;
OPENNEODEVICE icsneoOpenNeoDevice;
OPENDEVICE icsneoOpenDevice;
CLOSEPORT icsneoClosePort;
FREEOBJECT icsneoFreeObject;
@@ -134,10 +132,6 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
if((hAPIDLL = LoadLibrary(_T("icsneo40.dll"))) == NULL)
return false;
icsneoFindNeoDevices = (FINDNEODEVICES) GetProcAddress(hAPIDLL, "icsneoFindNeoDevices");
icsneoOpenNeoDevice = (OPENNEODEVICE) GetProcAddress(hAPIDLL, "icsneoOpenNeoDevice");
icsneoOpenDevice = (OPENDEVICE) GetProcAddress(hAPIDLL, "icsneoOpenDevice");
icsneoClosePort = (CLOSEPORT) GetProcAddress(hAPIDLL, "icsneoClosePort");
icsneoFreeObject = (FREEOBJECT) GetProcAddress(hAPIDLL, "icsneoFreeObject");
@@ -206,7 +200,7 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
icsneoEnableDOIPLine = (ENABLEDOIPACTIVATIONLINE)GetProcAddress(hAPIDLL, "icsneoEnableDOIPLine");
if(!icsneoFindNeoDevices || !icsneoOpenNeoDevice || !icsneoOpenDevice || !icsneoClosePort || !icsneoFreeObject ||
if(!icsneoOpenDevice || !icsneoClosePort || !icsneoFreeObject ||
!icsneoTxMessages || !icsneoGetMessages || !icsneoWaitForRxMessagesWithTimeOut ||
!icsneoGetTimeStampForMsg || !icsneoEnableNetworkRXQueue || !icsneoGetISO15765Status || !icsneoTxMessagesEx ||
!icsneoSetISO15765RxParameters || !icsneoGetConfiguration || !icsneoSendConfiguration ||
+2 -2
View File
@@ -1,5 +1,7 @@
//FILE: icsneo40DLLAPI.H
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include "icsneo/icsnVC40.h"
@@ -114,8 +116,6 @@ typedef int (__stdcall *SCRIPTWRITEISO15765TXMESSAGE)(void * hObject, unsigned
//Basic Functions
extern FINDNEODEVICES icsneoFindNeoDevices;
extern OPENNEODEVICE icsneoOpenNeoDevice;
extern OPENDEVICE icsneoOpenDevice;
extern CLOSEPORT icsneoClosePort;
extern FREEOBJECT icsneoFreeObject;
+370 -188
View File
@@ -2,8 +2,6 @@
#error "icsneolegacy.cpp must be compiled with a C++ compiler!"
#endif
#define NOMINMAX
#define ICSNEOC_MAKEDLL
#include "icsneo/icsneolegacy.h"
#include "icsneo/J2534.h"
@@ -14,55 +12,44 @@
#include "icsneo/communication/network.h"
#include <map>
#include <algorithm>
#include <cstring>
#include <climits>
#ifdef _MSC_VER
#pragma warning(disable : 4100) // unreferenced formal parameter
#pragma warning(disable : 4996) // STL time functions
#endif
using namespace icsneo;
typedef uint64_t legacymaphandle_t;
static std::map<legacymaphandle_t, neodevice_t> neodevices;
static std::map<neodevice_t*, NeoDeviceEx*> openneodevices;
static const std::map<size_t, size_t> mp_netIDToVnetOffSet = {
{NETID_HSCAN, 1},
{NETID_MSCAN, 2},
{NETID_HSCAN2, 18},
{NETID_HSCAN3, 19},
{NETID_HSCAN4, 32},
{NETID_HSCAN5, 33},
{NETID_HSCAN6, 47},
{NETID_HSCAN7, 48},
{NETID_DWCAN_01, 1},
{NETID_DWCAN_08, 2},
{NETID_DWCAN_02, 18},
{NETID_DWCAN_03, 19},
{NETID_DWCAN_04, 32},
{NETID_DWCAN_05, 33},
{NETID_DWCAN_06, 47},
{NETID_DWCAN_07, 48},
};
static const std::map<size_t, size_t> mp_HWnetIDToCMnetID = {
{NETID_HSCAN, 0},
{NETID_MSCAN, 1},
{NETID_HSCAN2, 5},
{NETID_HSCAN3, 8},
{NETID_HSCAN4, 14},
{NETID_HSCAN5, 15},
{NETID_HSCAN6, 32},
{NETID_HSCAN7, 33},
{NETID_DWCAN_01, 0},
{NETID_DWCAN_08, 1},
{NETID_DWCAN_02, 5},
{NETID_DWCAN_03, 8},
{NETID_DWCAN_04, 14},
{NETID_DWCAN_05, 15},
{NETID_DWCAN_06, 32},
{NETID_DWCAN_07, 33},
};
static unsigned long vnet_table[] = {0, PLASMA_SLAVE1_OFFSET, PLASMA_SLAVE2_OFFSET};
static NeoDevice OldNeoDeviceFromNew(const neodevice_t* newnd)
{
NeoDevice oldnd = {0};
oldnd.DeviceType = newnd->type;
oldnd.SerialNumber = icsneo_serialStringToNum(newnd->serial);
oldnd.NumberOfClients = 0;
oldnd.MaxAllowedClients = 1;
static_assert(sizeof(neodevice_handle_t) == sizeof(oldnd.Handle),
"neodevice_handle_t size must be sizeof(int) for compatibility reasons");
oldnd.Handle = newnd->handle;
return oldnd;
}
static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t& newmsg, icsSpyMessage& oldmsg)
{
@@ -73,6 +60,25 @@ static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t
return false;
const neomessage_frame_t& frame = *reinterpret_cast<const neomessage_frame_t*>(&newmsg);
auto copyStatusData = [&]() {
oldmsg.NetworkID = static_cast<uint8_t>(frame.netid); // Note: NetID remapping from the original API is not supported
oldmsg.NetworkID2 = static_cast<uint8_t>(frame.netid >> 8);
oldmsg.DescriptionID = frame.description;
oldmsg.StatusBitField = frame.status.statusBitfield[0];
oldmsg.StatusBitField2 = frame.status.statusBitfield[1];
oldmsg.StatusBitField3 = frame.status.statusBitfield[2];
oldmsg.StatusBitField4 = frame.status.statusBitfield[3];
};
auto copyFrameData = [&]() {
oldmsg.ExtraDataPtr = (void*)frame.data;
oldmsg.ExtraDataPtrEnabled = frame.length > 8 ? 1 : 0;
memcpy(oldmsg.Data, frame.data, std::min(frame.length, (size_t)8));
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
copyStatusData();
};
switch (Network::Type(frame.type))
{
case Network::Type::CAN:
@@ -81,28 +87,43 @@ static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t
oldmsg.Protocol = frame.status.canfdFDF ? SPY_PROTOCOL_CANFD : SPY_PROTOCOL_CAN;
oldmsg.NumberBytesData = static_cast<uint8_t>(std::min(frame.length, (size_t)255));
oldmsg.NumberBytesHeader = 4;
copyFrameData();
break;
case Network::Type::Ethernet:
case Network::Type::AutomotiveEthernet:
oldmsg.Protocol = SPY_PROTOCOL_ETHERNET;
oldmsg.NumberBytesData = static_cast<uint8_t>(frame.length & 0xFF);
oldmsg.NumberBytesHeader = static_cast<uint8_t>(frame.length >> 8);
copyFrameData();
break;
case Network::Type::LIN:
{
const neomessage_lin_t& linFrame = *reinterpret_cast<const neomessage_lin_t*>(&frame);
icsSpyMessageJ1850& linSpyMsg = *reinterpret_cast<icsSpyMessageJ1850*>(&oldmsg);
linSpyMsg.Protocol = SPY_PROTOCOL_LIN;
linSpyMsg.NumberBytesHeader = static_cast<uint8_t>(std::min(linFrame.length, static_cast<size_t>(3)));
linSpyMsg.NumberBytesData = static_cast<uint8_t>(linFrame.length - linSpyMsg.NumberBytesHeader);
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
copyStatusData();
if ((2 < linFrame.length) && (linFrame.length <= 10)) {
auto copyBytes = std::min(linSpyMsg.NumberBytesData, static_cast<uint8_t>(6));
std::memcpy(oldmsg.Data, frame.data, copyBytes);
oldmsg.Data[copyBytes] = linFrame.checksum;
} else if (2 == linFrame.length) {
std::memset(oldmsg.Data, 0, 8);
linSpyMsg.Header[linSpyMsg.NumberBytesHeader] = linFrame.checksum;
++linSpyMsg.NumberBytesHeader;
} else {
std::memset(oldmsg.Data, 0, 8);
}
if (linFrame.linStatus.txCommander)
linSpyMsg.StatusBitField |= SPY_STATUS_INIT_MESSAGE;
break;
}
default:
return false;
}
oldmsg.ExtraDataPtr = (void*)frame.data;
oldmsg.ExtraDataPtrEnabled = frame.length > 8 ? 1 : 0;
memcpy(oldmsg.Data, frame.data, std::min(frame.length, (size_t)8));
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
oldmsg.NetworkID = static_cast<uint8_t>(frame.netid); // Note: NetID remapping from the original API is not supported
oldmsg.NetworkID2 = static_cast<uint8_t>(frame.netid >> 8);
oldmsg.DescriptionID = frame.description;
oldmsg.StatusBitField = frame.status.statusBitfield[0];
oldmsg.StatusBitField2 = frame.status.statusBitfield[1];
oldmsg.StatusBitField3 = frame.status.statusBitfield[2];
oldmsg.StatusBitField4 = frame.status.statusBitfield[3];
// Timestamp - epoch = 1/1/2007 - 25ns per tick most of the time
uint64_t t = frame.timestamp;
uint16_t res = 0;
@@ -127,6 +148,90 @@ static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t
return true;
}
static bool SpyMessageToNeoMessage(const icsSpyMessage& oldmsg, neomessage_frame_t& frame, unsigned int& lNetworkID)
{
frame.netid = static_cast<uint16_t>(lNetworkID);
frame.description = oldmsg.DescriptionID;
frame.status.statusBitfield[0] = oldmsg.StatusBitField;
frame.status.statusBitfield[1] = oldmsg.StatusBitField2;
frame.status.statusBitfield[2] = oldmsg.StatusBitField3;
frame.status.statusBitfield[3] = oldmsg.StatusBitField4;
auto copyFrameDataPtr = [&]() {
memcpy(frame.header, &oldmsg.ArbIDOrHeader, sizeof(frame.header));
if ((oldmsg.ExtraDataPtr != nullptr) && (oldmsg.ExtraDataPtrEnabled == 1))
frame.data = reinterpret_cast<const uint8_t *>(oldmsg.ExtraDataPtr);
else
frame.data = oldmsg.Data;
};
switch(oldmsg.Protocol)
{
case SPY_PROTOCOL_ETHERNET:
{
frame.length = ((oldmsg.NumberBytesHeader & 255) << 8) | (oldmsg.NumberBytesData & 255);
copyFrameDataPtr();
break;
}
case SPY_PROTOCOL_LIN:
{
neomessage_lin_t& linFrame = *reinterpret_cast<neomessage_lin_t*>(&frame);
const uint8_t numberBytesHeader = std::min(oldmsg.NumberBytesHeader, static_cast<uint8_t>(3));
const uint8_t numberBytesData = std::min(oldmsg.NumberBytesData, static_cast<uint8_t>(7));
frame.length = numberBytesHeader + numberBytesData;
linFrame.type = ICSNEO_NETWORK_TYPE_LIN;
if (oldmsg.StatusBitField & SPY_STATUS_INIT_MESSAGE)
linFrame.linStatus.txCommander = true;
else
linFrame.linStatus.txResponder = true;
copyFrameDataPtr();
uint8_t protID = linFrame.header[0] & 0x3Fu;
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);
linFrame.header[0] = protID;
if (frame.length > 2) {
size_t checksum = 0;
uint8_t* lastByte = nullptr;
for(size_t idx = 1; idx < (frame.length - 1); ++idx) {
if (idx < oldmsg.NumberBytesHeader) {
checksum += frame.header[idx];
lastByte = (frame.header + idx + 1);
} else {
checksum += frame.data[idx-numberBytesHeader];
lastByte = const_cast<uint8_t*>(frame.data) + idx - numberBytesHeader + 1;
}
if (checksum > 255) { checksum -= 255; }
}
size_t enhanced = frame.header[0] + checksum;
if (enhanced > 255) { enhanced -= 255; }
checksum ^= 0xff;
enhanced ^= 0xff;
if ((lastByte != nullptr) && (*lastByte != checksum) && (*lastByte == enhanced))
linFrame.linStatus.txChecksumEnhanced = true;
}
break;
}
case SPY_PROTOCOL_CANFD:
{
frame.length = oldmsg.NumberBytesData;
frame.status.canfdFDF = true;
copyFrameDataPtr();
break;
}
default:
{
frame.length = oldmsg.NumberBytesData;
copyFrameDataPtr();
break;
}
}
return true;
}
static inline bool Within(size_t value, size_t min, size_t max)
{
return ((min <= value) && (value < max));
@@ -200,107 +305,79 @@ static inline size_t GetVnetAgnosticNetid(size_t fullNetid)
int LegacyDLLExport icsneoFindDevices(NeoDeviceEx* devs, int* devCount, unsigned int* devTypes, unsigned int devTypeCount,
POptionsFindNeoEx* POptionsFindNeoEx, unsigned int* zero)
{
if (!devs || !devCount)
// Match the legacy API maximum, this derives from the maximum COM Port on old windows versions.
constexpr int MAX_NEO_DEVICES = 255;
// Validate arguments
if (!devCount && *devCount < 0) {
return 0;
if (*devCount < 0 || *devCount > 255)
return 0;
// Find the devices without filtering by the device type
// We allow this to find more than the requested number,
// as we may filter out some devices.
constexpr const size_t MAX_DEVICES = 255;
NeoDevice foundDevices[MAX_DEVICES];
int NumDevices = MAX_DEVICES;
int filteredDeviceCount = 0;
if (!icsneoFindNeoDevices(0, foundDevices, &NumDevices))
return 0;
for (auto i = 0; i < NumDevices; i++)
{
// Check if the next device would overrun the user's buffer
// We check this up here since the documentation allows zero
// to be specified.
if (filteredDeviceCount >= *devCount)
break;
if (devTypes && devTypeCount)
{
for (unsigned int j = 0; j < devTypeCount; j++)
{
if (foundDevices[i].DeviceType == devTypes[j])
{
devs[filteredDeviceCount++].neoDevice = foundDevices[i];
break;
}
}
}
else
{
devs[filteredDeviceCount++].neoDevice = foundDevices[i];
}
}
*devCount = filteredDeviceCount;
return 1; // If the function succeeds but no devices are found 1 will still be returned and devCount will equal 0
}
int LegacyDLLExport icsneoFindNeoDevices(unsigned long DeviceTypes, NeoDevice* pNeoDevice, int* pNumDevices)
{
constexpr size_t MAX_DEVICES = 255;
size_t count = MAX_DEVICES;
if (pNumDevices == nullptr)
return 0;
if (pNeoDevice == nullptr)
// return the size only if devs is NULL.
if (!devs)
{
icsneo_findAllDevices(nullptr, &count);
*pNumDevices = (int)count;
icsneo_findAllDevices(nullptr, (size_t*)devCount);
return 1;
}
size_t bufferSize = (size_t)*pNumDevices;
if (*pNumDevices < 0 || bufferSize > MAX_DEVICES)
return 0;
neodevice_t devices[MAX_DEVICES];
icsneo_findAllDevices(devices, &count);
if (bufferSize < count)
count = bufferSize;
*pNumDevices = (int)count;
for (size_t i = 0; i < count; i++)
{
pNeoDevice[i] = OldNeoDeviceFromNew(&devices[i]); // Write out into user memory
neodevices[uint64_t(devices[i].handle) << 32 | icsneo_serialStringToNum(devices[i].serial)] = devices[i]; // Fill the look up table
// shrink the number of devices allowed to find
if (*devCount > MAX_NEO_DEVICES) {
*devCount = MAX_NEO_DEVICES;
}
return 1;
}
int LegacyDLLExport icsneoOpenNeoDevice(NeoDevice* pNeoDevice, void** hObject, unsigned char* bNetworkIDs, int bConfigRead, int bSyncToPC)
{
if (pNeoDevice == nullptr || hObject == nullptr)
return false;
neodevice_t *device;
try
{
device = &neodevices.at(uint64_t(pNeoDevice->Handle) << 32 | pNeoDevice->SerialNumber);
// Find all the neodevice_t devices
std::vector<neodevice_t> neoDevices(*devCount);
auto neoDevicesSize = neoDevices.size();
icsneo_findAllDevices(neoDevices.data(), &neoDevicesSize);
neoDevices.resize(neoDevicesSize);
// Filter out the devices if needed
// No filtering needed
if (devTypes && devTypeCount > 0) {
neoDevices.erase(
std::remove_if(
neoDevices.begin(),
neoDevices.end(),
[&](const auto& iter) {
for (unsigned int i=0; i < devTypeCount; ++i) {
if (iter.type == devTypes[i]) {
return false;
}
}
return true;
}
),
neoDevices.end()
);
}
catch (const std::out_of_range&)
{
return false;
}
*hObject = device;
if (!icsneo_openDevice(device))
return false;
// Create a NeoDeviceEx From a neodevice_t
auto _createNeoDeviceExFrom = [](const neodevice_t* neoDevice) -> NeoDeviceEx {
NeoDeviceEx nde = {};
nde.neoDevice.DeviceType = neoDevice->type;
nde.neoDevice.SerialNumber = icsneo_serialStringToNum(neoDevice->serial);
nde.neoDevice.NumberOfClients = 0;
nde.neoDevice.MaxAllowedClients = 1;
static_assert(sizeof(neodevice_handle_t) == sizeof(nde.neoDevice.Handle),
"neodevice_handle_t size must be sizeof(int) for compatibility reasons");
nde.neoDevice.Handle = neoDevice->handle;
return nde;
};
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
// Create the NeoDeviceEx from the neodevice_t
auto i = 0;
for (const auto& neoDevice : neoDevices) {
// Fill the look up table
neodevices[uint64_t(neoDevice.handle) << 32 | icsneo_serialStringToNum(neoDevice.serial)] = neoDevice;
// Create the NeoDeviceEx
devs[i] = _createNeoDeviceExFrom(&neoDevice);
NeoDeviceEx* nde = &devs[i];
++i;
// Lookup the open NeoDeviceEx devices and match the NumberOfClients value if available.
for (auto& [neo_device, open_nde]: openneodevices) {
// SerialNumber should always be unique so lets compare against that.
if (nde->neoDevice.SerialNumber == open_nde->neoDevice.SerialNumber) {
nde->neoDevice.NumberOfClients = open_nde->neoDevice.NumberOfClients;
}
}
}
*devCount = (int)neoDevices.size();
return 1;
}
int LegacyDLLExport icsneoOpenDevice(
@@ -325,19 +402,50 @@ int LegacyDLLExport icsneoOpenDevice(
return false;
}
*hObject = device;
if(!icsneo_openDevice(device))
if (pNeoDeviceEx->neoDevice.NumberOfClients >= pNeoDeviceEx->neoDevice.MaxAllowedClients) {
return false;
}
*hObject = device;
if(!icsneo_openDevice(device)) {
return false;
}
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
if (icsneo_isOnlineSupported(device)) {
if (!icsneo_setPollingMessageLimit(device, 20000)) {
icsneo_closeDevice(device);
return false;
}
if (!icsneo_enableMessagePolling(device)) {
icsneo_closeDevice(device);
return false;
}
if (!icsneo_goOnline(device)) {
icsneo_closeDevice(device);
return false;
}
}
pNeoDeviceEx->neoDevice.NumberOfClients = 1;
// Add the open NeoDevice to the container so we can decrement NumberOfClients on close
openneodevices[device] = pNeoDeviceEx;
return true;
}
int LegacyDLLExport icsneoClosePort(void* hObject, int* pNumberOfErrors)
{
if (!icsneoValidateHObject(hObject))
return false;
if (pNumberOfErrors) {
*pNumberOfErrors = 0;
}
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (openneodevices.find(device) != openneodevices.end()) {
openneodevices[device]->neoDevice.NumberOfClients -= 1;
openneodevices.erase(device);
}
return icsneo_closeDevice(device);
}
@@ -396,25 +504,9 @@ int LegacyDLLExport icsneoTxMessagesEx(void* hObject, icsSpyMessage* pMsg, unsig
*NumTxed = 0;
for (unsigned int i = 0; i < lNumMessages; i++)
{
const icsSpyMessage& oldmsg = pMsg[i];
newmsg = {};
newmsg.netid = (uint16_t)lNetworkID;
newmsg.description = oldmsg.DescriptionID;
memcpy(newmsg.header, &oldmsg.ArbIDOrHeader, sizeof(newmsg.header));
if (oldmsg.Protocol != SPY_PROTOCOL_ETHERNET)
newmsg.length = oldmsg.NumberBytesData;
else
newmsg.length = ((oldmsg.NumberBytesHeader & 255) << 8) | (oldmsg.NumberBytesData & 255);
if (oldmsg.ExtraDataPtr != nullptr && oldmsg.ExtraDataPtrEnabled == 1)
newmsg.data = reinterpret_cast<const uint8_t *>(oldmsg.ExtraDataPtr);
else
newmsg.data = oldmsg.Data;
newmsg.status.statusBitfield[0] = oldmsg.StatusBitField;
newmsg.status.statusBitfield[1] = oldmsg.StatusBitField2;
newmsg.status.statusBitfield[2] = oldmsg.StatusBitField3;
newmsg.status.statusBitfield[3] = oldmsg.StatusBitField4;
if (oldmsg.Protocol == SPY_PROTOCOL_CANFD)
newmsg.status.canfdFDF = true;
const icsSpyMessage& oldMsg = pMsg[i];
SpyMessageToNeoMessage(oldMsg, newmsg, lNetworkID);
if (icsneo_transmit(device, reinterpret_cast<neomessage_t*>(&newmsg)))
(*NumTxed)++;
}
@@ -464,6 +556,54 @@ void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork,
return;
}
int LegacyDLLExport icsneoGetRTC(void* hObject, icsSpyTime* time)
{
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
uint64_t time64 = 0;
if(!icsneo_getRTC(device, &time64))
return false;
std::time_t seconds = time64;
/* To accommodate local time bugzilla #6600 https://intrepidcs.homeip.net:100/bugzilla/show_bug.cgi?id=6600 */
// local time must be used here
const auto timeInfo = std::localtime(&seconds);
if(!timeInfo)
return false;
time->sec = (unsigned char)timeInfo->tm_sec; // Will never hit 60 (leap second) because tm_sec comes from RTCCTIME
time->min = (unsigned char)timeInfo->tm_min;
time->hour = (unsigned char)timeInfo->tm_hour;
time->day = (unsigned char)timeInfo->tm_mday;
time->month = (unsigned char)timeInfo->tm_mon + 1;
time->year = (unsigned char)timeInfo->tm_year % 100;
return true;
}
int LegacyDLLExport icsneoSetRTC(void* hObject, const icsSpyTime* time)
{
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
std::tm timeInfo{};
timeInfo.tm_sec = time->sec;
timeInfo.tm_min = time->min;
timeInfo.tm_hour = time->hour;
timeInfo.tm_mday = time->day;
timeInfo.tm_mon = time->month - 1;
timeInfo.tm_year = time->year + 100;
#ifdef _MSC_VER
#define timegm _mkgmtime
#endif
return icsneo_setRTC(device, (uint64_t)timegm(&timeInfo));
}
//Device Functions
int LegacyDLLExport icsneoGetConfiguration(void* hObject, unsigned char* pData, int* lNumBytes)
{
@@ -653,11 +793,43 @@ int LegacyDLLExport icsneoGetErrorMessages(void* hObject, int* pErrorMsgs, int*
return false;
}
int LegacyDLLExport icsneoGetErrorInfo(int lErrorNumber, TCHAR* szErrorDescriptionShort, TCHAR* szErrorDescriptionLong,
int LegacyDLLExport icsneoGetErrorInfo(int lErrorNumber, char* szErrorDescriptionShort, char* szErrorDescriptionLong,
int* lMaxLengthShort, int* lMaxLengthLong, int* lErrorSeverity, int* lRestartNeeded)
{
// TODO Implement
return false;
if (szErrorDescriptionShort == nullptr || szErrorDescriptionLong == nullptr
|| lMaxLengthShort == nullptr || lMaxLengthLong == nullptr || lErrorSeverity == nullptr
|| lRestartNeeded == nullptr)
{
return false;
}
//Set and send back 0. We will not restart the software.
*lRestartNeeded = 0;
//Using the error number, get the description from the event.
const char* tempDescription = APIEvent::DescriptionForType(APIEvent::Type(lErrorNumber));
int descrLength = int(std::strlen(tempDescription));
//Check to make sure the length of the error is not >= the buffer.
if (descrLength >= *lMaxLengthShort || descrLength >= *lMaxLengthLong)
{
return false;
}
//Copy the error description to the inout Short and Long arguments.
std::copy(tempDescription, tempDescription + descrLength, szErrorDescriptionShort);
std::copy(tempDescription, tempDescription + descrLength, szErrorDescriptionLong);
//Add the null terminator.
szErrorDescriptionShort[descrLength] = '\0';
szErrorDescriptionLong[descrLength] = '\0';
//Update the inout lengths to what the actual length of the error is
*lMaxLengthShort = *lMaxLengthLong = descrLength;
//Update the inout severity argument.
*lErrorSeverity = int(APIEvent::Severity::Any);
return true;
}
//ISO15765-2 Functions
@@ -736,6 +908,18 @@ int LegacyDLLExport icsneoStopSockServer(void* hObject)
return false;
}
int LegacyDLLExport icsneoGetDeviceStatus(void* hObject, icsDeviceStatus* deviceStatus, size_t* deviceStatusSize)
{
if (!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (deviceStatus == nullptr || deviceStatusSize == nullptr)
return false;
return icsneo_getDeviceStatus(device, deviceStatus, deviceStatusSize);
}
//CoreMini Script functions
int LegacyDLLExport icsneoScriptStart(void* hObject, int iLocation)
{
@@ -797,20 +981,7 @@ int LegacyDLLExport icsneoScriptWriteAppSignal(void* hObject, unsigned int iInde
return false;
}
//Deprecated (but still suppored in the DLL)
int LegacyDLLExport icsneoOpenPortEx(void* lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB,
int lIPAddressLSBOrBaudRate, int bConfigRead, unsigned char* bNetworkID, int* hObject)
{
// TODO Implement
return false;
}
int LegacyDLLExport icsneoOpenPort(int lPortNumber, int lPortType, int lDriverType, unsigned char *bNetworkID,
unsigned char* bSCPIDs, int* hObject)
{
// TODO Implement
return false;
}
int LegacyDLLExport icsneoEnableNetworkCom(void* hObject, int Enable)
{
@@ -824,19 +995,6 @@ int LegacyDLLExport icsneoEnableNetworkCom(void* hObject, int Enable)
return icsneo_goOffline(device);
}
int LegacyDLLExport icsneoFindAllCOMDevices(int lDriverType, int lGetSerialNumbers, int lStopAtFirst, int lUSBCommOnly,
int* p_lDeviceTypes, int* p_lComPorts, int* p_lSerialNumbers, int* lNumDevices)
{
// TODO Implement
return false;
}
int LegacyDLLExport icsneoOpenNeoDeviceByChannels(NeoDevice* pNeoDevice, void** hObject, unsigned char* uChannels, int iSize,
int bConfigRead, int iOptions)
{
// TODO Implement
return false;
}
int LegacyDLLExport icsneoGetVCAN4Settings(void* hObject, SVCAN4Settings* pSettings, int iNumBytes)
{
@@ -915,6 +1073,21 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_RADGIGALOG:
*pDeviceSettingsType = DeviceRADGigalogSettingsType;
break;
case NEODEVICE_RADMOON3:
*pDeviceSettingsType = DeviceRADMoon3SettingsType;
break;
case NEODEVICE_RADGEMINI:
*pDeviceSettingsType = DeviceRADGeminiSettingsType;
break;
case NEODEVICE_RED2:
*pDeviceSettingsType = DeviceRed2SettingsType;
break;
case NEODEVICE_FIRE3:
*pDeviceSettingsType = DeviceFire3SettingsType;
break;
case NEODEVICE_FIRE3_FLEXRAY:
*pDeviceSettingsType = DeviceFire3FlexraySettingsType;
break;
default:
return 0;
}
@@ -952,6 +1125,15 @@ int LegacyDLLExport icsneoGetDeviceSettings(void* hObject, SDeviceSettings* pSet
return !!icsneo_settingsReadStructure(device, &pSettings->Settings, iNumBytes - offset);
}
int LegacyDLLExport icsneoLoadDefaultSettings(void* hObject)
{
if (!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return icsneo_settingsApplyDefaults(device);
}
int LegacyDLLExport icsneoSetBitRateEx(void* hObject, unsigned long BitRate, int NetworkID, int iOptions)
{
if (!icsneoValidateHObject(hObject))
@@ -1292,7 +1474,7 @@ int LegacyDLLExport icsneoSerialNumberFromString(unsigned long* serial, char* da
return false;
}
int LegacyDLLExport icsneoGetMiniportAdapterInfo(void* hObject, NETWORK_ADAPTER_INFO* aInfo)
int LegacyDLLExport icsneoGetMiniportAdapterInfo(void* hObject, NDIS_ADAPTER_INFORMATION* aInfo)
{
return false;
}
+3
View File
@@ -0,0 +1,3 @@
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
add_subdirectory(python)
endif()
+62
View File
@@ -0,0 +1,62 @@
cmake_minimum_required(VERSION 3.20)
set(PYBIND11_FINDPYTHON ON)
if(PYBIND11_ROOT)
find_package(pybind11 CONFIG REQUIRED)
else()
include(FetchContent)
FetchContent_Declare(
pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v3.0.3
)
FetchContent_MakeAvailable(pybind11)
endif()
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/io.cpp
icsneopy/communication/livedata.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/spimessage.cpp
icsneopy/communication/message/scriptstatusmessage.cpp
icsneopy/communication/message/ethphymessage.cpp
icsneopy/communication/message/livedatamessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/core/macseccfg.cpp
icsneopy/flexray/flexray.cpp
icsneopy/disk/diskdriver.cpp
icsneopy/disk/diskdetails.cpp
icsneopy/device/chipid.cpp
icsneopy/device/versionreport.cpp
icsneopy/device/device.cpp
icsneopy/device/extensions/deviceextension.cpp
icsneopy/device/idevicesettings.cpp
icsneopy/icsneocpp.cpp
)
target_link_libraries(icsneopy PRIVATE icsneocpp)
install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN_EXE stubgen)
if(STUBGEN_EXE)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND stubgen -v -p icsneopy -o .)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi py.typed DESTINATION icsneopy)
endif()
install(FILES __init__.py DESTINATION icsneopy)
+1
View File
@@ -0,0 +1 @@
from .icsneopy import *
+163
View File
@@ -0,0 +1,163 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/api/event.h"
namespace icsneo {
void init_event(pybind11::module_& m) {
pybind11::classh<APIEvent> apiEvent(m, "APIEvent");
pybind11::native_enum<APIEvent::Type>(apiEvent, "Type", "enum.IntEnum")
.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("FixedPointOverflow", APIEvent::Type::FixedPointOverflow)
.value("FixedPointPrecision", APIEvent::Type::FixedPointPrecision)
.value("SyscallError", APIEvent::Type::SyscallError)
.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("GPTPNotSupported", APIEvent::Type::GPTPNotSupported)
.value("SettingNotAvaiableDevice", APIEvent::Type::SettingNotAvaiableDevice)
.value("DiskFormatNotSupported", APIEvent::Type::DiskFormatNotSupported)
.value("DiskFormatInvalidCount", APIEvent::Type::DiskFormatInvalidCount)
.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("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("ServdBindError", APIEvent::Type::ServdBindError)
.value("ServdNonblockError", APIEvent::Type::ServdNonblockError)
.value("ServdTransceiveError", APIEvent::Type::ServdTransceiveError)
.value("ServdOutdatedError", APIEvent::Type::ServdOutdatedError)
.value("ServdInvalidResponseError", APIEvent::Type::ServdInvalidResponseError)
.value("ServdLockError", APIEvent::Type::ServdLockError)
.value("ServdSendError", APIEvent::Type::ServdSendError)
.value("ServdRecvError", APIEvent::Type::ServdRecvError)
.value("ServdPollError", APIEvent::Type::ServdPollError)
.value("ServdNoDataError", APIEvent::Type::ServdNoDataError)
.value("ServdJoinMulticastError", APIEvent::Type::ServdJoinMulticastError)
.value("DXXErrorSys", APIEvent::Type::DXXErrorSys)
.value("DXXErrorInt", APIEvent::Type::DXXErrorInt)
.value("DXXErrorOverflow", APIEvent::Type::DXXErrorOverflow)
.value("DXXErrorIO", APIEvent::Type::DXXErrorIO)
.value("DXXErrorArg", APIEvent::Type::DXXErrorArg)
.value("NoErrorFound", APIEvent::Type::NoErrorFound)
.value("TooManyEvents", APIEvent::Type::TooManyEvents)
.value("Unknown", APIEvent::Type::Unknown)
.finalize();
pybind11::native_enum<APIEvent::Severity>(apiEvent, "Severity", "enum.IntEnum")
.value("Any", APIEvent::Severity::Any)
.value("EventInfo", APIEvent::Severity::EventInfo)
.value("EventWarning", APIEvent::Severity::EventWarning)
.value("Error", APIEvent::Severity::Error)
.finalize();
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::classh<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::classh<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::classh<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::classh<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,19 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/io.h"
namespace icsneo {
void init_io(pybind11::module_& m) {
pybind11::enum_<IO>(m, "IO")
.value("EthernetActivation", IO::EthernetActivation)
.value("USBHostPower", IO::USBHostPower)
.value("BackupPowerEnabled", IO::BackupPowerEnabled)
.value("BackupPowerGood", IO::BackupPowerGood)
.value("Misc", IO::Misc)
.value("EMisc", IO::EMisc);
}
} // namespace icsneo
@@ -0,0 +1,79 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/livedata.h"
namespace icsneo {
void init_livedata(pybind11::module_& m) {
// LiveDataValue struct
pybind11::classh<LiveDataValue>(m, "LiveDataValue")
.def(pybind11::init<>())
.def_readwrite("value", &LiveDataValue::value);
// LiveDataArgument struct
pybind11::classh<LiveDataArgument>(m, "LiveDataArgument")
.def(pybind11::init<>())
.def_readwrite("object_type", &LiveDataArgument::objectType)
.def_readwrite("object_index", &LiveDataArgument::objectIndex)
.def_readwrite("signal_index", &LiveDataArgument::signalIndex)
.def_readwrite("value_type", &LiveDataArgument::valueType);
// LiveDataCommand enum
pybind11::native_enum<LiveDataCommand>(m, "LiveDataCommand", "enum.IntEnum")
.value("STATUS", LiveDataCommand::STATUS)
.value("SUBSCRIBE", LiveDataCommand::SUBSCRIBE)
.value("UNSUBSCRIBE", LiveDataCommand::UNSUBSCRIBE)
.value("RESPONSE", LiveDataCommand::RESPONSE)
.value("CLEAR_ALL", LiveDataCommand::CLEAR_ALL)
.value("SET_VALUE", LiveDataCommand::SET_VALUE)
.finalize();
// LiveDataStatus enum
pybind11::native_enum<LiveDataStatus>(m, "LiveDataStatus", "enum.IntEnum")
.value("SUCCESS", LiveDataStatus::SUCCESS)
.value("ERR_UNKNOWN_COMMAND", LiveDataStatus::ERR_UNKNOWN_COMMAND)
.value("ERR_HANDLE", LiveDataStatus::ERR_HANDLE)
.value("ERR_DUPLICATE", LiveDataStatus::ERR_DUPLICATE)
.value("ERR_FULL", LiveDataStatus::ERR_FULL)
.finalize();
// LiveDataObjectType enum
pybind11::enum_<LiveDataObjectType>(m, "LiveDataObjectType")
.value("MISC", LiveDataObjectType::MISC)
.value("SNA", LiveDataObjectType::SNA)
.export_values();
// LiveDataValueType enum
pybind11::native_enum<LiveDataValueType>(m, "LiveDataValueType", "enum.IntEnum")
.value("GPS_LATITUDE", LiveDataValueType::GPS_LATITUDE)
.value("GPS_LONGITUDE", LiveDataValueType::GPS_LONGITUDE)
.value("GPS_ALTITUDE", LiveDataValueType::GPS_ALTITUDE)
.value("GPS_SPEED", LiveDataValueType::GPS_SPEED)
.value("GPS_VALID", LiveDataValueType::GPS_VALID)
.value("GPS_ENABLE", LiveDataValueType::GPS_ENABLE)
.value("MANUAL_TRIGGER", LiveDataValueType::MANUAL_TRIGGER)
.value("TIME_SINCE_MSG", LiveDataValueType::TIME_SINCE_MSG)
.value("GPS_ACCURACY", LiveDataValueType::GPS_ACCURACY)
.value("GPS_BEARING", LiveDataValueType::GPS_BEARING)
.value("GPS_TIME", LiveDataValueType::GPS_TIME)
.value("GPS_TIME_VALID", LiveDataValueType::GPS_TIME_VALID)
.value("DAQ_ENABLE", LiveDataValueType::DAQ_ENABLE)
.finalize();
// LiveDataUtil namespace functions
m.def("get_new_handle", &LiveDataUtil::getNewHandle,
"Generate a new unique LiveData handle");
m.def("livedata_value_to_double", &LiveDataUtil::liveDataValueToDouble,
pybind11::arg("val"),
"Convert LiveDataValue to double (32.32 fixed-point to floating-point)");
m.def("livedata_double_to_value", &LiveDataUtil::liveDataDoubleToValue,
pybind11::arg("d"),
"Convert double to LiveDataValue (32.32 fixed-point format). Returns LiveDataValue or None on failure.");
}
} // 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::classh<MessageCallback>(m, "MessageCallback")
.def(pybind11::init<MessageCallback::fn_messageCallback, std::shared_ptr<MessageFilter>>());
}
} // namespace icsneo
@@ -0,0 +1,40 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/message/canerrormessage.h"
namespace icsneo {
void init_errorcodes(pybind11::module_& m) {
pybind11::native_enum<CANErrorCode>(m, "CANErrorCode", "enum.IntEnum")
.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)
.finalize();
}
void init_canerrormessage(pybind11::module_& m) {
init_errorcodes(m);
pybind11::classh<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,25 @@
#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::classh<CANMessage, Frame>(m, "CANMessage")
.def(pybind11::init())
.def_readwrite("arbid", &CANMessage::arbid)
.def_readwrite("dlcOnWire", &CANMessage::dlcOnWire)
.def_readwrite("isRemote", &CANMessage::isRemote)
.def_readwrite("isExtended", &CANMessage::isExtended)
.def_readwrite("isCANFD", &CANMessage::isCANFD)
.def_readwrite("baudrateSwitch", &CANMessage::baudrateSwitch)
.def_readwrite("errorStateIndicator", &CANMessage::errorStateIndicator)
.def_readwrite("txAborted", &CANMessage::txAborted)
.def_readwrite("txLostArb", &CANMessage::txLostArb)
.def_readwrite("txError", &CANMessage::txError);
}
} // namespace icsneo
@@ -0,0 +1,38 @@
#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::classh<MACAddress>(m, "MACAddress")
.def("to_string", &MACAddress::toString)
.def("__repr__", &MACAddress::toString);
pybind11::classh<EthernetMessage, Frame>(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_readwrite("fcsVerified", &EthernetMessage::fcsVerified)
.def_readwrite("txAborted", &EthernetMessage::txAborted)
.def_readwrite("crcError", &EthernetMessage::crcError)
.def_readwrite("isT1S", &EthernetMessage::isT1S)
.def_readwrite("isT1SSymbol", &EthernetMessage::isT1SSymbol)
.def_readwrite("isT1SBurst", &EthernetMessage::isT1SBurst)
.def_readwrite("txCollision", &EthernetMessage::txCollision)
.def_readwrite("isT1SWake", &EthernetMessage::isT1SWake)
.def_readwrite("t1sNodeId", &EthernetMessage::t1sNodeId)
.def_readwrite("t1sBurstCount", &EthernetMessage::t1sBurstCount)
.def_readwrite("t1sSymbolType", &EthernetMessage::t1sSymbolType)
.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,36 @@
#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::classh<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)
.value("LinkModeNone", EthernetStatusMessage::LinkMode::LinkModeNone);
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,34 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethphymessage.h"
namespace icsneo {
void init_ethphymessage(pybind11::module_& m) {
pybind11::classh<Clause22Message>(m, "Clause22Message")
.def_readwrite("phyAddr", &Clause22Message::phyAddr)
.def_readwrite("page", &Clause22Message::page)
.def_readwrite("regAddr", &Clause22Message::regAddr)
.def_readwrite("regVal", &Clause22Message::regVal);
pybind11::classh<Clause45Message>(m, "Clause45Message")
.def_readwrite("port", &Clause45Message::port)
.def_readwrite("device", &Clause45Message::device)
.def_readwrite("regAddr", &Clause45Message::regAddr)
.def_readwrite("regVal", &Clause45Message::regVal);
pybind11::classh<PhyMessage>(m, "PhyMessage")
.def(pybind11::init())
.def_readwrite("Enabled", &PhyMessage::Enabled)
.def_readwrite("WriteEnable", &PhyMessage::WriteEnable)
.def_readwrite("Clause45Enable", &PhyMessage::Clause45Enable)
.def_readwrite("Version", &PhyMessage::Version)
.def_readwrite("BusIndex", &PhyMessage::BusIndex)
.def_readwrite("Clause22", &PhyMessage::Clause22)
.def_readwrite("Clause45", &PhyMessage::Clause45);
pybind11::classh<EthPhyMessage, Message>(m, "EthPhyMessage")
.def(pybind11::init())
.def_readwrite("messages", &EthPhyMessage::messages);
}
} // 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::classh<MessageFilter>(m, "MessageFilter")
.def(pybind11::init())
.def(pybind11::init<Message::Type>())
.def(pybind11::init<Network::NetID>());
}
} // namespace icsneo
@@ -0,0 +1,80 @@
#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::classh<GPTPStatus, Message> gptpStatus(m, "GPTPStatus");
pybind11::classh<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::classh<GPTPStatus::ScaledNanoSeconds>(gptpStatus, "ScaledNanoSeconds")
.def_readonly("nanoseconds_msb", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB)
.def_readonly("nanoseconds_lsb", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB)
.def_readonly("fractional_nanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds);
pybind11::classh<GPTPStatus::PortID>(gptpStatus, "PortID")
.def_readonly("clock_identity", &GPTPStatus::PortID::clockIdentity)
.def_readonly("port_number", &GPTPStatus::PortID::portNumber);
pybind11::classh<GPTPStatus::ClockQuality>(gptpStatus, "ClockQuality")
.def_readonly("clock_class", &GPTPStatus::ClockQuality::clockClass)
.def_readonly("clock_accuracy", &GPTPStatus::ClockQuality::clockAccuracy)
.def_readonly("offset_scaled_log_variance", &GPTPStatus::ClockQuality::offsetScaledLogVariance);
pybind11::classh<GPTPStatus::SystemID>(gptpStatus, "SystemID")
.def_readonly("priority1", &GPTPStatus::SystemID::priority1)
.def_readonly("clock_quality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("priority2", &GPTPStatus::SystemID::priority2)
.def_readonly("clock_id", &GPTPStatus::SystemID::clockID);
pybind11::classh<GPTPStatus::PriorityVector>(gptpStatus, "PriorityVector")
.def_readonly("sys_id", &GPTPStatus::PriorityVector::sysID)
.def_readonly("steps_removed", &GPTPStatus::PriorityVector::stepsRemoved)
.def_readonly("port_id", &GPTPStatus::PriorityVector::portID)
.def_readonly("port_number", &GPTPStatus::PriorityVector::portNumber);
pybind11::classh<GPTPStatus::ParentDS>(gptpStatus, "ParentDS")
.def_readonly("parent_port_identity", &GPTPStatus::ParentDS::parentPortIdentity)
.def_readonly("cumulative_rate_ratio", &GPTPStatus::ParentDS::cumulativeRateRatio)
.def_readonly("grandmaster_identity", &GPTPStatus::ParentDS::grandmasterIdentity)
.def_readonly("gm_clock_quality_clock_class", &GPTPStatus::ParentDS::gmClockQualityClockClass)
.def_readonly("gm_clock_quality_clock_accuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy)
.def_readonly("gm_clock_quality_offset_scaled_log_variance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance)
.def_readonly("gm_priority1", &GPTPStatus::ParentDS::gmPriority1)
.def_readonly("gm_priority2", &GPTPStatus::ParentDS::gmPriority2);
pybind11::classh<GPTPStatus::CurrentDS>(gptpStatus, "CurrentDS")
.def_readonly("steps_removed", &GPTPStatus::CurrentDS::stepsRemoved)
.def_readonly("offset_from_master", &GPTPStatus::CurrentDS::offsetFromMaster)
.def_readonly("lastgm_phase_change", &GPTPStatus::CurrentDS::lastgmPhaseChange)
.def_readonly("lastgm_freq_change", &GPTPStatus::CurrentDS::lastgmFreqChange)
.def_readonly("gm_time_base_indicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator)
.def_readonly("gm_change_count", &GPTPStatus::CurrentDS::gmChangeCount)
.def_readonly("time_of_lastgm_change_event", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent)
.def_readonly("time_of_lastgm_phase_change_event", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent)
.def_readonly("time_of_lastgm_freq_change_event", &GPTPStatus::CurrentDS::timeOfLastgmFreqChangeEvent);
gptpStatus.def_readonly("current_time", &GPTPStatus::currentTime)
.def_readonly("gm_priority", &GPTPStatus::gmPriority)
.def_readonly("ms_offset_ns", &GPTPStatus::msOffsetNs)
.def_readonly("is_sync", &GPTPStatus::isSync)
.def_readonly("link_status", &GPTPStatus::linkStatus)
.def_readonly("link_delay_ns", &GPTPStatus::linkDelayNS)
.def_readonly("selected_role", &GPTPStatus::selectedRole)
.def_readonly("as_capable", &GPTPStatus::asCapable)
.def_readonly("is_syntonized", &GPTPStatus::isSyntonized)
.def_readonly("last_rx_sync_ts", &GPTPStatus::lastRXSyncTS)
.def_readonly("current_ds", &GPTPStatus::currentDS)
.def_readonly("parent_ds", &GPTPStatus::parentDS)
.def_readonly("short_format", &GPTPStatus::shortFormat);
}
} // 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::classh<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::classh<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::classh<LINMessage, Frame> 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,50 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include "icsneo/communication/message/livedatamessage.h"
namespace icsneo {
void init_livedatamessage(pybind11::module_& m) {
// LiveDataMessage base class
pybind11::classh<LiveDataMessage, RawMessage>(m, "LiveDataMessage")
.def(pybind11::init<>())
.def_readwrite("handle", &LiveDataMessage::handle)
.def_readwrite("cmd", &LiveDataMessage::cmd);
// LiveDataCommandMessage (for subscribe/unsubscribe)
pybind11::classh<LiveDataCommandMessage, LiveDataMessage>(m, "LiveDataCommandMessage")
.def(pybind11::init<>())
.def_readwrite("update_period", &LiveDataCommandMessage::updatePeriod)
.def_readwrite("expiration_time", &LiveDataCommandMessage::expirationTime)
.def_readwrite("args", &LiveDataCommandMessage::args)
.def("append_signal_arg", &LiveDataCommandMessage::appendSignalArg,
pybind11::arg("value_type"),
"Append a signal argument to the command message");
// LiveDataValueMessage (received values)
pybind11::classh<LiveDataValueMessage, LiveDataMessage>(m, "LiveDataValueMessage")
.def(pybind11::init<>())
.def_readwrite("num_args", &LiveDataValueMessage::numArgs)
.def_readwrite("values", &LiveDataValueMessage::values);
// LiveDataStatusMessage (status responses)
pybind11::classh<LiveDataStatusMessage, LiveDataMessage>(m, "LiveDataStatusMessage")
.def(pybind11::init<>())
.def_readwrite("requested_command", &LiveDataStatusMessage::requestedCommand)
.def_readwrite("status", &LiveDataStatusMessage::status);
// LiveDataSetValueMessage (for setting values)
pybind11::classh<LiveDataSetValueMessage, LiveDataMessage>(m, "LiveDataSetValueMessage")
.def(pybind11::init<>())
.def_readwrite("args", &LiveDataSetValueMessage::args)
.def_readwrite("values", &LiveDataSetValueMessage::values)
.def("append_set_value", &LiveDataSetValueMessage::appendSetValue,
pybind11::arg("value_type"),
pybind11::arg("value"),
"Append a value to set in the message");
}
} // 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::classh<MDIOMessage, Frame> 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,57 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/message/message.h"
namespace icsneo {
void init_message(pybind11::module_& m) {
// Using py::smart_holder for safer lifetime management
pybind11::classh<Message> message(m, "Message");
pybind11::native_enum<Message::Type>(message, "Type", "enum.IntEnum")
.value("Frame", Message::Type::Frame)
.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("RawMessage", Message::Type::RawMessage)
.value("ReadSettings", Message::Type::ReadSettings)
.value("ResetStatus", Message::Type::ResetStatus)
.value("DeviceVersion", Message::Type::DeviceVersion)
.value("Main51", Message::Type::Main51)
.value("FlexRayControl", Message::Type::FlexRayControl)
.value("EthernetPhyRegister", Message::Type::EthernetPhyRegister)
.value("LogicalDiskInfo", Message::Type::LogicalDiskInfo)
.value("ExtendedResponse", Message::Type::ExtendedResponse)
.value("WiVICommandResponse", Message::Type::WiVICommandResponse)
.value("ScriptStatus", Message::Type::ScriptStatus)
.value("ComponentVersions", Message::Type::ComponentVersions)
.value("SupportedFeatures", Message::Type::SupportedFeatures)
.value("GenericBinaryStatus", Message::Type::GenericBinaryStatus)
.value("LiveData", Message::Type::LiveData)
.value("HardwareInfo", Message::Type::HardwareInfo)
.value("TC10Status", Message::Type::TC10Status)
.value("AppError", Message::Type::AppError)
.value("GPTPStatus", Message::Type::GPTPStatus)
.value("EthernetStatus", Message::Type::EthernetStatus)
.finalize();
message.def(pybind11::init<Message::Type>());
message.def_readonly("type", &Message::type);
message.def_readwrite("timestamp", &Message::timestamp);
pybind11::classh<RawMessage, Message>(m, "RawMessage")
.def_readwrite("network", &RawMessage::network)
.def_readwrite("data", &RawMessage::data);
pybind11::classh<Frame, RawMessage>(m, "Frame")
.def_readwrite("description", &Frame::description)
.def_readwrite("transmitted", &Frame::transmitted)
.def_readwrite("error", &Frame::error);
}
} // namespace icsneo
@@ -0,0 +1,30 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/scriptstatusmessage.h"
namespace icsneo {
void init_scriptstatusmessage(pybind11::module_& m) {
pybind11::classh<ScriptStatusMessage, Message>(m, "ScriptStatusMessage")
.def_readonly("isEncrypted", &ScriptStatusMessage::isEncrypted)
.def_readonly("isCoreminiRunning", &ScriptStatusMessage::isCoreminiRunning)
.def_readonly("sectorOverflows", &ScriptStatusMessage::sectorOverflows)
.def_readonly("numRemainingSectorBuffers", &ScriptStatusMessage::numRemainingSectorBuffers)
.def_readonly("lastSector", &ScriptStatusMessage::lastSector)
.def_readonly("readBinSize", &ScriptStatusMessage::readBinSize)
.def_readonly("minSector", &ScriptStatusMessage::minSector)
.def_readonly("maxSector", &ScriptStatusMessage::maxSector)
.def_readonly("currentSector", &ScriptStatusMessage::currentSector)
.def_readonly("coreminiCreateTime", &ScriptStatusMessage::coreminiCreateTime)
.def_readonly("fileChecksum", &ScriptStatusMessage::fileChecksum)
.def_readonly("coreminiVersion", &ScriptStatusMessage::coreminiVersion)
.def_readonly("coreminiHeaderSize", &ScriptStatusMessage::coreminiHeaderSize)
.def_readonly("diagnosticErrorCode", &ScriptStatusMessage::diagnosticErrorCode)
.def_readonly("diagnosticErrorCodeCount", &ScriptStatusMessage::diagnosticErrorCodeCount)
.def_readonly("maxCoreminiSizeKB", &ScriptStatusMessage::maxCoreminiSizeKB);
}
} // namespace icsneo
@@ -0,0 +1,24 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/spimessage.h"
namespace icsneo {
void init_spimessage(pybind11::module_& m) {
pybind11::classh<SPIMessage, Frame> spiMessage(m, "SPIMessage");
pybind11::enum_<SPIMessage::Direction>(spiMessage, "Direction")
.value("Write", SPIMessage::Direction::Write)
.value("Read", SPIMessage::Direction::Read);
spiMessage
.def(pybind11::init())
.def_readwrite("direction", &SPIMessage::direction)
.def_readwrite("address", &SPIMessage::address)
.def_readwrite("mms", &SPIMessage::mms)
.def_readwrite("stats", &SPIMessage::stats)
.def_readwrite("payload", &SPIMessage::payload);
}
} // 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::classh<TC10StatusMessage, Message>(m, "TC10StatusMessage")
.def_readonly("wakeStatus", &TC10StatusMessage::wakeStatus)
.def_readonly("sleepStatus", &TC10StatusMessage::sleepStatus);
}
} // namespace icsneo
@@ -0,0 +1,202 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/network.h"
namespace icsneo {
void init_network(pybind11::module_& m) {
pybind11::classh<Network> network(m, "Network");
pybind11::native_enum<Network::NetID>(network, "NetID", "enum.IntEnum")
.value("Device", Network::NetID::Device)
.value("DWCAN_01", Network::NetID::DWCAN_01)
.value("DWCAN_08", Network::NetID::DWCAN_08)
.value("SWCAN_01", Network::NetID::SWCAN_01)
.value("LSFTCAN_01", Network::NetID::LSFTCAN_01)
.value("FordSCP", Network::NetID::FordSCP)
.value("J1708", Network::NetID::J1708)
.value("Aux", Network::NetID::Aux)
.value("J1850VPW", Network::NetID::J1850VPW)
.value("ISO9141_01", Network::NetID::ISO9141_01)
.value("DiskData", Network::NetID::DiskData)
.value("Main51", Network::NetID::Main51)
.value("RED", Network::NetID::RED)
.value("SCI", Network::NetID::SCI)
.value("ISO9141_02", Network::NetID::ISO9141_02)
.value("ISO14230", Network::NetID::ISO14230)
.value("LIN_01", Network::NetID::LIN_01)
.value("AE_01", Network::NetID::AE_01)
.value("AE_02", Network::NetID::AE_02)
.value("AE_03", Network::NetID::AE_03)
.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_03", Network::NetID::ISO9141_03)
.value("DWCAN_02", Network::NetID::DWCAN_02)
.value("DWCAN_03", Network::NetID::DWCAN_03)
.value("AE_04", Network::NetID::AE_04)
.value("AE_05", Network::NetID::AE_05)
.value("ISO9141_04", Network::NetID::ISO9141_04)
.value("LIN_02", Network::NetID::LIN_02)
.value("LIN_03", Network::NetID::LIN_03)
.value("LIN_04", Network::NetID::LIN_04)
.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("DWCAN_04", Network::NetID::DWCAN_04)
.value("DWCAN_05", Network::NetID::DWCAN_05)
.value("RS232", Network::NetID::RS232)
.value("UART_01", Network::NetID::UART_01)
.value("UART_02", Network::NetID::UART_02)
.value("UART_03", Network::NetID::UART_03)
.value("UART_04", Network::NetID::UART_04)
.value("SWCAN_02", Network::NetID::SWCAN_02)
.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("SPI_01", Network::NetID::SPI_01)
.value("AE_06", Network::NetID::AE_06)
.value("Red_VBat", Network::NetID::Red_VBat)
.value("AE_07", Network::NetID::AE_07)
.value("AE_08", Network::NetID::AE_08)
.value("AE_09", Network::NetID::AE_09)
.value("AE_10", Network::NetID::AE_10)
.value("AE_11", Network::NetID::AE_11)
.value("FLEXRAY_01A", Network::NetID::FLEXRAY_01A)
.value("FLEXRAY_01B", Network::NetID::FLEXRAY_01B)
.value("FLEXRAY_02A", Network::NetID::FLEXRAY_02A)
.value("FLEXRAY_02B", Network::NetID::FLEXRAY_02B)
.value("LIN_05", Network::NetID::LIN_05)
.value("FLEXRAY_01", Network::NetID::FLEXRAY_01)
.value("FLEXRAY_02", Network::NetID::FLEXRAY_02)
.value("AE_12", Network::NetID::AE_12)
.value("I2C_01", Network::NetID::I2C_01)
.value("MOST_25", Network::NetID::MOST_25)
.value("MOST_50", Network::NetID::MOST_50)
.value("MOST_150", Network::NetID::MOST_150)
.value("ETHERNET_01", Network::NetID::ETHERNET_01)
.value("GMFSA", Network::NetID::GMFSA)
.value("TCP", Network::NetID::TCP)
.value("DWCAN_06", Network::NetID::DWCAN_06)
.value("DWCAN_07", Network::NetID::DWCAN_07)
.value("LIN_06", Network::NetID::LIN_06)
.value("LSFTCAN_02", Network::NetID::LSFTCAN_02)
.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("I2C_02", Network::NetID::I2C_02)
.value("I2C_03", Network::NetID::I2C_03)
.value("I2C_04", Network::NetID::I2C_04)
.value("ETHERNET_02", Network::NetID::ETHERNET_02)
.value("ETHERNET_TX_WRAP", Network::NetID::ETHERNET_TX_WRAP)
.value("A2B_01", Network::NetID::A2B_01)
.value("A2B_02", Network::NetID::A2B_02)
.value("ETHERNET_03", Network::NetID::ETHERNET_03)
.value("WBMS_01", Network::NetID::WBMS_01)
.value("DWCAN_09", Network::NetID::DWCAN_09)
.value("DWCAN_10", Network::NetID::DWCAN_10)
.value("DWCAN_11", Network::NetID::DWCAN_11)
.value("DWCAN_12", Network::NetID::DWCAN_12)
.value("DWCAN_13", Network::NetID::DWCAN_13)
.value("DWCAN_14", Network::NetID::DWCAN_14)
.value("DWCAN_15", Network::NetID::DWCAN_15)
.value("DWCAN_16", Network::NetID::DWCAN_16)
.value("LIN_07", Network::NetID::LIN_07)
.value("LIN_08", Network::NetID::LIN_08)
.value("SPI_02", Network::NetID::SPI_02)
.value("MDIO_01", Network::NetID::MDIO_01)
.value("MDIO_02", Network::NetID::MDIO_02)
.value("MDIO_03", Network::NetID::MDIO_03)
.value("MDIO_04", Network::NetID::MDIO_04)
.value("MDIO_05", Network::NetID::MDIO_05)
.value("MDIO_06", Network::NetID::MDIO_06)
.value("MDIO_07", Network::NetID::MDIO_07)
.value("MDIO_08", Network::NetID::MDIO_08)
.value("AE_13", Network::NetID::AE_13)
.value("AE_14", Network::NetID::AE_14)
.value("AE_15", Network::NetID::AE_15)
.value("AE_16", Network::NetID::AE_16)
.value("SPI_03", Network::NetID::SPI_03)
.value("SPI_04", Network::NetID::SPI_04)
.value("SPI_05", Network::NetID::SPI_05)
.value("SPI_06", Network::NetID::SPI_06)
.value("SPI_07", Network::NetID::SPI_07)
.value("SPI_08", Network::NetID::SPI_08)
.value("LIN_09", Network::NetID::LIN_09)
.value("LIN_10", Network::NetID::LIN_10)
.value("LIN_11", Network::NetID::LIN_11)
.value("LIN_12", Network::NetID::LIN_12)
.value("LIN_13", Network::NetID::LIN_13)
.value("LIN_14", Network::NetID::LIN_14)
.value("LIN_15", Network::NetID::LIN_15)
.value("LIN_16", Network::NetID::LIN_16)
.value("Any", Network::NetID::Any)
.value("Invalid", Network::NetID::Invalid)
.finalize();
pybind11::native_enum<Network::Type>(network, "Type", "enum.Enum")
.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("AutomotiveEthernet", Network::Type::AutomotiveEthernet)
.value("Any", Network::Type::Any)
.value("Other", Network::Type::Other)
.finalize();
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
+166
View File
@@ -0,0 +1,166 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/core/macseccfg.h"
namespace icsneo {
void init_macsecconfig(pybind11::module_ & m)
{
pybind11::enum_<MACsecPacketType>(m, "MACsecPacketType")
.value("DEFAULT", MACsecPacketType::Default)
.value("SINGLE_VLAN", MACsecPacketType::SingleVLAN)
.value("DUAL_VLAN", MACsecPacketType::DualVLAN)
.value("MPLS", MACsecPacketType::MPLS)
.value("SINGLE_VLAN_FOLLOWED_BY_MPLS", MACsecPacketType::SingleVLANFollowedByMPLS)
.value("DUAL_VLAN_FOLLOWED_BY_MPLS", MACsecPacketType::DualVLANFollowedByMPLS)
.value("UNSUPPORTED", MACsecPacketType::Unsupported);
pybind11::enum_<MACsecValidation>(m, "MACsecValidation")
.value("DISABLED", MACsecValidation::Disabled)
.value("CHECK", MACsecValidation::Check)
.value("STRICT", MACsecValidation::Strict)
.value("NA", MACsecValidation::NA);
pybind11::enum_<MACsecStrip>(m, "MACsecStrip")
.value("STRIP_SECTAG_AND_ICV", MACsecStrip::StripSecTagAndIcv)
.value("STRIP_SECTAG_PRESERVE_ICV", MACsecStrip::StripSecTagPreserveICV)
.value("PRESERVE_SECTAG_STRIP_ICV", MACsecStrip::PreserveSecTagStripICV)
.value("NO_STRIP", MACsecStrip::NoStrip);
pybind11::enum_<MACsecCipherSuite>(m, "MACsecCipherSuite")
.value("GCM_AES_128", MACsecCipherSuite::GcmAes128)
.value("GCM_AES_256", MACsecCipherSuite::GcmAes256)
.value("GCM_AES_128_XPN", MACsecCipherSuite::GcmAes128Xpn)
.value("GCM_AES_256_XPN", MACsecCipherSuite::GcmAes256Xpn);
pybind11::classh<MACsecVLANTag>(m, "MACsecVLANTag")
.def(pybind11::init())
.def_readwrite("vid", &MACsecVLANTag::vid)
.def_readwrite("pri_cfi", &MACsecVLANTag::priCfi);
pybind11::classh<MACsecMPLSOuter>(m, "MACsecMPLSOuter")
.def(pybind11::init())
.def_readwrite("mpls_label", &MACsecMPLSOuter::mplsLabel)
.def_readwrite("exp", &MACsecMPLSOuter::exp);
pybind11::classh<MACsecTci>(m, "MACsecTci")
.def(pybind11::init())
.def_readwrite("es", &MACsecTci::es)
.def_readwrite("sc", &MACsecTci::sc)
.def_readwrite("scb", &MACsecTci::scb)
.def_readwrite("e", &MACsecTci::e)
.def_readwrite("c", &MACsecTci::c);
pybind11::classh<MACsecRxRule>(m, "MACsecRxRule")
.def(pybind11::init())
.def_readwrite("key_mac_da", &MACsecRxRule::keyMacDa)
.def_readwrite("mask_mac_da", &MACsecRxRule::maskMacDa)
.def_readwrite("key_mask_sa", &MACsecRxRule::keyMacSa)
.def_readwrite("mask_mac_sa", &MACsecRxRule::maskMacSa)
.def_readwrite("key_ether_type", &MACsecRxRule::keyEthertype)
.def_readwrite("mask_ether_type", &MACsecRxRule::maskEthertype)
.def_readwrite("key_vlan_tag_outer1", &MACsecRxRule::keyVlanTagOuter1)
.def_readwrite("key_mpls_outer1", &MACsecRxRule::keyMplsOuter1)
.def_readwrite("mask_vlan_tag_outer1", &MACsecRxRule::maskVlanTagOuter1)
.def_readwrite("mask_mpls_outer1", &MACsecRxRule::maskMplsOuter1)
.def_readwrite("key_vlan_tag_outer2", &MACsecRxRule::keyVlanTagOuter2)
.def_readwrite("key_mpls_outer2", &MACsecRxRule::keyMplsOuter2)
.def_readwrite("mask_vlan_tag_outer2", &MACsecRxRule::maskVlanTagOuter2)
.def_readwrite("mask_mpls_outer2", &MACsecRxRule::maskMplsOuter2)
.def_readwrite("key_bonus_data", &MACsecRxRule::keyBonusData)
.def_readwrite("mask_bonus_data", &MACsecRxRule::maskBonusData)
.def_readwrite("key_tag_match_bitmap", &MACsecRxRule::keyTagMatchBitmap)
.def_readwrite("mask_tag_match_bitmap", &MACsecRxRule::maskTagMatchBitmap)
.def_readwrite("key_packet_type", &MACsecRxRule::keyPacketType)
.def_readwrite("mask_packet_type", &MACsecRxRule::maskPacketType)
.def_readwrite("key_inner_vlan_type", &MACsecRxRule::keyInnerVlanType)
.def_readwrite("mask_inner_vlan_type", &MACsecRxRule::maskInnerVlanType)
.def_readwrite("key_outer_vlan_type", &MACsecRxRule::keyOuterVlanType)
.def_readwrite("mask_outer_vlan_type", &MACsecRxRule::maskOuterVlanType)
.def_readwrite("key_num_tags", &MACsecRxRule::keyNumTags)
.def_readwrite("mask_num_tags", &MACsecRxRule::maskNumTags)
.def_readwrite("key_express", &MACsecRxRule::keyExpress)
.def_readwrite("mask_express", &MACsecRxRule::maskExpress)
.def_readwrite("is_mpls", &MACsecRxRule::isMpls);
pybind11::classh<MACsecTxSecY>(m, "MACsecTxSecY")
.def(pybind11::init())
.def_readwrite("enable_control_port", &MACsecTxSecY::enableControlPort)
.def_readwrite("cipher", &MACsecTxSecY::cipher)
.def_readwrite("confidentiality_offset", &MACsecTxSecY::confidentialityOffset)
.def_readwrite("icv_includes_da_sa", &MACsecTxSecY::icvIncludesDaSa)
.def_readwrite("protect_frames", &MACsecTxSecY::protectFrames)
.def_readwrite("sec_tag_offset", &MACsecTxSecY::secTagOffset)
.def_readwrite("sec_tag_tci", &MACsecTxSecY::tci)
.def_readwrite("mtu", &MACsecTxSecY::mtu)
.def_readwrite("is_control_packet", &MACsecTxSecY::isControlPacket)
.def_readwrite("auxiliary_policy", &MACsecTxSecY::auxiliaryPolicy)
.def_readwrite("sci", &MACsecTxSecY::sci);
pybind11::classh<MACsecRxSecY>(m, "MACsecRxSecY")
.def(pybind11::init())
.def_readwrite("enable_control_port", &MACsecRxSecY::enableControlPort)
.def_readwrite("frame_validation", &MACsecRxSecY::frameValidation)
.def_readwrite("frame_strip", &MACsecRxSecY::frameStrip)
.def_readwrite("cipher", &MACsecRxSecY::cipher)
.def_readwrite("confidentiality_offset", &MACsecRxSecY::confidentialityOffset)
.def_readwrite("icv_includes_da_sa", &MACsecRxSecY::icvIncludesDaSa)
.def_readwrite("replay_protect", &MACsecRxSecY::replayProtect)
.def_readwrite("replay_window", &MACsecRxSecY::replayWindow)
.def_readwrite("is_control_packet", &MACsecRxSecY::isControlPacket)
.def_readwrite("sci", &MACsecRxSecY::sci);
pybind11::classh<MACsecTxSa>(m, "MACsecTxSa")
.def(pybind11::init())
.def_readwrite("sak", &MACsecTxSa::sak)
.def_readwrite("hash_key", &MACsecTxSa::hashKey)
.def_readwrite("salt", &MACsecTxSa::salt)
.def_readwrite("ssci", &MACsecTxSa::ssci)
.def_readwrite("next_pn", &MACsecTxSa::nextPn)
.def_readwrite("an", &MACsecTxSa::an);
pybind11::classh<MACsecRxSa>(m, "MACsecRxSa")
.def(pybind11::init())
.def_readwrite("sak", &MACsecRxSa::sak)
.def_readwrite("hash_key", &MACsecRxSa::hashKey)
.def_readwrite("salt", &MACsecRxSa::salt)
.def_readwrite("ssci", &MACsecRxSa::ssci)
.def_readwrite("next_pn", &MACsecRxSa::nextPn);
pybind11::classh<MACsecConfig>(m, "MACsecConfig")
.def(pybind11::init<icsneo::DeviceType>())
.def("add_rx_secy", &MACsecConfig::addRxSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_tx_secY", &MACsecConfig::addTxSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_rx_rule", &MACsecConfig::addRxRule, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_rx_sa", &MACsecConfig::addRxSa, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("add_tx_sa", &MACsecConfig::addTxSa, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_rx_secy", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxSecY& { return cfg.getRxSecY(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tx_secy", [](MACsecConfig& cfg, uint8_t index) -> MACsecTxSecY& { return cfg.getTxSecY(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_rx_sa", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxSa& { return cfg.getRxSa(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tx_sa", [](MACsecConfig& cfg, uint8_t index) -> MACsecTxSa& { return cfg.getTxSa(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_rx_rule", [](MACsecConfig& cfg, uint8_t index) -> MACsecRxRule& { return cfg.getRxRule(index); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_tx_sa_index", &MACsecConfig::setTxSaIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("enable_tx_rekey", &MACsecConfig::enableTxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_tx_sa_rekey_index", &MACsecConfig::setTxSaRekeyIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("disable_tx_rekey", &MACsecConfig::disableTxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rx_sa_index", &MACsecConfig::setRxSaIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("enable_rx_rekey", &MACsecConfig::enableRxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rx_sa_rekey_index", &MACsecConfig::setRxSaRekeyIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("disable_rx_rekey", &MACsecConfig::disableRxRekey, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rx_enable", &MACsecConfig::setRxEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_tx_enable", &MACsecConfig::setTxEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_storage", &MACsecConfig::setStorage, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear", &MACsecConfig::clear, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("serialize", &MACsecConfig::serialize, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_bin_index", &MACsecConfig::getBinIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_type", &MACsecConfig::getType, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_rule", &MACsecConfig::getMaxNumRule, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_secy", &MACsecConfig::getMaxNumSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_sa", &MACsecConfig::getMaxNumSa, pybind11::call_guard<pybind11::gil_scoped_release>());
}
} // namespace icsneo
+142
View File
@@ -0,0 +1,142 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/device/chipid.h"
namespace icsneo {
void init_chipid(pybind11::module_& m) {
pybind11::native_enum<ChipID>(m, "ChipID", "enum.IntEnum")
.value("neoVIFIRE_MCHIP", ChipID::neoVIFIRE_MCHIP)
.value("neoVIFIRE_LCHIP", ChipID::neoVIFIRE_LCHIP)
.value("neoVIFIRE_UCHIP", ChipID::neoVIFIRE_UCHIP)
.value("neoVIFIRE_JCHIP", ChipID::neoVIFIRE_JCHIP)
.value("ValueCAN3_MCHIP", ChipID::ValueCAN3_MCHIP)
.value("neoVIECU_MPIC", ChipID::neoVIECU_MPIC)
.value("neoVIIEVB_MPIC", ChipID::neoVIIEVB_MPIC)
.value("neoVIPENDANT_MPIC", ChipID::neoVIPENDANT_MPIC)
.value("neoVIFIRE_VNET_MCHIP", ChipID::neoVIFIRE_VNET_MCHIP)
.value("neoVIFIRE_VNET_LCHIP", ChipID::neoVIFIRE_VNET_LCHIP)
.value("neoVIPLASMA_Core", ChipID::neoVIPLASMA_Core)
.value("neoVIPLASMA_HID", ChipID::neoVIPLASMA_HID)
.value("neoVIANALOG_MPIC", ChipID::neoVIANALOG_MPIC)
.value("neoVIPLASMA_ANALOG_Core", ChipID::neoVIPLASMA_ANALOG_Core)
.value("neoVIPLASMA_FlexRay_Core", ChipID::neoVIPLASMA_FlexRay_Core)
.value("neoVIPLASMA_Core_1_12", ChipID::neoVIPLASMA_Core_1_12)
.value("neoVIFIRE_Slave_VNET_MCHIP", ChipID::neoVIFIRE_Slave_VNET_MCHIP)
.value("neoVIFIRE_Slave_VNET_LCHIP", ChipID::neoVIFIRE_Slave_VNET_LCHIP)
.value("neoVIION_Core", ChipID::neoVIION_Core)
.value("neoVIION_HID", ChipID::neoVIION_HID)
.value("neoVIION_Core_Loader", ChipID::neoVIION_Core_Loader)
.value("neoVIION_HID_Loader", ChipID::neoVIION_HID_Loader)
.value("neoVIION_FPGA_BIT", ChipID::neoVIION_FPGA_BIT)
.value("neoVIFIRE_VNET_EP_MCHIP", ChipID::neoVIFIRE_VNET_EP_MCHIP)
.value("neoVIFIRE_VNET_EP_LCHIP", ChipID::neoVIFIRE_VNET_EP_LCHIP)
.value("neoVIAnalogOut_MCHIP", ChipID::neoVIAnalogOut_MCHIP)
.value("neoVIMOST25_MCHIP", ChipID::neoVIMOST25_MCHIP)
.value("neoVIMOST50_MCHIP", ChipID::neoVIMOST50_MCHIP)
.value("neoVIMOST150_MCHIP", ChipID::neoVIMOST150_MCHIP)
.value("ValueCAN4_4_MCHIP", ChipID::ValueCAN4_4_MCHIP)
.value("ValueCAN4_4_SCHIP", ChipID::ValueCAN4_4_SCHIP)
.value("cmProbe_ZYNQ", ChipID::cmProbe_ZYNQ)
.value("EEVB_STM32", ChipID::EEVB_STM32)
.value("neoVIFIRE_Slave_VNET_EP_MCHIP", ChipID::neoVIFIRE_Slave_VNET_EP_MCHIP)
.value("neoVIFIRE_Slave_VNET_EP_LCHIP", ChipID::neoVIFIRE_Slave_VNET_EP_LCHIP)
.value("RADStar_MCHIP", ChipID::RADStar_MCHIP)
.value("ValueCANrf_MCHIP", ChipID::ValueCANrf_MCHIP)
.value("neoVIFIRE2_MCHIP", ChipID::neoVIFIRE2_MCHIP)
.value("neoVIFIRE2_CCHIP", ChipID::neoVIFIRE2_CCHIP)
.value("neoVIFIRE2_Core", ChipID::neoVIFIRE2_Core)
.value("neoVIFIRE2_BLECHIP", ChipID::neoVIFIRE2_BLECHIP)
.value("neoVIFIRE2_ZYNQ", ChipID::neoVIFIRE2_ZYNQ)
.value("neoVIFIRE2_SECURITYCHIP", ChipID::neoVIFIRE2_SECURITYCHIP)
.value("RADGalaxy_ZYNQ", ChipID::RADGalaxy_ZYNQ)
.value("neoVIFIRE2_VNET_MCHIP", ChipID::neoVIFIRE2_VNET_MCHIP)
.value("neoVIFIRE2_Slave_VNET_A_MCHIP", ChipID::neoVIFIRE2_Slave_VNET_A_MCHIP)
.value("neoVIFIRE2_Slave_VNET_A_CCHIP", ChipID::neoVIFIRE2_Slave_VNET_A_CCHIP)
.value("neoVIFIRE2_VNET_CCHIP", ChipID::neoVIFIRE2_VNET_CCHIP)
.value("neoVIFIRE2_VNET_Core", ChipID::neoVIFIRE2_VNET_Core)
.value("RADStar2_ZYNQ", ChipID::RADStar2_ZYNQ)
.value("VividCAN_MCHIP", ChipID::VividCAN_MCHIP)
.value("neoOBD2SIM_MCHIP", ChipID::neoOBD2SIM_MCHIP)
.value("neoVIFIRE2_VNETZ_MCHIP", ChipID::neoVIFIRE2_VNETZ_MCHIP)
.value("neoVIFIRE2_VNETZ_ZYNQ", ChipID::neoVIFIRE2_VNETZ_ZYNQ)
.value("neoVIFIRE2_Slave_VNETZ_A_MCHIP", ChipID::neoVIFIRE2_Slave_VNETZ_A_MCHIP)
.value("neoVIFIRE2_Slave_VNETZ_A_ZYNQ", ChipID::neoVIFIRE2_Slave_VNETZ_A_ZYNQ)
.value("VividCAN_EXT_FLASH", ChipID::VividCAN_EXT_FLASH)
.value("VividCAN_NRF52", ChipID::VividCAN_NRF52)
.value("cmProbe_ZYNQ_Unused", ChipID::cmProbe_ZYNQ_Unused)
.value("neoOBD2PRO_MCHIP", ChipID::neoOBD2PRO_MCHIP)
.value("ValueCAN4_1_MCHIP", ChipID::ValueCAN4_1_MCHIP)
.value("ValueCAN4_2_MCHIP", ChipID::ValueCAN4_2_MCHIP)
.value("ValueCAN4_4_2EL_Core", ChipID::ValueCAN4_4_2EL_Core)
.value("neoOBD2PRO_SCHIP", ChipID::neoOBD2PRO_SCHIP)
.value("ValueCAN4_2EL_MCHIP", ChipID::ValueCAN4_2EL_MCHIP)
.value("neoECUAVBTSN_MCHIP", ChipID::neoECUAVBTSN_MCHIP)
.value("neoOBD2PRO_Core", ChipID::neoOBD2PRO_Core)
.value("RADSupermoon_ZYNQ", ChipID::RADSupermoon_ZYNQ)
.value("RADMoon2_ZYNQ", ChipID::RADMoon2_ZYNQ)
.value("VividCANPRO_MCHIP", ChipID::VividCANPRO_MCHIP)
.value("VividCANPRO_EXT_FLASH", ChipID::VividCANPRO_EXT_FLASH)
.value("RADPluto_MCHIP", ChipID::RADPluto_MCHIP)
.value("RADMars_ZYNQ", ChipID::RADMars_ZYNQ)
.value("neoECU12_MCHIP", ChipID::neoECU12_MCHIP)
.value("RADIOCANHUB_MCHIP", ChipID::RADIOCANHUB_MCHIP)
.value("FlexRay_VNETZ_ZCHIP", ChipID::FlexRay_VNETZ_ZCHIP)
.value("neoOBD2_LCBADGE_MCHIP", ChipID::neoOBD2_LCBADGE_MCHIP)
.value("neoOBD2_LCBADGE_SCHIP", ChipID::neoOBD2_LCBADGE_SCHIP)
.value("RADMoonDuo_MCHIP", ChipID::RADMoonDuo_MCHIP)
.value("neoVIFIRE3_ZCHIP", ChipID::neoVIFIRE3_ZCHIP)
.value("FlexRay_VNETZ_FCHIP", ChipID::FlexRay_VNETZ_FCHIP)
.value("RADJupiter_MCHIP", ChipID::RADJupiter_MCHIP)
.value("ValueCAN4Industrial_MCHIP", ChipID::ValueCAN4Industrial_MCHIP)
.value("EtherBADGE_MCHIP", ChipID::EtherBADGE_MCHIP)
.value("RADMars_3_ZYNQ", ChipID::RADMars_3_ZYNQ)
.value("RADGigastar_USBZ_ZYNQ", ChipID::RADGigastar_USBZ_ZYNQ)
.value("RADGigastar_ZYNQ", ChipID::RADGigastar_ZYNQ)
.value("RAD4G_MCHIP", ChipID::RAD4G_MCHIP)
.value("neoVIFIRE3_SCHIP", ChipID::neoVIFIRE3_SCHIP)
.value("RADEpsilon_MCHIP", ChipID::RADEpsilon_MCHIP)
.value("RADA2B_ZCHIP", ChipID::RADA2B_ZCHIP)
.value("neoOBD2Dev_MCHIP", ChipID::neoOBD2Dev_MCHIP)
.value("neoOBD2Dev_SCHIP", ChipID::neoOBD2Dev_SCHIP)
.value("neoOBD2SIMDoIP_MCHIP", ChipID::neoOBD2SIMDoIP_MCHIP)
.value("SFPModule_88q2112_MCHIP", ChipID::SFPModule_88q2112_MCHIP)
.value("RADEpsilonT_MCHIP", ChipID::RADEpsilonT_MCHIP)
.value("RADEpsilonExpress_MCHIP", ChipID::RADEpsilonExpress_MCHIP)
.value("RADProxima_MCHIP", ChipID::RADProxima_MCHIP)
.value("NewDevice57_ZCHIP", ChipID::NewDevice57_ZCHIP)
.value("RAD_GALAXY_2_ZMPCHIP_ID", ChipID::RAD_GALAXY_2_ZMPCHIP_ID)
.value("NewDevice59_MCHIP", ChipID::NewDevice59_MCHIP)
.value("RADMoon2_Z7010_ZYNQ", ChipID::RADMoon2_Z7010_ZYNQ)
.value("neoVIFIRE2_Core_SG4", ChipID::neoVIFIRE2_Core_SG4)
.value("RADBMS_MCHIP", ChipID::RADBMS_MCHIP)
.value("RADMoon2_ZL_MCHIP", ChipID::RADMoon2_ZL_MCHIP)
.value("RADGigastar_USBZ_Z7010_ZYNQ", ChipID::RADGigastar_USBZ_Z7010_ZYNQ)
.value("neoVIFIRE3_LINUX", ChipID::neoVIFIRE3_LINUX)
.value("RADGigastar_USBZ_Z7007S_ZYNQ", ChipID::RADGigastar_USBZ_Z7007S_ZYNQ)
.value("VEM_01_8DW_ZCHIP", ChipID::VEM_01_8DW_ZCHIP)
.value("RADGalaxy_FFG_Zynq", ChipID::RADGalaxy_FFG_Zynq)
.value("RADMoon3_MCHIP", ChipID::RADMoon3_MCHIP)
.value("RADComet_ZYNQ", ChipID::RADComet_ZYNQ)
.value("VEM_02_FR_ZCHIP", ChipID::VEM_02_FR_ZCHIP)
.value("RADA2B_REVB_ZCHIP", ChipID::RADA2B_REVB_ZCHIP)
.value("RADGigastar_FFG_ZYNQ", ChipID::RADGigastar_FFG_ZYNQ)
.value("VEM_02_FR_FCHIP", ChipID::VEM_02_FR_FCHIP)
.value("Connect_ZCHIP", ChipID::Connect_ZCHIP)
.value("SFPModule_88q2221_MCHIP", ChipID::SFPModule_88q2221_MCHIP)
.value("RADGALAXY2_SYSMON_CHIP", ChipID::RADGALAXY2_SYSMON_CHIP)
.value("SFPModule_88q3244_MCHIP", ChipID::SFPModule_88q3244_MCHIP)
.value("RADCOMET3_ZCHIP", ChipID::RADCOMET3_ZCHIP)
.value("Connect_LINUX", ChipID::Connect_LINUX)
.value("SFPModule_lan8670_MCHIP", ChipID::SFPModule_lan8670_MCHIP)
.value("RADGigastar2_ZYNQ", ChipID::RADGigastar2_ZYNQ)
.value("SFPModule_ent11100_MCHIP", ChipID::SFPModule_ent11100_MCHIP)
.value("RADGemini_MCHIP", ChipID::RADGemini_MCHIP)
.value("Invalid", ChipID::Invalid)
.finalize();
}
} // namespace icsneo
@@ -0,0 +1,77 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include "icsneo/device/device.h"
#include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/disk/diskdetails.h"
#include <fstream>
namespace icsneo {
void init_device(pybind11::module_& m) {
pybind11::classh<Device>(m, "Device")
.def("__repr__", &Device::describe)
.def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear_script", &Device::clearScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("close", &Device::close, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("describe", &Device::describe)
.def("disable_message_polling", &Device::disableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("enable_message_polling", &Device::enableMessagePolling, pybind11::arg("filter") = std::nullopt, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_current_message_count", &Device::getCurrentMessageCount)
.def("get_digital_io", &Device::getDigitalIO, pybind11::arg("type"), pybind11::arg("number"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_extension", static_cast<std::shared_ptr<DeviceExtension>(Device::*)(const std::string&) const>(&Device::getExtension)) // This has to be static_casted rather than overload_casted because DeviceExtension is forward declared in device.h
.def("get_flexray_controllers", &Device::getFlexRayControllers)
.def("get_gptp_status", &Device::getGPTPStatus, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_messages", [](Device& device) { return device.getMessages(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_polling_message_limit", &Device::getPollingMessageLimit)
.def("get_product_name", &Device::getProductName)
.def("get_rtc", &Device::getRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_script_status", &Device::getScriptStatus, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_serial_number", &Device::getSerialNumber)
.def("get_serial", &Device::getSerial)
.def("get_pcb_serial", &Device::getPCBSerial, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_mac_address", &Device::getMACAddress, 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_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_type", &Device::getType)
.def("go_offline", &Device::goOffline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("go_online", &Device::goOnline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_message_polling_enabled", &Device::isMessagePollingEnabled)
.def("is_online_supported", &Device::isOnlineSupported)
.def("is_online", &Device::isOnline)
.def("is_open", &Device::isOpen)
.def("open", [](Device& device) { return device.open(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("prepare_script_load", &Device::prepareScriptLoad, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("remove_message_callback", &Device::removeMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_sleep", &Device::requestTC10Sleep, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_wake", &Device::requestTC10Wake, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_digital_io", pybind11::overload_cast<IO, size_t, bool>(&Device::setDigitalIO), pybind11::arg("type"), pybind11::arg("number"), pybind11::arg("value"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("start_script", &Device::startScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("stop_script", &Device::stopScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_tc10", &Device::supportsTC10)
.def("supports_live_data", &Device::supportsLiveData)
.def("subscribe_live_data", &Device::subscribeLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("unsubscribe_live_data", &Device::unsubscribeLiveData, pybind11::arg("handle"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear_all_live_data", &Device::clearAllLiveData, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_value_live_data", &Device::setValueLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("upload_coremini", [](Device& device, std::string& path, Disk::MemoryType memType) { std::ifstream ifs(path, std::ios::binary); return device.uploadCoremini(ifs, memType); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("write_macsec_config", &Device::writeMACsecConfig, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("send_eth_phy_msg", &Device::sendEthPhyMsg, pybind11::arg("message"), pybind11::arg("timeout") = std::chrono::milliseconds(50), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_chip_versions", &Device::getChipVersions, pybind11::arg("refreshComponents") = true, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_disk_formatting", &Device::supportsDiskFormatting, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_disk_count", &Device::getDiskCount, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_disk_details", &Device::getDiskDetails, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("force_disk_config_update", &Device::forceDiskConfigUpdate, pybind11::arg("config"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("format_disk", [](Device& device, const DiskDetails& config) -> bool { return device.formatDisk(config); }, pybind11::arg("config"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def_readonly("settings", &Device::settings);
}
} // namespace icsneo
@@ -0,0 +1,82 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include <pybind11/native_enum.h>
#include "icsneo/device/devicetype.h"
namespace icsneo {
void init_devicetype(pybind11::module_& m) {
pybind11::classh<DeviceType> deviceType(m, "DeviceType");
pybind11::native_enum<DeviceType::Enum>(deviceType, "Enum", "enum.IntEnum")
.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("RADEpsilonXL", DeviceType::Enum::RADEpsilonXL)
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADGemini", DeviceType::Enum::RADGemini)
.value("RADComet", DeviceType::Enum::RADComet)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("FIRE3_T1S_LIN", DeviceType::Enum::FIRE3_T1S_LIN)
.value("FIRE3_T1S_SENT", DeviceType::Enum::FIRE3_T1S_SENT)
.value("Connect", DeviceType::Enum::Connect)
.value("RADComet3", DeviceType::Enum::RADComet3)
.value("RADMoonT1S", DeviceType::Enum::RADMoonT1S)
.value("RADGigastar2", DeviceType::Enum::RADGigastar2)
.value("RED", DeviceType::Enum::RED)
.value("ECU", DeviceType::Enum::ECU)
.value("IEVB", DeviceType::Enum::IEVB)
.value("Pendant", DeviceType::Enum::Pendant)
.value("OBD2_PRO", DeviceType::Enum::OBD2_PRO)
.value("ECUChip_UART", DeviceType::Enum::ECUChip_UART)
.value("PLASMA", DeviceType::Enum::PLASMA)
.value("DONT_REUSE0", DeviceType::Enum::DONT_REUSE0)
.value("NEOAnalog", DeviceType::Enum::NEOAnalog)
.value("CT_OBD", DeviceType::Enum::CT_OBD)
.value("DONT_REUSE1", DeviceType::Enum::DONT_REUSE1)
.value("DONT_REUSE2", DeviceType::Enum::DONT_REUSE2)
.value("ION", DeviceType::Enum::ION)
.value("RADStar", DeviceType::Enum::RADStar)
.value("DONT_REUSE3", DeviceType::Enum::DONT_REUSE3)
.value("VCAN4_4", DeviceType::Enum::VCAN4_4)
.value("VCAN4_2", DeviceType::Enum::VCAN4_2)
.value("CMProbe", DeviceType::Enum::CMProbe)
.value("EEVB", DeviceType::Enum::EEVB)
.value("VCANrf", DeviceType::Enum::VCANrf)
.value("FIRE2", DeviceType::Enum::FIRE2)
.value("Flex", DeviceType::Enum::Flex)
.value("RADGalaxy", DeviceType::Enum::RADGalaxy)
.value("RADStar2", DeviceType::Enum::RADStar2)
.value("VividCAN", DeviceType::Enum::VividCAN)
.value("OBD2_SIM", DeviceType::Enum::OBD2_SIM)
.finalize();
deviceType.def(pybind11::init<DeviceType::Enum>());
deviceType.def("get_device_type", &DeviceType::getDeviceType);
deviceType.def("get_generic_product_name", &DeviceType::getGenericProductName);
}
} // namespace icsneo
@@ -0,0 +1,14 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/device/extensions/deviceextension.h"
namespace icsneo {
void init_deviceextension(pybind11::module_& m) {
pybind11::classh<DeviceExtension>(m, "DeviceExtension")
.def("get_name", &DeviceExtension::getName);
}
} // namespace icsneo
@@ -0,0 +1,129 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
#include "icsneo/device/idevicesettings.h"
#include <fstream>
namespace icsneo {
struct DeviceSettingsNamespace {
using EthLinkMode = AELinkMode;
};
void init_idevicesettings(pybind11::module_& m) {
pybind11::classh<DeviceSettingsNamespace> settings(m, "Settings");
pybind11::enum_<DeviceSettingsNamespace::EthLinkMode>(settings, "EthernetLinkMode")
.value("Auto", DeviceSettingsNamespace::EthLinkMode::AE_LINK_AUTO)
.value("Slave", DeviceSettingsNamespace::EthLinkMode::AE_LINK_SLAVE)
.value("Master", DeviceSettingsNamespace::EthLinkMode::AE_LINK_MASTER);
pybind11::enum_<EthPhyLinkMode>(settings, "PhyLinkMode")
.value("ETH_LINK_MODE_AUTO_NEGOTIATION", ETH_LINK_MODE_AUTO_NEGOTIATION)
.value("ETH_LINK_MODE_10MBPS_HALFDUPLEX", ETH_LINK_MODE_10MBPS_HALFDUPLEX)
.value("ETH_LINK_MODE_10MBPS_FULLDUPLEX", ETH_LINK_MODE_10MBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_100MBPS_HALFDUPLEX", ETH_LINK_MODE_100MBPS_HALFDUPLEX)
.value("ETH_LINK_MODE_100MBPS_FULLDUPLEX", ETH_LINK_MODE_100MBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_1GBPS_HALFDUPLEX", ETH_LINK_MODE_1GBPS_HALFDUPLEX)
.value("ETH_LINK_MODE_1GBPS_FULLDUPLEX", ETH_LINK_MODE_1GBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_2_5GBPS_FULLDUPLEX", ETH_LINK_MODE_2_5GBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_5GBPS_FULLDUPLEX", ETH_LINK_MODE_5GBPS_FULLDUPLEX)
.value("ETH_LINK_MODE_10GBPS_FULLDUPLEX", ETH_LINK_MODE_10GBPS_FULLDUPLEX);
pybind11::enum_<LINMode>(settings, "LINMode")
.value("Sleep", LINMode::SLEEP_MODE)
.value("Slow", LINMode::SLOW_MODE)
.value("Normal", LINMode::NORMAL_MODE)
.value("Fast", LINMode::FAST_MODE);
pybind11::enum_<MiscIOAnalogVoltage>(settings, "MiscIOAnalogVoltage")
.value("V0", MiscIOAnalogVoltage::V0)
.value("V1", MiscIOAnalogVoltage::V1)
.value("V2", MiscIOAnalogVoltage::V2)
.value("V3", MiscIOAnalogVoltage::V3)
.value("V4", MiscIOAnalogVoltage::V4)
.value("V5", MiscIOAnalogVoltage::V5);
pybind11::classh<IDeviceSettings>(m, "IDeviceSettings")
.def("apply", &IDeviceSettings::apply, pybind11::arg("temporary") = 0, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("apply_defaults", &IDeviceSettings::applyDefaults, pybind11::arg("temporary") = 0, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("refresh", &IDeviceSettings::refresh, pybind11::call_guard<pybind11::gil_scoped_release>())
// Baudrate methods
.def("get_baudrate", &IDeviceSettings::getBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_baudrate", &IDeviceSettings::setBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_fd_baudrate", &IDeviceSettings::getFDBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_fd_baudrate", &IDeviceSettings::setFDBaudrateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
// Termination methods
.def("is_termination_supported", &IDeviceSettings::isTerminationSupportedFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("can_termination_be_enabled", &IDeviceSettings::canTerminationBeEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_termination_enabled", &IDeviceSettings::isTerminationEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_termination", &IDeviceSettings::setTerminationFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_termination_groups", &IDeviceSettings::getTerminationGroups, pybind11::call_guard<pybind11::gil_scoped_release>())
// LIN methods
.def("is_commander_resistor_enabled", &IDeviceSettings::isCommanderResistorEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_commander_resistor", &IDeviceSettings::setCommanderResistorFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_lin_mode", &IDeviceSettings::getLINModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_lin_mode", &IDeviceSettings::setLINModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_lin_commander_response_time", &IDeviceSettings::getLINCommanderResponseTimeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_lin_commander_response_time", &IDeviceSettings::setLINCommanderResponseTimeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
// Ethernet PHY methods (index-based for switch devices)
.def("get_phy_enable", &IDeviceSettings::getPhyEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_mode", &IDeviceSettings::getPhyMode, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_speed", &IDeviceSettings::getPhySpeed, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_enable", &IDeviceSettings::setPhyEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_mode", &IDeviceSettings::setPhyMode, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_speed", &IDeviceSettings::setPhySpeed, pybind11::call_guard<pybind11::gil_scoped_release>())
// Ethernet PHY methods (network-based for multi-interface devices)
.def("get_phy_enable_for", &IDeviceSettings::getPhyEnableFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_role_for", &IDeviceSettings::getPhyRoleFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_phy_link_mode_for", &IDeviceSettings::getPhyLinkModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_enable_for", &IDeviceSettings::setPhyEnableFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_role_for", &IDeviceSettings::setPhyRoleFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_phy_link_mode_for", &IDeviceSettings::setPhyLinkModeFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_supported_phy_link_modes_for", &IDeviceSettings::getSupportedPhyLinkModesFor, pybind11::call_guard<pybind11::gil_scoped_release>())
// 10BASE-T1S methods
.def("is_t1s_plca_enabled", &IDeviceSettings::isT1SPLCAEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_plca", &IDeviceSettings::setT1SPLCAFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_local_id", &IDeviceSettings::getT1SLocalIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_local_id", &IDeviceSettings::setT1SLocalIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_max_nodes", &IDeviceSettings::getT1SMaxNodesFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_max_nodes", &IDeviceSettings::setT1SMaxNodesFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_tx_opp_timer", &IDeviceSettings::getT1STxOppTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_tx_opp_timer", &IDeviceSettings::setT1STxOppTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_max_burst", &IDeviceSettings::getT1SMaxBurstFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_max_burst", &IDeviceSettings::setT1SMaxBurstFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_burst_timer", &IDeviceSettings::getT1SBurstTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_burst_timer", &IDeviceSettings::setT1SBurstTimerFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_local_id_alternate", &IDeviceSettings::getT1SLocalIDAlternateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_local_id_alternate", &IDeviceSettings::setT1SLocalIDAlternateFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_t1s_termination_enabled", &IDeviceSettings::isT1STerminationEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_termination", &IDeviceSettings::setT1STerminationFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_t1s_bus_decoding_beacons_enabled", &IDeviceSettings::isT1SBusDecodingBeaconsEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_bus_decoding_beacons", &IDeviceSettings::setT1SBusDecodingBeaconsFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_t1s_bus_decoding_all_enabled", &IDeviceSettings::isT1SBusDecodingAllEnabledFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_bus_decoding_all", &IDeviceSettings::setT1SBusDecodingAllFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_multi_id_enable_mask", &IDeviceSettings::getT1SMultiIDEnableMaskFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_multi_id_enable_mask", &IDeviceSettings::setT1SMultiIDEnableMaskFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_t1s_multi_id", &IDeviceSettings::getT1SMultiIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_t1s_multi_id", &IDeviceSettings::setT1SMultiIDFor, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_misc_io_analog_output_enabled", &IDeviceSettings::setMiscIOAnalogOutputEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_misc_io_analog_output", &IDeviceSettings::setMiscIOAnalogOutput, pybind11::call_guard<pybind11::gil_scoped_release>())
// Status properties
.def_readonly("disabled", &IDeviceSettings::disabled)
.def_readonly("readonly", &IDeviceSettings::readonly);
}
} // namespace icsneo
@@ -0,0 +1,19 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/device/versionreport.h"
namespace icsneo {
void init_versionreport(pybind11::module_& m) {
pybind11::classh<VersionReport>(m, "VersionReport")
.def_readonly("id", &VersionReport::id)
.def_readonly("name", &VersionReport::name)
.def_readonly("major", &VersionReport::major)
.def_readonly("minor", &VersionReport::minor)
.def_readonly("maintenance", &VersionReport::maintenance)
.def_readonly("build", &VersionReport::build);
}
} // namespace icsneo
@@ -0,0 +1,29 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "icsneo/disk/diskdetails.h"
namespace icsneo {
void init_diskdetails(pybind11::module_& m) {
pybind11::enum_<DiskLayout>(m, "DiskLayout")
.value("Spanned", DiskLayout::Spanned)
.value("RAID0", DiskLayout::RAID0);
pybind11::classh<DiskInfo>(m, "DiskInfo")
.def(pybind11::init())
.def_readwrite("present", &DiskInfo::present)
.def_readwrite("initialized", &DiskInfo::initialized)
.def_readwrite("formatted", &DiskInfo::formatted)
.def_readwrite("sectors", &DiskInfo::sectors)
.def_readwrite("bytes_per_sector", &DiskInfo::bytesPerSector)
.def("size", &DiskInfo::size);
pybind11::classh<DiskDetails>(m, "DiskDetails")
.def(pybind11::init())
.def_readwrite("layout", &DiskDetails::layout)
.def_readwrite("full_format", &DiskDetails::fullFormat)
.def_readwrite("disks", &DiskDetails::disks);
}
} // namespace icsneo
@@ -0,0 +1,26 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/disk/diskdriver.h"
namespace icsneo {
// binding namespace workaround to avoid submodules
struct DiskNamespace {
using Access = icsneo::Disk::Access;
using MemoryType = icsneo::Disk::MemoryType;
};
void init_diskdriver(pybind11::module_& m) {
pybind11::classh<DiskNamespace> disk(m, "Disk");
pybind11::enum_<Disk::Access>(disk, "Access")
.value("None", Disk::Access::None)
.value("EntireCard", Disk::Access::EntireCard)
.value("VSA", Disk::Access::VSA);
pybind11::enum_<Disk::MemoryType>(disk, "MemoryType")
.value("Flash", Disk::MemoryType::Flash)
.value("SD", Disk::MemoryType::SD);
}
} // namespace icsneo
@@ -0,0 +1,195 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/flexray/flexraymessage.h"
#include "icsneo/device/extensions/flexray/symbol.h"
#include "icsneo/device/extensions/flexray/channel.h"
#include "icsneo/device/extensions/flexray/crcstatus.h"
#include "icsneo/device/extensions/flexray/controller.h"
namespace icsneo {
struct FlexRayNamespace {
using Symbol = icsneo::FlexRay::Symbol;
using CRCStatus = icsneo::FlexRay::CRCStatus;
using Channel = icsneo::FlexRay::Channel;
};
namespace FlexRay {
struct ClusterNamespace {
using SpeedType = icsneo::FlexRay::Cluster::SpeedType;
using SPPType = icsneo::FlexRay::Cluster::SPPType;
};
void init_extension(pybind11::classh<FlexRayNamespace>& c) {
pybind11::classh<MessageBuffer>(c, "MessageBuffer")
.def(pybind11::init())
.def_readwrite("is_dynamic", &MessageBuffer::isDynamic)
.def_readwrite("is_sync", &MessageBuffer::isSync)
.def_readwrite("is_startup", &MessageBuffer::isStartup)
.def_readwrite("is_network_management_frame", &MessageBuffer::isNetworkManagementFrame)
.def_readwrite("is_transmit", &MessageBuffer::isTransmit)
.def_readwrite("frame_id", &MessageBuffer::frameID)
.def_readwrite("channel_a", &MessageBuffer::channelA)
.def_readwrite("channel_b", &MessageBuffer::channelB)
.def_readwrite("frame_length_bytes", &MessageBuffer::frameLengthBytes)
.def_readwrite("base_cycle", &MessageBuffer::baseCycle)
.def_readwrite("cycle_repetition", &MessageBuffer::cycleRepetition)
.def_readwrite("continuous_mode", &MessageBuffer::continuousMode);
auto controller = pybind11::classh<Controller>(c, "Controller")
.def("get_network", &Controller::getNetwork)
.def("get_configuration", &Controller::getConfiguration)
.def("set_configuration", &Controller::setConfiguration)
.def("get_start_when_going_online", &Controller::getStartWhenGoingOnline)
.def("set_start_when_going_online", &Controller::setStartWhenGoingOnline)
.def("get_allow_coldstart", &Controller::getAllowColdstart)
.def("set_allow_coldstart", &Controller::setAllowColdstart)
.def("get_wakeup_before_start", &Controller::getWakeupBeforeStart)
.def("set_wakeup_before_start", &Controller::setWakeupBeforeStart)
.def("add_message_buffer", &Controller::addMessageBuffer)
.def("clear_message_buffers", &Controller::clearMessageBuffers)
.def("wakeup", &Controller::wakeup)
.def("configure", &Controller::getReady)
.def("start", &Controller::start)
.def("transmit", &Controller::transmit)
.def("halt", &Controller::halt)
.def("freeze", &Controller::freeze)
.def("trigger_mts", &Controller::triggerMTS);
pybind11::classh<Controller::Configuration>(controller, "Configuration")
.def(pybind11::init())
.def_readwrite("accept_startup_range_microticks", &Controller::Configuration::AcceptStartupRangeMicroticks)
.def_readwrite("allow_passive_to_active_cycle_pairs", &Controller::Configuration::AllowPassiveToActiveCyclePairs)
.def_readwrite("cluster_drift_damping", &Controller::Configuration::ClusterDriftDamping)
.def_readwrite("allow_halt_due_to_clock", &Controller::Configuration::AllowHaltDueToClock)
.def_readwrite("channel_a", &Controller::Configuration::ChannelA)
.def_readwrite("channel_b", &Controller::Configuration::ChannelB)
.def_readwrite("decoding_correction_microticks", &Controller::Configuration::DecodingCorrectionMicroticks)
.def_readwrite("delay_compensation_a_microticks", &Controller::Configuration::DelayCompensationAMicroticks)
.def_readwrite("delay_compensation_b_microticks", &Controller::Configuration::DelayCompensationBMicroticks)
.def_readwrite("extern_offset_correction_control", &Controller::Configuration::ExternOffsetCorrectionControl)
.def_readwrite("extern_rate_correction_control", &Controller::Configuration::ExternRateCorrectionControl)
.def_readwrite("extern_offset_correction_microticks", &Controller::Configuration::ExternOffsetCorrectionMicroticks)
.def_readwrite("extern_rate_correction_microticks", &Controller::Configuration::ExternRateCorrectionMicroticks)
.def_readwrite("key_slot_id", &Controller::Configuration::KeySlotID)
.def_readwrite("key_slot_only_enabled", &Controller::Configuration::KeySlotOnlyEnabled)
.def_readwrite("key_slot_used_for_startup", &Controller::Configuration::KeySlotUsedForStartup)
.def_readwrite("key_slot_used_for_sync", &Controller::Configuration::KeySlotUsedForSync)
.def_readwrite("latest_tx_minislot", &Controller::Configuration::LatestTxMinislot)
.def_readwrite("listen_timeout", &Controller::Configuration::ListenTimeout)
.def_readwrite("macro_initial_offset_a", &Controller::Configuration::MacroInitialOffsetA)
.def_readwrite("macro_initial_offset_b", &Controller::Configuration::MacroInitialOffsetB)
.def_readwrite("micro_initial_offset_a", &Controller::Configuration::MicroInitialOffsetA)
.def_readwrite("micro_initial_offset_b", &Controller::Configuration::MicroInitialOffsetB)
.def_readwrite("micro_per_cycle", &Controller::Configuration::MicroPerCycle)
.def_readwrite("mts_on_a", &Controller::Configuration::MTSOnA)
.def_readwrite("mts_on_b", &Controller::Configuration::MTSOnB)
.def_readwrite("offset_correction_out_microticks", &Controller::Configuration::OffsetCorrectionOutMicroticks)
.def_readwrite("rate_correction_out_microticks", &Controller::Configuration::RateCorrectionOutMicroticks)
.def_readwrite("second_key_slot_id", &Controller::Configuration::SecondKeySlotID)
.def_readwrite("two_key_slot_mode", &Controller::Configuration::TwoKeySlotMode)
.def_readwrite("wakeup_pattern", &Controller::Configuration::WakeupPattern)
.def_readwrite("wakeup_on_channel_b", &Controller::Configuration::WakeupOnChannelB);
// Dummy class for cluster namespace
pybind11::classh<ClusterNamespace> cluster(c, "Cluster");
pybind11::enum_<Cluster::SpeedType>(cluster, "SpeedType")
.value("FLEXRAY_BAUDRATE_10M", Cluster::SpeedType::FLEXRAY_BAUDRATE_10M)
.value("FLEXRAY_BAUDRATE_5M", Cluster::SpeedType::FLEXRAY_BAUDRATE_5M)
.value("FLEXRAY_BAUDRATE_2M5", Cluster::SpeedType::FLEXRAY_BAUDRATE_2M5)
.value("FLEXRAY_BAUDRATE_2M5_ALT", Cluster::SpeedType::FLEXRAY_BAUDRATE_2M5_ALT);
pybind11::enum_<Cluster::SPPType>(cluster, "SPPType")
.value("FLEXRAY_SPP_5", Cluster::SPPType::FLEXRAY_SPP_5)
.value("FLEXRAY_SPP_4", Cluster::SPPType::FLEXRAY_SPP_4)
.value("FLEXRAY_SPP_6", Cluster::SPPType::FLEXRAY_SPP_6)
.value("FLEXRAY_SPP_5_ALT", Cluster::SPPType::FLEXRAY_SPP_5_ALT);
pybind11::classh<Cluster::Configuration>(cluster, "Configuration")
.def(pybind11::init())
.def_readwrite("speed", &Cluster::Configuration::Speed)
.def_readwrite("strobe_point_position", &Cluster::Configuration::StrobePointPosition)
.def_readwrite("action_point_offset", &Cluster::Configuration::ActionPointOffset)
.def_readwrite("casr_x_low_max", &Cluster::Configuration::CASRxLowMax)
.def_readwrite("cold_start_attempts", &Cluster::Configuration::ColdStartAttempts)
.def_readwrite("cycle_duration_micro_sec", &Cluster::Configuration::CycleDurationMicroSec)
.def_readwrite("dynamic_slot_idle_phase_minislots", &Cluster::Configuration::DynamicSlotIdlePhaseMinislots)
.def_readwrite("listen_noise_macroticks", &Cluster::Configuration::ListenNoiseMacroticks)
.def_readwrite("macroticks_per_cycle", &Cluster::Configuration::MacroticksPerCycle)
.def_readwrite("macrotick_duration_micro_sec", &Cluster::Configuration::MacrotickDurationMicroSec)
.def_readwrite("max_without_clock_correction_fatal", &Cluster::Configuration::MaxWithoutClockCorrectionFatal)
.def_readwrite("max_without_clock_correction_passive", &Cluster::Configuration::MaxWithoutClockCorrectionPassive)
.def_readwrite("minislot_action_point_offset_macroticks", &Cluster::Configuration::MinislotActionPointOffsetMacroticks)
.def_readwrite("minislot_duration_macroticks", &Cluster::Configuration::MinislotDurationMacroticks)
.def_readwrite("network_idle_time_macroticks", &Cluster::Configuration::NetworkIdleTimeMacroticks)
.def_readwrite("network_management_vector_length_bytes", &Cluster::Configuration::NetworkManagementVectorLengthBytes)
.def_readwrite("number_of_minislots", &Cluster::Configuration::NumberOfMinislots)
.def_readwrite("number_of_static_slots", &Cluster::Configuration::NumberOfStaticSlots)
.def_readwrite("offset_correction_start_macroticks", &Cluster::Configuration::OffsetCorrectionStartMacroticks)
.def_readwrite("payload_length_of_static_slot_in_words", &Cluster::Configuration::PayloadLengthOfStaticSlotInWords)
.def_readwrite("static_slot_macroticks", &Cluster::Configuration::StaticSlotMacroticks)
.def_readwrite("symbol_window_macroticks", &Cluster::Configuration::SymbolWindowMacroticks)
.def_readwrite("symbol_window_action_point_offset_macroticks", &Cluster::Configuration::SymbolWindowActionPointOffsetMacroticks)
.def_readwrite("sync_frame_id_count_max", &Cluster::Configuration::SyncFrameIDCountMax)
.def_readwrite("transmission_start_sequence_duration_bits", &Cluster::Configuration::TransmissionStartSequenceDurationBits)
.def_readwrite("wakeup_rx_idle_bits", &Cluster::Configuration::WakeupRxIdleBits)
.def_readwrite("wakeup_rx_low_bits", &Cluster::Configuration::WakeupRxLowBits)
.def_readwrite("wakeup_rx_window_bits", &Cluster::Configuration::WakeupRxWindowBits)
.def_readwrite("wakeup_tx_active_bits", &Cluster::Configuration::WakeupTxActiveBits)
.def_readwrite("wakeup_tx_idle_bits", &Cluster::Configuration::WakeupTxIdleBits);
}
} // namespace FlexRay
void init_flexraymessage(pybind11::module_& m) {
pybind11::classh<FlexRayMessage, Frame>(m, "FlexRayMessage")
.def(pybind11::init())
.def_readwrite("slotid", &FlexRayMessage::slotid)
.def_readwrite("tsslen", &FlexRayMessage::tsslen)
.def_readwrite("framelen", &FlexRayMessage::framelen)
.def_readwrite("symbol", &FlexRayMessage::symbol)
.def_readwrite("header_crc_status", &FlexRayMessage::headerCRCStatus)
.def_readwrite("header_crc", &FlexRayMessage::headerCRC)
.def_readwrite("frame_crc_status", &FlexRayMessage::crcStatus)
.def_readwrite("frame_crc", &FlexRayMessage::frameCRC)
.def_readwrite("channel", &FlexRayMessage::channel)
.def_readwrite("null_frame", &FlexRayMessage::nullFrame)
.def_readwrite("payload_preamble", &FlexRayMessage::payloadPreamble)
.def_readwrite("sync_frame", &FlexRayMessage::sync)
.def_readwrite("startup_frame", &FlexRayMessage::startup)
.def_readwrite("dynamic_frame", &FlexRayMessage::dynamic)
.def_readwrite("cycle", &FlexRayMessage::cycle)
.def_readwrite("cycle_repetition", &FlexRayMessage::cycleRepetition);
//// TODO: Eliminate FlexRayControlMessage class references in controller class and eliminate getStatus function in bindings
}
void init_flexray(pybind11::module_& m) {
// Dummy class to act as FlexRay namespace
pybind11::classh<FlexRayNamespace> flexray(m, "FlexRay");
pybind11::enum_<FlexRayNamespace::Symbol>(flexray, "Symbol")
.value("None", FlexRayNamespace::Symbol::None)
.value("Unknown", FlexRayNamespace::Symbol::Unknown)
.value("Wakeup", FlexRayNamespace::Symbol::Wakeup)
.value("CAS", FlexRayNamespace::Symbol::CAS);
pybind11::enum_<FlexRayNamespace::CRCStatus>(flexray, "CRCStatus")
.value("OK", FlexRayNamespace::CRCStatus::OK)
.value("Error", FlexRayNamespace::CRCStatus::Error)
.value("NoCRC", FlexRayNamespace::CRCStatus::NoCRC);
pybind11::enum_<FlexRayNamespace::Channel>(flexray, "Channel")
.value("None", FlexRayNamespace::Channel::None)
.value("A", FlexRayNamespace::Channel::A)
.value("B", FlexRayNamespace::Channel::B)
.value("AB", FlexRayNamespace::Channel::AB);
init_flexraymessage(m);
FlexRay::init_extension(flexray);
}
} // namespace icsneo
+85
View File
@@ -0,0 +1,85 @@
#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_io(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_spimessage(pybind11::module_&);
void init_ethernetstatusmessage(pybind11::module_&);
void init_macsecconfig(pybind11::module_&);
void init_scriptstatusmessage(pybind11::module_&);
void init_diskdriver(pybind11::module_&);
void init_diskdetails(pybind11::module_&);
void init_deviceextension(pybind11::module_&);
void init_chipid(pybind11::module_&);
void init_versionreport(pybind11::module_&);
void init_device(pybind11::module_&);
void init_messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&);
void init_flexray(pybind11::module_& m);
void init_idevicesettings(pybind11::module_&);
void init_ethphymessage(pybind11::module_&);
void init_livedata(pybind11::module_&);
void init_livedatamessage(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_io(m);
init_livedata(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_macsecconfig(m);
init_scriptstatusmessage(m);
init_spimessage(m);
init_livedatamessage(m);
init_messagefilter(m);
init_messagecallback(m);
init_diskdriver(m);
init_diskdetails(m);
init_flexray(m);
init_ethphymessage(m);
init_chipid(m);
init_versionreport(m);
init_device(m);
init_deviceextension(m);
init_idevicesettings(m);
m.def("find_all_devices", &FindAllDevices);
m.def("get_supported_devices", &GetSupportedDevices);
m.def("get_last_error", &GetLastError);
}
} // namespace icsneo
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
yum install -y flex ca-certificates || exit 1
echo "$ICS_IPA_CA_CRT" >/etc/pki/ca-trust/source/anchors/ica-ipa-ca.crt
update-ca-trust || exit 1
+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
+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_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
+8 -11
View File
@@ -1,12 +1,9 @@
REM clean intermediate directories
rmdir /s /q build
mkdir build
@setlocal
@echo off
REM build
cd build
set CFLAGS=/WX
set CXXFLAGS=/WX
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_TESTS=ON ..
if %errorlevel% neq 0 exit /b %errorlevel%
cmake --build .
if %errorlevel% neq 0 exit /b %errorlevel%
mkdir build >nul 2>&1
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_UNIT_TESTS=ON ^
-DLIBICSNEO_ENABLE_TCP=ON || exit /b 1
cmake --build build || exit /b 1
+1 -1
View File
@@ -1,2 +1,2 @@
call "%VCVARS32%"
call "%VCVARS32_2022%"
call "ci\build-windows.bat"
+1 -1
View File
@@ -1,2 +1,2 @@
call "%VCVARS64%"
call "%VCVARS64_2022%"
call "ci\build-windows.bat"
+101 -54
View File
@@ -13,14 +13,19 @@
#include "icsneo/communication/message/filter/main51messagefilter.h"
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/versionmessage.h"
#include "icsneo/communication/message/componentversionsmessage.h"
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/icspb.h"
#include <commands/generic/v1/client_id.pb.h>
#include <commands/network/v1/mutex.pb.h>
using namespace icsneo;
int Communication::messageCallbackIDCounter = 1;
Communication::~Communication() {
if(redirectingRead)
clearRedirectRead();
if(isOpen())
close();
}
@@ -38,24 +43,28 @@ bool Communication::open() {
}
void Communication::spawnThreads() {
closing = false;
readTaskThread = std::thread(&Communication::readTask, this);
}
void Communication::joinThreads() {
if(pauseReadTask) {
resumeReads();
}
closing = true;
if(readTaskThread.joinable())
readTaskThread.join();
closing = false;
}
bool Communication::close() {
joinThreads();
if(!isOpen() && !isDisconnected()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
joinThreads();
return driver->close();
}
@@ -95,23 +104,6 @@ bool Communication::sendCommand(ExtendedCommand cmd, std::vector<uint8_t> argume
return sendCommand(Command::Extended, arguments);
}
bool Communication::redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo) {
if(redirectingRead)
return false;
redirectionFn = redirectTo;
redirectingRead = true;
return true;
}
void Communication::clearRedirectRead() {
if(!redirectingRead)
return;
// The mutex is required to clear the redirection, but not to set it
std::lock_guard<std::mutex> lk(redirectingReadMutex);
redirectingRead = false;
redirectionFn = std::function<void(std::vector<uint8_t>&&)>();
}
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
@@ -260,44 +252,99 @@ void Communication::dispatchMessage(const std::shared_ptr<Message>& msg) {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
}
void Communication::readTask() {
std::vector<uint8_t> readBytes;
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() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
readBytes.clear();
if(driver->readWait(readBytes)) {
handleInput(*packetizer, readBytes);
if(pauseReadTask) {
std::unique_lock<std::mutex> lk(pauseReadTaskMutex);
pauseReadTaskCv.wait(lk, [this]() { return !pauseReadTask; });
}
}
}
void Communication::handleInput(Packetizer& p, std::vector<uint8_t>& readBytes) {
if(redirectingRead) {
// redirectingRead is an atomic so it can be set without acquiring a mutex
// However, we do not clear it without the mutex. The idea is that if another
// thread calls clearRedirectRead(), it will block until the redirectionFn
// finishes, and after that the redirectionFn will not be called again.
std::unique_lock<std::mutex> lk(redirectingReadMutex);
// So after we acquire the mutex, we need to check the atomic again, and
// if it has become cleared, we *can not* run the redirectionFn.
if(redirectingRead) {
redirectionFn(std::move(readBytes));
} else {
// The redirectionFn got cleared while we were acquiring the lock
lk.unlock(); // We don't need the lock anymore
handleInput(p, readBytes); // and we might as well process this input ourselves
}
} else {
if(p.input(readBytes)) {
for(const auto& packet : p.output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue;
dispatchMessage(msg);
if(driver->waitForRx(readTaskWakeLimit, readTaskWakeTimeout)) {
if(pauseReadTask) {
/**
* Reads could have paused while the driver was not available
*/
continue;
}
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));
}
std::optional<uint32_t> Communication::getClientIDSync() {
constexpr auto timeout = std::chrono::milliseconds(250);
commands::generic::v1::ClientId msg;
msg.Clear();
std::vector<uint8_t> payload = protoapi::getPayload(protoapi::Command::GET, msg);
std::shared_ptr<Message> response = waitForMessageSync(
[this, payload](){
return sendCommand(ExtendedCommand::ProtobufAPI, payload);
},
std::make_shared<MessageFilter>(Message::Type::ClientId),
timeout
);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return std::nullopt;
}
auto clientIdMessage = std::dynamic_pointer_cast<ClientIdMessage>(response);
if(!clientIdMessage) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return std::nullopt;
}
return clientIdMessage->clientId;
}
+233 -36
View File
@@ -3,14 +3,28 @@
#include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/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/logdatamessage.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/message/networkmutexmessage.h"
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
@@ -24,6 +38,17 @@
#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 "icsneo/communication/packet/spipacket.h"
#include "icsneo/communication/icspb.h"
#include <iostream>
using namespace icsneo;
@@ -37,8 +62,9 @@ uint64_t Decoder::GetUInt64FromLEBytes(const uint8_t* bytes) {
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
switch(packet->network.getType()) {
case Network::Type::Ethernet: {
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
case Network::Type::Ethernet:
case Network::Type::AutomotiveEthernet: {
result = HardwareEthernetPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
@@ -76,7 +102,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
break;
}
case Message::Type::CANErrorCount: {
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get());
CANErrorMessage& can = *static_cast<CANErrorMessage*>(result.get());
can.network = packet->network;
break;
}
@@ -138,6 +164,57 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
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::SPI: {
result = HardwareSPIPacket::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
}
SPIMessage& msg = *static_cast<SPIMessage*>(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;
}
case Network::Type::Internal: {
switch(packet->network.getNetID()) {
case Network::NetID::Reset_Status: {
@@ -182,21 +259,26 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true;
}
result = HardwareCANPacket::DecodeToMessage(packet->data);
if(!result) {
const auto can = std::dynamic_pointer_cast<CANMessage>(HardwareCANPacket::DecodeToMessage(packet->data));
if(!can) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
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;
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
auto* raw = dynamic_cast<RawMessage*>(result.get());
if(raw == nullptr) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
raw->timestamp *= timestampResolution;
raw->network = packet->network;
result->timestamp = can->timestamp * timestampResolution;
return true;
}
case Network::NetID::DeviceStatus: {
@@ -204,6 +286,18 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = std::make_shared<RawMessage>(packet->network, packet->data);
return true;
}
case Network::NetID::RED_INT_MEMORYREAD: {
if(packet->data.size() != 512 + sizeof(uint16_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<FlashMemoryMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint16_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 2, packet->data.end());
return true;
}
case Network::NetID::NeoMemorySDRead: {
if(packet->data.size() != 512 + sizeof(uint32_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
@@ -217,16 +311,100 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true;
}
case Network::NetID::ExtendedCommand: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse))
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::PackedGenericResponse*>(packet->data.data());
if(resp.header.command != ExtendedCommand::GenericReturn)
break; // Handle as a raw message
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::SoftwareUpdate: {
result = std::make_shared<ExtendedResponseMessage>(ExtendedCommand::SoftwareUpdate, ExtendedResponse::OperationPending, 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, packet->data);
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;
}
case ExtendedCommand::ProtobufAPI: {
// get the proto id
std::vector<uint8_t> responseBody(
packet->data.begin() + sizeof(ExtendedResponseMessage::ResponseHeader),
packet->data.end()
);
protoapi::Id protoId = protoapi::getProtoId(responseBody.data(), responseBody.size());
switch(protoId) {
case protoapi::Id::NetworkMutex:
result = NetworkMutexMessage::DecodeToMessage(responseBody);
return true;
case protoapi::Id::ClientId:
result = ClientIdMessage::DecodeToMessage(responseBody);
return true;
default:
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
}
case ExtendedCommand::GetDiskDetails:
case ExtendedCommand::DiskFormatProgress: {
std::vector<uint8_t> responseBody(
packet->data.begin() + sizeof(ExtendedResponseMessage::ResponseHeader),
packet->data.end()
);
auto response = std::make_shared<ExtendedResponseMessage>(resp.command);
response->data = std::move(responseBody);
result = response;
return true;
}
default:
// No defined handler, treat this as a RawMessage
break;
}
break;
}
case Network::NetID::ExtendedData: {
if(packet->data.size() < sizeof(ExtendedDataMessage::ExtendedDataHeader))
break;
const auto& header = *reinterpret_cast<ExtendedDataMessage::ExtendedDataHeader*>(packet->data.data());
const auto msg = std::make_shared<ExtendedResponseMessage>(resp.command, resp.returnCode);
result = msg;
return true;
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);
@@ -271,6 +449,16 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true;
}
case Command::GetHardwareInfo: {
result = HardwareInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
default:
auto msg = std::make_shared<Main51Message>();
msg->command = Command(packet->data[0]);
@@ -294,6 +482,14 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
packet->data.resize(length);
return decode(result, packet);
}
case Network::NetID::RED_App_Error: {
result = AppErrorMessage::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::ReadSettings: {
auto msg = std::make_shared<ReadSettingsMessage>();
msg->response = ReadSettingsMessage::Response(packet->data[0]);
@@ -345,26 +541,27 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
}
return true;
}
case Network::NetID::DiskData: {
result = std::make_shared<DiskDataMessage>(std::move(packet->data));
return true;
}
case Network::NetID::Data_To_Host: {
result = LogDataMessage::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
default:
break;
}
break;
}
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;
return true;
}
}
// For the moment other types of messages will automatically be decoded as raw messages
result = std::make_shared<RawMessage>(packet->network, packet->data);
return true;
}
}
+34 -23
View File
@@ -8,37 +8,44 @@
using namespace icsneo;
bool Driver::read(std::vector<uint8_t>& bytes, size_t limit) {
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
bool Driver::pushRx(const uint8_t* buf, size_t numReceived) {
bool ret = readBuffer.write(buf, numReceived);
if(limit > (readQueue.size_approx() + 4))
limit = (readQueue.size_approx() + 4);
rxWaitCv.notify_all();
if(bytes.capacity() < limit)
bytes.resize(limit);
return ret;
}
size_t actuallyRead = readQueue.try_dequeue_bulk(bytes.data(), limit);
void Driver::clearBuffers()
{
WriteOperation flushop;
if(bytes.size() > actuallyRead)
bytes.resize(actuallyRead);
readBuffer.clear();
rxWaitCv.notify_all();
return true;
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;
// wait until we have enough data, or the timeout occurs
waitForRx(limit, timeout);
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);
size_t actuallyRead = readBuffer.size();
bytes.resize(actuallyRead);
readBuffer.read(bytes.data(), 0, actuallyRead);
readBuffer.pop(actuallyRead);
bytes.resize(actuallyRead);
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
@@ -64,8 +71,12 @@ bool Driver::write(const std::vector<uint8_t>& bytes) {
if(writeBlocks) {
if(writeQueueFull()) {
while(writeQueueAlmostFull()) // Wait until we have some decent amount of space
while(writeQueueAlmostFull() && !isDisconnected() && !isClosing()) // Wait until we have some decent amount of space
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if(isDisconnected() || isClosing()) {
return false;
}
}
} else {
if(writeQueueFull()) {
@@ -79,4 +90,4 @@ bool Driver::write(const std::vector<uint8_t>& bytes) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return ret;
}
}
+72 -7
View File
@@ -1,6 +1,8 @@
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/main51message.h"
#include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/canpacket.h"
@@ -9,7 +11,9 @@
#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"
#include "icsneo/communication/packet/spipacket.h"
using namespace icsneo;
@@ -28,19 +32,31 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
netid = uint16_t(frame->network.getNetID());
switch(frame->network.getType()) {
case Network::Type::Ethernet: {
case Network::Type::Ethernet:
case Network::Type::AutomotiveEthernet: {
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
return false;
}
shortFormat = false; // Ensure long-format RED header is added
netid = static_cast<uint16_t>(Network::NetID::ETHERNET_TX_WRAP);
buffer = &result;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report)) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
if(result.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
break;
} // End of Network::Type::Ethernet
}
case Network::Type::Internal:
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
@@ -96,6 +112,41 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
}
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
case Network::Type::SPI: {
auto msg = std::dynamic_pointer_cast<SPIMessage>(message);
if(!msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed LiveDataMessage
}
if(!HardwareSPIPacket::EncodeFromMessage(*msg, result, report))
return false;
result = packetizer.packetWrap(result, false);
return true;
} // End of Network::Type::SPI
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
@@ -172,6 +223,17 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
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;
}
@@ -182,7 +244,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
// Size for the host-to-device long format is the size of the entire packet + 1
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
// Then an extra +1, due to a firmware idiosyncrasy
uint16_t size = uint16_t(buffer->size()) + 1 + 1 + 2 + 2 + 1;
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)size, // Size, little endian 16-bit
@@ -191,7 +254,6 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
(uint8_t)(netid >> 8)
});
}
result = packetizer.packetWrap(*buffer, shortFormat);
return true;
}
@@ -223,9 +285,12 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
case Command::RequestSerialNumber:
case Command::EnableNetworkCommunication:
case Command::EnableNetworkCommunicationEx:
case Command::KeepAlive:
case Command::GetMainVersion:
case Command::GetSecondaryVersions:
case Command::NeoReadMemory:
case Command::ClearCoreMini:
case Command::LoadCoreMini:
// There is a firmware handling idiosyncrasy with these commands
// They must be encoded in the short format
m51msg->forceShortFormat = true;
+80
View File
@@ -0,0 +1,80 @@
#include "icsneo/communication/livedata.h"
#include <cmath>
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;
}
std::optional<LiveDataValue> liveDataDoubleToValue(const double& dFloat) {
LiveDataValue value;
union {
struct
{
uint32_t ValueFractionPart;
int32_t ValueInt32;
} parts;
int64_t ValueLarge;
} CminiFixedPt;
constexpr double CM_FIXED_POINT_TO_DOUBLEVALUE = (1.0 / (double)(1ULL << 32)); // 2^-32
constexpr double CM_DOUBLEVALUE_TO_FIXED_POINT = ((double)(1ULL << 32)); // 2^32
// Use const for limits (C++98 compatible)
const double INT32_MAX_DOUBLE =
static_cast<double>(std::numeric_limits<int32_t>::max()) + (1.0 - std::numeric_limits<double>::epsilon());
const double INT32_MIN_DOUBLE = static_cast<double>(std::numeric_limits<int32_t>::min());
const double MIN_FIXED_POINT_DOUBLE = (double)(1ull * CM_FIXED_POINT_TO_DOUBLEVALUE);
// This needs to be assigned separately, otherwise, for dFloat >= 2^31,
// long double dBigFloat = dFloat * CM_DOUBLEVALUE_TO_FIXED_POINT overflows
// long long (value is >= 2^63) and so the assignment ValueLarge = dBigFloat is undefined
int32_t intPart; //creating temp variable due to static analysis warning about writing and reading to different union members
if(dFloat < 0.0)
intPart = (int32_t)std::floor(dFloat);
else
intPart = (int32_t)dFloat;
//using temp varialbes to avoid static analysis warning about read/write to different union members
double frac = dFloat - (double)(intPart);
uint32_t fracPart = (uint32_t)std::floor((frac * CM_DOUBLEVALUE_TO_FIXED_POINT) + 0.5);
//write temp vars back into the union
CminiFixedPt.parts.ValueInt32 = intPart;
CminiFixedPt.parts.ValueFractionPart = fracPart;
value.value = CminiFixedPt.ValueLarge;
if(dFloat == (double)0.0)
return value;
//check if double can be stored as 32.32
// 0x1 0000 0000 0000 0000 * CM_FIXED_POINT_TO_DOUBLEVALUE = 0x1 0000 0000
if(dFloat > INT32_MAX_DOUBLE || dFloat < INT32_MIN_DOUBLE) {
EventManager::GetInstance().add(APIEvent::Type::FixedPointOverflow, APIEvent::Severity::Error);
return std::nullopt;
}
// Use absolute value for minimum fixed point check
double absFloat = (dFloat < 0.0) ? -dFloat : dFloat;
if(absFloat < MIN_FIXED_POINT_DOUBLE) {
EventManager::GetInstance().add(APIEvent::Type::FixedPointPrecision, APIEvent::Severity::Error);
return std::nullopt;
}
return value;
}
} // 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
@@ -1,100 +1,234 @@
#include "icsneo/communication/message/callback/streamoutput/a2bwavoutput.h"
#include "icsneo/device/tree/rada2b/rada2b.h"
#include "icsneo/icsneocpp.h"
namespace icsneo
{
namespace icsneo {
void A2BWAVOutput::writeHeader(const std::shared_ptr<A2BMessage>& firstMsg) const {
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;
}
WaveFileHeader header = WaveFileHeader(2 * firstMsg->getNumChannels(), wavSampleRate, firstMsg->getBitDepth());
header.write(stream);
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(closed)
{
if(!initialized) {
return false;
}
if(message->type != Message::Type::Frame)
return false;
const auto& frame = std::static_pointer_cast<Frame>(message);
if(frame->network.getType() != Network::Type::A2B)
return false;
const auto& a2bmsg = std::static_pointer_cast<A2BMessage>(frame);
if(firstMessageFlag) {
writeHeader(a2bmsg);
firstMessageFlag = false;
}
if(!writeSamples(a2bmsg, A2BMessage::A2BDirection::DownStream)) {
close();
if(closed) {
return false;
}
if(!writeSamples(a2bmsg, A2BMessage::A2BDirection::UpStream)) {
close();
if(message->type != Message::Type::Frame) {
return false;
}
const auto& frameMsg = std::dynamic_pointer_cast<Frame>(message);
if(!frameMsg) {
return false;
}
if(frameMsg->network.getType() != Network::Type::A2B)
return false;
const auto& a2bMsg = std::dynamic_pointer_cast<A2BMessage>(frameMsg);
if(!a2bMsg) {
return false;
}
size_t frameSize = a2bMsg->getFrameSize();
size_t wavFrameSize = numChannelsWAV * bytesPerSampleWAV;
size_t bytesPerChannel = static_cast<size_t>(a2bMsg->getBytesPerChannel());
size_t numMessageChannels = 2 * a2bMsg->numChannels;
size_t numFrames = a2bMsg->getNumFrames();
const uint8_t* audioBuffer = a2bMsg->data.data();
if(maxMessageChannel >= numMessageChannels) {
// The max message channel in our channel map is larger than the number of channels in this message
// this is likely due to the user inputting incorrect settings
return false;
}
for(size_t frame = 0; frame < numFrames; frame++) {
// Check to see if we can read another frame in wavBuffer, otherwise write and clear the buffer
if(wavBufferOffset + wavFrameSize >= wavBufferSize) {
if(!writeCurrentBuffer()) {
return false;
}
}
for(size_t wavChannel = 0; wavChannel < numChannelsWAV; wavChannel++) {
if(auto iter = chMap.find(static_cast<uint8_t>(wavChannel)); iter != chMap.end()) {
auto messageChannel = iter->second;
size_t messageChannelOffset = messageChannel * bytesPerChannel + frameSize* frame;
// Samples in the WAV are little endian signed integers
// Samples in the message channels are little endian signed integers that are
// most significant bit aligned
if(a2bMsg->channelSize16) {
// In this case, the channel size will be less than or equal to the sample we are writing
// so we zero out any of the least significant bytes which won't be occupied by a sample byte
for(size_t zeroByte = 0; zeroByte < bytesPerSampleWAV - bytesPerChannel; zeroByte++) {
wavBuffer[wavBufferOffset++] = 0;
}
// Write the channel data in the most signifant bytes of the wav sample, this effectively
// writes a sample which is scaled up.
for(size_t channelByte = 0; channelByte < bytesPerChannel; channelByte++) {
wavBuffer[wavBufferOffset++] = audioBuffer[messageChannelOffset + channelByte];
}
} else {
// In this case, the channel size will be greater than or equal to the sample we are reading
// Align the wav sample with the most significant bytes of the channel
size_t channelByte = messageChannelOffset + (bytesPerChannel - bytesPerSampleWAV);
// Read the most significant bytes of the channel into the wavBuffer
for(size_t sampleByte = 0; sampleByte < bytesPerSampleWAV; sampleByte++, channelByte++) {
wavBuffer[wavBufferOffset++] = audioBuffer[channelByte];
}
}
} else {
// If this channel wasn't specified in the channel map, set a zero sample
for(
size_t sampleByte = 0;
sampleByte < bytesPerSampleWAV;
sampleByte++
) {
wavBuffer[wavBufferOffset++] = 0;
}
}
}
}
return true;
}
void A2BWAVOutput::close() const
{
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);
write((void*)&subChunk2Size, 4);
stream->write(reinterpret_cast<const char*>(&subChunk2Size), 4);
stream->seekp(4, std::ios::beg);
write((void*)&chunkSize, 4);
stream->write(reinterpret_cast<const char*>(&chunkSize), 4);
closed = true;
}
bool A2BWAVOutput::writeSamples(const std::shared_ptr<A2BMessage>& msg, A2BMessage::A2BDirection dir) const
{
uint8_t numChannels = msg->getNumChannels();
bool A2BWAVOutput::writeCurrentBuffer() const {
uint8_t channel = 0;
uint32_t frame = 0;
uint8_t bitDepth = msg->getBitDepth();
while(true) {
auto sample = msg->getSample(dir, channel, frame);
if(!sample) {
if(channel == 0) {
break;
}
return false;
}
uint32_t audioSample = sample.value() >> (32 - bitDepth);
write((void*)(&audioSample), A2BPCM_SAMPLE_SIZE);
channel = (channel + 1) % numChannels;
if(channel == 0) {
frame++;
}
if(!stream->write(reinterpret_cast<const char*>(wavBuffer.data()), wavBufferOffset)) {
return false;
}
wavBufferOffset = 0;
return true;
}
}
+21
View File
@@ -0,0 +1,21 @@
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/icspb.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
using namespace icsneo;
std::shared_ptr<ClientIdMessage> ClientIdMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
ClientIdMessage decoded;
commands::generic::v1::ClientId msg;
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
return nullptr;
}
if(msg.has_client_id()) {
decoded.clientId.emplace(msg.client_id());
}
return std::make_shared<ClientIdMessage>(decoded);
}
@@ -0,0 +1,80 @@
#include "icsneo/communication/message/ethernetstatusmessage.h"
using namespace icsneo;
#pragma pack(push, 1)
enum LinkSpeed {
ethSpeed10,
ethSpeed100,
ethSpeed1000,
ethSpeedAutoNeg,
ethSpeed2500,
ethSpeed5000,
ethSpeed10000,
};
enum TLinkMode {
T_LINK_NONE,
T_LINK_MASTER,
T_LINK_SLAVE,
T_LINK_AUTO,
T_LINK_INVALID = 255,
};
enum AELinkMode {
AE_LINK_AUTO,
AE_LINK_MASTER,
AE_LINK_SLAVE,
AE_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(Network::GetTypeOfNetID((Network::NetID)packet->network, false)) {
case Network::Type::Ethernet:
switch(packet->mode) {
case T_LINK_NONE: mode = EthernetStatusMessage::LinkMode::LinkModeNone; break;
case T_LINK_MASTER: mode = EthernetStatusMessage::LinkMode::LinkModeMaster; break;
case T_LINK_SLAVE: mode = EthernetStatusMessage::LinkMode::LinkModeSlave; break;
case T_LINK_AUTO: mode = EthernetStatusMessage::LinkMode::LinkModeAuto; break;
case T_LINK_INVALID: mode = EthernetStatusMessage::LinkMode::LinkModeInvalid; break;
default: return nullptr;
}
break;
case Network::Type::AutomotiveEthernet:
switch(packet->mode) {
case AE_LINK_AUTO: mode = EthernetStatusMessage::LinkMode::LinkModeAuto; break;
case AE_LINK_MASTER: mode = EthernetStatusMessage::LinkMode::LinkModeMaster; break;
case AE_LINK_SLAVE: mode = EthernetStatusMessage::LinkMode::LinkModeSlave; break;
case AE_LINK_INVALID: mode = EthernetStatusMessage::LinkMode::LinkModeInvalid; break;
default: return nullptr;
}
break;
default: return nullptr;
}
return std::make_shared<EthernetStatusMessage>(packet->network, packet->state, speed, packet->duplex, mode);
}
+9 -9
View File
@@ -8,7 +8,7 @@ bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t ph
msg->Clause45Enable = clause45;
msg->Enabled = enabled;
msg->WriteEnable = writeEnable;
msg->version = 1u;
msg->Version = 1u;
if( (FiveBits < phyAddrOrPort) ||
(clause45 && (FiveBits < pageOrDevice)) ||
(!clause45 && (FiveBits < regAddr)) )
@@ -18,17 +18,17 @@ bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t ph
if(clause45)
{
msg->clause45.port = phyAddrOrPort;
msg->clause45.device = pageOrDevice;
msg->clause45.regAddr = regAddr;
msg->clause45.regVal = regVal;
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;
msg->Clause22.phyAddr = phyAddrOrPort;
msg->Clause22.page = pageOrDevice;
msg->Clause22.regAddr = regAddr;
msg->Clause22.regVal = regVal;
}
return appendPhyMessage(msg);
}
@@ -8,9 +8,8 @@ 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
const uint16_t size = static_cast<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));
+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
+25
View File
@@ -0,0 +1,25 @@
#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;
}
void LiveDataSetValueMessage::appendSetValue(LiveDataValueType valueType, const LiveDataValue& value) {
auto& arg = args.emplace_back(std::make_shared<LiveDataArgument>());
arg->objectType = LiveDataObjectType::MISC;
arg->objectIndex = 0u;
arg->signalIndex = 0u;
arg->valueType = valueType;
values.push_back(std::make_shared<LiveDataValue>(value));
}
} // namespace icsneo
+12
View File
@@ -0,0 +1,12 @@
#include "icsneo/communication/message/logdatamessage.h"
#include <iostream>
using namespace icsneo;
std::shared_ptr<LogDataMessage> LogDataMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() % 2 != 0)
return nullptr;
const auto* begin = (char16_t*)bytestream.data();
const auto* end = begin + (bytestream.size() / sizeof(char16_t));
return std::make_shared<LogDataMessage>(std::wstring(begin,end));
}
+99 -5
View File
@@ -1,7 +1,8 @@
#include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h"
using namespace icsneo;
@@ -17,6 +18,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<Frame>(message);
const auto netType = framemsg->network.getType();
frame.netid = (neonetid_t)framemsg->network.getNetID();
frame.type = (neonettype_t)netType;
frame.description = framemsg->description;
@@ -42,17 +44,61 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
can.status.canfdESI = canmsg->errorStateIndicator;
break;
}
case Network::Type::Ethernet: {
case Network::Type::Ethernet:
case Network::Type::AutomotiveEthernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags;
eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcsAvailable;
//eth.status.xyz = ethmsg->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, // .txChecksumEnhanced
linmsg->statusFlags.TxCommander, // .txCommander
linmsg->statusFlags.TxResponder, // .txResponder
0, // .txAborted
linmsg->statusFlags.UpdateResponderOnce, // .updateResponderOnce
linmsg->statusFlags.HasUpdatedResponderOnce, // .hasUpdatedResponderOnce
linmsg->statusFlags.BusRecovered, // .busRecovered
linmsg->statusFlags.BreakOnly // .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;
@@ -61,7 +107,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
}
case Message::Type::CANErrorCount: {
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message);
auto canerrormsg = std::static_pointer_cast<CANErrorMessage>(message);
canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
canerror.status.canBusOff = canerrormsg->busOff;
@@ -97,7 +143,8 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
canmsg->errorStateIndicator = can.status.canfdESI;
return canmsg;
}
case Network::Type::Ethernet: {
case Network::Type::Ethernet:
case Network::Type::AutomotiveEthernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
auto ethmsg = std::make_shared<EthernetMessage>();
ethmsg->network = network;
@@ -105,6 +152,53 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
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;
@@ -0,0 +1,89 @@
#include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/icspb.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
using namespace icsneo;
std::shared_ptr<NetworkMutexMessage> NetworkMutexMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
NetworkMutexMessage decoded;
commands::network::v1::NetworkMutex msg;
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
return nullptr;
}
if(msg.has_client_id()) {
decoded.owner_id.emplace(msg.client_id());
}
if(msg.has_type()) {
decoded.type.emplace(static_cast<NetworkMutexType>(msg.type()));
}
if(msg.has_priority()) {
decoded.priority.emplace(msg.priority());
}
if(msg.has_ttl()){
decoded.ttlMs.emplace(msg.ttl());
}
if(msg.has_event()){
decoded.event.emplace(static_cast<NetworkMutexEvent>(msg.event()));
}
for(int i = 0 ; i < msg.network_ids_size(); ++i){
decoded.networks.emplace(static_cast<Network::NetID>(msg.network_ids(i)));
}
return std::make_shared<NetworkMutexMessage>(decoded);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForLock(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const std::set<Network::NetID>& networks, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
for(auto&& network_id : networks) {
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network_id));
}
msg.set_client_id(client_id);
msg.set_priority(priority);
msg.set_ttl(ttlMs);
msg.set_type(static_cast<commands::network::v1::MutexType>(type));
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForLockAll(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.set_client_id(client_id);
msg.set_priority(priority);
msg.set_ttl(ttlMs);
msg.set_type(static_cast<commands::network::v1::MutexType>(type));
msg.set_global(true);
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForUnlock(uint32_t client_id, const std::set<Network::NetID>& networks, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.Clear();
for(auto&& network_id : networks)
{
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network_id));
}
msg.set_client_id(client_id);
msg.set_release(true);
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForUnlockAll(uint32_t client_id, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.Clear();
msg.set_client_id(client_id);
msg.set_release(true);
msg.set_global(true);
return protoapi::getPayload(protoapi::Command::PUT, msg);
}
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForStatus(Network::NetID network, const device_eventhandler_t& /* report */) {
commands::network::v1::NetworkMutex msg;
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network));
return protoapi::getPayload(protoapi::Command::GET, msg);
}
@@ -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);
}
+201
View File
@@ -0,0 +1,201 @@
#include "icsneo/communication/message/transmitmessage.h"
// packet defs
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/linpacket.h"
using namespace icsneo;
static std::vector<uint8_t> EncodeFromMessageEthernet(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(frame);
if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
std::vector<uint8_t> encoded;
size_t messageLen = ethmsg->data.size();
encoded.resize(sizeof(TransmitMessage) + messageLen);
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareEthernetPacket* const ethpacket = (HardwareEthernetPacket*)(msg->commonHeader);
uint8_t* const payload = encoded.data() + sizeof(TransmitMessage);
ethpacket->header.ENABLE_PADDING = ethmsg->noPadding ? 0 : 1;
ethpacket->header.FCS_OVERRIDE = ethmsg->fcs ? 1 : 0;
ethpacket->eid.txlen = static_cast<uint16_t>(messageLen);
ethpacket->Length = static_cast<uint16_t>(messageLen);
ethpacket->stats = ethmsg->description;
ethpacket->NetworkID = static_cast<uint16_t>(ethmsg->network.getNetID());
std::copy(ethmsg->data.begin(), ethmsg->data.end(), payload);
return encoded;
}
static std::vector<uint8_t> EncodeFromMessageCAN(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(frame);
if(!canmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
if(canmsg->isCANFD && canmsg->isRemote) {
report(APIEvent::Type::RTRNotSupported, APIEvent::Severity::Error);
return {}; // RTR frames can not be used with CAN FD
}
std::vector<uint8_t> encoded;
size_t messageLen = canmsg->data.size();
size_t extraLen = 0;
if(messageLen > 8) {
extraLen = messageLen - 8;
}
encoded.resize(sizeof(TransmitMessage) + extraLen);
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareCANPacket* const canpacket = (HardwareCANPacket*)(msg->commonHeader);
uint8_t* const extra_payload = encoded.data() + sizeof(TransmitMessage);
const size_t dataSize = canmsg->data.size();
std::optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, canmsg->isCANFD);
if(!dlc.has_value()) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return {}; // Too much data for the protocol
}
// arb id
if(canmsg->isExtended) {
canpacket->header.IDE = 1;
canpacket->header.SID = (canmsg->arbid >> 18) & 0x7FF;
canpacket->eid.EID = (canmsg->arbid >> 6) & 0xfff;
canpacket->dlc.EID2 = canmsg->arbid & 0x3f;
} else {
canpacket->header.IDE = 0;
canpacket->header.SID = canmsg->arbid & 0x7FF;
}
// DLC
canpacket->dlc.DLC = dlc.value();
// FDF/BRS or remote frames
if(canmsg->isCANFD) {
canpacket->header.EDL = 1;
canpacket->header.BRS = canmsg->baudrateSwitch ? 1 : 0;
canpacket->header.ESI = canmsg->errorStateIndicator ? 1 : 0;
canpacket->dlc.RTR = 0;
canpacket->timestamp.IsExtended = 1;
} else {
canpacket->header.EDL = 0;
canpacket->header.BRS = 0;
canpacket->header.ESI = 0;
canpacket->dlc.RTR = canmsg->isRemote ? 1 : 0;
}
// network
canpacket->NetworkID = static_cast<uint16_t>(canmsg->network.getNetID());
canpacket->Length = static_cast<uint16_t>(extraLen);
// description id
canpacket->stats = canmsg->description;
// first 8 bytes
std::copy(canmsg->data.begin(), canmsg->data.begin() + (messageLen > 8 ? 8 : messageLen), canpacket->data);
// extra bytes
if(extraLen > 0) {
// copy extra data after the can packet
std::copy(canmsg->data.begin() + 8, canmsg->data.end(), extra_payload);
}
return encoded;
}
static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
auto linmsg = std::dynamic_pointer_cast<LINMessage>(frame);
if(!linmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return {};
}
if(linmsg->linMsgType == LINMessage::Type::NOT_SET) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return {};
}
size_t dataLen = std::min<size_t>(8, linmsg->data.size());
std::vector<uint8_t> encoded;
encoded.resize(sizeof(TransmitMessage));
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
HardwareLINPacket* const linpacket = (HardwareLINPacket*)(msg->commonHeader);
memset(linpacket, 0, sizeof(HardwareLINPacket));
// Protected ID and ID
linmsg->protectedID = linmsg->calcProtectedID(linmsg->ID);
linpacket->CoreMiniBitsLIN.ID = linmsg->protectedID & 0x3F;
// LIN message type flags
switch(linmsg->linMsgType) {
case LINMessage::Type::LIN_COMMANDER_MSG:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
break;
case LINMessage::Type::LIN_HEADER_ONLY:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
break;
case LINMessage::Type::LIN_UPDATE_RESPONDER:
linpacket->CoreMiniBitsLIN.TXResponder = 1;
break;
case LINMessage::Type::LIN_BREAK_ONLY:
linpacket->CoreMiniBitsLIN.BreakOnly = 1;
break;
default:
break;
}
// Enhanced checksum
linpacket->CoreMiniBitsLIN.TxChkSumEnhanced = linmsg->isEnhancedChecksum ? 1 : 0;
// Data and checksum
bool hasData = (linmsg->linMsgType == LINMessage::Type::LIN_COMMANDER_MSG ||
linmsg->linMsgType == LINMessage::Type::LIN_UPDATE_RESPONDER) && dataLen > 0;
if(hasData) {
// len includes data bytes + 1 checksum byte
linpacket->CoreMiniBitsLIN.len = static_cast<uint16_t>(dataLen + 1);
std::copy(linmsg->data.begin(), linmsg->data.begin() + dataLen, linpacket->data);
// Checksum goes after data: in data[dataLen] if < 8, otherwise in LINByte9
if(dataLen < 8)
linpacket->data[dataLen] = linmsg->checksum;
else
linpacket->CoreMiniBitsLIN.LINByte9 = linmsg->checksum;
} else {
linpacket->CoreMiniBitsLIN.len = 0;
}
// Description/stats and network
linpacket->stats = linmsg->description;
return encoded;
}
std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> frame, uint32_t client_id, const device_eventhandler_t& report) {
std::vector<uint8_t> result;
switch(frame->network.getType()) {
case Network::Type::Ethernet:
case Network::Type::AutomotiveEthernet:
result = EncodeFromMessageEthernet(frame, report);
break;
case Network::Type::Internal:
case Network::Type::CAN:
result = EncodeFromMessageCAN(frame, report);
break;
case Network::Type::LIN:
result = EncodeFromMessageLIN(frame, report);
break;
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return result;
}
// common fields
if(result.empty())
return result;
TransmitMessage* const msg = (TransmitMessage*)result.data();
msg->options.clientId = client_id;
msg->options.networkId = static_cast<uint32_t>(frame->network.getNetID());
msg->options.reserved[0] = 0;
msg->options.reserved[1] = 0;
msg->options.reserved[2] = 0;
return result;
}
+22 -10
View File
@@ -9,7 +9,7 @@ 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) {
Communication(err, std::move(com), makeConfiguredPacketizer, std::move(e), std::move(md)), numVnets(vnetCount), packetRB(2048) {
vnetThreads.resize(numVnets);
vnetQueues.resize(numVnets);
}
@@ -24,6 +24,7 @@ void MultiChannelCommunication::spawnThreads() {
void MultiChannelCommunication::joinThreads() {
closing = true;
ringBufCV.notify_all();
if(hidReadThread.joinable())
hidReadThread.join();
for(auto& thread : vnetThreads) {
@@ -148,9 +149,13 @@ void MultiChannelCommunication::hidReadTask() {
break;
}
if(!currentQueue->enqueue(std::move(payloadBytes)) && gotPacket)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
payloadBytes.clear();
{
std::unique_lock lk(ringBufMutex);
if(!packetRB.write(std::move(payloadBytes)) && gotPacket)
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
payloadBytes.clear();
}
ringBufCV.notify_all();
gotPacket = true;
state = PreprocessState::SearchForCommand;
break;
@@ -160,7 +165,6 @@ void MultiChannelCommunication::hidReadTask() {
}
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;
@@ -174,11 +178,19 @@ void MultiChannelCommunication::vnetReadTask(size_t vnetIndex) {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
if(queue.wait_dequeue_timed(payloadBytes, std::chrono::milliseconds(250))) {
if(closing)
break;
handleInput(*vnetPacketizer, payloadBytes);
std::unique_lock lk(ringBufMutex);
ringBufCV.wait(lk);
if(closing) {
break;
}
if(vnetPacketizer->input(packetRB)) {
for(const auto& packet : vnetPacketizer->output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet))
continue;
dispatchMessage(msg);
}
}
}
}
+25 -128
View File
@@ -1,161 +1,58 @@
#include "icsneo/communication/packet/a2bpacket.h"
#include <cstring>
#include <vector>
namespace icsneo {
const size_t HardwareA2BPacket::coreMiniMessageHeaderSize = 28;
const size_t HardwareA2BPacket::a2bMessageMaxLength = (size_t)HardwareA2BPacket::coreMiniMessageHeaderSize + 1024;
const size_t HardwareA2BPacket::a2bHeaderSize = 6;
const size_t HardwareA2BPacket::a2bMessageMaxLength = sizeof(HardwareA2BPacket) + 1024;
std::shared_ptr<Message> HardwareA2BPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < coreMiniMessageHeaderSize)
if(bytestream.size() < sizeof(HardwareA2BPacket))
{
return nullptr;
}
auto getSampleFromBytes = [](uint8_t bytesPerSample, const uint8_t *bytes) {
A2BPCMSample result = 0;
for(auto i = 0; i < bytesPerSample; i++) {
result |= static_cast<uint32_t>(bytes[i]) << (i * 8);
}
const HardwareA2BPacket* data = (const HardwareA2BPacket*)bytestream.data();
return result;
};
size_t totalPackedLength = static_cast<size_t>(bytestream.size()) - sizeof(HardwareA2BPacket); // First 28 bytes are message header.
if(totalPackedLength == 0) {
return nullptr;
}
const HardwareA2BPacket *data = (const HardwareA2BPacket*)bytestream.data();
std::shared_ptr<A2BMessage> msg = std::make_shared<A2BMessage>();
uint32_t totalPackedLength = static_cast<uint32_t>(bytestream.size()) - static_cast<uint32_t>(coreMiniMessageHeaderSize); // First 28 bytes are message header.
uint8_t bytesPerChannel = data->header.channelSize16 ? 2 : 4;
uint8_t numChannels = data->header.channelNum;
uint8_t bitDepth = data->header.channelSize16 ? A2BPCM_L16 : A2BPCM_L24;
std::shared_ptr<A2BMessage> msg = std::make_shared<A2BMessage>(bitDepth, bytesPerChannel, numChannels);
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;
const uint8_t *bytes = bytestream.data();
bytes+=coreMiniMessageHeaderSize;
uint8_t channel = 0;
for(uint32_t i = 0; i < totalPackedLength; i += 2 * static_cast<uint32_t>(bytesPerChannel), bytes += 2 * bytesPerChannel, channel = (channel + 1) % numChannels) {
msg->addSample(
getSampleFromBytes(bytesPerChannel, bytes),
A2BMessage::A2BDirection::DownStream,
channel
);
msg->addSample(
getSampleFromBytes(bytesPerChannel, bytes + bytesPerChannel),
A2BMessage::A2BDirection::UpStream,
channel
);
}
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) {
bool HardwareA2BPacket::EncodeFromMessage(const A2BMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& /*report*/) {
constexpr size_t a2btxMessageHeaderSize = 6;
if(message.getBytesPerSample() != 2 && message.getBytesPerSample() != 4) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
size_t audioBufferSize = message.data.size();
size_t totalSize = a2btxMessageHeaderSize + audioBufferSize;
size_t sampleBytes = message.getNumSamples() * static_cast<size_t>(message.getBytesPerSample());
size_t totalSize = coreMiniMessageHeaderSize + sampleBytes;
if(totalSize > a2bMessageMaxLength) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
bytestream.reserve(totalSize);
bytestream.push_back(message.getNumChannels());
bytestream.push_back(message.channelSize16 ? 1 : 0);
bytestream.resize(totalSize, 0);
uint32_t offset = 0;
uint8_t a2b2Bits = 0;
if(message.monitor) {
a2b2Bits = a2b2Bits | 1;
}
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);
if(message.txmsg) {
a2b2Bits = a2b2Bits | (1 << 1);
}
if(message.errIndicator) {
a2b2Bits = a2b2Bits | (1 << 2);
}
if(message.syncFrame) {
a2b2Bits = a2b2Bits | (1 << 3);
}
bytestream.push_back(a2b2Bits);
bytestream.push_back(0);
bytestream.push_back(static_cast<uint8_t>(message.rfu2));
bytestream.push_back(static_cast<uint8_t>(message.rfu2 >> 8));
for(size_t i = 0; i < (coreMiniMessageHeaderSize - a2bHeaderSize); i++)
bytestream.push_back(0);
uint8_t numChannels = message.getNumChannels();
uint8_t channel = 0;
uint32_t frame = 0;
auto writeSample = [&](A2BPCMSample&& sample) {
for(uint32_t i = 0; i < static_cast<uint32_t>(message.getBytesPerSample()); i++) {
bytestream.push_back(static_cast<uint8_t>((sample >> (i*8))));
}
};
while(true) {
auto dsSample = message.getSample(A2BMessage::A2BDirection::DownStream, channel, frame);
auto usSample = message.getSample(A2BMessage::A2BDirection::UpStream, channel, frame);
// Check if getSample failed for both downstream and upstream
if(!dsSample && !usSample) {
if(channel != 0) {
//Incomplete frame, the frame we are currently on does not contain all channel samples
report(APIEvent::Type::A2BMessageIncompleteFrame, APIEvent::Severity::Error);
return false;
}
// Since no samples have been written for the current frame yet and there are no more
// samples in both upstream and downstream, we can break and end parsing.
break;
}
// Since the first case failed, at least one of the streams still has samples.
// This case checks to see if the other stream does not have a sample.
else if(!dsSample || !usSample) {
// Report an error since we must have a one to one correspondence between upstream
// and downstream.
report(APIEvent::Type::A2BMessageIncompleteFrame, APIEvent::Severity::Error);
return false;
}
writeSample(std::move(dsSample.value()));
writeSample(std::move(usSample.value()));
channel = (channel + 1) % numChannels;
if(channel == 0)
frame++;
}
std::copy(message.data.begin(), message.data.end(), bytestream.begin() + offset);
return true;
}
+18 -12
View File
@@ -1,5 +1,5 @@
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/canerrormessage.h"
using namespace icsneo;
@@ -29,8 +29,7 @@ static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
return std::nullopt;
}
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
{
std::optional<uint8_t> icsneo::CAN_LengthToDLC(size_t dataLength, bool fd) {
if (dataLength <= 8)
return uint8_t(dataLength);
@@ -53,16 +52,18 @@ static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
return std::nullopt;
}
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting
const bool busOff = data->data[0] & 0b00100000;
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
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;
@@ -112,13 +113,18 @@ std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<ui
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;
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket);
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
}
}
msg->transmitted = data->eid.TXMSG;
// Set the generic frame error state
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
// Set specific error states for CANError
msg->txAborted = data->eid.TXAborted;
msg->txLostArb = data->eid.TXLostArb;
msg->txError = data->eid.TXError;
msg->description = data->stats;
return msg;
@@ -0,0 +1,52 @@
#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(PackedComponentVersion));
// 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,
packedVersion.expansionSlot
);
}
return msg;
}
+99 -51
View File
@@ -1,98 +1,146 @@
#include "icsneo/communication/packet/ethernetpacket.h"
#include <cstring> // memcpy
#include <algorithm>
#include <iostream>
using namespace icsneo;
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareEthernetPacket* packet = (const HardwareEthernetPacket*)((const void*)bytestream.data());
const uint16_t* rawWords = (const uint16_t*)bytestream.data();
// Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(HardwareEthernetPacket))
return nullptr;
// packet->Length will also encompass the two uint16_t's at the end of the struct, make sure that at least they are here
if(packet->Length < 4)
const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0;
// Ensure Length is sufficient for FCS extraction to avoid invalid iterator arithmetic
if(packet->Length < fcsSize)
return nullptr;
const size_t ethernetFrameSize = packet->Length - (sizeof(uint16_t) * 2);
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize;
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + packet->Length;
const size_t bytestreamActualSize = bytestream.size();
if(bytestreamActualSize < bytestreamExpectedSize)
return nullptr;
// Check for oversized packets, noting that some devices will send an extra byte to have an even number of bytes
if(bytestreamActualSize > bytestreamExpectedSize + 1)
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
auto messagePtr = std::make_shared<EthernetMessage>();
EthernetMessage& message = *messagePtr;
// Standard Ethernet fields
message.transmitted = packet->eid.TXMSG;
if(message.transmitted)
message.description = packet->stats;
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.fcsAvailable = packet->header.FCS_AVAIL;
message.frameTooShort = packet->header.RUNT_FRAME;
message.noPadding = !packet->header.ENABLE_PADDING;
message.fcsVerified = packet->header.FCS_VERIFIED;
message.txAborted = packet->eid.TXAborted;
message.crcError = packet->header.CRC_ERROR;
if(message.frameTooShort)
message.error = true;
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
message.timestamp = packet->timestamp.TS;
// Network ID is also not set, this will be fixed in the Decoder as well
// Check if this is a T1S packet and populate T1S-specific fields
message.isT1S = packet->header.T1S_ETHERNET;
if(message.isT1S) {
message.isT1SSymbol = packet->eid.T1S_SYMBOL;
message.isT1SBurst = packet->eid.T1S_BURST;
message.txCollision = packet->t1s_status.TXCollision;
message.isT1SWake = packet->t1s_status.T1SWake;
message.t1sNodeId = packet->t1s_node.T1S_NODE_ID;
message.t1sBurstCount = packet->t1s_node.T1S_BURST_COUNT;
}
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + (sizeof(HardwareEthernetPacket) - (sizeof(uint16_t) * 2));
const std::vector<uint8_t>::const_iterator dataend = databegin + ethernetFrameSize;
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket);
const std::vector<uint8_t>::const_iterator dataend = databegin + packet->Length - fcsSize;
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;
}
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t&) {
const size_t unpaddedSize = message.data.size();
size_t paddedSize = unpaddedSize;
uint16_t description = message.description;
if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60; // Pad out short messages
size_t sizeWithHeader = paddedSize + 4; // DescriptionID and Padded Count
if(unpaddedSize == 0)
return false;
// Description ID Most Significant bit is used to identify preemption frames
uint16_t description = message.description;
if(description & 0x8000)
return false;
if(message.preemptionEnabled) {
sizeWithHeader++; // Make space for the preemption flags
const bool preempt = message.preemptionEnabled;
// full header including parent
const size_t headerByteCount = preempt ? 15 : 14;
// local header for netID, description, and flags
const size_t localHeader = preempt ? 10 : 9;
// allocate space for fcs override
const size_t fcsSize = message.fcs ? 4 : 0;
if(preempt)
description |= 0x8000;
size_t paddedSize = unpaddedSize;
if(!message.noPadding && unpaddedSize < 60)
paddedSize = 60;
// size of full payload including optional fcs
size_t payloadSize = paddedSize + fcsSize;
// totalBufferSize is local header + ethernet payload and option fcs
const size_t totalBufferSize = localHeader + paddedSize + fcsSize;
bytestream.clear();
bytestream.reserve(totalBufferSize);
// Header size field (little endian)
bytestream.push_back(static_cast<uint8_t>(payloadSize & 0xFF));
bytestream.push_back(static_cast<uint8_t>((payloadSize >> 8) & 0xFF));
// Description (big endian)
bytestream.push_back(static_cast<uint8_t>(description >> 8));
bytestream.push_back(static_cast<uint8_t>(description));
bytestream.push_back(0x00);
bytestream.push_back(static_cast<uint8_t>(headerByteCount));
// Network ID (little endian)
uint16_t realID = static_cast<uint16_t>(message.network.getNetID());
bytestream.push_back(static_cast<uint8_t>(realID & 0xFF));
bytestream.push_back(static_cast<uint8_t>((realID >> 8) & 0xFF));
// Flags
constexpr uint8_t FLAG_PADDING = 0x01;
constexpr uint8_t FLAG_FCS = 0x04;
constexpr uint8_t FLAG_PREEMPTION = 0x08;
uint8_t flags = 0x00;
if(!message.noPadding) flags |= FLAG_PADDING;
if(message.fcs) flags |= FLAG_FCS;
if(message.preemptionEnabled) flags |= FLAG_PREEMPTION;
bytestream.push_back(flags);
if(preempt)
bytestream.push_back(static_cast<uint8_t>(message.preemptionFlags));
bytestream.insert(bytestream.end(), message.data.begin(), message.data.end());
// Only zero-fill when we want padding
if(!message.noPadding && unpaddedSize < 60) {
size_t paddingNeeded = 60 - unpaddedSize;
bytestream.insert(bytestream.end(), paddingNeeded, 0); // Zero-fill for padding
}
bytestream.reserve(sizeWithHeader + 8); // Also reserve space for the bytes we'll use later on
bytestream.resize(sizeWithHeader);
size_t index = 0;
// Padded size, little endian
bytestream[index++] = uint8_t(paddedSize);
bytestream[index++] = uint8_t(paddedSize >> 8);
// Description ID, big endian
bytestream[index++] = uint8_t(description >> 8);
bytestream[index++] = uint8_t(description);
// The header is one byte larger if preemption is enabled, shifting the data
if(message.preemptionEnabled)
bytestream[index++] = message.preemptionFlags;
// We only copy in the unpadded size, the rest will be 0
memcpy(bytestream.data() + index, message.data.data(), unpaddedSize);
if(message.fcs) {
uint32_t fcs = message.fcs.value();
const uint8_t* fcsBytes = reinterpret_cast<const uint8_t*>(&fcs);
bytestream.insert(bytestream.end(), fcsBytes, fcsBytes + sizeof(fcs));
}
return true;
}
}
+18 -16
View File
@@ -34,11 +34,12 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
phyMessage->Enabled = (pEntry->Enabled != 0u);
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
phyMessage->Clause45Enable = (pEntry->Clause45Enable != 0u);
phyMessage->version = static_cast<uint8_t>(pEntry->version);
phyMessage->BusIndex = static_cast<uint8_t>(pEntry->BusIndex);
phyMessage->Version = static_cast<uint8_t>(pEntry->version);
if(phyMessage->Clause45Enable)
phyMessage->clause45 = pEntry->clause45;
phyMessage->Clause45 = pEntry->clause45;
else
phyMessage->clause22 = pEntry->clause22;
phyMessage->Clause22 = pEntry->clause22;
msg->messages.push_back(phyMessage);
}
}
@@ -69,34 +70,35 @@ bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& m
PhyRegisterPacket_t tempPacket;
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
tempPacket.version = (phyMessage->version & 0xF);
tempPacket.BusIndex = (phyMessage->BusIndex & 0xF);
tempPacket.version = (phyMessage->Version & 0xF);
if(phyMessage->Clause45Enable)
{
if( (FiveBits < phyMessage->clause45.port) ||
(FiveBits < phyMessage->clause45.device) )
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;
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) )
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;
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));
@@ -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;
}
+1 -1
View File
@@ -49,7 +49,7 @@ namespace icsneo
report(APIEvent::Type::I2CMessageExceedsMaxLength, APIEvent::Severity::Error);
return false;
}
if(message.controlBytes.empty() || message.dataBytes.empty())
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
+146
View File
@@ -0,0 +1,146 @@
#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->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 false;
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
+152
View File
@@ -0,0 +1,152 @@
#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;
}
case LiveDataCommand::SET_VALUE: {
auto setValMsg = reinterpret_cast<LiveDataSetValueMessage*>(&message);
const auto numArgs = setValMsg->args.size();
if(numArgs) {
payloadSize = static_cast<uint16_t>(sizeof(LiveDataSetValue) + (sizeof(LiveDataSetValueEntry) * (numArgs-1)));
bytestream.resize((payloadSize + sizeof(ExtendedCommandHeader)),0);
LiveDataSetValue* out = reinterpret_cast<LiveDataSetValue*>(bytestream.data() + sizeof(ExtendedCommandHeader));
out->version = icsneo::LiveDataUtil::LiveDataVersion;
out->cmd = static_cast<uint32_t>(setValMsg->cmd);
if(!setValMsg->handle)
setValMsg->handle = LiveDataUtil::getNewHandle();
out->handle = setValMsg->handle;
out->numSetValues = (uint32_t)numArgs;
for(size_t i = 0; i < numArgs; ++i) {
out->values[i].arg.objectType = setValMsg->args[i]->objectType;
out->values[i].arg.objectIndex = setValMsg->args[i]->objectIndex;
out->values[i].arg.signalIndex = setValMsg->args[i]->signalIndex;
out->values[i].arg.valueType = setValMsg->args[i]->valueType;
out->values[i].value.value = setValMsg->values[i]->value;
out->values[i].value.header.length = sizeof(LiveDataValue::value);
}
} else {
report(APIEvent::Type::LiveDataInvalidArgument, APIEvent::Severity::Error);
return false;
}
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
+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;
}
}
+82
View File
@@ -0,0 +1,82 @@
#include "icsneo/communication/packet/spipacket.h"
#include "icsneo/communication/command.h"
#include <cstring>
#include <vector>
using namespace icsneo;
static size_t SPISubHeaderLength = 5u;
std::shared_ptr<Message> HardwareSPIPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(HardwareSPIPacket)) {
return nullptr;
}
const HardwareSPIPacket* packet = (const HardwareSPIPacket*)bytestream.data();
size_t totalPackedLength = static_cast<size_t>(bytestream.size()) - sizeof(HardwareSPIPacket); // First 28 bytes are message header.
if(totalPackedLength < SPISubHeaderLength) {
return nullptr;
}
const uint8_t* bytes = bytestream.data() + sizeof(HardwareSPIPacket);
std::shared_ptr<SPIMessage> msg = std::make_shared<SPIMessage>();
msg->direction = static_cast<SPIMessage::Direction>(bytes[0]);
msg->address = *reinterpret_cast<const uint16_t*>(&bytes[1]);
msg->mms = bytes[3];
msg->stats = packet->stats;
msg->timestamp = packet->timestamp.TS;
size_t numWords = (totalPackedLength - SPISubHeaderLength) / 4;
msg->payload.reserve(numWords);
for(size_t offset = SPISubHeaderLength; offset < totalPackedLength; offset += 4) {
msg->payload.push_back(*reinterpret_cast<const uint32_t*>(bytes + offset));
}
return msg;
}
bool HardwareSPIPacket::EncodeFromMessage(const SPIMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& /*report*/) {
// Payload length is everything excluding cmdHeader (note at the beginning there is an offset of 2)
uint16_t payloadLength = static_cast<uint16_t>(
2 +
sizeof(HardwareSPIPacket) +
SPISubHeaderLength +
message.payload.size() * sizeof(uint32_t)
);
if(payloadLength % 2) {
// Pad payload to even number
payloadLength++;
}
// +1 for AA, another +1 for firmware nuance
uint16_t fullSize = 1 + sizeof(ExtendedCommandHeader) + payloadLength + 1;
uint16_t unwrappedSize = sizeof(ExtendedCommandHeader) + payloadLength; // fullSize without AA and firmware nuance
bytestream.resize(unwrappedSize, 0);
uint32_t offset = 0;
auto* cmdHeader = reinterpret_cast<ExtendedCommandHeader*>(bytestream.data() + offset);
cmdHeader->netid = static_cast<uint8_t>(Network::NetID::Main51);
cmdHeader->fullLength = fullSize;
cmdHeader->command = static_cast<uint8_t>(Command::Extended);
cmdHeader->extendedCommand = static_cast<uint16_t>(ExtendedCommand::TransmitCoreminiMessage);
cmdHeader->payloadLength = payloadLength;
offset += sizeof(ExtendedCommandHeader) + 2; // Offset of 2 between header and packet
auto* packet = reinterpret_cast<HardwareSPIPacket*>(bytestream.data() + offset);
packet->header.frameLength = static_cast<uint16_t>(SPISubHeaderLength + message.payload.size() * sizeof(uint32_t));
packet->networkID = static_cast<uint16_t>(message.network.getNetID());
packet->length = packet->header.frameLength;
packet->timestamp.IsExtended = 1;
offset += sizeof(HardwareSPIPacket);
// Write the sub header details
bytestream[offset++] = static_cast<uint8_t>(message.direction);
bytestream[offset++] = static_cast<uint8_t>(message.address & 0xFF);
bytestream[offset++] = static_cast<uint8_t>((message.address >> 8) & 0xFF);
bytestream[offset++] = static_cast<uint8_t>(message.mms);
bytestream[offset++] = static_cast<uint8_t>(message.payload.size());
// Write the words
for(uint32_t word : message.payload) {
*reinterpret_cast<uint32_t*>(bytestream.data() + offset) = word;
offset += sizeof(uint32_t);
}
return true;
}
@@ -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;
}
+41 -7
View File
@@ -31,24 +31,46 @@ std::shared_ptr<WiVI::ResponseMessage> WiVI::CommandPacket::DecodeToMessage(cons
break;
}
case WiVI::Command::GetAll: {
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll))
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAllHeader))
return {};
const auto& getAll = *reinterpret_cast<const WiVI::CommandPacket::GetAll*>(bytestream.data());
const auto& getAll = *reinterpret_cast<const WiVI::CommandPacket::GetAllHeader*>(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))
size_t captureInfosSize = sizeof(WiVI::CaptureInfo) * getAll.numCaptureInfos;
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAllHeader) + captureInfosSize)
return {};
const WiVI::CaptureInfo* const captureInfos = (const WiVI::CaptureInfo*)(bytestream.data() + sizeof(WiVI::CommandPacket::GetAllHeader));
msg->info->captures.resize(getAll.numCaptureInfos);
for(uint16_t i = 0; i < getAll.numCaptureInfos; i++)
msg->info->captures[i] = getAll.captureInfos[i];
msg->info->captures[i] = captureInfos[i];
// New field vinAvail was added - check if it is present:
if(bytestream.size() >= sizeof(WiVI::CommandPacket::GetAllHeader) + captureInfosSize + 2) {
msg->info->vinAvailable = *(bytestream.data() + sizeof(WiVI::CommandPacket::GetAllHeader) + captureInfosSize);
} else {
msg->info->vinAvailable = 0;
}
break;
}
case WiVI::Command::GetVIN: {
if (bytestream.size() < sizeof(WiVI::CommandPacket::GetVIN))
return {};
const auto& getVIN = *reinterpret_cast<const WiVI::CommandPacket::GetVIN*>(bytestream.data());
msg->responseTo = WiVI::Command::GetVIN;
msg->vin = getVIN.VIN;
break;
}
default: // Unknown command response
return {};
}
@@ -78,9 +100,9 @@ std::vector<uint8_t> WiVI::CommandPacket::SetSignal::Encode(WiVI::SignalType typ
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());
std::vector<uint8_t> WiVI::CommandPacket::GetAllHeader::Encode() {
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetAllHeader));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetAllHeader*>(ret.data());
frame.header.cmd = WiVI::Command::GetAll;
frame.header.length = sizeof(frame) - sizeof(frame.header);
@@ -98,3 +120,15 @@ std::vector<uint8_t> WiVI::CommandPacket::ClearUploads::Encode(const std::vector
return ret;
}
std::vector<uint8_t> WiVI::CommandPacket::GetVIN::Encode()
{
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetVIN));
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetVIN*>(ret.data());
frame.header.cmd = WiVI::Command::GetVIN;
frame.header.length = sizeof(frame) - sizeof(frame.header);
return ret;
}

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