Completed
Push — master ( 6e9b0d...d025ba )
by Chris
16:34
created

FrameEncoder::encodeOriginFlagsAndProtocolNo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace DaveRandom\LibLifxLan\Encoding;
4
5
use DaveRandom\LibLifxLan\Encoding\Exceptions\InvalidMessageHeaderException;
6
use DaveRandom\LibLifxLan\Header\Frame;
7
use DaveRandom\LibLifxLan\Options;
8
9
final class FrameEncoder
10
{
11
    use Options;
12
13
    /**
14
     * If enabled, allow origin values other than 0
15
     */
16
    public const OP_ALLOW_ORIGIN_VARIANCE = 0b01;
17
18
    /**
19
     * If enabled, allow protocol numbers other than 1024
20
     */
21
    public const OP_ALLOW_PROTOCOL_NUMBER_VARIANCE = 0b10;
22
23
    /**
24
     * @param Frame $frame
25
     * @return string
26
     */
27 13
    private function encodeMessageSize(Frame $frame): string
28
    {
29 13
        return \pack('v', $frame->getSize());
30
    }
31
32
    /**
33
     * @param Frame $frame
34
     * @return int
35
     * @throws InvalidMessageHeaderException
36
     */
37 13
    private function getValidOrigin(Frame $frame): int
38
    {
39 13
        $origin = $frame->getOrigin();
40
41 13
        if ($origin !== 0 && !$this->options[self::OP_ALLOW_ORIGIN_VARIANCE]) {
42 2
            throw new InvalidMessageHeaderException("Message origin value expected to be 0, got {$origin}");
43
        }
44
45 11
        return $origin << 14;
46
    }
47
48 11
    private function getFlags(Frame $frame): int
49
    {
50 11
        return (((int)$frame->isTagged()) << 13) | (((int)$frame->isAddressable()) << 12);
51
    }
52
53
    /**
54
     * @param Frame $frame
55
     * @return int
56
     * @throws InvalidMessageHeaderException
57
     */
58 11
    private function getValidProtocolNumber(Frame $frame): int
59
    {
60 11
        $protocolNo = $frame->getProtocolNo();
61
62 11
        if ($protocolNo !== 1024 && !$this->options[self::OP_ALLOW_PROTOCOL_NUMBER_VARIANCE]) {
63 2
            throw new InvalidMessageHeaderException("Protocol number value expected to be 1024, got {$protocolNo}");
64
        }
65
66 9
        return $protocolNo;
67
    }
68
69
    /**
70
     * @param Frame $frame
71
     * @return string
72
     * @throws InvalidMessageHeaderException
73
     */
74 13
    private function encodeOriginFlagsAndProtocolNo(Frame $frame): string
75
    {
76 13
        $origin = $this->getValidOrigin($frame);
77 11
        $flags = $this->getFlags($frame);
78 11
        $protocolNo = $this->getValidProtocolNumber($frame);
79
80 9
        return \pack('v', $origin | $flags | $protocolNo);
81
    }
82
83
    /**
84
     * @param Frame $frame
85
     * @return string
86
     */
87 9
    private function encodeSource(Frame $frame): string
88
    {
89 9
        return \pack('V', $frame->getSource());
90
    }
91
92
    /**
93
     * @param Frame $frame
94
     * @return string
95
     * @throws InvalidMessageHeaderException
96
     */
97 13
    public function encodeFrame(Frame $frame): string
98
    {
99 13
        return $this->encodeMessageSize($frame)
100 13
            . $this->encodeOriginFlagsAndProtocolNo($frame)
101 9
            . $this->encodeSource($frame);
102
    }
103
104 13
    public function __construct(array $options = [])
105
    {
106 13
        $this->options = $options + [
107 13
            self::OP_ALLOW_ORIGIN_VARIANCE => false,
108 13
            self::OP_ALLOW_PROTOCOL_NUMBER_VARIANCE => false,
109
        ];
110
    }
111
}
112