apex-aprs 1.0.2 → 1.0.4

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
2
  SHA256:
3
- metadata.gz: 2dbd006d7d8e71ef14b082177848ada159139d92012d859b7ff2c0dfd23bd3d4
4
- data.tar.gz: ffc8ec190f0f310a3842732adedf1be2bed6b01488efc8d90cbd213174f85707
3
+ metadata.gz: 50aaeb1837b3f6a1515f98e798727ec7ca74815b0b4c6c6e197710b11916bd04
4
+ data.tar.gz: 7a0aeaafac5d7dc07bd4d74afa2b1eaaf29fad3c64bf6eb8e160f244bd0a7bd7
5
5
  SHA512:
6
- metadata.gz: 4b829cea663db7673ae6f53531031f63736f5445cb7c48899a94ee1d7ca3b9848194479858c88fcd23abba18b48229e46ba811e54523c00ea21efcfef133c8ef
7
- data.tar.gz: 0a831f1f9dffa31f6f76b4b060be04e997cc315f7604b701bb8086e4873337aaeea8c62fb4c80409d2a351b0355156cb5187c7e01cfc03bcb5938bfe28b7cee4
6
+ metadata.gz: 4186b7b390dee0744b860b060150adb3fcbb05f9b59890eca04758ae46a60bdc1938351983a59893c27f09badcf458e7fefcd7261651afd1ef5b418311b12970
7
+ data.tar.gz: 3c772a99fe98e6049036c20465a6cf687dc04f17ca30ab1ea5fc895dcd47eda5ea82dd90328f0c4b2ebbeb77ca998a94d2e78db7caa6b97e0899cc6a86290e6e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.4
4
+
5
+ * Frames are now classes rather than a map
6
+ * Added mechanism for comparing frames for equivalence.
7
+
8
+ ## 1.0.3
9
+
10
+ * Implemented the IGateTcp class for handling internet gateways.
11
+
3
12
  ## 1.0.2
4
13
 
5
14
  * Updates to dependencies only.
data/README.md CHANGED
@@ -30,7 +30,20 @@ After checking out the repo, run `bin/setup` to install dependencies. You can al
30
30
 
31
31
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
32
 
33
- ## Contributing
33
+ ### Unit Tests
34
+
35
+ To run all unit tests first make sure you have dependencies installed:
36
+
37
+ ```bash
38
+ bundle install
39
+ ```
34
40
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/Syncleus/apex-aprs
41
+ then run the tests with:
42
+
43
+ ```bash
44
+ bundle exec rake test
45
+ ```
46
+
47
+ ## Contributing
36
48
 
49
+ Bug reports and pull requests are welcome on Git at https://git.qoto.org/digipex/apex-aprs
data/apex-aprs.gemspec CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency 'kiss-tnc', '~> 1.0'
35
35
  spec.add_development_dependency 'bundler', '~> 2.2'
36
36
  spec.add_development_dependency 'rake', '~> 13.0'
37
- spec.add_development_dependency 'rdoc', '~> 6.3'
37
+ spec.add_development_dependency 'test-unit', '~> 3.6'
38
+ #spec.add_development_dependency 'rdoc', '~> 6.3'
38
39
  spec.add_development_dependency 'aruba', '~> 2.0'
39
40
  end
data/lib/apex/app_info.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Apex
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.4"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'kiss/constants'
2
+ require 'apex/frame'
2
3
 
3
4
  module Apex
4
5
  class AprsKiss
@@ -11,7 +12,6 @@ module Apex
11
12
 
12
13
  private
13
14
  def self.decode_frame(raw_frame)
14
- frame = {}
15
15
  frame_len = raw_frame.length
16
16
 
17
17
  if frame_len > 16
@@ -22,12 +22,12 @@ module Apex
22
22
  # Less than 2 callsigns?
23
23
  if 1.0 < i and i < 11.0
24
24
  if raw_frame[raw_slice + 1] & 0x03 == 0x03 and [0xf0, 0xcf].include? raw_frame[raw_slice + 2]
