[0x00,'v',2], // Orig Node 'dnode' => [0x02,'v',2], // Dest Node 'y' => [0x04,'v',2], // Year 'm' => [0x06,'v',2], // Month 'd' => [0x08,'v',2], // Day 'H' => [0x0a,'v',2], // Hour 'M' => [0x0c,'v',2], // Minute 'S' => [0x0e,'v',2], // Second 'baud' => [0x10,'v',2], // Baud 'type' => [0x12,'v',2], // Packet Version (should be 2) 'onet' => [0x14,'v',2], // Orig Net (0xFFFF when OrigPoint != 0) 'dnet' => [0x16,'v',2], // Dest Net 'prodcode-lo' => [0x18,'C',1], // Product Code Lo 'prodrev-maj' => [0x19,'C',1], // Product Version Major 'password' => [0x1a,'a8',8], // Packet Password 'ozone' => [0x22,'v',2], // Orig Zone 'dzone' => [0x24,'v',2], // Dest Zone 'auxnet' => [0x26,'v',2], // Aux Net 'capvalid' => [0x28,'n',2], // fsc-0039.004 (copy of 0x2c) 'prodcode-hi' => [0x2a,'C',1], // Product Code Hi 'prodrev-min' => [0x2b,'C',1], // Product Version Minor 'capword' => [0x2c,'v',2], // Capability Word fsc-0039.004/fsc-0048.002 'dozone' => [0x2e,'v',2], // Orig Zone 'ddzone' => [0x30,'v',2], // Dest Zone 'opoint' => [0x32,'v',2], // Orig Point 'dpoint' => [0x34,'v',2], // Dest Point 'proddata' => [0x36,'a4',4], // ProdData ]; public const TYPE = '2+'; public const VERS = self::MSG_TYPE2; //|self::MSG_TYPE4; public function __get($key) { switch ($key) { case 'capability': return sprintf('%016b',Arr::get($this->header,'capword')); case 'fn': // If the packet is from a point, then onet will be 0xffff return ($x=Arr::get($this->header,'onet')) === 0xffff ? Arr::get($this->header,'auxnet') : $x; default: return parent::__get($key); } } /** * Create our message packet header */ protected function header(Collection $msgs): string { $oldest = $msgs->sortBy('date')->last(); return pack(collect(self::HEADER)->pluck(1)->join(''), $this->fftn_p->node_id, // Orig Node $this->tftn_p->node_id, // Dest Node $oldest->datetime->format('Y'), // Year $oldest->datetime->format('m')-1, // Month $oldest->datetime->format('d'), // Day $oldest->datetime->format('H'), // Hour $oldest->datetime->format('i'), // Minute $oldest->datetime->format('s'), // Second 0, // Baud 2, // Packet Version (should be 2) $this->fftn_p->point_id ? 0xffff : $this->fftn_p->host_id, // Orig Net (0xFFFF when OrigPoint != 0) $this->tftn_p->host_id, // Dest Net (Setup::PRODUCT_ID & 0xff), // Product Code Lo Setup::PRODUCT_VERSION_MAJ, // Product Version Major $this->pass_p ?: $this->tftn_p->pass_packet, // Packet Password $this->fftn_p->zone->zone_id, // Orig Zone $this->tftn_p->zone->zone_id, // Dest Zone $this->fftn_p->point_id ? $this->fftn_p->host_id : 0x00, // Aux Net static::VERS, // fsc-0039.004 (copy of 0x2c) ((Setup::PRODUCT_ID >> 8) & 0xff), // Product Code Hi Setup::PRODUCT_VERSION_MIN, // Product Version Minor static::VERS, // Capability Word $this->fftn_p->zone->zone_id, // Orig Zone $this->tftn_p->zone->zone_id, // Dest Zone $this->fftn_p->point_id, // Orig Point $this->tftn_p->point_id, // Dest Point strtoupper(hexstr(Setup::PRODUCT_ID)), // ProdData ); } /** * Determine if this is a fsc-0045 packet * * @param string $header * @return bool * @throws \Exception */ public static function is_type(string $header): bool { $head = unpack(self::unpackheader(self::HEADER),$header); return ( (Arr::get($head,'type') === 2) && (Arr::get($head,'capword') === Arr::get($head,'capvalid')) && ((Arr::get($head,'opoint') === 0) || (Arr::get($head,'onet') === 0xffff)) && Arr::get($head,'auxnet') ); } }