kiss_abstract.rb 4.73 KB
Newer Older
1
2
require 'thread'
require 'abstraction'
3
require 'kiss/constants'
4

5
6
module Kiss
    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
            while frame[0] and frame[0].chr == ' '
22
23
                frame.shift
            end
24
            while frame[-1] and frame[-1].chr == ' '
25
26
                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
            read_data = read_interface
Jeffrey Phillips Freeman's avatar
Jeffrey Phillips Freeman committed
70
            while read_data 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(*args, **kwargs)
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
        def write(frame_bytes, port=0, *args, **kwargs)
150
            @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