25
- text_as_array = raw_frame[raw_slice + 3..-1].map { |b| b.chr }
26
- frame[:text] = text_as_array.join
27
- frame[:destination] = identity_as_string(extract_callsign(raw_frame))
28
- frame[:source] = identity_as_string(extract_callsign(raw_frame[7..-1]))
29
- frame[:path] = extract_path(i.to_i, raw_frame)
30
- return frame
25
+ payload_as_array = raw_frame[raw_slice + 3..-1].map { |b| b.chr }
26
+ payload = payload_as_array.join
27
+ destination = identity_as_string(extract_callsign(raw_frame))
28
+ source = identity_as_string(extract_callsign(raw_frame[7..-1]))
29
+ path = extract_path(i.to_i, raw_frame)
30
+ return Frame.new(source, destination, path, payload)
31
31
  end
32
32
  end
33
33
  end
@@ -94,13 +94,13 @@ module Apex
94
94
 
95
95
  private
96
96
  def self.encode_frame(frame)
97
- enc_frame = encode_callsign(parse_identity_string(frame[:destination])) + encode_callsign(parse_identity_string(frame[:source]))
97
+ enc_frame = encode_callsign(parse_identity_string(frame.destination)) + encode_callsign(parse_identity_string(frame.source))
98
98
 
99
- frame[:path].each do |path|
99
+ frame.path.each do |path|
100
100
  enc_frame += encode_callsign(parse_identity_string(path))
101
101
  end
102
102
 
103
- return enc_frame[0...-1] + [enc_frame[-1] | 0x01] + [Kiss::SLOT_TIME] + [0xf0] + frame[:text].chars.map { |c| c.ord }
103
+ return enc_frame[0...-1] + [enc_frame[-1] | 0x01] + [Kiss::SLOT_TIME] + [0xf0] + frame.payload.chars.map { |c| c.ord }
104
104
  end
105
105
 
106
106
  private
@@ -170,4 +170,4 @@ module Apex
170
170
  end
171
171
  end
172
172
  end
