All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.huskerdev.grapl.ext.display.DisplayExt.kt Maven / Gradle / Ivy

@file:OptIn(ExperimentalUnsignedTypes::class)

package com.huskerdev.grapl.ext.display

import com.huskerdev.grapl.core.Size
import com.huskerdev.grapl.core.display.Display
import com.huskerdev.grapl.ext.display.utils.intAt
import java.time.LocalDate
import java.time.Month

enum class VideoInterface {
    UNDEFINED,
    DVI,
    HDMI,
    MDDI,
    DISPLAY_PORT
}


val manufacturers by lazy {
    object {}::class.java.getResourceAsStream("/com/huskerdev/grapl/ext/display/manufacturers")
        ?.reader()?.readLines()?.associate { line ->
            val key = line.split(" ")[0]
            key to line.replace("$key ", "")
        } ?: emptyMap()
}

val Display.manufacturerId: String
    get() = edid.run {
        val third = (this[9] and 0b00011111u).toInt()
        val second = (this[8].toInt() and 0b00000011 shl 3) or (this[9].toInt() and 0b11100000 shr 5)
        val first = (this[8].toInt() and 0b01111100 shr 2)

        return@run "${(first + 64).toChar()}${(second + 64).toChar()}${(third + 64).toChar()}"
    }

val Display.manufacturerName: String?
    get() = manufacturers[this.manufacturerId]

val Display.manufactureYear: Int
    get() = edid[17].toInt() + 1990

val Display.manufactureWeek: Int
    get() = edid[16].toInt()

val Display.manufactureDate: LocalDate
    get() = edid.run {
        return@run LocalDate.of(this[17].toInt() + 1990, Month.JANUARY, 1)
            .plusWeeks(this[16].toLong())
    }

val Display.productId: String
    get() = edid.run {
        return@run ((this[11].toLong() shl 8) or this[10].toLong())
            .toString(16).padStart(4, '0')
    }

val Display.serialNumber: String
    get() = edid.run {
        return@run (this[15].toString(16) +
                   this[14].toString(16) +
                   this[13].toString(16) +
                   this[12].toString(16)).padStart(8, '0')
    }

val Display.isDigital: Boolean
    get() = edid[20] and 0b10000000.toUByte() == 0b10000000.toUByte()

val Display.videoInterface: VideoInterface
    get() = if(isDigital) edid.run {
        when(intAt(20) and 0b00001111) {
            1 -> VideoInterface.DVI
            2, 3 -> VideoInterface.HDMI
            4 -> VideoInterface.MDDI
            5 -> VideoInterface.DISPLAY_PORT
            else -> {
                // Iterate over extensions
                for(i in 1..intAt(126)){
                    val o = i * 128
                    // If extension is CTA v3
                    if(intAt(o) == 2 && intAt(o+1) == 3){
                        var r = 4
                        val dtdEnd = intAt(o+2)
                        while(r < dtdEnd){
                            // If block is Vendor Specific Data Block
                            if((intAt(o+r) and 0b11100000 shr 5) == 3){
                                val k3 = intAt(o+r+1)
                                val k2 = intAt(o+r+2)
                                val k1 = intAt(o+r+3)
                                // If IEEE Registration Identifier is:
                                // HDMI Licensing, LLC (00 0C 03)
                                // or
                                // HDMI Forum          (C4 5D D8)
                                if((k1 == 0x00 && k2 == 0x0C && k3 == 0x03) ||
                                   (k1 == 0xC4 && k2 == 0x5D && k3 == 0xD8)
                                ) return@run VideoInterface.HDMI
                            }
                            r += 1 + (intAt(o+r) and 0b00011111)
                        }
                    }
                }
                VideoInterface.UNDEFINED
            }
        }
    } else VideoInterface.UNDEFINED


val Display.edidVersion: String
    get() = edid.run { "${this[18]}.${this[19]}" }

val Display.mmSize: Size
    get() = edid.run {
        if(this[54].toInt() != 0 && this[55].toInt() != 0)
            Size(intAt(54 + 12) or (intAt(54 + 14) and 0b11110000 shl 4),
                 intAt(54 + 13) or (intAt(54 + 14) and 0b00001111 shl 8))
        else
            Size(this[21].toInt() * 10,
                 this[22].toInt() * 10)
    }

val Display.name: String
    get() = edid.run {
        for(i in 54..108 step 18){
            if(intAt(i) == 0 && intAt(i + 1) == 0 && intAt(i + 2) == 0 &&
                (intAt(i + 3) == 0xFC || intAt(i + 3) == 0xFE)
            ){
                var name = ""
                var r = i + 5
                while(intAt(r) != 10 && r < i + 18){
                    name += intAt(r).toChar()
                    r++
                }
                return@run name
            }
        }
        return@run "Display"
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy