kiss-tnc 1.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 394d48eb1bdb8bda7bc9283a58b8b7ec8d53585b
4
- data.tar.gz: ce5f3281c95c4d13e740944a3b709715e527cbe6
2
+ SHA256:
3
+ metadata.gz: '09b09122da0f586f8c540ad8327c90ac04b5461b1fc6a7ed82e4a19319f23330'
4
+ data.tar.gz: 1c126ad07648e80290e873ed49cf9bf9c6672d3ea9e2d181ff977a54d6208a46
5
5
  SHA512:
6
- metadata.gz: 768bfa681b99bc095b97499cdf73b73490bd0abee0319710d13af7e57a81785ff09ef260a74476fd826748475ba0e9b538849666676509b970ddb4c9f4594b2a
7
- data.tar.gz: 1bcf99dd124fdea56a27529e76a0cd706ecf42fed6f9ece186781143242be71a9b702506df4f9a116f84d589c6feebf9f14acca36b2455caf99e5b2c22c2cf1b
6
+ metadata.gz: 2b0df5c966c1e2082162902ec988dff74d455ebe831f774e4df32768e6ea91ece147168714fa36cd71014616f6eb384550391003a22092bace28ab6672c066f8
7
+ data.tar.gz: f6fa098359c055522eddbcabd135244e06a4d06e37b0682556e77fbd9b0c0d017bce82c25c6fad12f06c2be358647511b562be09db7ee354514720230a226764
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ html
5
5
  Gemfile.lock
6
6
  .idea/
7
7
  *.gem
8
+ /public/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.1.0
4
+
5
+ * Added a parent interface to KissAbstract called Kiss
6
+
7
+ ## 2.0.0
8
+
9
+ * Moved abstraction over to abstractify library.
10
+ * Added more parsing methods so entry points now take strings rather than KISS encoded data.
11
+ * Added errors where appropriate, for example writing invalid frames now throw an IOError.
12
+ * The write and read methods now take frames in the form of a map of strings, all encoding is now handled by the library.
13
+
3
14
  ## 1.0.3
4
15
 
5
16
  * Changed KissSerial so its methods can accept any arguments, used for abstraction purposes.
@@ -16,4 +27,4 @@
16
27
 
17
28
  ## 1.0.0
18
29
 
19
- * Initial release
30
+ * Initial release
data/CONTRIBUTORS.md CHANGED
@@ -1,4 +1,10 @@
1
+ ## Current Project Lead
2
+
1
3
  * Jeffrey Phillips Freeman (WI2ARD) - http://JeffreyFreeman.me
4
+
5
+ ## Contributors
6
+
7
+ * Greg Albrecht W2GMD <oss@undef.net>
2
8
  * Martin Murray (KD8LVZ)
3
9
  * Paul McMillan - https://github.com/PaulMcMillan
4
10
  * Russ Innes
data/Rakefile CHANGED
@@ -24,44 +24,43 @@ def dump_load_path
24
24
  end
25
25
  end
26
26
 
27
- gem 'json', '~> 1.8.3'
28
-
29
- gem 'bundler', '~> 1.7'
27
+ # gem 'json', '~> 1.8.3'
28
+ #
29
+ # gem 'bundler', '~> 1.7'
30
30
  require 'bundler'
31
31
 
32
- gem 'rake', '~> 11.3.0'
32
+ # gem 'rake', '~> 11.3.0'
33
33
  require 'rake/clean'
34
34
  require 'rake/testtask'
35
35
 
36
36
 
37
- require 'cucumber'
38
- require 'cucumber/rake/task'
39
- gem 'rdoc' # we need the installed RDoc gem, not the system one
40
- require 'rdoc/task'
37
+ # require 'cucumber'
38
+ # require 'cucumber/rake/task'
39
+ # gem 'rdoc' # we need the installed RDoc gem, not the system one
40
+ # require 'rdoc/task'
41
41
 
42
42
  include Rake::DSL
43
43
 
44
44
  Bundler::GemHelper.install_tasks
45
45
 
46
46
 
