begin Kernel::require 'serialport' rescue Exception require 'serialport' end require 'monitor.rb' module X class Entry attr_accessor :path, :name, :mtime def initialize data = nil @data = data end def mtime @mtime ||= Time.parse @data["mtime"] end def path @path ||= @data["uri"] end def name @name ||= (path.split %r|[:/]|)[-1] end def to_s "name: #{name}\npath: #{path}\nmtime: #{mtime}" end def self.find path, recurse = 0 json = (Gom::Remote.connection.read "#{path}.json") clazz, key = /:/.match(path) ? [Attribute, "attribute"] : [Node, "node"] a = clazz.new JSON.parse(json)[key] a =begin json = (connection.read "#{path}.json") (JSON.parse json)["node"]["entries"].select do |entry| # 1. select attribute entries entry.has_key? "attribute" end.inject({}) do |h, a| # 2. make it a key, value list h[a["attribute"]["name"].to_sym] = a["attribute"]["value"] h end =end end end class Attribute < Entry attr_writer :value def value @value ||= @data["value"] end end class Node < Entry def entries debugger if(defined? debugger) @entries ||= @data["entries"].map do |entry| if a = entry['attribute'] (Attribute.new a) else X::Entry.find entry['node'] end end end def to_s "#{super.to_s}\n#{entries.inspect}" end end end module RfidUsbGomSensor class Node < Gom::Remote::Entry # raised on all kinds of comm errors class BrokenRead < Exception; end Defaults = { :device => "/dev/ttyUSB0", :baudrate => 9600, :legacy => false, :hex_id => false, } include OAttr oattr :device, :baudrate def initialize path, options = {} @path = path @options = Defaults.merge(gnode @path).merge(options) puts "options: #{@options.inspect}" @ip = connection.callback_server.host @sp = SerialPort.new device, baudrate @sensor_tags = {}.extend(MonitorMixin) @gom_tags = find_tags end def hex_id @hex_id ||= @options[:hex_id] end def find_tags tag_node = X::Entry.find "#{@path}/tags" #puts "-->#{tag_node.inspect}<---" #puts "--->\n#{tag_node}\n<---" tag_node.entries.inject({}) do |tags, node| tags.update node.name => node.mtime end end # reader commands STX = 0x02 ETX = 0x03 GetInfo = [STX, 0x01, 0x47, 0x46, ETX].pack "c*" GoContinuous = [STX, 0x01, 0x43, 0x04, 0x46, ETX].pack "c*" def preroll #info = [0x02, 0x01, 0x47, 0x46, 0x03] #info.each {|c| @sp.putc c.to_i} @sp.puts GetInfo 2.times { @sp.getc} print "Detected reader: " 37.times {putc(@sp.getc)} print "\n" 6.times {@sp.getc} #continuous = [0x02, 0x01, 0x43, 0x04, 0x46, 0x03] #continuous.each {|c| @sp.putc c.to_i} @sp.puts GoContinuous 6.times {@sp.getc} end class << self def raise_broken_read cc, expected, buf msg = "checksum missmatch: #{cc} != #{expected} -- #{buf.unpack 'H*'}" raise BrokenRead, msg end # blk format: # # 0 STX 0x02 # 1 ADR 0x01 # 2 UID7 0xE0 # 3 UID6 # 4 UID5 # 5 UID4 # 6 UID3 # 7 UID2 # 8 UID1 # 9 UID0 # 10 ERR 0x00 # 11 BCC XOR[1..10] # 12 ETX 0x03 # # :legacy => true -> makes this compatible to the tag id readout code # in: rfid-readers/app/models/rfid_reader.rb # def decode blk, opts = { } opts = ({:hex_id => false, :legacy => false }.merge opts) #validate rec = (blk.unpack 'c2Qc*') if opts[:legacy] id = rec[2] rec[2] = Integer("0x#{(([id].pack 'q').unpack 'H*').first}") end if opts[:hex_id] id = rec[2] rec[2] = "0x#{([id].pack 'Q').unpack 'H*'}" end expected = rec[4] cc = (calc_checksum blk[1..10]) # (blk[1..10].unpack "C*").inject(0) {|cc, c| cc^c} (cc == expected) or (raise_broken_read cc, expected, blk) #checksum blk[1..10], rec[4] #puts "-#{rec.inspect}-" rec end def calc_checksum blk (blk.unpack "C*").inject(0) {|cc, c| cc^c} end end def detect loop do uid = next_tag @sensor_tags.synchronize { @sensor_tags[uid] = Time.now } end rescue BrokenRead => e (resync_from_broken_read e) and retry rescue SignalException => e :stop # if (e.signm == "INT") end def push_active_tags_to_gom active_tags = [] @sensor_tags.synchronize do active_tags = @sensor_tags.keys @sensor_tags.clear end #puts "active tags: #{active_tags.inspect}" #connection.write "#{@path}/tags/#{uid}:sensor_ip", @ip # 1. which gom tags are not longer active? active_tags.each { |tag| @gom_tags.delete tag } (to_be_deleted = @gom_tags.keys).each do |tag_id| puts "disappeared: #{@path}/tags/#{tag_id}" connection.destroy "#{@path}/tags/#{tag_id}" end @gom_tags.clear # 2. active_tags becomes the new gom_tags active_tags.each do |tag_id| @gom_tags[tag_id] = Time.now puts " active: #{@path}/tags/#{tag_id}" connection.write "#{@path}/tags/#{tag_id}:sensor_ip", @ip end end private def resync_from_broken_read e puts " !! broken read resync not yet implemented: #{e}" raise e end def next_tag (blk = @sp.read(13)) stx, adx, uid, err, bcc, etx = (Node.decode blk, @options) uid end end end __END__ def _detect =begin Format: 0 STX 0x02 1 ADR 0x01 2 UID7 0xE0 3 UID6 4 UID5 5 UID4 6 UID3 7 UID2 8 UID1 9 UID0 10 ERR 0x00 11 BCC XOR[1..10] 12 ETX 0x03 =end while @sp.getc!=0x02 do end # STX while @sp.getc!=0x01 do end # ADR v = 0 0.upto(7) do |i| v += @sp.getc*2**((7-i)*8) # UID end while @sp.getc!=0x00 do end # ERR puts "Detected tag: #{v}" connection.write "#{@path}/tags/#{v}:sensor_ip", @ip puts "-#{@sp.getc}-" # BCC while @sp.getc!=0x03 do end # ETX rescue SignalException => e :stop # if (e.signm == "INT") end