Skip to main content

mx_remote/types/
osd.rs

1// Author: Lars Op den Kamp (lars@opdenkamp-it.nl)
2// Copyright (c) 2026 Op den Kamp IT Solutions
3
4//! Overlay sync: a management unit having other units copy its overlay
5//! settings and logos.
6//!
7//! The source sends a sync naming what it copies and how many settings
8//! follow. Each unit asks the source for the settings it lacks, takes them,
9//! and reports how that went. Every frame of a sync carries the same `seq`,
10//! which the source numbers on its own.
11
12use std::net::Ipv4Addr;
13
14use crate::wire::{
15    DeviceUid, OsdCaptionAlign, OsdCaptionFormat, OsdSyncSize, OsdSyncState, OsdSyncWhat,
16};
17
18/// The logo slots a sync can copy.
19pub const OSD_SYNC_SLOTS: usize = 4;
20
21/// One logo slot, as a sync describes it.
22#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
23pub struct OsdSyncSlot {
24    /// The PNG's size in bytes; zero empties the slot.
25    pub bytes: u32,
26    /// The PNG's CRC-32.
27    pub crc32: u32,
28    /// The size it is shown at, in percent.
29    pub percent: u8,
30}
31
32/// A sync, as its source sent it.
33///
34/// A unit takes one only from a management unit: the mesh controller, or
35/// one that reports [`DeviceFeature::MANAGER`](crate::DeviceFeature::MANAGER).
36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct OsdSync {
38    /// The sync's number at its source.
39    pub seq: u16,
40    /// The unit it is for, or [`DeviceUid::ZERO`] for every unit.
41    pub target: DeviceUid,
42    /// What it copies.
43    pub what: OsdSyncWhat,
44    /// The source's HTTP port, zero meaning 80.
45    pub http_port: u16,
46    /// The source's address, unspecified meaning the sender's.
47    pub source_ip: Ipv4Addr,
48    /// How many settings follow.
49    pub records: u16,
50    /// The logo slots, when it copies them. A unit fetches a slot whose size
51    /// or CRC differs from its own from
52    /// `http://source_ip:http_port/osd-sync/slotN.png`, N being 1 to 4.
53    pub slots: Option<[OsdSyncSlot; OSD_SYNC_SLOTS]>,
54}
55
56/// A unit asking for a sync, or for settings of one it is taking, or
57/// management asking for a new sync for a unit.
58#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct OsdSyncRequest {
60    /// The unit the sync is for, which sent the request unless management
61    /// did.
62    pub target: DeviceUid,
63    /// The sync whose settings it asks for, or zero asking for a new sync.
64    pub seq: u16,
65    /// What it asks a new sync to copy.
66    pub what: OsdSyncWhat,
67    /// The settings it lacks, bit `i` standing for setting `i`.
68    pub missing: [u8; 16],
69    /// Who sent the sync it asks about. [`DeviceUid::ZERO`] when it asks for
70    /// a new sync, and from a unit whose module does not name the source.
71    pub source: DeviceUid,
72}
73
74impl OsdSyncRequest {
75    /// Whether the unit lacks setting `index`.
76    pub fn is_missing(&self, index: u16) -> bool {
77        self.missing
78            .get(usize::from(index / 8))
79            .is_some_and(|b| b & (1 << (index % 8)) != 0)
80    }
81}
82
83/// A caption, as a setting gives it.
84#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct OsdCaption {
86    /// The font's name, empty for the layout's.
87    pub font: String,
88    /// The size, zero for the layout's.
89    pub size: u16,
90    /// The horizontal position, `i16::MIN` for the layout's.
91    pub x: i16,
92    /// The vertical position, `i16::MIN` for the layout's.
93    pub y: i16,
94    /// The wrap width in pixels: -1 automatic, 0 none, -2 the layout's.
95    pub wrap: i16,
96    /// The alignment.
97    pub align: OsdCaptionAlign,
98    /// How the text is read.
99    pub format: OsdCaptionFormat,
100    /// The colour as 0xRRGGBB, `u32::MAX` for the layout's.
101    pub colour: u32,
102    /// The text.
103    pub text: String,
104}
105
106/// A logo choice and place, as a setting gives it.
107#[derive(Clone, Copy, Debug, PartialEq, Eq)]
108pub struct OsdLogo {
109    /// 0 the built-in logo, -1 none, 1 to 4 a slot.
110    pub logo: i8,
111    /// The horizontal position, `i16::MIN` for the layout's.
112    pub x: i16,
113    /// The vertical position, `i16::MIN` for the layout's.
114    pub y: i16,
115}
116
117/// What one setting of a sync sets.
118#[derive(Clone, Debug, PartialEq, Eq)]
119pub enum OsdSyncValue {
120    /// A caption.
121    Caption(OsdCaption),
122    /// A logo choice and place.
123    Logo(OsdLogo),
124    /// A background colour as 0xRRGGBB, `u32::MAX` for the layout's.
125    Background(u32),
126}
127
128/// One setting of a sync, which its source sends to one unit.
129#[derive(Clone, Debug, PartialEq, Eq)]
130pub struct OsdSyncSetting {
131    /// The sync it belongs to.
132    pub seq: u16,
133    /// The unit it is for.
134    pub target: DeviceUid,
135    /// Its place in the sync, below `records`.
136    pub index: u16,
137    /// How many settings the sync has.
138    pub records: u16,
139    /// The output size it applies at.
140    pub size: OsdSyncSize,
141    /// The layers it applies to, a bit per layer.
142    pub layers: u16,
143    /// The fields it gives: [`OsdCaptionField`](crate::OsdCaptionField)
144    /// bits for a caption, [`OsdLogoField`](crate::OsdLogoField) bits for a
145    /// logo, and bit 0 for a background's colour.
146    pub set: u16,
147    /// What it sets.
148    pub value: OsdSyncValue,
149}
150
151/// How a unit is getting on with a sync.
152///
153/// A unit reports taking, then done or failed. One in power save reports
154/// deferred, and reports again once it takes the sync on waking.
155#[derive(Clone, Debug, PartialEq, Eq)]
156pub struct OsdSyncReport {
157    /// The sync it reports on, numbered by the source that sent it.
158    pub seq: u16,
159    /// How far it has got.
160    pub state: OsdSyncState,
161    /// The settings it wrote.
162    pub written: u16,
163    /// The settings it refused.
164    pub refused: u16,
165    /// Why it failed or refused any.
166    pub reason: String,
167}
168
169/// The most settings one sync carries.
170pub const OSD_SYNC_RECORDS_MAX: usize = 128;
171
172/// The longest caption font name, in bytes.
173pub const OSD_SYNC_FONT_MAX: usize = 31;
174
175/// The longest caption text a unit shows, in bytes. It cuts a longer one
176/// short.
177pub const OSD_SYNC_TEXT_MAX: usize = 360;
178
179/// The largest logo image a unit takes, in bytes.
180pub const OSD_SYNC_IMAGE_MAX: usize = 512 * 1024;
181
182/// The widest and tallest logo image a unit takes, in pixels.
183pub const OSD_SYNC_IMAGE_WIDTH_MAX: u32 = 1920;
184/// See [`OSD_SYNC_IMAGE_WIDTH_MAX`].
185pub const OSD_SYNC_IMAGE_HEIGHT_MAX: u32 = 1080;
186
187/// The largest size a logo is shown at, in percent.
188pub const OSD_SYNC_PERCENT_MAX: u8 = 100;
189
190/// One setting of a sync this client sends.
191#[derive(Clone, Debug, PartialEq, Eq)]
192pub struct OsdSyncEntry {
193    /// The output size it applies at.
194    pub size: OsdSyncSize,
195    /// The layers it applies to, a bit per layer. A unit leaves out the
196    /// layers it does not have, and skips the setting when none is left.
197    pub layers: u16,
198    /// The fields it gives, as in [`OsdSyncSetting::set`]. A field given its
199    /// default value goes back to the layout's.
200    pub set: u16,
201    /// What it sets.
202    pub value: OsdSyncValue,
203}
204
205/// The logo image for one slot.
206#[derive(Clone, Debug, Default, PartialEq, Eq)]
207pub struct OsdSyncImage {
208    /// The PNG. Empty empties the slot.
209    pub png: Vec<u8>,
210    /// The size it is shown at: 0 at its own pixels, 1 to 100 its longer
211    /// side as a percent of the large overlay.
212    pub percent: u8,
213}
214
215/// What this client has units copy.
216#[derive(Clone, Debug, Default, PartialEq, Eq)]
217pub struct OsdSyncContent {
218    /// The kinds of setting it copies.
219    /// [`OsdSyncWhat::LOGO_SLOTS`] follows from `images`.
220    pub what: OsdSyncWhat,
221    /// The settings, which units write in this order.
222    pub entries: Vec<OsdSyncEntry>,
223    /// The four logo slots, or `None` to leave every unit's own.
224    pub images: Option<[OsdSyncImage; OSD_SYNC_SLOTS]>,
225}