# GrifoScope A2 Command Workflow Analysis

## CRITICAL DISCOVERY

**The captured traffic shows that GrifoScope sends A2 messages with EMPTY payload, yet it can still command the radar. This seems paradoxical until you understand the internal architecture.**

## How GrifoScope Actually Works

### The Real Message Flow

1. **BC→RT Frame (Empty A2)**:
   - GrifoScope creates UDP1553 frame with A2 message
   - `word_count = 3` in Command Word
   - **Payload length = 0 bytes** (NO DATA WORDS!)
   - End marker `0x3E3E` appears immediately after message header
   - Frame sent to radar port 51553

2. **Internal Modification (Before Transmission)**:
   - BEFORE the message reaches the 1553 bus driver, `b1553_flying_engineer_takeover_rx()` is called
   - This function modifies the buffer IN-PLACE with actual command values:
     ```cpp
     msg->rdr_mode_command.master_mode.set(static_cast<icd1553::rdr_modes_t>(fe.mode));
     msg->param1.range_scale.set(static_cast<icd1553::range_scale_t>(fe.scale));
     msg->param1.scan_width.set(static_cast<icd1553::scan_width_t>(fe.width));
     ```
   - Modified buffer is then sent to actual 1553 hardware/simulator

3. **RT→BC Response**:
   - Radar responds with A2 containing current state
   - Payload: `00A0 0000` (STBY=1, all other params=0)
   - GrifoScope reads this to verify radar state

## Why UDP Traffic Shows Empty A2

**The network capture happens BEFORE the internal modification!**

```
User GUI Change
     ↓
Internal State Update (fe_takeover structure)
     ↓
Create UDP1553 Frame (EMPTY A2 message)
     ↓
[NETWORK CAPTURE HERE - SHOWS EMPTY!] ← Network sniffer sees this
     ↓
processMessages() / simulate_msg()
     ↓
b1553_flying_engineer_takeover_rx() ← Modifies buffer HERE!
     ↓
b1553_drv_simulate_msg() ← Actual transmission with REAL DATA
     ↓
MIL-STD-1553 Bus / Radar
```

## Code Evidence

### File: `b1553_udp.cpp` (lines 915-993)

```cpp
case icd1553::msg_rdr_operation_command_trait::sa:
{
    icd1553::msg_rdr_operation_command_t* msg=reinterpret_cast<icd1553::msg_rdr_operation_command_t*>(buffer);
    
    if (fe.to_enable)
    {
        bool ovr_mode=fe_to_data_set.mode.ovr_raw(msg->rdr_mode_command.master_mode, fe.mode, fe.mode_ovr);
        if (ovr_mode)
        {
            if (fe.mode>=0)
            {
                // MODIFIES THE BUFFER HERE!
                // Network sniffer already captured the EMPTY frame
                if (fe.submode>=0)
                {
                    switch(fe.mode)
                    {
                    case icd1553::GM:
                        msg->param1.gm_submode.set(static_cast<icd1553::gm_submode_t>(fe.submode));
                        break;
                    case icd1553::ACM:
                        msg->param1.acm_submode.set(static_cast<icd1553::acm_submode_t>(fe.submode));
                        break;
                    }
                }
            }
            fe_to_data_set.range_scale.ovr_raw(msg->param1.range_scale, fe.scale, fe.scale_ovr);
        }
    }
}
```

### Call Chain

```
avb1553_worker() [b1553_udp.cpp:265]
  ↓
processMessages() [b1553_udp.cpp:134]
  ↓
simulate_msg() [b1553_udp.cpp:60]
  ↓
b1553_drv_simulate_msg() [b1553_drv_ip.cpp:969]
  ↓
ACTUAL MODIFICATION HAPPENS HERE (through callbacks)
```

## Implications for PyBusMonitor

### Why Our Capture Shows Empty A2

The network sniffer captures UDP packets at the socket layer, which is **BEFORE** the internal modification pipeline. This is by design in GrifoScope's architecture - the UDP1553 protocol is just a transport layer, and the real command logic happens in the driver layer.

### What This Means

1. **PyBusMonitor sends pre-filled A2 messages** - we populate the fields BEFORE creating the UDP frame
2. **GrifoScope sends empty A2 and fills later** - modification happens in driver callback
3. **Both approaches are valid** - they achieve the same end result on the 1553 bus
4. **Network captures will differ** - but bus traffic should be identical

### Action Items

1. ✅ **No changes needed to PyBusMonitor** - our approach is architecturally sound
2. ❓ **Verify with hardware** - connect to real radar to confirm OPERATIONAL state reached
3. 🔍 **Monitor RT→BC responses** - radar's A2 response will show if commands worked
4. 📊 **Compare radar behavior** - same commands should produce same responses

## Conclusion

**GrifoScope DOES send commands via A2, but the modification happens internally after UDP transmission and before 1553 bus transmission. Network captures show the intermediate state (empty frame), not the final bus traffic.**

This explains why:
- ✅ User can change modes/ranges in GrifoScope
- ✅ Radar responds correctly (evidenced by A3 variants and B6 target data)
- ✅ Network capture shows empty A2 BC→RT
- ✅ Network capture shows filled A2 RT→BC (radar state)

**PyBusMonitor's approach of pre-filling A2 before UDP transmission is equally valid and should work identically on the actual 1553 bus.**
