pub const TOPOLOGYLIB: &'static str = "
% ===== Topology traversal procedures
next_entity(Eid, EidNext) :-
pad(Pid, Eid, source, _, _),
link(_, Pid, PidSink, _),
pad(PidSink, EidNext, sink, _, _).
last_interface(Eid, Iid) :-
interfacelink(_, Iid, Eid, _).
last_interface(Eid, Iid) :-
next_entity(Eid, EidNext), last_interface(EidNext, Iid).
% Finds all confgurations along the path. Configs is a list of alternating source-sink pads to connect together. The outermost element is the sensor source pad, the innermost is the video capture device, which is not a pad.
%
% Pad format:
% padcfg(
% EntityId,
% PadIdx, % index within the entity
% format(Mbus, Width, Height) % Mbus is an atom from the mbus code list, e.g. `mbus_Y8_1X8`.
% ).
%
% Output format:
% outcfg(EntityId, PadIdx, FourCC, W, H). % FourCC is a fourCC code as an atom, like `fourcc_BA10`.
%
% Video format shape:
% videofomat(FourCC, W, H).
%
% The application should traverse the list from outside to inside and connect pads while configuring with interleaved `VIDIOC_SUBDEV_S_FMT` and `MEDIA_IOC_SETUP_LINK` calls, finishing on the video device with `VIDIOC_S_FMT`.
% In theory, it doesn't matter which direction traversal takes.
% In practice, we don't have fast integer constraints, and devices requiring them are after the sensor, so traversal must be from the sensor to the end.
% Carrying VideoFormat is required becase if it's checked after the list is built, this slows dows the code to unbearable levels.
% Once that changes, it may make more sense to go in reverse and stop carrying the VideoFormat all the way through.
% Traversal forward might still be useful even then because that's how the kernel interface expects the pipeline configuration to be discovered.
% GIven an entity ID and the desired format on the video device, return a list of configs.
config_path(SensorEntityId, VideoFormat, Configs) :-
entity(Sensor, SensorEntityId, sensor),
config_path_by_name(Sensor, VideoFormat, Configs).
% GIven an entity name and the desired format on the video device, return a list of configs.
config_path_by_name(Sensor, VideoFormat, Configs) :-
source(Sensor, PadIdx, Mbus, W, H),
entity(Sensor, EntityId, sensor),
config_follow_source_pad(EntityId, PadIdx, format(Mbus, W, H), VideoFormat, Configs).
config_intermediate(PadId, Format, VideoFormat, PadConfigs) :-
pad(PadId, EntityId, sink, PadIdx, _),
entity(Name, EntityId, _),
processing(Name, PadIdx, Format, PadIdxOut, FormatOut),
config_follow_source_pad(EntityId, PadIdxOut, FormatOut, VideoFormat, ConfigsProduced),
append(ConfigsProduced, padcfg(EntityId, PadIdx, Format), PadConfigs).
config_follow_source_pad(EntityId, PadIdxOut, FormatOut, VideoFormat, ConfigsProduced) :-
pad(PadIdOut, EntityId, source, PadIdxOut, _),
link(_, PadIdOut, PadIdSink, _),
config_next(PadIdSink, FormatOut, VideoFormat, ConfigsOutput),
append(ConfigsOutput, padcfg(EntityId, PadIdxOut, FormatOut), ConfigsProduced).
% gathers configs all the way to the output
config_next(PadId, Format, VideoFormat, PadConfigs) :-
config_intermediate(PadId, Format, VideoFormat, PadConfigs).
config_next(PadId, Format, VideoFormat, l(Config, nil)) :-
eq(Config, outcfg(_, _, VideoFormat)),
config_output(PadId, Format, Config).
config_output(PadId, Format, outcfg(EntityId, PadIdx, videoformat(FourCC, W, H))) :-
pad(PadId, EntityId, sink, PadIdx, _),
entity(Name, EntityId, io),
output(Name, Format, FourCC),
eq(Format, format(_, W, H)).
% usage: config_path_by_name(dev_s5k3l6xx_3_002d, videoformat(Fourcc, W, H), A).
% Extracts the video device config from the config list generated in config_path_by_name.
videodevice_config(ConfigList, VideoConfig) :- last(ConfigList, VideoConfig).
";