Skip to content
Snippets Groups Projects
SmartData.php 8.11 KiB
Newer Older
root's avatar
root committed
<?php

namespace SmartData;

require_once( __DIR__ . '/Exception.php');
require_once( __DIR__ . '/Packer.php');
require_once( __DIR__ . '/Unit.php');

use SmartData\Utility\Pack;
use SmartData\Utility\Unpack;

abstract class SmartData
{
    const STATIC_VERSION = (1<<4)+(1<<0);
    const MOBILE_VERSION = (1<<4)+(2<<0);

    public $version;
    private $unit;
    public $value;
    public $error;
    public $confidence;
    public $x;
    public $y;
    public $z;
    public $time;
    public $dev;

    public $gw; //TODO

    public function __construct($version, $u, $v, $e, $c, $x,$y,$z, $t, $dev)
    {
        $this->version    = $version;
        $this->unit       = ($u instanceof Unit) ? $u : Unit::interpret($u);
        $this->value      = $v;
        $this->error      = $e;
        $this->confidence = $c;
        $this->x          = $x;
        $this->y          = $y;
        $this->z          = $z;
        $this->time       = $t;
        $this->dev        = $dev;
    }

    public function unit()
    {
        return $this->unit;
    }

    //public function put()
    //{
    //    return API::put($this->pack());
    //}

    public function pack(array $suppress = array())
    {
        $bin  = '';
        if(!in_array("version", $suppress))
            $bin .= Pack::uInt8($this->version);
        if(!in_array("unit", $suppress))
            $bin .= Pack::uInt32($this->unit->cod);
        if(!in_array("value", $suppress)){
            if($this->unit()->is_digital())
                $bin .= Pack::d64($this->value); //TODO
            else
                $bin .= Pack::d64($this->value);
        }
        if(!in_array("error", $suppress))
            $bin .= Pack::uInt8($this->error);
        if(!in_array("confidence", $suppress))
            $bin .= Pack::uInt8($this->confidence);
        if(!in_array("x", $suppress))
            $bin .= Pack::int32($this->x);
        if(!in_array("y", $suppress))
            $bin .= Pack::int32($this->y);
        if(!in_array("z", $suppress))
            $bin .= Pack::int32($this->z);
        if(!in_array("t", $suppress))
            $bin .= Pack::uInt64($this->time);
        if(!in_array("dev", $suppress))
            $bin .= Pack::uint32($this->dev);
        return $bin;
    }

    public static function unpack(& $bin, array $compl = array())
    {
        $ver = $compl['version'] ?? Unpack::uInt8($bin, true);
        if(array_key_exists('unit', $compl))
            $u = Unit::interpret($compl['unit']);
        else
            $u = Unit::unpack($bin);
        if(array_key_exists('value', $compl)) {
            $v = $compl['value'];
        } else {
            if($u->is_digital()){
                //Logger::debug("lenght: ".$u->lenght, true);
                $v  = substr($bin, 0, $u->lenght);
                $bin = substr($bin, $u->lenght);
                //$v = Unpack::d64($bin, true); // TODO
            }else
                $v = Unpack::d64($bin, true); //value
        }
        $e = $compl['error'] ?? Unpack::uInt8($bin, true);
        $c = $compl['confidence'] ?? Unpack::uInt8($bin, true);
        $x = $compl['x'] ?? Unpack::int32($bin, true);
        $y = $compl['y'] ?? Unpack::int32($bin, true);
        $z = $compl['z'] ?? Unpack::int32($bin, true);
        $t = $compl['t'] ?? Unpack::uInt64($bin, true);
        if($t<0)
           $t = PHP_INT_MAX;
        $d = $compl['dev'] ?? Unpack::uint32($bin, true);

        switch($ver) {
        case self::STATIC_VERSION:
            return StaticSmartData::unpack($bin, $compl, $u, $v, $e, $c, $x, $y, $z, $t, $d);
        case self::MOBILE_VERSION:
            return MobileSmartData::unpack($bin, $compl, $u, $v, $e, $c, $x, $y, $z, $t, $d);
        default:
            throw new \Exception("Unsupported SmartData version [{$ver}]");
            return null;
        }
    }