47
- Rake::TestTask.new do |t|
48
- t.pattern = 'test/tc_*.rb'
49
- end
50
-
51
-
52
- CUKE_RESULTS = 'results.html'
53
- CLEAN << CUKE_RESULTS
54
- Cucumber::Rake::Task.new(:features) do |t|
55
- t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty --no-source -x"
56
- t.fork = false
57
- end
58
-
59
- Rake::RDocTask.new do |rd|
47
+ # Rake::TestTask.new do |t|
48
+ # t.pattern = 'test/tc_*.rb'
49
+ # end
60
50
 
61
- rd.main = "README.rdoc"
62
-
63
- rd.rdoc_files.include("README.rdoc", "lib/**/*.rb", "bin/**/*")
64
- end
65
51
 
66
- task :default => [:test, :features]
52
+ # CUKE_RESULTS = 'results.html'
53
+ # CLEAN << CUKE_RESULTS
54
+ # Cucumber::Rake::Task.new(:features) do |t|
55
+ # t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty --no-source -x"
56
+ # t.fork = false
57
+ # end
67
58
 
59
+ # Rake::RDocTask.new do |rd|
60
+ #
61
+ # rd.main = "README.rdoc"
62
+ #
63
+ # rd.rdoc_files.include("README.rdoc", "lib/**/*.rb", "bin/**/*")
64
+ # end
65
+ #
66
+ # task :default => [:test, :features]
data/kiss-tnc.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = %q{Library for KISS communication with TNCs.}
14
14
  spec.description = %q{Ruby library for KISS communication with Terminal Node Controllers.}
15
- spec.homepage = 'https://github.com/Syncleus/aprs'
15
+ spec.homepage = 'https://git.qoto.org/digipex/kiss-tnc'
16
16
 
17
17
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
18
  # to allow pushing to a single host or delete this section to allow pushing to any host.
@@ -29,10 +29,12 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ['lib']
31
31
 
32
- spec.add_dependency 'abstraction', '~> 0.0.4'
32
+ spec.add_dependency 'abstractify', '~> 1.1'
33
33
  spec.add_dependency 'serialport', '~> 1.3'
34
- spec.add_development_dependency 'bundler', '~> 1.7'
35
- spec.add_development_dependency 'rake', '~> 11.3'
36
- spec.add_development_dependency 'rdoc', '~> 4.2'
37
- spec.add_development_dependency 'aruba', '~> 0.14'
34
+ spec.add_development_dependency 'bundler', '~> 2.3'
35
+ spec.add_development_dependency 'rake', '~> 13.0'
36
+ spec.add_development_dependency 'rspec', '~> 3.12'
37
+ spec.add_development_dependency 'simplecov', '~> 0.22'
38
+ spec.add_development_dependency 'simplecov-console', '~> 0.9'
39
+ #spec.add_development_dependency 'rdoc', '~> 6.5'
38
40
  end
data/lib/kiss/app_info.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kiss
2
- VERSION = "1.0.3"
2
+ VERSION = "2.1.0"
3
3
  end
data/lib/kiss/kiss.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'abstractify'
2
+
3
+ module Kiss
4
+ class Kiss
5
+ include Abstractify::Abstract
6
+
7
+ abstract :write_interface, :read_interface, :connect, :close
8
+ end
9
+ end
@@ -1,10 +1,13 @@
1
1
  require 'thread'
2
- require 'abstraction'
2
+ require 'abstractify'
3
3
  require 'kiss/constants'
4
+ require 'kiss/kiss'
4
5
 
5
6
  module Kiss
6
- class KissAbstract
7
- abstract
7
+ class KissAbstract < Kiss
8
+ include Abstractify::Abstract
9
+
10
+ abstract :write_interface, :read_interface, :connect, :close
8
11
 
9
12
  protected
10
13
  def initialize(strip_df_start=true)
@@ -52,9 +55,132 @@ module Kiss
52
55
  (port << 4) & command_code
53
56
  end
54
57
 
