<?php namespace SmartData; require_once( __DIR__ . '/Packer.php'); use SmartData\Utility\Pack; use SmartData\Utility\Unpack; abstract class Unit { // Formats // Bit 31 16 0 // +--+----------------------------------+-------------------------------------+ // Digital |0 | type | length | // +--+----------------------------------+-------------------------------------+ // Bit 31 29 27 24 21 18 15 12 9 6 3 0 // +--+----+----+------+------+------+------+------+------+------+------+------+ // SI |1 |NUM |MOD |sr+4 |rad+4 |m+4 |kg+4 |s+4 |A+4 |K+4 |mol+4 |cd+4 | // +--+----+----+------+------+------+------+------+------+------+------+------+ // Bits 1 2 2 3 3 3 3 3 3 3 3 3 // Valid values for field SI public const DIGITAL = 0 << 31; public const SI = 1 << 31; // Valid values for field NUM public const I32 = 0 << 29; // Value is an integral number stored in the 32 last significant bits of a 32-bit little-endian integer. public const I64 = 1 << 29; // Value is an integral number stored in the 64 last significant bits of a 64-bit little-endian integer. public const F32 = 2 << 29; // Value is a real number stored as an IEEE 754 binary32 little-endian floating point. public const D64 = 3 << 29; // Value is a real number stored as an IEEE 754 binary64 little-endian double precision floating point. public const NUM = self::D64; // AND mask to select NUM bits // Valid values for field MOD public const DIR = 0 << 27; // Unit is described by the product of SI base units raised to the powers recorded in the remaining fields. public const DIV = 1 << 27; // Unit is U/U, where U is described by the product SI base units raised to the powers recorded in the remaining fields. public const LOG = 2 << 27; // Unit is log_e(U), where U is described by the product of SI base units raised to the powers recorded in the remaining fields. public const LOG_DIV = 3 << 27; // Unit is log_e(U/U), where U is described by the product of SI base units raised to the powers recorded in the remaining fields. public const MOD = self::LOG_DIV; // AND mask to select MOD bits // Masks to select the SI units public const SR = 7 << 24; public const RAD = 7 << 21; public const M = 7 << 18; public const KG = 7 << 15; public const S = 7 << 12; public const A = 7 << 9; public const K = 7 << 6; public const MOL = 7 << 3; public const CD = 7 << 0; // Masks to digital fields public const LENGHT = (1 << 16) - 1; public const TYPE = (self::LENGHT << 16); public const SIZE = 4; // bytes public function __construct($u) { $this->_unit = $u; } public static function interpret($u) { switch ($u & (1 << 31)) { case self::DIGITAL: return new Digital_Unit($u); break; case self::SI: return new SI_Unit($u); break; default: throw new InvalidUnitException("Invalid Unit: ".$u); } return null; } public function pack() { return Pack::uInt32($this->_unit); } public static function unpack(& $bin) { return self::interpret(Unpack::uInt32($bin, true)); } public function is_digital() : bool { return (($this->_unit & (1 << 31)) == self::DIGITAL); } protected $_unit; } // Typical SI Quantities final class TypicalUnit extends Unit { // si | mod | sr | rad | m | kg | s | A | K | mol | cd const Length = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Distance = TypicalUnit::Length; const Mass = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+1)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Time = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+1)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Current = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+1)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Electric_Current = TypicalUnit::Current; const Temperature = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+1)<<6 | (4+0)<<3 | (4+0); const Amount_of_Substance = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+1)<<3 | (4+0); const Luminous_Intensity = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+1); const Area = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+2)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Volume = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+3)<<18 | (4+0)<<15 | (4+0)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Speed = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+0)<<15 | (4-1)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Velocity = TypicalUnit::Speed; const Acceleration = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+0)<<15 | (4-2)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Angular_Speed = 1<<31 | 0<<27 | (4+0)<<24 | (4+1)<<21 | (4+0)<<18 | (4+0)<<15 | (4-1)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Water_Flow = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+3)<<18 | (4+0)<<15 | (4-1)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Sound_Intensity = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+0)<<18 | (4+1)<<15 | (4-3)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Force = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+1)<<18 | (4+1)<<15 | (4-2)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Voltage = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+2)<<18 | (4+1)<<15 | (4-3)<<12 | (4-1)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); const Power = 1<<31 | 0<<27 | (4+0)<<24 | (4+0)<<21 | (4+2)<<18 | (4+1)<<15 | (4-3)<<12 | (4+0)<<9 | (4+0)<<6 | (4+0)<<3 | (4+0); } class Digital_Unit extends Unit { public function __get($property) { switch ($property) { case 'cod': return $this->_unit; case 'type': return (($this->_unit & self::TYPE) >> 16); case 'lenght': return ($this->_unit & self::LENGHT); default: return null; } } public function __toString() { return "{{$this->cod}, D, t={$this->type}, l={$this->lenght}}"; } } class SI_Unit extends Unit { public function __get($property) { switch ($property) { case 'cod': return $this->_unit; case 'num': return (($this->_unit & self::NUM) >> 29); case 'mod': return (($this->_unit & self::MOD) >> 27); case 'sr': return (($this->_unit & self::SR) >> 24) - 4; case 'rad': return (($this->_unit & self::RAD) >> 21) - 4; case 'm': return (($this->_unit & self::M) >> 18) - 4; case 'kg': return (($this->_unit & self::KG) >> 15) - 4; case 's': return (($this->_unit & self::S) >> 12) - 4; case 'a': return (($this->_unit & self::A) >> 9) - 4; case 'k': return (($this->_unit & self::K) >> 6) - 4; case 'mol': return (($this->_unit & self::MOL) >> 3) - 4; case 'cd': return (($this->_unit & self::CD) >> 0) - 4; default: return null; } } public function __toString() { $string = "{{$this->cod}, SI, n={$this->num}, m={$this->mod}, "; $string .= ($this->sr != 0) ? "sr^{$this->sr}" : ''; $string .= ($this->rad != 0) ? "rad^{$this->rad}" : ''; $string .= ($this->m != 0) ? "m^{$this->m}" : ''; $string .= ($this->kg != 0) ? "kg^{$this->kg}" : ''; $string .= ($this->s != 0) ? "s^{$this->s}" : ''; $string .= ($this->a != 0) ? "A^{$this->a}" : ''; $string .= ($this->k != 0) ? "K^{$this->k}" : ''; $string .= ($this->mol != 0) ? "mol^{$this->mol}" : ''; $string .= ($this->cd != 0) ? "cd^{$this->cd}" : ''; $string .= '}'; return $string; } }