kiss_abstract.rb 4.68 KB
Newer Older
1
2
3
4
5
require 'thread'
require 'abstraction'
require_relative 'constants'

module KISS
6
    class KISSAbstract
7
8
9
        abstract

        protected
10
        def initialize(strip_df_start=true)
11
            @strip_df_start = strip_df_start
12
            @frame_buffer = []
13
14
15
16
17
            @lock = Mutex.new
        end

        private
        def self.strip_df_start(frame)
18
            while frame[0] == DATA_FRAME
19
20
                frame.shift
            end
21
22
23
24
25
26
            while frame[0]&.chr == ' '
                frame.shift
            end
            while frame[-1]&.chr == ' '
                frame.pop
            end
27
            frame
28
29
30
31
32
33
        end

        private
        def self.escape_special_codes(raw_code_bytes)
            encoded_bytes = []
            raw_code_bytes.each do |raw_code_byte|
34
35
36
37
                if raw_code_byte == FESC
                    encoded_bytes += FESC_TFESC
                elsif raw_code_byte == FEND
                    encoded_bytes += FESC_TFEND
38
39
40
41
                else
                    encoded_bytes += [raw_code_byte]
                end
            end
42
            encoded_bytes
43
44
45
46
47
48
49
50
51
        end

        private
        def self.command_byte_combine(port, command_code)
            if port > 127 or port < 0
                raise 'port out of range'
            elsif command_code > 127 or command_code < 0
                raise 'command_Code out of range'
            end
52
            (port << 4) & command_code
53
54
        end

55
        protected
56
        def write_setting(command, value)
57
            write_interface(
58
59
60
61
62
                [FEND] +
                [command] +
                escape_special_codes(value) +
                [FEND]
            )
63
64
        end

65
66
67
68
        private
        def fill_buffer
            new_frames = []
            read_buffer = []
69
70
            read_data = read_interface
            while read_data&.length and read_data.length > 0
71
72
                split_data = [[]]
                read_data.each do |read_byte|
73
                    if read_byte == FEND
74
75
76
77
78
79
80
81
82
83
84
85
                        split_data << []
                    else
                        split_data[-1] << read_byte
                    end
                end
                len_fend = split_data.length

                # No FEND in frame
                if len_fend == 1
                    read_buffer += split_data[0]
                # Single FEND in frame
                elsif len_fend == 2
86
                    # Closing FEND found
87
88
89
90
91
92
93
94
95
96
97
98
99
                    if split_data[0]
                        # Partial frame continued, otherwise drop
                        new_frames << read_buffer + split_data[0]
                        read_buffer = []
                    # Opening FEND found
                    else
                        new_frames << read_buffer
                        read_buffer = split_data[1]
                    end
                # At least one complete frame received
                elsif len_fend >= 3
                    (0...len_fend - 1).each do |i|
                        read_buffer_tmp = read_buffer + split_data[i]
100
                        if read_buffer_tmp.length > 0
101
102
103
104
105
106
107
108
109
                            new_frames << read_buffer_tmp
                            read_buffer = []
                        end
                    end
                    if split_data[len_fend - 1]
                        read_buffer = split_data[len_fend - 1]
                    end
                end
                # Get anymore data that is waiting
110
                read_data = read_interface
111
            end
112
            
113
            new_frames.each do |new_frame|
114
                if new_frame.length > 0 and new_frame[0] == 0
115
                    if @strip_df_start
116
                        new_frame = KISSAbstract.strip_df_start(new_frame)
117
118
119
120
121
122
                    end
                    @frame_buffer << new_frame
                end
            end
        end

123
        public
124
        def connect(mode_init=nil, *args, **kwargs)
125
126
        end

127
        public
128
        def close
129
130
        end

131
        public
132
        def read
133
            @lock.synchronize do
134
135
                if @frame_buffer.length == 0
                    fill_buffer
136
137
                end

138
                if @frame_buffer.length > 0
139
140
141
142
143
144
                    return_frame = @frame_buffer[0]
                    @frame_buffer.shift
                    return return_frame
                else
                    return nil
                end
145
146
147
            end
        end

148
        public
149
150
        def write(frame_bytes, port=0)
            @lock.synchronize do
151
152
                kiss_packet = [FEND] + [KISSAbstract.command_byte_combine(port, DATA_FRAME)] +
                    KISSAbstract.escape_special_codes(frame_bytes) + [FEND]
153

154
                write_interface(kiss_packet)
155
156
157
158
            end
        end
    end
end