173
- end
173
+ end
data/lib/apex/frame.rb ADDED
@@ -0,0 +1,124 @@
1
+ module Apex
2
+ public
3
+ class UnpathedFrame
4
+ attr_accessor :source, :destination, :payload
5
+
6
+ protected
7
+ def initialize(source, destination, payload)
8
+ @source = source
9
+ @destination = destination
10
+ @payload = payload
11
+ end
12
+
13
+ public
14
+ def path_agnostic_eql?(other)
15
+ raise ArgumentError.new("The argument must be either an UnpathedFrame or a PathAgnosticFrame") if not ((other.instance_of? UnpathedFrame) || (other.instance_of? PathAgnosticFrame))
16
+
17
+ return self == other
18
+ end
19
+
20
+ public
21
+ def path_agnostic_equality?(other)
22
+ return false if (not other.respond_to? :source) ||
23
+ (not other.respond_to? :destination) ||
24
+ (not other.respond_to? :payload)
25
+
26
+ if (self.source.eql? other.source) && (self.destination.eql? other.destination) && (self.payload.eql? other.payload)
27
+ return true
28
+ else
29
+ return false
30
+ end
31
+ end
32
+
33
+ public
34
+ def path_agnostic_hash
35
+ return [self.source, self.destination, self.payload].hash
36
+ end
37
+
38
+ public
39
+ def ==(other)
40
+ return self.path_agnostic_equality? other
41
+ end
42
+
43
+ public
44
+ def eql?(other)
45
+ self.path_agnostic_eql? other
46
+ end
47
+
48
+ public
49
+ def hash
50
+ return self.path_agnostic_hash
51
+ end
52
+ end
53
+
54
+ public
55
+ class Frame < UnpathedFrame
56
+ attr_accessor :path
57
+
58
+ protected
59
+ def initialize(source, destination, path, payload)
60
+ super(source, destination, payload)
61
+
62
+ @path = path
63
+ end
64
+
65
+ public
66
+ def eql?(other)
67
+ raise ArgumentError.new("The argument can not be a UnpathedFrame or a PathAgnosticFrame") if ((other.instance_of? UnpathedFrame) || (other.instance_of? PathAgnosticFrame))
68
+ raise ArgumentError.new("The argument must be of type Frame (or a child class).") if not other.kind_of? Frame
69
+
70
+ return self == other
71
+ end
72
+
73
+ public
74
+ def ==(other)
75
+ return false if not super(other)
76
+
77
+ return false if not other.respond_to? :path
78
+
79
+ if self.path.eql? other.path
80
+ return true
81
+ else
82
+ return false
83
+ end
84
+ end
85
+
86
+ public
87
+ def hash
88
+ return [super, self.path].hash
89
+ end
90
+
91
+ public
92
+ def path_agnostic_identity
93
+ return PathAgnosticFrame.new(self)
94
+ end
95
+ end
96
+
97
+ private
98
+ class PathAgnosticFrame < Frame
99
+ protected
100
+ def initialize(frame)
101
+ super(frame.source, frame.destination, frame.path, frame.payload)
102
+ end
103
+
104
+ public
105
+ def eql?(other)
106
+ return self.path_agnostic_eql? other
107
+ end
108
+
109
+ public
110
+ def ==(other)
111
+ return self.path_agnostic_equality? other
112
+ end
113
+
114
+ public
115
+ def hash
116
+ return self.path_agnostic_hash
117
+ end
118
+
119
+ public
120
+ def path_agnostic_identity
121
+ return self
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,178 @@
1
+ require 'apex/app_info'
2
+
3
+ module Apex
4
+ class IGateTcp
5
+ DEFAULT_APRSIS_URL = 'http://srvr.aprs-is.net:8080'
6
+ DEFAULT_APRSIS_SERVER = 'rotate.aprs.net'
7
+ DEFAULT_APRSIS_FILTER_PORT = 14580
8
+
9
+ protected
10
+ def initialize(user, password=nil)
11
+ @user = user
12
+ password = IGateTcp.calculatePasscode(user) if password.nil?
13
+ @auth = ['user', user, 'pass', password, 'vers', "APEX #{VERSION}"].join(' ')
14
+ @aprsis_sock = nil
15
+ @data_buffer = ''
16
+ @packet_buffer = []
17
+ @lock = Mutex.new
18
+ end
19
+
20
+ private
21
+ def reset_buffer
22
+ @data_buffer = ''
23
+ @packet_buffer = []
24
+ end
25
+
26
+ private
27
+ def self.format_path(path_list)
28
+ path_list.join(',')
29
+ end
30
+
31
+ private
32
+ def self.encode_frame(frame)
33
+ formatted_frame = [frame.source, frame.destination].join('>')
34
+ if frame.path and frame.path.length > 0
35
+ formatted_frame = [formatted_frame, IGateTcp::format_path(frame.path)].join(',')
36
+ end
37
+ formatted_frame += ':'
38
+ formatted_frame += frame.payload
39
+ return formatted_frame
40
+ end
41
+
42
+ private
43
+ def self.decode_frame(frame)
44
+ decoded_source = nil
45
+ frame_so_far = ''
46
+ path = nil
47
+ frame.chars.each do |char|
48
+ if char == '>' and decoded_source.nil?
49
+ decoded_source = frame_so_far
50
+ frame_so_far = ''
51
+ elsif char == ':' and !path
52
+ path = frame_so_far
53
+ frame_so_far = ''
54
+ else
55
+ frame_so_far = [frame_so_far, char].join
56
+ end
57
+ end
58
+
59
+ path = path.split(',')
60
+ decoded_destination = path.shift
61
+ decoded_path = path
62
+ decoded_payload = frame_so_far
63
+
64
+ return Frame.new(decoded_source, decoded_destination, decoded_path, decoded_payload)
65
+ end
66
+
67
+ private
68
+ def self.calculatePasscode(callsign_raw)
69
+ callsign = callsign_raw.upcase.split('-').first
70
+ hash = 0x73e2
71
+ flag = true
72
+
73
+ callsign.split('').each do |c|
74
+ hash = if flag
75
+ (hash ^ (c.ord << 8))
76
+ else
77
+ (hash ^ c.ord)
78
+ end
79
+ flag = !flag
80
+ end
81
+ hash & 0x7fff
82
+ end
83
+
84
+ public
85
+ def connect(server=nil, port=nil, aprs_filter=nil, *args, **kwargs)
86
+ @lock.synchronize do
87
+ unless @aprsis_sock
88
+ reset_buffer
89
+
90
+ unless server
91
+ server = DEFAULT_APRSIS_SERVER
92
+ end
93
+
94
+ unless port
95
+ port = DEFAULT_APRSIS_FILTER_PORT
96
+ end
97
+
98
+ if aprs_filter.nil?
99
+ @full_auth = @auth
100
+ else
101
+ @full_auth = [@auth, 'filter', aprs_filter].join(' ')
102
+ end
103
+
104
+ @server = server
105
+ @port = port
106
+ @aprsis_sock = TCPSocket.open(@server, @port)
107
+ @aprsis_sock.puts( @full_auth + "\r\n" )
108
+ end
109
+ end
110
+ end
111
+
112
+ public
113
+ def close(*args, **kwargs)
114
+ @lock.synchronize do
115
+ if @aprsis_sock
116
+ @aprsis_sock.close
117
+ reset_buffer
118
+ @aprsis_sock = nil
119
+ end
120
+ end
121
+ end
122
+
123
+ public
124
+ def read(filter_logresp=true, *args, **kwargs)
125
+ @lock.synchronize do
126
+ # check if there is any data waiting
127
+ read_more = true
128
+ while read_more
129
+ begin
130
+ read_line = @aprsis_sock.read_nonblock(100)
131
+ unless read_line.nil?
132
+ @data_buffer << read_line
133
+ end
134
+ rescue IO::WaitReadable
135
+ read_more = false
136
+ end
137
+ end
138
+
139
+ # check for any complete packets and move them to the packet buffer
140
+ if @data_buffer.include? "\r\n"
141
+ partial = true
142
+ if @data_buffer.end_with? "\r\n"
143
+ partial = false
144
+ end
145
+
146
+ packets = @data_buffer.split("\r\n")
147
+ if partial
148
+ @data_buffer = packets.pop.dup
149
+ else
150
+ @data_buffer = ''
151
+ end
152
+
153
+ packets.each do |packet|
154
+ @packet_buffer << packet.dup
155
+ end
156
+ end
157
+
158
+ # return the next packet that matches the filter
159
+ while @packet_buffer.length > 0
160
+ packet = @packet_buffer.pop
161
+ unless (filter_logresp and packet.start_with?('#'))
162
+ return IGateTcp::decode_frame(packet)
163
+ end
164
+ end
165
+
166
+ return nil
167
+ end
168
+ end
169
+
170
+ public
171
+ def write(frame, *args, **kwargs)
172
+ @lock.synchronize do
173
+ encoded_frame = IGateTcp::encode_frame(frame)
174
+ @aprsis_sock.puts( encoded_frame )
175
+ end
176
+ end
177
+ end
178
+ end
data/lib/apex.rb CHANGED
@@ -1 +1,2 @@
1
- require 'apex/aprs_kiss'
1
+ require 'apex/aprs_kiss'
2
+ require 'apex/igate_tcp'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apex-aprs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.4
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: 2021-09-04 00:00:00.000000000 Z
11
+ date: 2023-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: abstraction
@@ -81,19 +81,19 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '13.0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rdoc
84
+ name: test-unit
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '6.3'
89
+ version: '3.6'
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: '6.3'
96
+ version: '3.6'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: aruba
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -129,12 +129,14 @@ files:
129
129
  - lib/apex.rb
130
130
  - lib/apex/app_info.rb
131
131
  - lib/apex/aprs_kiss.rb
132
+ - lib/apex/frame.rb
133
+ - lib/apex/igate_tcp.rb
132
134
  homepage: https://github.com/Syncleus/apex-aprs
133
135
  licenses:
134
136
  - Apache-2.0
135
137
  metadata:
136
138
  allowed_push_host: https://rubygems.org
137
- post_install_message:
139
+ post_install_message:
138
140
  rdoc_options: []
139
141
  require_paths:
140
142
  - lib
@@ -149,8 +151,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  - !ruby/object:Gem::Version
150
152
  version: '0'
151
153
  requirements: []
152
- rubygems_version: 3.2.5
153
- signing_key:
154
+ rubygems_version: 3.4.16
155
+ signing_key:
154
156
  specification_version: 4
155
157
  summary: Library for APRS, Automatic Packet Reporting System, communications including
156
158
  the next-generation APEX extensions. Includes an APRS-IS client.