    public function __get($property)
    {
        if (property_exists($this, $property)) {
            switch ($property) {
                case 'unit':
                    if($this->unit instanceof Unit)
                        return $this->unit->cod;
                    else
                        return $this->unit;
                default:
                    return $this->$property;
            }
        }
    }

    public function toArray()
    {
        $json = array();
        $ver_human = ($this->version>>4).'.'.($this->version&0x01);
        $json['version']    = $this->version;
        $json['unit']       = $this->unit->cod;
        $json['timestamp']  = $this->time;
        $json['value']      = $this->value;
        $json['error']      = $this->error;
        $json['confidence'] = $this->confidence;
        $json['x']          = $this->x;
        $json['y']          = $this->y;
        $json['z']          = $this->z;
        $json['dev']        = $this->dev;
        return $json;
    }

    public function toJson()
    {
        $json = json_encode($this->toArray());
        $json = preg_replace('/:"([0-9]*)"/',':$1',$json);
        return $json;
    }

    public static function fromJson(\stdClass $json)
    {
        $version = $json->version;
        if(is_numeric($version) && is_int($version+0)){
            // nothing
        } else {
            $version = explode(".", $version);
            $version = ($version[0]<<4) + $version[1];
        }

        $u = Unit::interpret($json->unit);
        if($u->is_digital())
            $v = base64_decode($json->value);
        else
            $v = $json->value;
        $e = $json->error;
        $c = $json->confidence;
        $x = $json->x;
        $y = $json->y;
        $z = $json->z;
        $t = $json->t      ?? $json->time ?? $json->timestamp; // TODO: remove this
        $d = $json->dev    ??0;            // TODO: remove this

        switch($version) {
        case self::STATIC_VERSION:
            return StaticSmartData::fromJson($json, $u, $v, $e, $c, $x, $y, $z, $t, $d);
        case self::MOBILE_VERSION:
            return MobileSmartData::fromJson($json, $u, $v, $e, $c, $x, $y, $z, $t, $d);
        default:
            throw new \Exception("Unsupported SmartData version [{$version}]");
            return null;
        }
    }

    public function __toString()
    {
        $string  = "u={$this->unit}, ";
        $string .= "v={$this->value}, ";
        $string .= "e={$this->error}, ";
        $string .= "c={$this->confidence}, ";
        $string .= "x={$this->x}, ";
        $string .= "y={$this->y}, ";
        $string .= "z={$this->z}, ";
        $string .= "t={$this->time}, ";
        $string .= "d={$this->dev}";
        return $string;
    }
}

class StaticSmartData extends SmartData {
    public function __construct($u, $v, $e, $c, $x,$y,$z, $t, $dev)
    {
        parent::__construct(SmartData::STATIC_VERSION, $u, $v, $e, $c, $x,$y,$z, $t, $dev);
    }

    public function pack(array $suppress = array())
    {
        return parent::pack($suppress);
    }

    public static function unpack(& $bin, array $compl = array(), ...$fields)
    {
        return new self(...$fields);
    }

    public static function fromJson(\stdClass $json, ...$fields)
    {
        return new self(...$fields);
    }

    public function __toString() {
        return '{S, '.(string)parent::__toString().'}';
    }
}

class MobileSmartData extends SmartData
{
    public $signature;

    public function __construct($u, $v, $e, $c, $x,$y,$z, $t, $dev, $signature)
    {
        parent::__construct(SmartData::MOBILE_VERSION, $u, $v, $e, $c, $x,$y,$z, $t, $dev);
        $this->signature = $signature;
    }

    public function pack(array $suppress = array())
    {
        $bin = parent::pack($suppress);
        if(!in_array("signature", $suppress))
            $bin .= Pack::uInt64($this->signature);
        return $bin;
    }

    public static function unpack(& $bin, array $compl = array(), ...$fields)
    {
        $s = $compl['signature'] ?? Unpack::uInt64($bin, true);
        array_push($fields, $s);
        return new self(...$fields);
    }

    public static function fromJson(\stdClass $json, ...$fields)
    {
        array_push($fields, $json->signature);
        return new self(...$fields);
    }

    public function __toString()
    {
        return '{M, '.(string)parent::__toString().", sig={$this->signature}}";
    }
}