diff --git a/bindings/python/icsneopy/flexray/flexray.cpp b/bindings/python/icsneopy/flexray/flexray.cpp index a66a0a5..df48129 100644 --- a/bindings/python/icsneopy/flexray/flexray.cpp +++ b/bindings/python/icsneopy/flexray/flexray.cpp @@ -64,6 +64,7 @@ void init_extension(pybind11::classh& c) { .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) @@ -74,6 +75,7 @@ void init_extension(pybind11::classh& c) { .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) @@ -114,6 +116,7 @@ void init_extension(pybind11::classh& c) { .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) @@ -159,7 +162,8 @@ void init_flexraymessage(pybind11::module_& m) { .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", &FlexRayMessage::cycle) + .def_readwrite("cycle_repetition", &FlexRayMessage::cycleRepetition); //// TODO: Eliminate FlexRayControlMessage class references in controller class and eliminate getStatus function in bindings } diff --git a/docs/icsneopy/flexray_getting_started.rst b/docs/icsneopy/flexray_getting_started.rst new file mode 100644 index 0000000..d6e4bfe --- /dev/null +++ b/docs/icsneopy/flexray_getting_started.rst @@ -0,0 +1,191 @@ +======================= +FlexRay Getting Started +======================= + +Prerequisites +============= + +- icsneopy library installed +- FlexRay hardware device connected (e.g., Fire3 Flexray) +- Proper FlexRay bus termination (100Ω on each channel end) + +Physical Hardware Setup for Two-Node Testing +--------------------------------------------- + +For testing the basic transmit and receive examples with a single device: + +- Hardware: Device with dual FlexRay controllers (e.g., neoVI FIRE 3 Flexray) +- Connection: FLEXRAY_01 Channel A looped to FLEXRAY_02 Channel A +- Termination: 100Ω termination resistors on both ends of the loopback +- Cable: Use proper FlexRay twisted pair cable (impedance matched) + +.. note:: + The basic transmit/receive examples are configured for this loopback setup + where both controllers act as coldstart nodes. For use on an existing + FlexRay network, see the passive monitoring configuration notes in the + receive example. + +FlexRay Coldstart +----------------- + +FlexRay networks require at least one "coldstart node" to initialize the network timing. +The coldstart node is responsible for starting the FlexRay communication cycle. + +For a complete standalone coldstart example, see the Additional Examples section below. + +Basic Setup +=========== + +1. Import the library and find FlexRay device: + +.. code-block:: python + + import icsneopy + + devices = icsneopy.find_all_devices() + + # Find a device with FlexRay support + device = None + for dev in devices: + if dev.get_extension("FlexRay"): + device = dev + break + + if not device: + raise RuntimeError("No FlexRay-capable device found") + +2. Configure FlexRay controller: + +.. literalinclude:: ../../examples/python/flexray/flexray_transmit_basic.py + :language: python + :lines: 12-111 + +3. Open device and go online: + +.. code-block:: python + + if not device.open(): + raise RuntimeError("Failed to open device") + + if not device.go_online(): + raise RuntimeError("Failed to go online") + +Transmitting FlexRay Frames +============================ + +This example demonstrates a coldstart node that initiates a FlexRay network +and transmits simulated sensor data continuously in slot 1. + +**Hardware Setup**: FLEXRAY_01 looped to FLEXRAY_02 + +**Usage**: +1. Start the receive example first +2. Start this transmit example second +3. Network will initialize and frames will be transmitted + +.. literalinclude:: ../../examples/python/flexray/flexray_transmit_basic.py + :language: python + :lines: 113-170 + +Key Configuration Parameters: + +- **slotid**: The FlexRay slot ID for transmission (1-2047 for static segment) +- **cycle**: The FlexRay cycle number (0-63) +- **cycle_repetition**: How often the frame repeats (1 = every cycle, 2 = every other cycle) +- **channel**: Transmission channel (A, B, or AB for both) +- **key_slot_id**: Must be unique per node on the network +- **key_slot_used_for_startup**: True for coldstart nodes +- **key_slot_used_for_sync**: True to provide synchronization frames + +Receiving FlexRay Frames +========================= + +This example demonstrates receiving FlexRay frames on FLEXRAY_02 Channel A. + +**Hardware Setup**: FLEXRAY_01 looped to FLEXRAY_02 + +**Configuration Note**: This example is configured with coldstart capability +for two-node loopback testing. For passive monitoring on an existing FlexRay +network: + +1. Set ``key_slot_used_for_startup = False`` in the controller configuration +2. Remove the ``controller.set_allow_coldstart(True)`` call +3. Ensure all cluster parameters match the existing network +4. The node will sync and receive without transmitting + +**Usage**: +1. Start this receive example first +2. Start the transmit example second +3. Frames from slot 1 will be displayed with hex and decimal payload views + +.. literalinclude:: ../../examples/python/flexray/flexray_receive_basic.py + :language: python + :lines: 103-170 + +FlexRay Coldstart Configuration +================================ + +To use the Coldstart example, ensure the following: + +Set the Flexray network in neoVI Explorer to Coldstart. + +No other nodes should be present on the network during testing. + +Nothing connected to Fire3 FlexRay bus. + +Critical Coldstart Settings +---------------------------- + +.. literalinclude:: ../../examples/python/flexray/flexray_coldstart.py + :language: python + :lines: 40-48 + +Configuration Example: + +.. literalinclude:: ../../examples/python/flexray/flexray_coldstart.py + :language: python + :lines: 20-64 + +Setting Coldstart on Controller: + +.. code-block:: python + + controller.set_allow_coldstart(True) + controller.set_start_when_going_online(True) + +Cleanup and Resource Management +================================ + +Always close the device when finished: + +.. code-block:: python + + try: + # Your FlexRay operations here + pass + finally: + device.close() + +See the basic transmit and receive examples for complete implementations. + +Additional Examples +=================== + +Transmit Basic +-------------- + +Complete working example with coldstart node transmitting simulated sensor data. + +All example files are available for download: + +**Transmit Basic** - Coldstart node transmitting simulated sensor data + +:download:`flexray_transmit_basic.py <../../examples/python/flexray/flexray_transmit_basic.py>` + +**Receive Basic** - Receiving and displaying FlexRay frames with formatted output + +:download:`flexray_receive_basic.py <../../examples/python/flexray/flexray_receive_basic.py>` + +**Coldstart** - Standalone coldstart example demonstrating network initialization + +:download:`flexray_coldstart.py <../../examples/python/flexray/flexray_coldstart.py>` \ No newline at end of file diff --git a/docs/icsneopy/index.rst b/docs/icsneopy/index.rst index 8ee71d2..15f7bf3 100644 --- a/docs/icsneopy/index.rst +++ b/docs/icsneopy/index.rst @@ -7,6 +7,7 @@ icsneopy can_getting_started ethernet_getting_started + flexray_getting_started examples api radepsilon diff --git a/examples/python/flexray/flexray_coldstart.py b/examples/python/flexray/flexray_coldstart.py new file mode 100644 index 0000000..f919400 --- /dev/null +++ b/examples/python/flexray/flexray_coldstart.py @@ -0,0 +1,218 @@ +""" +FlexRay coldstart example using icsneopy library. + +Demonstrates coldstart capability where one FlexRay device can start +the network without needing other devices connected. + +CRITICAL COLDSTART REQUIREMENTS: +1. key_slot_used_for_startup = True +2. key_slot_used_for_sync = True +3. set_allow_coldstart(True) +4. Each controller needs a unique key_slot_id +5. Proper bus termination (required for FlexRay) +""" + +import icsneopy +import time + + +def get_coldstart_controller_config(slot_id): + """ + Create FlexRay controller configuration for COLDSTART. + + The three critical settings for coldstart are marked below. + """ + config = icsneopy.FlexRay.Controller.Configuration() + config.accept_startup_range_microticks = 160 + config.allow_halt_due_to_clock = True + config.allow_passive_to_active_cycle_pairs = 15 + config.cluster_drift_damping = 2 + config.channel_a = True + config.channel_b = True + config.decoding_correction_microticks = 56 + config.delay_compensation_a_microticks = 28 + config.delay_compensation_b_microticks = 28 + config.extern_offset_correction_control = 0 + config.extern_rate_correction_control = 0 + config.extern_offset_correction_microticks = 0 + config.extern_rate_correction_microticks = 0 + + # CRITICAL FOR COLDSTART: Set the key slot ID + config.key_slot_id = slot_id + + config.key_slot_only_enabled = False + + # CRITICAL FOR COLDSTART: Enable startup and sync on key slot + config.key_slot_used_for_startup = True # Required for coldstart + config.key_slot_used_for_sync = True # Required for coldstart + + config.latest_tx_minislot = 226 + config.listen_timeout = 401202 + config.macro_initial_offset_a = 7 + config.macro_initial_offset_b = 7 + config.micro_initial_offset_a = 36 + config.micro_initial_offset_b = 36 + config.micro_per_cycle = 200000 + config.mts_on_a = False + config.mts_on_b = False + config.offset_correction_out_microticks = 189 + config.rate_correction_out_microticks = 601 + config.second_key_slot_id = 0 + config.two_key_slot_mode = False + config.wakeup_pattern = 55 + config.wakeup_on_channel_b = False + return config + + +def get_cluster_config(): + """Create FlexRay cluster configuration.""" + config = icsneopy.FlexRay.Cluster.Configuration() + config.speed = icsneopy.FlexRay.Cluster.SpeedType.FLEXRAY_BAUDRATE_10M + config.strobe_point_position = icsneopy.FlexRay.Cluster.SPPType.FLEXRAY_SPP_5 + config.action_point_offset = 4 + config.casr_x_low_max = 64 + config.cold_start_attempts = 8 + config.cycle_duration_micro_sec = 5000 + config.dynamic_slot_idle_phase_minislots = 1 + config.listen_noise_macroticks = 4 + config.macroticks_per_cycle = 5000 + config.macrotick_duration_micro_sec = 1 + config.max_without_clock_correction_fatal = 2 + config.max_without_clock_correction_passive = 2 + config.minislot_action_point_offset_macroticks = 4 + config.minislot_duration_macroticks = 10 + config.network_idle_time_macroticks = 40 + config.network_management_vector_length_bytes = 1 + config.number_of_minislots = 0 + config.number_of_static_slots = 32 + config.offset_correction_start_macroticks = 4991 + config.payload_length_of_static_slot_in_words = 67 + config.static_slot_macroticks = 155 + config.symbol_window_macroticks = 0 + config.symbol_window_action_point_offset_macroticks = 0 + config.sync_frame_id_count_max = 15 + config.transmission_start_sequence_duration_bits = 11 + config.wakeup_rx_idle_bits = 40 + config.wakeup_rx_low_bits = 40 + config.wakeup_rx_window_bits = 301 + config.wakeup_tx_active_bits = 60 + config.wakeup_tx_idle_bits = 180 + return config + + +def flexray_coldstart(): + """Perform FlexRay coldstart operation.""" + devices = icsneopy.find_all_devices() + if not devices: + raise RuntimeError("No devices found") + + # Find a device with FlexRay support + device = None + for dev in devices: + if dev.get_extension("FlexRay"): + device = dev + break + + if not device: + raise RuntimeError("No FlexRay-capable device found") + + print(f"Using device: {device.get_product_name()} {device.get_serial()}") + + try: + # Get FlexRay controllers + controllers = device.get_flexray_controllers() + if not controllers: + raise RuntimeError("Device has no FlexRay controllers") + + print(f"Device has {len(controllers)} FlexRay controller(s)") + + # Configure controllers for coldstart + cluster_config = get_cluster_config() + base_slot_id = 1 + + for i, controller in enumerate(controllers): + slot_id = base_slot_id + i + controller_config = get_coldstart_controller_config(slot_id) + + print(f"\nConfiguring controller {i} for COLDSTART:") + print(f" Key Slot ID: {slot_id}") + print(f" Key Slot Used for Startup: {controller_config.key_slot_used_for_startup}") + print(f" Key Slot Used for Sync: {controller_config.key_slot_used_for_sync}") + + # CRITICAL FOR COLDSTART: Enable coldstart capability + controller.set_allow_coldstart(True) + print(f" Allow Coldstart: True") + + # Configure to start when going online + controller.set_start_when_going_online(True) + + # Set the configuration + controller.set_configuration(cluster_config, controller_config) + + # Open device + print("\nOpening device...") + if not device.open(): + raise RuntimeError("Failed to open device") + print("Device opened successfully") + + # Go online - this triggers coldstart + print("\nGoing online (coldstart will initiate)...") + if not device.go_online(): + raise RuntimeError("Failed to go online - check bus termination and configuration") + + print("Device online successfully!") + print("\n" + "=" * 60) + print("✓ FlexRay network started via COLDSTART") + print("=" * 60) + + # Transmit test messages on the coldstart key slot + print("\nTransmitting initial test messages...") + for i in range(5): + frame = icsneopy.FlexRayMessage() + frame.network = icsneopy.Network(icsneopy.Network.NetID.FLEXRAY_01) + frame.slotid = base_slot_id # Use the first key slot + frame.cycle = 0 + frame.cycle_repetition = 1 + frame.channel = icsneopy.FlexRay.Channel.AB + frame.data = (0xAA, 0xBB, 0xCC, 0xDD, i, i+1, i+2, i+3) + + if device.transmit(frame): + print(f" ✓ Transmitted message {i+1}") + else: + print(f" ✗ Failed to transmit message {i+1}") + + time.sleep(0.1) + + print("\n" + "=" * 60) + print("Network is now active and will stay alive.") + print("You can now run transmit/receive examples in another terminal.") + print("Press Ctrl+C to stop and shut down the network.") + print("=" * 60) + + # Keep transmitting periodically to maintain network presence + counter = 0 + try: + while True: + frame = icsneopy.FlexRayMessage() + frame.network = icsneopy.Network(icsneopy.Network.NetID.FLEXRAY_01) + frame.slotid = base_slot_id + frame.cycle = 0 + frame.cycle_repetition = 1 + frame.channel = icsneopy.FlexRay.Channel.AB + frame.data = (0xCA, 0xFE, 0xBA, 0xBE, counter & 0xFF, + (counter >> 8) & 0xFF, (counter >> 16) & 0xFF, (counter >> 24) & 0xFF) + + device.transmit(frame) + counter += 1 + time.sleep(1) # Transmit every second + except KeyboardInterrupt: + print("\n\nStopping coldstart node...") + + print("\n✓ Coldstart example completed successfully!") + + finally: + device.close() + + +if __name__ == "__main__": + flexray_coldstart() diff --git a/examples/python/flexray/flexray_receive_basic.py b/examples/python/flexray/flexray_receive_basic.py new file mode 100644 index 0000000..8b7b472 --- /dev/null +++ b/examples/python/flexray/flexray_receive_basic.py @@ -0,0 +1,188 @@ + +# Basic FlexRay frame reception example using icsneopy library. + + +import icsneopy +import time +import signal +import sys + + +def get_controller_config(slot_id): + """Create a FlexRay controller configuration matching the network. + + Args: + slot_id: The key slot ID for this node (must be unique per node) + + Returns: + FlexRay.Controller.Configuration with all parameters set + + Note: + For passive listening on an existing network, set: + - key_slot_used_for_startup = False + - Remove set_allow_coldstart(True) call below + """ + config = icsneopy.FlexRay.Controller.Configuration() + config.accept_startup_range_microticks = 160 + config.allow_halt_due_to_clock = True + config.allow_passive_to_active_cycle_pairs = 15 + config.cluster_drift_damping = 2 + + # Physical channel configuration (Channel A only for this example) + config.channel_a = True + config.channel_b = False # Single channel A only + + config.decoding_correction_microticks = 56 + config.delay_compensation_a_microticks = 28 + config.delay_compensation_b_microticks = 28 + config.extern_offset_correction_control = 0 + config.extern_rate_correction_control = 0 + config.extern_offset_correction_microticks = 0 + config.extern_rate_correction_microticks = 0 + + # KEY SLOT CONFIGURATION - Critical for FlexRay operation + config.key_slot_id = slot_id # Must be unique per node + config.key_slot_only_enabled = False + config.key_slot_used_for_startup = True # True = participate in coldstart + config.key_slot_used_for_sync = True # True = synchronize with network + + config.latest_tx_minislot = 226 + config.listen_timeout = 401202 + config.macro_initial_offset_a = 7 + config.macro_initial_offset_b = 7 + config.micro_initial_offset_a = 36 + config.micro_initial_offset_b = 36 + config.micro_per_cycle = 200000 + config.mts_on_a = False + config.mts_on_b = False + config.offset_correction_out_microticks = 189 + config.rate_correction_out_microticks = 601 + config.second_key_slot_id = 0 + config.two_key_slot_mode = False + config.wakeup_pattern = 55 + config.wakeup_on_channel_b = False + return config + + +def get_cluster_config(): + """Create a FlexRay cluster configuration matching the network.""" + config = icsneopy.FlexRay.Cluster.Configuration() + config.speed = icsneopy.FlexRay.Cluster.SpeedType.FLEXRAY_BAUDRATE_10M + config.strobe_point_position = icsneopy.FlexRay.Cluster.SPPType.FLEXRAY_SPP_5 + config.action_point_offset = 4 + config.casr_x_low_max = 64 + config.cold_start_attempts = 8 + config.cycle_duration_micro_sec = 5000 + config.dynamic_slot_idle_phase_minislots = 1 + config.listen_noise_macroticks = 4 + config.macroticks_per_cycle = 5000 + config.macrotick_duration_micro_sec = 1 + config.max_without_clock_correction_fatal = 2 + config.max_without_clock_correction_passive = 2 + config.minislot_action_point_offset_macroticks = 4 + config.minislot_duration_macroticks = 10 + config.network_idle_time_macroticks = 40 + config.network_management_vector_length_bytes = 1 + config.number_of_minislots = 0 + config.number_of_static_slots = 32 + config.offset_correction_start_macroticks = 4991 + config.payload_length_of_static_slot_in_words = 67 + config.static_slot_macroticks = 155 + config.symbol_window_macroticks = 0 + config.symbol_window_action_point_offset_macroticks = 0 + config.sync_frame_id_count_max = 15 + config.transmission_start_sequence_duration_bits = 11 + config.wakeup_rx_idle_bits = 40 + config.wakeup_rx_low_bits = 40 + config.wakeup_rx_window_bits = 301 + config.wakeup_tx_active_bits = 60 + config.wakeup_tx_idle_bits = 180 + return config + + +def receive_flexray_frames(): + """Receive FlexRay frames as passive node with callback handling.""" + devices = icsneopy.find_all_devices() + if not devices: + raise RuntimeError("No devices found") + + # Find a device with FlexRay support + device = None + for dev in devices: + if dev.get_extension("FlexRay"): + device = dev + break + + if not device: + raise RuntimeError("No FlexRay-capable device found") + + frame_count = 0 + running = True + + def on_frame(frame): + nonlocal frame_count + if isinstance(frame, icsneopy.FlexRayMessage): + # Only show frames from slot 1 (filter out null frames) + if frame.slotid == 1: + frame_count += 1 + # Nice formatted view of the frame + payload_hex = ' '.join([f'{b:02X}' for b in frame.data[:8]]) + payload_dec = ' '.join([f'{b:3d}' for b in frame.data[:8]]) + print(f"[Frame {frame_count:4d}] Slot: {frame.slotid:2d} | Cycle: {frame.cycle:2d} | " + f"Channel: {str(frame.channel):10s}") + print(f" Hex: [{payload_hex}]") + print(f" Dec: [{payload_dec}]\n") + + def signal_handler(sig, frame): + nonlocal running + print("\nShutting down...") + running = False + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + frame_filter = icsneopy.MessageFilter(icsneopy.Network.NetID.FLEXRAY_02) + callback = icsneopy.MessageCallback(on_frame, frame_filter) + + try: + # Configure FlexRay controller 1 (FLEXRAY_02) as passive node + controllers = device.get_flexray_controllers() + if len(controllers) < 2: + raise RuntimeError("Device needs at least 2 FlexRay controllers") + + controller = controllers[1] # Use controller 1 + cluster_config = get_cluster_config() + controller_config = get_controller_config(slot_id=2) + + # Enable coldstart so this node transmits and coldstart node sees activity + controller.set_allow_coldstart(True) + controller.set_configuration(cluster_config, controller_config) + controller.set_start_when_going_online(True) + + if not device.open(): + raise RuntimeError("Failed to open device") + + if not device.go_online(): + raise RuntimeError("Failed to go online") + + device.add_message_callback(callback) + print("="*60) + print("FlexRay Receive Node - Coldstart Config Loaded") + print("="*60) + print(f"Controller: FLEXRAY_02 | Slot ID: 2 | Channel: A") + print(f"Listening for frames...") + print(f"Start the transmit script now to begin communication") + print("="*60) + print("Press Ctrl+C to stop\n") + + while running: + time.sleep(0.1) + + print(f"\nTotal frames received: {frame_count}") + + finally: + device.close() + + +if __name__ == "__main__": + receive_flexray_frames() diff --git a/examples/python/flexray/flexray_transmit_basic.py b/examples/python/flexray/flexray_transmit_basic.py new file mode 100644 index 0000000..b085083 --- /dev/null +++ b/examples/python/flexray/flexray_transmit_basic.py @@ -0,0 +1,218 @@ + +# Basic FlexRay frame transmission example using icsneopy library. + + +import icsneopy +import time +import signal +import sys +import random + + +def get_controller_config(slot_id, is_coldstart=False): + """Create a FlexRay controller configuration matching the network. + + Args: + slot_id: The key slot ID for this node (must be unique per node) + is_coldstart: True if this node participates in coldstart + + Returns: + FlexRay.Controller.Configuration with all parameters set + """ + config = icsneopy.FlexRay.Controller.Configuration() + config.accept_startup_range_microticks = 160 + config.allow_halt_due_to_clock = True + config.allow_passive_to_active_cycle_pairs = 15 + config.cluster_drift_damping = 2 + + # Physical channel configuration (Channel A only for this example) + config.channel_a = True + config.channel_b = False # Single channel A only + + config.decoding_correction_microticks = 56 + config.delay_compensation_a_microticks = 28 + config.delay_compensation_b_microticks = 28 + config.extern_offset_correction_control = 0 + config.extern_rate_correction_control = 0 + config.extern_offset_correction_microticks = 0 + config.extern_rate_correction_microticks = 0 + + # KEY SLOT CONFIGURATION - Critical for FlexRay operation + config.key_slot_id = slot_id # Must be unique per node + config.key_slot_only_enabled = False + config.key_slot_used_for_startup = is_coldstart # True = coldstart node + config.key_slot_used_for_sync = is_coldstart # True = provides sync + + config.latest_tx_minislot = 226 + config.listen_timeout = 401202 + config.macro_initial_offset_a = 7 + config.macro_initial_offset_b = 7 + config.micro_initial_offset_a = 36 + config.micro_initial_offset_b = 36 + config.micro_per_cycle = 200000 + config.mts_on_a = False + config.mts_on_b = False + config.offset_correction_out_microticks = 189 + config.rate_correction_out_microticks = 601 + config.second_key_slot_id = 0 + config.two_key_slot_mode = False + config.wakeup_pattern = 55 + config.wakeup_on_channel_b = False + return config + + +def get_cluster_config(): + """Create a FlexRay cluster configuration matching the network. + + All nodes on the FlexRay network must have identical cluster parameters. + These define the timing and structure of the FlexRay communication cycle. + + Key parameters: + - cycle_duration_micro_sec: 5000 = 5ms cycle time + - macroticks_per_cycle: 5000 macroticks per cycle + - number_of_static_slots: 32 static slots for guaranteed transmission + - payload_length_of_static_slot_in_words: 67 words = 134 bytes max payload + + Returns: + FlexRay.Cluster.Configuration with all timing parameters set + """ + config = icsneopy.FlexRay.Cluster.Configuration() + config.speed = icsneopy.FlexRay.Cluster.SpeedType.FLEXRAY_BAUDRATE_10M + config.strobe_point_position = icsneopy.FlexRay.Cluster.SPPType.FLEXRAY_SPP_5 + config.action_point_offset = 4 + config.casr_x_low_max = 64 + config.cold_start_attempts = 8 + config.cycle_duration_micro_sec = 5000 + config.dynamic_slot_idle_phase_minislots = 1 + config.listen_noise_macroticks = 4 + config.macroticks_per_cycle = 5000 + config.macrotick_duration_micro_sec = 1 + config.max_without_clock_correction_fatal = 2 + config.max_without_clock_correction_passive = 2 + config.minislot_action_point_offset_macroticks = 4 + config.minislot_duration_macroticks = 10 + config.network_idle_time_macroticks = 40 + config.network_management_vector_length_bytes = 1 + config.number_of_minislots = 0 + config.number_of_static_slots = 32 + config.offset_correction_start_macroticks = 4991 + config.payload_length_of_static_slot_in_words = 67 + config.static_slot_macroticks = 155 + config.symbol_window_macroticks = 0 + config.symbol_window_action_point_offset_macroticks = 0 + config.sync_frame_id_count_max = 15 + config.transmission_start_sequence_duration_bits = 11 + config.wakeup_rx_idle_bits = 40 + config.wakeup_rx_low_bits = 40 + config.wakeup_rx_window_bits = 301 + config.wakeup_tx_active_bits = 60 + config.wakeup_tx_idle_bits = 180 + return config + + +def transmit_flexray_frame(): + """Transmit FlexRay frames as coldstart node.""" + devices = icsneopy.find_all_devices() + if not devices: + raise RuntimeError("No devices found") + + # Find a device with FlexRay support + device = None + for dev in devices: + if dev.get_extension("FlexRay"): + device = dev + break + + if not device: + raise RuntimeError("No FlexRay-capable device found") + + running = True + + def signal_handler(sig, frame): + nonlocal running + print("\nShutting down...") + running = False + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + try: + # Configure FlexRay controller 0 (FLEXRAY_01) as coldstart node + controllers = device.get_flexray_controllers() + if not controllers: + raise RuntimeError("Device has no FlexRay controllers") + + controller = controllers[0] # Use controller 0 + cluster_config = get_cluster_config() + controller_config = get_controller_config(slot_id=1, is_coldstart=True) + + # Enable coldstart capability + controller.set_allow_coldstart(True) + controller.set_configuration(cluster_config, controller_config) + controller.set_start_when_going_online(True) + + if not device.open(): + raise RuntimeError("Failed to open device") + + if not device.go_online(): + raise RuntimeError("Failed to go online") + + print("="*60) + print("FlexRay Transmit Node - Starting Network") + print("="*60) + print(f"Controller: FLEXRAY_01 | Slot ID: 1 | Channel: A") + print(f"Transmitting frames continuously...") + print("="*60) + print("Press Ctrl+C to stop\n") + + # Transmit frames continuously starting immediately + counter = 0 + sensor_temp = 20.0 # Simulated temperature sensor + sensor_pressure = 100.0 # Simulated pressure sensor + + while running: + # Create new frame each time (important for FlexRay) + frame = icsneopy.FlexRayMessage() + frame.network = icsneopy.Network(icsneopy.Network.NetID.FLEXRAY_01) + frame.slotid = 1 + frame.cycle = 0 + frame.cycle_repetition = 1 + frame.channel = icsneopy.FlexRay.Channel.A + + # Simulate realistic sensor data + sensor_temp += random.uniform(-0.5, 0.5) # Temperature varies + sensor_pressure += random.uniform(-2.0, 2.0) # Pressure varies + + # Pack data: [status, counter, temp_high, temp_low, pressure_high, pressure_low, checksum_placeholder, sequence] + status_byte = 0xA0 | (counter % 16) # Status with rolling bits + temp_int = int(sensor_temp * 10) & 0xFFFF + pressure_int = int(sensor_pressure * 10) & 0xFFFF + + frame.data = ( + status_byte, + counter & 0xFF, + (temp_int >> 8) & 0xFF, + temp_int & 0xFF, + (pressure_int >> 8) & 0xFF, + pressure_int & 0xFF, + random.randint(0, 255), # Random data + (counter >> 8) & 0xFF + ) + + success = device.transmit(frame) + if counter % 100 == 0: # Print every 100th to reduce spam + if success: + print(f" [TX {counter}] Temp: {sensor_temp:.1f}°C | Pressure: {sensor_pressure:.1f} kPa") + else: + print(f" Frame {counter}: Failed to transmit") + counter += 1 + time.sleep(0.005) # 5ms per cycle + + print("\nTransmission complete!") + + finally: + device.close() + + +if __name__ == "__main__": + transmit_flexray_frame()