...

Source file src/edge-infra.dev/pkg/sds/display/k8s/apis/v2/displayconfig.go

Documentation: edge-infra.dev/pkg/sds/display/k8s/apis/v2

     1  package v2
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"edge-infra.dev/pkg/lib/kernel/drm"
     7  	v1 "edge-infra.dev/pkg/sds/display/k8s/apis/v1"
     8  	"edge-infra.dev/pkg/sds/lib/set"
     9  )
    10  
    11  const (
    12  	// A display's card where the card could not be found.
    13  	UnknownCard = "unknown"
    14  	// A display which was disconnected during the V1 to V2 upgrade.
    15  	DisconnectedPort = "disconnected"
    16  )
    17  
    18  // DisplayConfig defines the configuration for displays.
    19  type DisplayConfig struct {
    20  	// Maps monitor display-ports to display configurations.
    21  	Displays Displays `json:"displays,omitempty"`
    22  	// DPMS configuration
    23  	DPMS *DPMS `json:"dpms,omitempty"`
    24  	// Layout of the displays as slice, ordered left to right.
    25  	Layout Layout `json:"layout,omitempty"`
    26  
    27  	// The V1 spec following conversion from V1 to V2 by the
    28  	// conversion webhook. This will be used by displayctl to
    29  	// upgrade the spec to V2.
    30  	//
    31  	// This must only be set during conversion from V1 to V2
    32  	// and cannot be set after the upgrade is complete.
    33  	V1 *v1.DisplayConfig `json:"v1-displayConfig,omitempty"`
    34  }
    35  
    36  // The set of display-ports from both the displays and layout fields.
    37  func (displayConfig *DisplayConfig) DisplayPorts() []DisplayPort {
    38  	if displayConfig == nil {
    39  		return []DisplayPort{}
    40  	}
    41  	dps := set.OrderedFromSlice(displayConfig.Displays.DisplayPorts())
    42  	dps.Add(displayConfig.Layout...)
    43  	return dps.ToSlice()
    44  }
    45  
    46  // Whether there is V1 spec which is yet to be upgraded.
    47  func (displayConfig *DisplayConfig) HasV1() bool {
    48  	return displayConfig != nil && displayConfig.V1 != nil
    49  }
    50  
    51  // Whether any of the displays were disconnected during V1 to V2
    52  // upgrade and still requrie display-port identification.
    53  func (displayConfig *DisplayConfig) HasDisconnected() bool {
    54  	if displayConfig == nil {
    55  		return false
    56  	}
    57  	for _, display := range displayConfig.Displays {
    58  		if !display.IsConnected() {
    59  			return true
    60  		}
    61  	}
    62  	for _, dp := range displayConfig.Layout {
    63  		if !dp.IsConnected() {
    64  			return true
    65  		}
    66  	}
    67  	return false
    68  }
    69  
    70  type Displays []Display
    71  
    72  // Updates the display with matching display-port.
    73  // Adds a new display if it is not yet present.
    74  func (displays *Displays) UpdateDisplay(display Display) {
    75  	if display.DisplayPort == "" {
    76  		return
    77  	}
    78  	if currentDisplay := displays.FindByDisplayPort(display.DisplayPort); currentDisplay != nil {
    79  		*currentDisplay = display
    80  	} else {
    81  		*displays = append(*displays, display)
    82  	}
    83  }
    84  
    85  // The display with given display-port (nil if not found).
    86  func (displays Displays) FindByDisplayPort(dp DisplayPort) *Display {
    87  	for idx, display := range displays {
    88  		if display.DisplayPort == dp {
    89  			return &displays[idx]
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  // The display with given MPID (nil if not found).
    96  func (displays Displays) FindByMPID(mpid MPID) *Display {
    97  	for idx, display := range displays {
    98  		if display.MPID != nil && *display.MPID == mpid {
    99  			return &displays[idx]
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  // The primary display.
   106  func (displays Displays) FindPrimary() *Display {
   107  	for _, display := range displays {
   108  		if display.IsPrimary() {
   109  			return &display
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  // Returns the displays display-ports.
   116  func (displays Displays) DisplayPorts() []DisplayPort {
   117  	dps := []DisplayPort{}
   118  	for _, display := range displays {
   119  		dps = append(dps, display.DisplayPort)
   120  	}
   121  	return dps
   122  }
   123  
   124  // Display configures a display's monitor and input devices.
   125  type Display struct {
   126  	// DisplayPort is the display card and physical port the
   127  	// display is connected to, e.g. card0-DP1, card1-HDMI2 etc.
   128  	//
   129  	// This field is NOT optional.
   130  	DisplayPort `json:"displayPort"`
   131  	// Manufacturer and Product-Code ID, a unique identifier
   132  	// for the display, i.e. "<manufacturer-ID>-<product-code>".
   133  	//
   134  	// It is NOT valid to configure this field in the
   135  	// NodeDisplayConfig spec.
   136  	*MPID `json:"mpid,omitempty"`
   137  	// Primary indicates whether this is the primary display.
   138  	*Primary `json:"primary,omitempty"`
   139  	// Orientation of the display, e.g "left" or "inverted".
   140  	Orientation *Orientation `json:"orientation,omitempty"`
   141  	// Resolution is the current resolution of the display.
   142  	*Resolution `json:"resolution,omitempty"`
   143  	// SupportedResolutions are the valid resolutions the
   144  	// display can be configured to use.
   145  	//
   146  	// It is NOT valid to configure this field in the
   147  	// NodeDisplayConfig spec. The resolution of the display
   148  	// can be configured via the Resolution field.
   149  	SupportedResolutions []Resolution `json:"supportedResolutions,omitempty"`
   150  	// InputDeviceMappings are the devices the display maps to.
   151  	InputDeviceMappings []InputDeviceName `json:"inputDeviceMappings,omitempty"`
   152  }
   153  
   154  // +kubebuilder:validation:Pattern=`^(unknown|card\d)(-[A-Za-z0-9]+)+$`
   155  //
   156  // DisplayPort is the display card and physical port the
   157  // display is connected to, e.g. card0-DP1, card1-HDMI-A-2 etc.
   158  //
   159  // If a card cannot be found for a display it will be marked
   160  // unknown, e.g. unknown-DP2.
   161  //
   162  // Displays that were disconnected during upgrade from V1 to V2
   163  // will be marked disconnected, e.g. unknown-disconnected-1.
   164  type DisplayPort string
   165  
   166  func NewDisplayPort(card, port string) DisplayPort {
   167  	return DisplayPort(fmt.Sprintf("%s-%s", card, port))
   168  }
   169  
   170  func (dp *DisplayPort) String() string {
   171  	if dp == nil {
   172  		return ""
   173  	}
   174  	return string(*dp)
   175  }
   176  
   177  // Whether a display is connected.
   178  //
   179  // A display can be disconnected if it was not
   180  // present during the V1 to V2 upgrade.
   181  func (dp DisplayPort) IsConnected() bool {
   182  	// if the display-port is not a valide connector name, it must be disconncted.
   183  	err := drm.ValidateConnectorName(dp.String())
   184  	return err == nil
   185  }
   186  
   187  // +kubebuilder:validation:Pattern=`^[A-Z]{3}-\d{1,5}$`
   188  //
   189  // Manufacturer and Product-Code ID, a unique identifier for
   190  // the display, i.e. "<manufacturer-ID>-<product-code>".
   191  type MPID string
   192  
   193  func NewMPID(manufacturer string, productCode uint) MPID {
   194  	return MPID(fmt.Sprintf("%s-%d", manufacturer, productCode))
   195  }
   196  
   197  func (mpid *MPID) String() string {
   198  	if mpid == nil {
   199  		return ""
   200  	}
   201  	return string(*mpid)
   202  }
   203  
   204  // Primary indicates whether a display is the primary display.
   205  type Primary bool
   206  
   207  func (display *Display) IsPrimary() bool {
   208  	if display.Primary == nil {
   209  		return false
   210  	}
   211  	return bool(*display.Primary)
   212  }
   213  
   214  func (display *Display) SetPrimary(primary bool) {
   215  	display.Primary = (*Primary)(&primary)
   216  }
   217  
   218  // +kubebuilder:validation:Enum=normal;left;right;inverted
   219  //
   220  // Orientation is the displays orientation, e.g "normal",
   221  // "left", "right" or "inverted".
   222  type Orientation string
   223  
   224  var (
   225  	NormalOrientation   Orientation = "normal"
   226  	LeftOrientation     Orientation = "left"
   227  	RightOrientation    Orientation = "right"
   228  	InvertedOrientation Orientation = "inverted"
   229  )
   230  
   231  func (o *Orientation) String() string {
   232  	if o == nil {
   233  		return ""
   234  	}
   235  	return string(*o)
   236  }
   237  
   238  // Resolution defines the resolution of a display.
   239  type Resolution struct {
   240  	// +kubebuilder:validation:Minimum=0
   241  	//
   242  	// Width of the display in pixels.
   243  	Width int `json:"width"`
   244  	// +kubebuilder:validation:Minimum=0
   245  	//
   246  	// Height of the display in pixels.
   247  	Height int `json:"height"`
   248  }
   249  
   250  func (res *Resolution) String() string {
   251  	if res == nil {
   252  		return ""
   253  	}
   254  	return fmt.Sprintf("%dx%d", res.Width, res.Height)
   255  }
   256  
   257  // InputDeviceName is the name of an input device
   258  type InputDeviceName string
   259  
   260  func (name *InputDeviceName) String() string {
   261  	if name == nil {
   262  		return ""
   263  	}
   264  	return string(*name)
   265  }
   266  
   267  // DPMS describes the DPMS configuration for a display.
   268  type DPMS struct {
   269  	// Enabled indicates whether DPMS is enabled for the node.
   270  	Enabled *bool `json:"enabled,omitempty"`
   271  	// +kubebuilder:validation:Minimum=0
   272  	//
   273  	// BlankTime configures the number of seconds of inactivity
   274  	// before reaching the blank phase of the screen saver.
   275  	BlankTime *int `json:"blankTime,omitempty"`
   276  	// +kubebuilder:validation:Minimum=0
   277  	//
   278  	// StandbyTime configures the number of seconds of inactivity
   279  	// before reaching the standby phase of the DPMS mode.
   280  	StandbyTime *int `json:"standybyTime,omitempty"`
   281  	// +kubebuilder:validation:Minimum=0
   282  	//
   283  	// SuspendTime configures the number of seconds of inactivity
   284  	// before reaching the suspend phase of the DPMS mode.
   285  	SuspendTime *int `json:"suspendTime,omitempty"`
   286  	// +kubebuilder:validation:Minimum=0
   287  	//
   288  	// OffTime configures the number of seconds of inactivity
   289  	// before reaching the off phase of the DPMS mode.
   290  	OffTime *int `json:"offTime,omitempty"`
   291  }
   292  
   293  // Layout describes the physical position of displays as their
   294  // display-port's ordered left to right.
   295  type Layout []DisplayPort
   296  

View as plain text