From 0e79655bbdcfec45431f809a66bb309a17115211 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman <jeffrey.freeman@syncleus.com> Date: Sat, 1 Oct 2016 12:19:36 -0400 Subject: [PATCH] Added APRSKiss class and finished implementing its methods. --- lib/aprs/aprs_kiss.rb | 148 ++++++++++++++++++++++++++++++++++++++++ lib/kiss/kiss_serial.rb | 2 +- 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 lib/aprs/aprs_kiss.rb diff --git a/lib/aprs/aprs_kiss.rb b/lib/aprs/aprs_kiss.rb new file mode 100644 index 0000000..8433b6f --- /dev/null +++ b/lib/aprs/aprs_kiss.rb @@ -0,0 +1,148 @@ +require_relative '../kiss/constants' + +module APRS + class APRSKiss + + protected + def initialize(data_stream) + @data_stream = data_stream + @lock = Mutex.new + end + + private + def self.decode_frame(raw_frame) + frame = {} + frame_len = raw_frame.length + + if frame_len > 16 + (0...frame_len - 2).each do |raw_slice| + # Is address field length correct? + if raw_frame[raw_slice] & 0x01 and ((raw_slice + 1) % 7) == 0 + i = (raw_slice.to_f + 1.0) / 7.0 + # Less than 2 callsigns? + if 1.0 < i < 11.0 + if raw_frame[raw_slice + 1] & 0x03 == 0x03 and [0xf0, 0xcf].include? raw_frame[raw_slice + 2] + text_as_array = raw_frame[raw_slice + 3..-1].map { |b| chr(b) } + frame['text'] = text_as_array.join + frame['destination'] = identity_as_string(extract_callsign(raw_frame)) + frame['source'] = identity_as_string(__extract_callsign(raw_frame[7..-1])) + frame['path'] = extract_path(i.to_i, raw_frame) + return frame + end + end + end + end + end + frame + end + + private + def self.extract_path(start, raw_frame) + full_path = [] + + (2...start).each do |i| + path = identity_as_string(extract_callsign(raw_frame[i * 7..-1])) + if path + if raw_frame[i * 7 + 6] & 0x80 + full_path << [path, '*'].join + else + full_path << path + end + end + end + full_path + end + + private + def self.extract_callsign(raw_frame) + callsign_as_array = raw_frame[0...6].map { |x| chr(x >> 1) } + callsign = callsign_as_array.join.strip + ssid = (raw_frame[6] >> 1) & 0x0f + return {'callsign': callsign, 'ssid': ssid} + end + + private + def self.identity_as_string(identity) + if identity['ssid'] > 0 + return [identity['callsign'], identity['ssid'].to_s].join('-') + else + return identity['callsign'] + end + end + + private + def self.encode_frame(frame) + enc_frame = encode_callsign(parse_identity_string(frame['destination'])) + encode_callsign(parse_identity_string(frame['source'])) + frame['path'].each do |p| + enc_frame += encode_callsign(parse_identity_string(p)) + end + + return enc_frame[0..-1] + [enc_frame[-1] | 0x01] + [KISS::SLOT_TIME] + [0xf0] + frame['text'].map { |c| ord(c) } + end + + private + def self.encode_callsign(callsign) + call_sign = callsign['callsign'] + + enc_ssid = (callsign['ssid'] << 1) | 0x60 + + if call_sign.include? '*' + call_sign.gsub!(/\*/,'') + enc_ssid |= 0x80 + end + + while call_sign.length < 6 + call_sign = [call_sign, ' '].join + end + + return call_sign.map { |p| ord(p) << 1 } + [enc_ssid] + end + + private + def self.parse_identity_string(identity_string) + # If we are parsing a spent token then first lets get rid of the astresick suffix. + if identity_string[-1] == '*' + identity_string = identity_string[0..-1] + end + + if identity_string.include? '-' + call_sign, ssid = identity_string.split('-') + else + call_sign = identity_string + ssid = 0 + end + + return {'callsign': call_sign, 'ssid': int(ssid)} + end + + public + def connect(*args, **kwargs) + @data_stream.connect(*args, **kwargs) + end + + public + def close(*args, **kwargs) + @data_stream.close(*args, **kwargs) + end + + public + def write(frame, *args, **kwargs) + @lock.synchronize do + encoded_frame = encode_frame(frame) + @data_stream.write(encoded_frame, *args, **kwargs) + end + end + + public + def read(*args, **kwargs) + @lock.synchronize do + frame = @data_stream.read(*args, **kwargs) + if frame&.length + return decode_frame(frame) + else + return nil + end + end + end + end +end \ No newline at end of file diff --git a/lib/kiss/kiss_serial.rb b/lib/kiss/kiss_serial.rb index b61d182..c69468b 100644 --- a/lib/kiss/kiss_serial.rb +++ b/lib/kiss/kiss_serial.rb @@ -17,7 +17,7 @@ module KISS read_bytes=DEFAULT_READ_BYTES, strip_df_start=true) super(strip_df_start) - + @com_port = com_port @baud = baud @parity = parity -- GitLab