<?php
namespace Models;

class Scales_php {
	public $f3, $sets, $config, $port;
    public $errors=array(
        17=>'Ошибка в значении тары',
        120=>'Неизвестная команда',
        121=>'Неверная длина данных команды',
        122=>'Неверный пароль',
        123=>'Команда не реализуется в данном режиме',
        124=>'Неверное значение параметра',
        150=>'Ошибка при попытке установки нуля',
        151=>'Ошибка при установке тары',
        152=>'Вес не фиксирован',
        166=>'Сбой энергонезависимой памяти',
        167=>'Команда не реализуется интерфейсом',
        170=>'Исчерпан лимит попыток обращения с неверным паролем',
        180=>'Режим градуировки блокирован градуировочным переключателем',
        181=>'Клавиатура заблокирована',
        182=>'Нельзя поменять тип текущего канала',
        183=>'Нельзя выключить текущий канал',
        184=>'С данным каналом ничего нельзя делать',
        185=>'Неверный номер канала',
        186=>'Нет ответа от АЦП'
    );
	
	function __construct($f3, $sets) {
		$this->f3=$f3;
		$this->sets=$sets;
		$this->config=parse_ini_file($sets['driver'].'/server.config'); // Настройки драйвера
        require_once $sets['driver'].'/Scales.ports.php';
        $this->config['PortType']=strtolower($this->config['PortType']);
        if($this->config['PortType']=='remote') {
            $sets['url']=mb_substr($sets['url'], mb_strrpos($sets['url'], '/')+1);
            $url=explode(':', $sets['url']);
            $host = $url[0];
            $port = $url[1];
            $this->port = new \RemoteScalesPort($host, $port);
        }
        elseif($this->config['PortType']=='socket') {
            $sets['url']=mb_substr($sets['url'], mb_strrpos($sets['url'], '/')+1);
            $url=explode(':', $sets['url']);
            $host = $url[0];
            $port = $url[1];
            $this->port = new \RemoteScalesSocket($host, $port);
        }
        elseif($this->config['PortType']=='ssh') {
            $u=mb_substr($sets['url'], mb_strrpos($sets['url'], '/'));
            $url=explode(':', $u);
            $host = $url[0];
            $port = $url[1];
            $this->port = new \SshScalesComPort($host, $port);
        }
        else {
            $this->port = new \LocalScalesComPort($sets['url']);
        }
        if(!$this->port->open()) {
            echo $error_txt='Не удалось подключиться';
            $this->f3->get('logs_model')->save_log($error_txt.' (Весы)');
            exit();
        };
        if(!$this->config['WaitTime']) $this->config['WaitTime']=10;
        if(!$this->config['Attempts']) $this->config['Attempts']=1;
        if($this->config['AlwaysExec']) {
            $this->always_exec($this->config['AlwaysExec']);
        }
	}

    function always_exec($exec) {
        foreach ($exec as $cmd) {
            if($cmd!='') {
                exec($cmd);
            }
        }
    }

    function makecrc($binaryCmd) {
        $n = strlen($binaryCmd);
        $crc = 0;
        for ($i = 0; $i < $n; $i++) {
            $dec = ord($binaryCmd{$i});
            $crc ^= $dec;
        }
        return $crc;
    }

    function makeBinaryCmd($cmdcode) {
        $passwd = '00000000';
        $cmd = pack('H*', $cmdcode . $passwd);

        $msg_len = pack('C', strlen($cmd));
        $cmdcrc = $this->makecrc($msg_len . $cmd);
        $cmd = pack('C*', 0x02) . $msg_len . $cmd . pack('C*', $cmdcrc);
        return $cmd;
    }

    function send_command($str, $length=12) {
        $data=$this->makeBinaryCmd($str);
        $res=$this->port->write($data);
        if($res) {
            $n=0;
            $res='';
            while ($n<$this->config['Attempts']) {
                usleep($this->config['WaitTime']);
                $res.=$this->port->read(1, 400);
                if($res && mb_strlen($res)==$length) {
                    $res=unpack('H*', $res)[1];
                    break;
                }
                $n++;
            }
            if(!$res) {
                echo $error_txt='Не удалось прочитать ответ: '.$str;
                $this->f3->get('logs_model')->save_log($error_txt.' (Весы)');
                exit();
            }
            return $res;
        }
        else {
            echo $error_txt='Не удалось отправить команду: '.$str;
            $this->f3->get('logs_model')->save_log($error_txt.' (Весы)');
            exit();
        }
    }

	function scales_init() {
		//$this->f3->set('SESSION.drivers_init', 1);
	}

    function prepareArg($num, $bytes) {
        return implode('', str_split(sprintf('%0' . ($bytes * 2) . 'x', $num), 2));
    }

    // Узнать вес
    function weight() {
        $weight=false;
        $pars='3a';
        $res=$this->send_command($pars, 12);
        if($res) {
            // 06020b 3a 00 1700 4d fe ff ff 00
            $error_code=mb_substr($res, 8, 2);
            if($error_code!='00') {
                $error_code=hexdec($error_code);
                $error_txt=$this->errors[$error_code]?$this->errors[$error_code]:'Не удалось получить вес';
                $this->f3->get('logs_model')->save_log( $error_txt.' (Весы)');
                return array(
                    'success'=>false,
                    'txt'=> $error_txt
                );
            }

            $s=mb_substr($res, 10, 2);
            $s=decbin(hexdec($s));
            $s=str_pad($s, 8, "0", STR_PAD_RIGHT);
            if((int)mb_substr($s, 4, 1)==0) {
                $error_txt='Не удалось получить вес. Вес нестабильный.';
                $this->f3->get('logs_model')->save_log($error_txt.' (Весы)');
                return array(
                    'success'=>false,
                    'txt'=>$error_txt,
                );
            }

            if((int)mb_substr($s, 6, 1)==1) {
                $error_txt='Весы перегружены';
                $this->f3->get('logs_model')->save_log($error_txt.' (Весы)');
                return array(
                    'success'=>false,
                    'txt'=>$error_txt,
                );
            }

            $weight=implode('', array_reverse(str_split(mb_substr($res, 14, 8), 2)));
            $weight = pack('s', hexdec($weight));
            $weight=unpack('s', $weight)[1];
        }
        
        if(is_numeric($weight)) {
            return array(
                'success'=>true,
                'weight'=>round($weight/1000, 3)
            );
        }
        $error_txt='Не удалось получить вес';
        $this->f3->get('logs_model')->save_log($error_txt.' (Весы)');
        return array(
            'success'=>false,
            'txt'=>$error_txt,
            'res'=>$weight
        );
    }
}