55
- protected
56
- def write_setting(command, value)
57
- write_interface([FEND] + [command] + escape_special_codes(value) + [FEND])
58
+ private
59
+ def self.extract_path(start, raw_frame)
60
+ full_path = []
61
+
62
+ (2...start).each do |i|
63
+ path = identity_as_string(extract_callsign(raw_frame[i * 7..-1]))
64
+ if path and path.length > 0
65
+ if raw_frame[i * 7 + 6] & 0x80 != 0
66
+ full_path << [path, '*'].join
67
+ else
68
+ full_path << path
69
+ end
70
+ end
71
+ end
72
+ return full_path
73
+ end
74
+
75
+ private
76
+ def self.parse_identity_string(identity_string)
77
+ # If we are parsing a spent token then first lets get rid of the astresick suffix.
78
+ if identity_string[-1] == '*'
79
+ identity_string = identity_string[0..-1]
80
+ end
81
+
82
+ if identity_string.include? '-'
83
+ call_sign, ssid = identity_string.split('-')
84
+ else
85
+ call_sign = identity_string
86
+ ssid = 0
87
+ end
88
+
89
+ return {:callsign => call_sign, :ssid => ssid.to_i}
90
+ end
91
+
92
+ private
93
+ def self.identity_as_string(identity)
94
+ if identity[:ssid] and identity[:ssid] > 0
95
+ return [identity[:callsign], identity[:ssid].to_s].join('-')
96
+ else
97
+ return identity[:callsign]
98
+ end
99
+ end
100
+
101
+ private
102
+ def self.extract_callsign(raw_frame)
103
+ callsign_as_array = raw_frame[0...6].map { |x| (x >> 1).chr }
104
+ callsign = callsign_as_array.join.strip
105
+ ssid = (raw_frame[6] >> 1) & 0x0f
106
+ ssid = (ssid == nil or ssid == 0 ? nil : ssid)
107
+ return {:callsign => callsign, :ssid => ssid}
108
+ end
109
+
110
+ private
111
+ def self.encode_callsign(callsign)
112
+ call_sign = callsign[:callsign]
113
+
114
+ enc_ssid = (callsign[:ssid] << 1) | 0x60
115
+
116
+ if call_sign.include? '*'
117
+ call_sign.gsub!(/\*/, '')
118
+ enc_ssid |= 0x80
119
+ end
120
+
121
+ while call_sign.length < 6
122
+ call_sign = [call_sign, ' '].join
123
+ end
124
+
125
+ return call_sign.chars.map { |p| p.ord << 1 } + [enc_ssid]
126
+ end
127
+
128
+ private
129
+ def self.encode_frame(frame)
130
+ enc_frame = encode_callsign(parse_identity_string(frame[:destination].to_s)) + encode_callsign(parse_identity_string(frame[:source].to_s))
131
+
132
+ frame[:path].each do |hop|
133
+ enc_frame += encode_callsign(parse_identity_string(hop.to_s))
134
+ end
135
+
136
+ return enc_frame[0...-1] + [enc_frame[-1] | 0x01] + [SLOT_TIME] + [0xf0] + frame[:payload].chars.map { |c| c.ord }
137
+ end
138
+
139
+ private
140
+ def self.decode_frame(raw_frame)
141
+ frame_len = raw_frame.length
142
+
143
+ if frame_len > 16
144
+ (0...frame_len - 2).each do |raw_slice|
145
+ # Is address field length correct?
146
+ if raw_frame[raw_slice] & 0x01 != 0 and ((raw_slice + 1) % 7) == 0
147
+ i = (raw_slice.to_f + 1.0) / 7.0
148
+ # Less than 2 callsigns?
149
+ if 1.0 < i and i < 11.0
150
+ if raw_frame[raw_slice + 1] & 0x03 == 0x03 and [0xf0, 0xcf].include? raw_frame[raw_slice + 2]
151
+ payload_as_array = raw_frame[raw_slice + 3..-1].map { |b| b.chr }
152
+ payload = payload_as_array.join
153
+ destination = identity_as_string(extract_callsign(raw_frame))
154
+ source = identity_as_string(extract_callsign(raw_frame[7..-1]))
155
+ path = extract_path(i.to_i, raw_frame)
156
+ return {:source => source, :destination => destination, :path => path, :payload => payload}
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ return nil
163
+ end
164
+
165
+ private
166
+ def self.valid_frame(raw_frame)
167
+ frame_len = raw_frame.length
168
+
169
+ if frame_len > 16
170
+ (0...frame_len - 2).each do |raw_slice|
171
+ # Is address field length correct?
172
+ if raw_frame[raw_slice] & 0x01 != 0 and ((raw_slice + 1) % 7) == 0
173
+ i = (raw_slice.to_f + 1.0) / 7.0
174
+ # Less than 2 callsigns?
175
+ if 1.0 < i and i < 11.0
176
+ if raw_frame[raw_slice + 1] & 0x03 == 0x03 and [0xf0, 0xcf].include? raw_frame[raw_slice + 2]
177
+ return true
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ return false
58
184
  end
