<?php

class CC100_HW extends IPSModule
{
    private $DigOutPID = "/sys/kernel/dout_drv/DOUT_DATA";
    private $PT1PID = "/sys/bus/iio/devices/iio:device2/in_voltage13_raw";
    private $PT2PID  = "/sys/bus/iio/devices/iio:device2/in_voltage1_raw";
    private $DIN_FILE = "/sys/devices/platform/soc/44009000.spi/spi_master/spi0/spi0.0/din";
    private $waitingTime = 1; // Waiting time (in ms) for a new attempt to write a digital output (if file is blocked)
    private $maxTime = 5000; // Max time (in ms) for the writing process

    public function Create()
    {
        parent::Create();
        $this->RegisterPropertyString("FilePath", $this->DigOutPID);
        $this->RegisterVariableBoolean("Bit1", "DO 1", "~Switch", 1);
        $this->RegisterVariableBoolean("Bit2", "DO 2", "~Switch", 2);
        $this->RegisterVariableBoolean("Bit3", "DO 3", "~Switch", 3);
        $this->RegisterVariableBoolean("Bit4", "DO 4", "~Switch", 4);

        $this->RegisterVariableBoolean("DI1", "DI1");
        $this->RegisterVariableBoolean("DI2", "DI2");
        $this->RegisterVariableBoolean("DI3", "DI3");
        $this->RegisterVariableBoolean("DI4", "DI4");
        $this->RegisterVariableBoolean("DI5", "DI5");
        $this->RegisterVariableBoolean("DI6", "DI6");
        $this->RegisterVariableBoolean("DI7", "DI7");
        $this->RegisterVariableBoolean("DI8", "DI8");

        $this->RegisterVariableFloat('PT1', 'PT1 Temperatur', '~Temperature', 5);
        $this->RegisterVariableFloat('PT2', 'PT2 Temperatur', '~Temperature', 6);
        $this->EnableAction("Bit1");
        $this->EnableAction("Bit2");
        $this->EnableAction("Bit3");
        $this->EnableAction("Bit4");

        // Timer für PT1 und PT2 einrichten
        // Timer für PT1 und PT2 einrichten
        $this->RegisterTimer("ReadPTValues", 30000, 'IPS_RequestAction(' . $this->InstanceID . ', "DOUT_ReadPTValues", "");');
        $this->RegisterTimer("WriteBits", 2000, 'IPS_RequestAction(' . $this->InstanceID . ', "UpdateFile", "");');
    }

    public function ApplyChanges()
    {
        parent::ApplyChanges();
        // Timer aktivieren
        $this->SetTimerInterval("ReadPTValues", 30000);
    }

    public function RequestAction($Ident, $Value)
    {
        switch ($Ident) {
            case "DOUT_ReadPTValues":
                $this->DOUT_ReadPTValues();
                break;
            case "UpdateFile":
                $this->UpdateFile();
                break;
            default:
                throw new Exception("Invalid Ident");
        }
    }

    private function UpdateFile()
    {
        $starttime = microtime(true) * 2000;
        $this->TryWriteFile($starttime);
    }

    private function readAndConvertToBools($filePath)
    {
        // Inhalt der Datei auslesen
        $content = @file_get_contents($filePath);

        if ($content === false) {
            throw new Exception("Fehler beim Lesen der Datei $filePath.");
        }

        // Die gelesene Zahl bereinigen (Leerzeichen oder Zeilenumbrüche entfernen)
        $number = trim($content);

        // Sicherstellen, dass die Zahl gültig ist
        if (!ctype_digit($number)) {
            throw new Exception(
                "Der Inhalt der Datei ist keine gültige Zahl: $number"
            );
        }

        // Die Zahl in einen Integer umwandeln
        $intValue = (int) $number;

        // Sicherstellen, dass die Zahl zwischen 0 und 255 liegt
        if ($intValue < 0 || $intValue > 255) {
            throw new Exception(
                "Die Zahl muss zwischen 0 und 255 liegen: $intValue"
            );
        }

        // In einen 8-Bit-Binärstring umwandeln
        $binaryString = str_pad(decbin($intValue), 8, "0", STR_PAD_LEFT);

        // Binärwerte in ein Array von booleschen Werten umwandeln
        $boolValues = array_map(
            fn($bit) => $bit === "1",
            str_split($binaryString)
        );

        $this->SetValue("DI1", $boolValues[7]);
        $this->SetValue("DI2", $boolValues[6]);
        $this->SetValue("DI3", $boolValues[5]);
        $this->SetValue("DI4", $boolValues[4]);
        $this->SetValue("DI5", $boolValues[3]);
        $this->SetValue("DI6", $boolValues[2]);
        $this->SetValue("DI7", $boolValues[1]);
        $this->SetValue("DI8", $boolValues[0]);
        return $boolValues;
    }

    private function TryWriteFile($starttime)
    {
        $this->readAndConvertToBools($this->DIN_FILE);

        $currentTime = microtime(true) * 1000;
        if ($currentTime - $starttime <= $this->maxTime) {
            $file = $this->ReadPropertyString("FilePath");
            if (is_writable($file)) {
                $bit1 = GetValueBoolean($this->GetIDForIdent("Bit1"));
                $bit2 = GetValueBoolean($this->GetIDForIdent("Bit2"));
                $bit3 = GetValueBoolean($this->GetIDForIdent("Bit3"));
                $bit4 = GetValueBoolean($this->GetIDForIdent("Bit4"));

                $value =
                    ($bit4 ? 8 : 0) +
                    ($bit3 ? 4 : 0) +
                    ($bit2 ? 2 : 0) +
                    ($bit1 ? 1 : 0);

                if (@file_put_contents($file, $value) === false) {
                    usleep($this->waitingTime * 1000);
                    $this->TryWriteFile($starttime);
                } 
            } else {

                usleep($this->waitingTime * 1000);
                $this->TryWriteFile($starttime);
            }
        } else {
            IPS_LogMessage(
                "DOUTModule",
                "Fehler: Schreibvorgang für Datei $file hat zu lange gedauert."
            );
        }
    }

    public function DOUT_ReadPTValues()
    {
        $pt1Value = $this->ReadPTValue($this->PT1PID);
        $pt2Value = $this->ReadPTValue($this->PT2PID);

        SetValue($this->GetIDForIdent("PT1"), $pt1Value);
        SetValue($this->GetIDForIdent("PT2"), $pt2Value);
    }

    private function ReadPTValue($file)
    {
        if (file_exists($file)) {
            $data = @file_get_contents($file);
            if ($data !== false) {
                $data = intval($data);
                $scale = 0;
                if ($data >= 600 && $data < 3600) {
                    $scale = 37;
                } elseif ($data >= 3600 && $data < 6700) {
                    $scale = 43;
                } elseif ($data >= 6700 && $data < 9750) {
                    $scale = 45;
                } elseif ($data >= 9750 && $data < 12740) {
                    $scale = 49;
                } elseif ($data >= 12740 && $data < 15700) {
                    $scale = 50.6;
                } elseif ($data >= 15700 && $data < 21000) {
                    $scale = 52.4;
                } elseif ($data > 21000) {
                    $scale = 53.7;
                }

                $numb = $data / $scale - 200;
                return round($numb, 1);
            } else {
                IPS_LogMessage(
                    "DOUTModule",
                    "Fehler: Datei $file konnte nicht gelesen werden."
                );
            }
        } else {
            IPS_LogMessage(
                "DOUTModule",
                "Fehler: Datei $file existiert nicht."
            );
        }
        return 0;
    }
}

?>