Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Yurek committed Jun 17, 2009
0 parents commit 01e580e
Show file tree
Hide file tree
Showing 8 changed files with 530 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,8 @@
log/*
tmp/*
*.DS_Store
*.swp
coverage*
tags

!.keep
24 changes: 24 additions & 0 deletions Rakefile
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'player'

desc 'Default: run unit tests.'
task :default => [:test]

desc 'Run the tests.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib' << 'profile' << 'test'
t.pattern = 'test/*_test.rb'
t.verbose = true
end

namespace :test do
desc 'Generate test coverage report.'
task :coverage do
rm_f "coverage"
rcov = 'rcov -I test -T -x "rubygems/*,/Library/Ruby/Site/*,gems/*,rcov*"'
system("#{rcov} --html test/*_test.rb")
system("open coverage/index.html") if PLATFORM['darwin']
end
end
103 changes: 103 additions & 0 deletions player.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,103 @@
require 'ostruct'

class Player

attr_accessor :port, :address, :network_speed, :password, :music_player,
:music_repo, :reentry_delay, :start_hour, :end_hour

attr_accessor :last_access_time, :last_access_user

attr_reader :door, :network, :reader, :hardware

def initialize config
config.each do |key, value|
send("#{key}=", value) if respond_to? "#{key}="
end
@last_access_time = Time.mktime(1970, 1, 1, 0, 0, 0)
@last_access_user = OpenStruct.new
raise NoAPI unless @door = WIN32OLE.new("TalosAPI.Application")
raise NoNetwork unless @network = @door.FindReaderNetwork(port)
end

def connect
raise NoConnection unless @network.Connect(network_speed.to_i)
raise NoReader unless @reader = @network.FindReader(address.to_i)
raise NoLogon unless @reader.Logon(2, password.to_i, true)
raise NoHardware unless @hardware = @reader.HardwareControl
end

def song_for name
Dir.glob(File.join(music_repo, "#{name}.*")).first
end

def command_for name
%Q{start "Theme Music" "#{music_player}" "#{song_for(name)}"}
end

def play_for name
command = command_for(name)
puts "User: #{name}, Command: #{command}"
system(command)
end

def should_play?
(start_hour.to_i...end_hour.to_i).include?(Time.now.hour)
end

def card_detected?
hardware.IsCarrierInField
end

def detect_card!
sleep 0.25 while not card_detected?
end

def detect_user!
user_detected = false
while not user_detected
detect_card!
user = hardware.LastUser
user_detected = trigger_access?(user)
self.last_access_user = user
self.last_access_time = Time.now
end
end

def trigger_access? user
same_user = user.CardNumber == last_access_user.CardNumber
in_delta = Time.now - last_access_time <= reentry_delay
not in_delta && same_user
end

def ensuring_connection &block
running = true
while running
begin
connect
block.call(self) while true
rescue WIN32OLERuntimeError, PlayerError
sleep 1 # There was an error with the connection, most likely.
rescue Interrupt
running = false # Ctrl-C hit. Bail.
end
end
end

def self.run config
new(config).ensuring_connection do |player|
player.detect_user!
sleep 0.5
player.play_for(player.last_access_user.Name) if player.should_play?
end
end

class PlayerError < StandardError; end
class NoAPI < PlayerError; end
class NoNetwork < PlayerError; end
class NoConnection < PlayerError; end
class NoReader < PlayerError; end
class NoLogon < PlayerError; end
class NoHardware < PlayerError; end
end

# Player.run( YAML.load_file(ARGV[0] || "player.yml") )
29 changes: 29 additions & 0 deletions player.yml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,29 @@
# The network (COM) port the reader is attached to.
# Can find this with XM3 Manage
port: 3

# The address on the network where the reader is found.
# Can find this with XM3 Manage
address: 23

# The baud rate to connect at. Can be 9600, 19200, or 38400
# Can find this with XM3 Manage
network_speed: 19200

# The installer PIN for the reader.
# Can find this with XM3 Manage but defaults to 123456789.
password: 123456789

# Delay in seconds before the same person can trigger the door again.
reentry_delay: 5

# Path to the music player program.
music_player: 'C:\Program Files\Winamp\winamp.exe'

# Path to the songs.
music_repo: 'C:\Theme Music\Songs'

# Only play songs between these hours.
# Same as (start_hour...end_hour) in ruby (note non-inclusive range).
start_hour: 6
end_hour: 11
128 changes: 128 additions & 0 deletions test/fake_door.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,128 @@
class FakeDoor
def self.card_present= val
@card_present = val
end
def self.card_present
@card_present
end

def self.find_network= val
@find_network = val
end
def self.find_network
@find_network
end

self.card_present = true
self.find_network = true

def FindReaderNetwork network
@network ||= Network.new(network) if self.class.find_network
end

class Network
def self.connect= val
@connect = val
end
def self.connect
@connect
end

def self.find_reader= val
@find_reader = val
end
def self.find_reader
@find_reader
end

self.connect = true
self.find_reader = true

def initialize port
@port = port
end

def Connect speed
@speed = speed
self.class.connect if self.class.connect
end

def Disconnect
raise unless self.class.connect
end

def FindReader address
@reader ||= Reader.new(address) if self.class.find_reader
end
end

class Reader
def self.logon= val
@logon = val
end
def self.logon
@logon
end

def self.find_hardware= val
@find_hardware = val
end
def self.find_hardware
@find_hardware
end

self.logon = true
self.find_hardware = true

def initialize address
@address = address
end

def Logon const, password, sync
@password = password
self.class.logon if self.class.logon
end

def Logout
raise unless self.class.logon
end

def HardwareControl
@hardware ||= Hardware.new if self.class.find_hardware
end
end

class Hardware
def self.user_name= val
@user_name = val
end
def self.user_name
@user_name
end

def self.card_number= val
@card_number = val
end
def self.card_number
@card_number
end

self.user_name = "Moe Syzslak"
self.card_number = "12345"

def IsCarrierInField
FakeDoor.card_present
end

def LastUser
user = User.new
user.CardNumber = self.class.card_number
user.Name = self.class.user_name
user
end
end

class User
attr_accessor :CardNumber, :Name
end
end
Loading

0 comments on commit 01e580e

Please sign in to comment.