diff --git a/lib/apex.rb b/lib/apex.rb index 8a4206b4ee1e95c1863808ac46230d0c7c206fc4..7318de0ffd9bc6bfbe23478b8da443b9890d4615 100644 --- a/lib/apex.rb +++ b/lib/apex.rb @@ -1 +1,2 @@ -require 'apex/aprs_kiss' \ No newline at end of file +require 'apex/aprs_kiss' +require 'apex/igate_tcp' \ No newline at end of file diff --git a/lib/apex/igate_tcp.rb b/lib/apex/igate_tcp.rb new file mode 100644 index 0000000000000000000000000000000000000000..7ec93b6f78884b4192cfcdb73a77bfd251fff771 --- /dev/null +++ b/lib/apex/igate_tcp.rb @@ -0,0 +1,164 @@ +module Apex + class IGateTcp + DEFAULT_APRSIS_URL = 'http://srvr.aprs-is.net:8080' + DEFAULT_APRSIS_SERVER = 'rotate.aprs.net' + DEFAULT_APRSIS_FILTER_PORT = 14580 + + protected + def initialize(user, password='-1', input_url=None) + @user = user + if input_url + @url = input_url + else + @url = DEFAULT_APRSIS_URL + end + @auth = ['user', user, 'pass', password, 'vers', 'APRS Python Module'].join(' ') + @aprsis_sock = nil + @data_buffer = '' + @packet_buffer = [] + @lock = Mutex.new + end + + private + def reset_buffer + @data_buffer = '' + @packet_buffer = [] + end + + private + def format_path(path_list) + path_list.join(',') + end + + private + def encode_frame(frame) + formatted_frame = [frame[:source], frame[:destination]].join('>') + if frame[:path] and frame[:path].length > 0 + formatted_frame = [formatted_frame, format_path(frame[:path])].join(',') + end + formatted_frame += ':' + formatted_frame += frame[:text] + return formatted_frame + end + + private + def decode_frame(frame) + decoded_frame = {} + frame_so_far = '' + path = nil + frame.chars.each do |char| + if char == '>' and !decoded_frame.include? :source + decoded_frame[:source] = frame_so_far + frame_so_far = '' + elsif char == ':' and !path + path = frame_so_far + frame_so_far = '' + else + frame_so_far = [frame_so_far, char].join + end + end + + path = path.split(',') + decoded_frame[:destination] = path.shift + decoded_frame[:path] = path + decoded_frame[:text] = frame_so_far + + decoded_frame + end + + public + def connect(server=nil, port=nil, aprs_filter=nil, *args, **kwargs) + @lock.synchronize do + unless @aprsis_sock + reset_buffer + + unless server + server = DEFAULT_APRSIS_SERVER + end + + unless port + port = DEFAULT_APRSIS_FILTER_PORT + end + + unless aprs_filter + aprs_filter = ['p', @user].join('/') + end + + @full_auth = [@auth, 'filter', aprs_filter].join(' ') + + @server = server + @port = port + @aprsis_sock = TCPSocket.open(@server, @port) + @aprsis_sock.puts( (@full_auth + '\r\n').map{ |c| c.ord } ) + end + end + end + + public + def close(*args, **kwargs) + @lock.synchronize do + if @aprsis_sock + @aprsis_sock.close + reset_buffer + @aprsis_sock = nil + end + end + end + + public + def read(filter_logresp=true, *args, **kwargs) + @lock.synchronize do + # check if there is any data waiting + read_more = true + while read_more + selected = IO.select([@aprsis_sock], [], [], 0) + if selected.first.length > 0 + recvd_data = @aprsis_sock.gets + if recvd_data + @data_buffer += recvd_data + end + else + read_more = false + end + end + + # check for any complete packets and move them to the packet buffer + if @data_buffer.include? '\r\n' + partial = true + if @data_buffer.end_with? '\r\n' + partial = false + end + + packets = @data_buffer.split('\r\n') + if partial + @data_buffer = packets.pop.dup + else + @data_buffer = '' + end + + packets.each do |packet| + @packet_buffer << packet.dup + end + end + + # return the next packet that matches the filter + while @packet_buffer.length > 0 + packet = @packet_buffer.pop + unless filter_logresp and packet.start_with?('#') and packet.include? 'logresp' + return decode_frame(packet) + end + end + + return nil + end + end + + public + def write(frame, *args, **kwargs) + @lock.synchronize do + encoded_frame = encode_frame(frame) + @aprsis_sock.puts( encoded_frame.map { |c| c.ord } ) + end + end + end +end \ No newline at end of file