59
185
 
60
186
  private
@@ -115,6 +241,34 @@ module Kiss
115
241
  end
116
242
  end
117
243
 
244
+ private
245
+ def read_bytes(*args, **kwargs)
246
+ if @frame_buffer.length == 0
247
+ fill_buffer
248
+ end
249
+
250
+ if @frame_buffer.length > 0
251
+ return_frame = @frame_buffer[0]
252
+ @frame_buffer.shift
253
+ return return_frame
254
+ else
255
+ return nil
256
+ end
257
+ end
258
+
259
+ private
260
+ def write_bytes(frame_bytes, port=0, *args, **kwargs)
261
+ kiss_packet = [FEND] + [KissAbstract.command_byte_combine(port, DATA_FRAME)] +
262
+ KissAbstract.escape_special_codes(frame_bytes) + [FEND]
263
+
264
+ write_interface(kiss_packet)
265
+ end
266
+
267
+ protected
268
+ def write_setting(command, value)
269
+ write_interface([FEND] + [command] + KissAbstract.escape_special_codes(value) + [FEND])
270
+ end
271
+
118
272
  public
119
273
  def connect(mode_init=nil, *args, **kwargs)
120
274
  end
@@ -125,29 +279,26 @@ module Kiss
125
279
 
126
280
  public
127
281
  def read(*args, **kwargs)
128
- @lock.synchronize do
129
- if @frame_buffer.length == 0
130
- fill_buffer
131
- end
132
-
133
- if @frame_buffer.length > 0
134
- return_frame = @frame_buffer[0]
135
- @frame_buffer.shift
136
- return return_frame
137
- else
138
- return nil
139
- end
140
- end
282
+ @lock.synchronize do
283
+ frame = self.read_bytes(*args, **kwargs)
284
+ if frame and frame.length > 0
285
+ return KissAbstract.decode_frame(frame)
286
+ else
287
+ return nil
288
+ end
289
+ end
141
290
  end
142
291
 
143
292
  public
144
- def write(frame_bytes, port=0, *args, **kwargs)
145
- @lock.synchronize do
146
- kiss_packet = [FEND] + [KissAbstract.command_byte_combine(port, DATA_FRAME)] +
147
- KissAbstract.escape_special_codes(frame_bytes) + [FEND]
148
-
149
- write_interface(kiss_packet)
150
- end
293
+ def write(frame, port=0, *args, **kwargs)
294
+ @lock.synchronize do
295
+ encoded_frame = KissAbstract.encode_frame(frame)
296
+ if KissAbstract.valid_frame(encoded_frame)
297
+ self.write_bytes(encoded_frame, *args, **kwargs)
298
+ else
299
+ raise IOError.new("frame was able to be encoded but was determined not to be valid")
300
+ end
301
+ end
151
302
  end
152
303
  end
153
- end
304
+ end
@@ -77,10 +77,10 @@ module Kiss
77
77
  end
78
78
 
79
79
  if @serial == nil or @serial.closed?
