pub const FAKE_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<RegisterDescription
ModelName="VivaCam Fake"
VendorName="vitavision.dev"
ToolTip="Simulated GigE Vision camera for testing"
StandardNameSpace="GEV"
SchemaMajorVersion="1"
SchemaMinorVersion="1"
SchemaSubMinorVersion="0"
MajorVersion="1"
MinorVersion="0"
SubMinorVersion="0"
ProductGuid="76697661-6361-6d00-0000-000000000000"
VersionGuid="76697661-6361-6d00-0000-000000000001">
<!-- ════════════════════════════════════════════════════════════════════
Category Hierarchy (SFNC Standard)
════════════════════════════════════════════════════════════════════ -->
<Category Name="Root" NameSpace="Standard">
<pFeature>DeviceControl</pFeature>
<pFeature>ImageFormatControl</pFeature>
<pFeature>AcquisitionControl</pFeature>
<pFeature>AnalogControl</pFeature>
<pFeature>TransportLayerControl</pFeature>
<pFeature>ChunkDataControl</pFeature>
</Category>
<Category Name="DeviceControl">
<DisplayName>Device Control</DisplayName>
<pFeature>DeviceVendorName</pFeature>
<pFeature>DeviceModelName</pFeature>
<pFeature>DeviceSerialNumber</pFeature>
<pFeature>DeviceFirmwareVersion</pFeature>
<pFeature>DeviceID</pFeature>
</Category>
<Category Name="ImageFormatControl">
<DisplayName>Image Format Control</DisplayName>
<pFeature>SensorType</pFeature>
<pFeature>SensorWidth</pFeature>
<pFeature>SensorHeight</pFeature>
<pFeature>Width</pFeature>
<pFeature>Height</pFeature>
<pFeature>OffsetX</pFeature>
<pFeature>OffsetY</pFeature>
<pFeature>PixelFormat</pFeature>
</Category>
<Category Name="AcquisitionControl">
<DisplayName>Acquisition Control</DisplayName>
<pFeature>AcquisitionMode</pFeature>
<pFeature>AcquisitionStart</pFeature>
<pFeature>AcquisitionStop</pFeature>
<pFeature>AcquisitionFrameRateEnable</pFeature>
<pFeature>AcquisitionFrameRate</pFeature>
<pFeature>ExposureTime</pFeature>
<pFeature>ExposureAuto</pFeature>
</Category>
<Category Name="AnalogControl">
<DisplayName>Analog Control</DisplayName>
<pFeature>Gain</pFeature>
<pFeature>GainAuto</pFeature>
<pFeature>BlackLevel</pFeature>
</Category>
<Category Name="TransportLayerControl">
<DisplayName>Transport Layer Control</DisplayName>
<pFeature>GevTimestampTickFrequency</pFeature>
<pFeature>GevTimestampValue</pFeature>
<pFeature>TimestampLatch</pFeature>
</Category>
<Category Name="ChunkDataControl">
<DisplayName>Chunk Data Control</DisplayName>
<pFeature>ChunkModeActive</pFeature>
<pFeature>ChunkSelector</pFeature>
<pFeature>ChunkEnable</pFeature>
</Category>
<Category Name="EventControl">
<DisplayName>Event Control</DisplayName>
<pFeature>EventSelector</pFeature>
<pFeature>EventNotification</pFeature>
</Category>
<!-- ════════════════════════════════════════════════════════════════════
Device Control Features
════════════════════════════════════════════════════════════════════ -->
<String Name="DeviceVendorName" NameSpace="Standard">
<ToolTip>Name of the device vendor</ToolTip>
<Address>0x20220</Address>
<Length>32</Length>
<AccessMode>RO</AccessMode>
</String>
<String Name="DeviceModelName" NameSpace="Standard">
<ToolTip>Name of the device model</ToolTip>
<Address>0x20200</Address>
<Length>32</Length>
<AccessMode>RO</AccessMode>
</String>
<String Name="DeviceSerialNumber" NameSpace="Standard">
<ToolTip>Serial number of the device</ToolTip>
<Address>0x20240</Address>
<Length>16</Length>
<AccessMode>RO</AccessMode>
</String>
<String Name="DeviceFirmwareVersion" NameSpace="Standard">
<ToolTip>Firmware version of the device</ToolTip>
<Address>0x20260</Address>
<Length>32</Length>
<AccessMode>RO</AccessMode>
</String>
<String Name="DeviceID" NameSpace="Standard">
<ToolTip>User-configurable device identifier</ToolTip>
<Address>0x20280</Address>
<Length>32</Length>
<AccessMode>RO</AccessMode>
</String>
<!-- ════════════════════════════════════════════════════════════════════
Image Format Control Features
════════════════════════════════════════════════════════════════════ -->
<Integer Name="SensorWidth" NameSpace="Standard">
<ToolTip>Physical sensor width in pixels</ToolTip>
<Address>0x20014</Address>
<Length>4</Length>
<AccessMode>RO</AccessMode>
<Min>1</Min>
<Max>4096</Max>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<Integer Name="SensorHeight" NameSpace="Standard">
<ToolTip>Physical sensor height in pixels</ToolTip>
<Address>0x20018</Address>
<Length>4</Length>
<AccessMode>RO</AccessMode>
<Min>1</Min>
<Max>4096</Max>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<Integer Name="Width" NameSpace="Standard">
<ToolTip>Width of the image in pixels</ToolTip>
<Address>0x20000</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<pMin>WidthMin</pMin>
<pMax>WidthMax</pMax>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<IntReg Name="WidthMin"><Address>0x20100</Address><Length>4</Length><AccessMode>RO</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<IntReg Name="WidthMax"><Address>0x20104</Address><Length>4</Length><AccessMode>RO</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Integer Name="Height" NameSpace="Standard">
<ToolTip>Height of the image in pixels</ToolTip>
<Address>0x20004</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<pMin>HeightMin</pMin>
<pMax>HeightMax</pMax>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<IntReg Name="HeightMin"><Address>0x20108</Address><Length>4</Length><AccessMode>RO</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<IntReg Name="HeightMax"><Address>0x2010c</Address><Length>4</Length><AccessMode>RO</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Integer Name="OffsetX" NameSpace="Standard">
<ToolTip>Horizontal offset from the sensor origin</ToolTip>
<Address>0x2000c</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<Min>0</Min>
<Max>4096</Max>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<Integer Name="OffsetY" NameSpace="Standard">
<ToolTip>Vertical offset from the sensor origin</ToolTip>
<Address>0x20010</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<Min>0</Min>
<Max>4096</Max>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<Enumeration Name="SensorType" NameSpace="Standard">
<ToolTip>Sensor variant (Monochrome / BayerRG / Color). On real hardware this would be read-only sensor metadata; here it is RW so tests can reconfigure the simulator.</ToolTip>
<EnumEntry Name="Monochrome"><Value>0</Value></EnumEntry>
<EnumEntry Name="BayerRG"><Value>1</Value></EnumEntry>
<EnumEntry Name="Color"><Value>2</Value></EnumEntry>
<pValue>SensorTypeReg</pValue>
</Enumeration>
<IntReg Name="SensorTypeReg"><Address>0x20058</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Enumeration Name="PixelFormat" NameSpace="Standard">
<ToolTip>Format of the pixel data — entries are gated by SensorType</ToolTip>
<EnumEntry Name="Mono8" NameSpace="Standard">
<Value>0x01080001</Value>
<pIsImplemented>PfMono8Avail</pIsImplemented>
</EnumEntry>
<EnumEntry Name="Mono16" NameSpace="Standard">
<Value>0x01100007</Value>
<pIsImplemented>PfMono16Avail</pIsImplemented>
</EnumEntry>
<EnumEntry Name="RGB8" NameSpace="Standard">
<Value>0x02180014</Value>
<pIsImplemented>PfRGB8Avail</pIsImplemented>
</EnumEntry>
<EnumEntry Name="BayerRG8" NameSpace="Standard">
<Value>0x01080009</Value>
<pIsImplemented>PfBayerRG8Avail</pIsImplemented>
</EnumEntry>
<pValue>PixelFormatReg</pValue>
</Enumeration>
<IntReg Name="PixelFormatReg"><Address>0x20008</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<!-- PixelFormat entry availability driven by SensorType:
Monochrome (0) → Mono8, Mono16
BayerRG (1) → BayerRG8
Color (2) → RGB8 -->
<IntSwissKnife Name="PfMono8Avail">
<Formula>ST = 0</Formula>
<pVariable Name="ST">SensorTypeReg</pVariable>
</IntSwissKnife>
<IntSwissKnife Name="PfMono16Avail">
<Formula>ST = 0</Formula>
<pVariable Name="ST">SensorTypeReg</pVariable>
</IntSwissKnife>
<IntSwissKnife Name="PfBayerRG8Avail">
<Formula>ST = 1</Formula>
<pVariable Name="ST">SensorTypeReg</pVariable>
</IntSwissKnife>
<IntSwissKnife Name="PfRGB8Avail">
<Formula>ST = 2</Formula>
<pVariable Name="ST">SensorTypeReg</pVariable>
</IntSwissKnife>
<!-- ════════════════════════════════════════════════════════════════════
Device capability inquiry bits
Real inquiry blocks are addressed as `<pAddress>` (the block base) plus
a fixed `<Address>` offset, and the individual bits come from a
<StructReg>. Both terms contribute: keeping only one reads the wrong
register, which is what made issue #35's camera misreport every
capability it had.
════════════════════════════════════════════════════════════════════ -->
<IntSwissKnife Name="DeviceRegBaseAddress">
<Formula>0x20000</Formula>
</IntSwissKnife>
<StructReg Comment="Device capability inquiry">
<pAddress>DeviceRegBaseAddress</pAddress>
<Address>0x5C</Address>
<Length>4</Length>
<AccessMode>RO</AccessMode>
<Endianess>BigEndian</Endianess>
<StructEntry Name="FrameRateControlInq_Bit"><Bit>0</Bit></StructEntry>
<StructEntry Name="ChunkSupportInq_Bit"><Bit>1</Bit></StructEntry>
<StructEntry Name="SequencerInq_Bit"><Bit>2</Bit></StructEntry>
</StructReg>
<!-- ════════════════════════════════════════════════════════════════════
GigE Vision stream channel registers
Stream channel N lives at 0x0D00 + N * 0x40, so the packet size
register is a fixed <Address> plus a <pIndex> scaled by the channel
stride. Ignoring the <pIndex> term always addresses channel 0.
════════════════════════════════════════════════════════════════════ -->
<Integer Name="GevStreamChannelSelector" NameSpace="Standard">
<ToolTip>Stream channel the GevSCP* features address</ToolTip>
<Address>0x20090</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<Sign>Unsigned</Sign>
<Min>0</Min>
<Max>1</Max>
<Endianess>BigEndian</Endianess>
</Integer>
<Integer Name="GevSCPSPacketSize" NameSpace="Standard">
<ToolTip>Stream channel packet size in bytes</ToolTip>
<Address>0x0D04</Address>
<pIndex Offset="0x40">GevStreamChannelSelector</pIndex>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<Sign>Unsigned</Sign>
<Min>0</Min>
<Max>65535</Max>
<Endianess>BigEndian</Endianess>
</Integer>
<!-- ════════════════════════════════════════════════════════════════════
Acquisition Control Features
════════════════════════════════════════════════════════════════════ -->
<Enumeration Name="AcquisitionMode" NameSpace="Standard">
<ToolTip>Camera acquisition mode</ToolTip>
<EnumEntry Name="Continuous"><Value>0</Value></EnumEntry>
<EnumEntry Name="SingleFrame"><Value>1</Value></EnumEntry>
<EnumEntry Name="MultiFrame"><Value>2</Value></EnumEntry>
<pValue>AcquisitionModeReg</pValue>
</Enumeration>
<IntReg Name="AcquisitionModeReg"><Address>0x20020</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Command Name="AcquisitionStart" NameSpace="Standard">
<ToolTip>Start image acquisition</ToolTip>
<Address>0x20024</Address>
<Length>4</Length>
<AccessMode>WO</AccessMode>
<CommandValue>1</CommandValue>
<Endianess>BigEndian</Endianess>
</Command>
<Command Name="AcquisitionStop" NameSpace="Standard">
<ToolTip>Stop image acquisition</ToolTip>
<Address>0x20028</Address>
<Length>4</Length>
<AccessMode>WO</AccessMode>
<CommandValue>1</CommandValue>
<Endianess>BigEndian</Endianess>
</Command>
<Boolean Name="AcquisitionFrameRateEnable" NameSpace="Standard">
<ToolTip>Enable manual control of AcquisitionFrameRate. When false, the frame rate is unavailable for read/write.</ToolTip>
<pValue>AcquisitionFrameRateEnableReg</pValue>
</Boolean>
<IntReg Name="AcquisitionFrameRateEnableReg"><Address>0x20054</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess>
<pIsImplemented>FrameRateControlInq_Bit</pIsImplemented>
</IntReg>
<Float Name="AcquisitionFrameRate" NameSpace="Standard">
<ToolTip>Target frame rate in Hz</ToolTip>
<Address>0x2002c</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<Min>1.0</Min>
<Max>120.0</Max>
<Endianess>BigEndian</Endianess>
<pIsAvailable>AcquisitionFrameRateEnable</pIsAvailable>
</Float>
<Float Name="ExposureTime" NameSpace="Standard">
<ToolTip>Exposure time in microseconds — locked to RO when ExposureAuto is not Off</ToolTip>
<Address>0x20030</Address>
<Length>8</Length>
<AccessMode>RW</AccessMode>
<Min>10.0</Min>
<Max>1000000.0</Max>
<Endianess>BigEndian</Endianess>
<pIsLocked>ExposureAutoActive</pIsLocked>
</Float>
<Enumeration Name="ExposureAuto" NameSpace="Standard">
<ToolTip>Automatic exposure control</ToolTip>
<EnumEntry Name="Off"><Value>0</Value></EnumEntry>
<EnumEntry Name="Once"><Value>1</Value></EnumEntry>
<EnumEntry Name="Continuous"><Value>2</Value></EnumEntry>
<pValue>ExposureAutoReg</pValue>
</Enumeration>
<IntReg Name="ExposureAutoReg"><Address>0x20038</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<IntSwissKnife Name="ExposureAutoActive">
<Formula>EA <> 0</Formula>
<pVariable Name="EA">ExposureAutoReg</pVariable>
</IntSwissKnife>
<!-- ════════════════════════════════════════════════════════════════════
Analog Control Features
════════════════════════════════════════════════════════════════════ -->
<Float Name="Gain" NameSpace="Standard">
<!-- CDATA-wrapped tooltip, as shipped by several vendors: the literal `&`
and `<` inside are legal here and must survive parsing (issue #45). -->
<ToolTip><![CDATA[Gain applied to the image in dB — locked to RO when GainAuto is not Off (0 < gain & gain < 48)]]></ToolTip>
<Address>0x20040</Address>
<Length>8</Length>
<AccessMode>RW</AccessMode>
<Min>0.0</Min>
<Max>48.0</Max>
<Endianess>BigEndian</Endianess>
<pIsLocked>GainAutoActive</pIsLocked>
</Float>
<Enumeration Name="GainAuto" NameSpace="Standard">
<ToolTip>Automatic gain control</ToolTip>
<EnumEntry Name="Off"><Value>0</Value></EnumEntry>
<EnumEntry Name="Once"><Value>1</Value></EnumEntry>
<EnumEntry Name="Continuous"><Value>2</Value></EnumEntry>
<pValue>GainAutoReg</pValue>
</Enumeration>
<IntReg Name="GainAutoReg"><Address>0x20048</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<IntSwissKnife Name="GainAutoActive">
<Formula>GA <> 0</Formula>
<pVariable Name="GA">GainAutoReg</pVariable>
</IntSwissKnife>
<Integer Name="BlackLevel" NameSpace="Standard">
<ToolTip>Analog black level offset</ToolTip>
<Address>0x20050</Address>
<Length>4</Length>
<AccessMode>RW</AccessMode>
<Min>0</Min>
<Max>255</Max>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<!-- ════════════════════════════════════════════════════════════════════
Transport Layer Control (Timestamp)
════════════════════════════════════════════════════════════════════ -->
<Integer Name="GevTimestampTickFrequency" NameSpace="Standard">
<ToolTip>Device timestamp tick frequency in Hz (1 GHz)</ToolTip>
<Address>0x20060</Address>
<Length>4</Length>
<AccessMode>RO</AccessMode>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<Integer Name="GevTimestampValue" NameSpace="Standard">
<ToolTip>Current device timestamp in ticks (latched)</ToolTip>
<Address>0x20068</Address>
<Length>8</Length>
<AccessMode>RO</AccessMode>
<Sign>Unsigned</Sign>
<Endianess>BigEndian</Endianess>
</Integer>
<Command Name="TimestampLatch" NameSpace="Standard">
<ToolTip>Latch the current timestamp into GevTimestampValue</ToolTip>
<Address>0x20070</Address>
<Length>4</Length>
<AccessMode>WO</AccessMode>
<CommandValue>1</CommandValue>
<Endianess>BigEndian</Endianess>
</Command>
<!-- ════════════════════════════════════════════════════════════════════
Chunk Data Control
════════════════════════════════════════════════════════════════════ -->
<!-- SFNC defines ChunkModeActive and ChunkEnable as IBoolean, and all 23
vendor-corpus documents that declare ChunkModeActive use <Boolean> over
a backing <IntReg> - none uses <Integer>. Declaring them as <Integer>
here made Camera::configure_chunks, which correctly calls set_bool,
fail against the only camera we can test with. -->
<Boolean Name="ChunkModeActive" NameSpace="Standard">
<ToolTip>Enable chunk data in image frames</ToolTip>
<pValue>ChunkModeActiveReg</pValue>
</Boolean>
<IntReg Name="ChunkModeActiveReg"><Address>0x20080</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Enumeration Name="ChunkSelector" NameSpace="Standard">
<ToolTip>Select which chunk feature to configure</ToolTip>
<EnumEntry Name="Timestamp"><Value>1</Value></EnumEntry>
<EnumEntry Name="ExposureTime"><Value>2</Value></EnumEntry>
<EnumEntry Name="Gain"><Value>3</Value></EnumEntry>
<pValue>ChunkSelectorReg</pValue>
</Enumeration>
<IntReg Name="ChunkSelectorReg"><Address>0x20084</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Boolean Name="ChunkEnable" NameSpace="Standard">
<ToolTip>Enable the selected chunk feature</ToolTip>
<pValue>ChunkEnableReg</pValue>
</Boolean>
<IntReg Name="ChunkEnableReg"><Address>0x20088</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<!-- Event delivery is selected through GenApi, not through a bootstrap
register: EventSelector picks a GigE Vision event id and
EventNotification turns it on. The ids are the standard ones
(GEV_EVENT_START_OF_TRANSFER = 0x0005, END_OF_TRANSFER = 0x0006). -->
<Enumeration Name="EventSelector" NameSpace="Standard">
<ToolTip>Select which event to configure</ToolTip>
<EnumEntry Name="StartOfTransfer"><Value>5</Value></EnumEntry>
<EnumEntry Name="EndOfTransfer"><Value>6</Value></EnumEntry>
<pValue>EventSelectorReg</pValue>
</Enumeration>
<IntReg Name="EventSelectorReg"><Address>0x200A0</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
<Enumeration Name="EventNotification" NameSpace="Standard">
<ToolTip>Enable notification for the selected event</ToolTip>
<EnumEntry Name="Off"><Value>0</Value></EnumEntry>
<EnumEntry Name="On"><Value>1</Value></EnumEntry>
<pValue>EventNotificationReg</pValue>
</Enumeration>
<IntReg Name="EventNotificationReg"><Address>0x200A4</Address><Length>4</Length><AccessMode>RW</AccessMode><Sign>Unsigned</Sign><Endianess>BigEndian</Endianess></IntReg>
</RegisterDescription>
"#;Expand description
GenApi XML describing a realistic fake camera following SFNC conventions.
The XML is organized with proper SFNC category hierarchy:
Root
├── DeviceControl — model name, vendor, serial, firmware, device ID
├── ImageFormatControl — width, height, offset, pixel format, sensor size
├── AcquisitionControl — start/stop, mode, frame rate, exposure, auto
├── AnalogControl — gain, gain auto, black level
├── TransportLayerControl — timestamp tick frequency, value, latch
└── ChunkDataControl — chunk mode, selector, enableAll feature registers use big-endian byte order. Register addresses are documented in the module-level doc comment.