80
- raise 'Attempting to close before the class has been started.'
80
+ raise IOError.new('Attempting to close before the class has been started.')
81
81
  else
82
82
  @serial.close
83
83
  end
84
84
  end
85
85
  end
86
- end
86
+ end
data/lib/kiss.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  require 'kiss/app_info'
2
2
  require 'kiss/kiss_serial'
3
- require 'kiss/constants'
3
+ require 'kiss/constants'
4
+ require 'kiss/kiss_abstract'
5
+ require 'kiss/kiss'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kiss-tnc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeffrey Phillips Freeman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-10-05 00:00:00.000000000 Z
11
+ date: 2023-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: abstraction
14
+ name: abstractify
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.4
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.4
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: serialport
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,56 +44,70 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.7'
47
+ version: '2.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.7'
54
+ version: '2.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '11.3'
61
+ version: '13.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '11.3'
68
+ version: '13.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rdoc
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '4.2'
75
+ version: '3.12'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '4.2'
82
+ version: '3.12'
83
83
  - !ruby/object:Gem::Dependency
84
- name: aruba
84
+ name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.14'
89
+ version: '0.22'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.14'
96
+ version: '0.22'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov-console
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.9'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.9'
97
111
  description: Ruby library for KISS communication with Terminal Node Controllers.
98
112
  email:
99
113
  - jeffrey.freeman@syncleus.com
@@ -102,6 +116,7 @@ extensions: []
102
116
  extra_rdoc_files: []
103
117
  files:
104
118
  - ".gitignore"
119
+ - ".rspec"
105
120
  - CHANGELOG.md
106
121
  - CONTRIBUTORS.md
107
122
  - Gemfile
@@ -113,16 +128,15 @@ files:
113
128
  - lib/kiss.rb
114
129
  - lib/kiss/app_info.rb
115
130
  - lib/kiss/constants.rb
131
+ - lib/kiss/kiss.rb
116
132
  - lib/kiss/kiss_abstract.rb
117
133
  - lib/kiss/kiss_serial.rb
118
- - lib/kiss/test.rb
119
- - lib/kiss/test/kiss_mock.rb
120
- homepage: https://github.com/Syncleus/aprs
134
+ homepage: https://git.qoto.org/digipex/kiss-tnc
121
135
  licenses:
122
136
  - Apache-2.0
123
137
  metadata:
124
138
  allowed_push_host: https://rubygems.org
125
- post_install_message:
139
+ post_install_message:
126
140
  rdoc_options: []
127
141
  require_paths:
128
142
  - lib
@@ -137,9 +151,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
151
  - !ruby/object:Gem::Version
138
152
  version: '0'
139
153
  requirements: []
140
- rubyforge_project:
141
- rubygems_version: 2.5.1
142
- signing_key:
154
+ rubygems_version: 3.4.17
155
+ signing_key:
143
156
  specification_version: 4
144
157
  summary: Library for KISS communication with TNCs.
145
158
  test_files: []
@@ -1,41 +0,0 @@
1
- require 'kiss/kiss_abstract'
2
-
3
- module Kiss
4
- class KissMock < KissAbstract
5
-
6
- def initialize(strip_df_start=true)
7
- super(strip_df_start)
8
- @read_from_interface = []
9
- @sent_to_interface = []
10
- end
11
-
12
- protected
13
- def read_interface
14
- if @read_from_interface.length == 0
15
- return nil
16
- end
17
- return @read_from_interface.shift
18
- end
19
-
20
- protected
21
- def write_interface(data)
22
- @sent_to_interface << data
23
- end
24
-
25
- public
26
- def clear_interface
27
- @read_from_interface = []
28
- @sent_to_interface = []
29
- end
30
-
31
- public
32
- def add_read_from_interface(raw_frame)
33
- @read_from_interface << raw_frame
34
- end
35
-
36
- public
37
- def get_sent_to_interface
38
- return @sent_to_interface
39
- end
40
- end
41
- end
data/lib/kiss/test.rb DELETED
@@ -1 +0,0 @@
1
- require 'kiss/test/kiss_mock'