-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jon Yurek
committed
Jun 17, 2009
0 parents
commit 01e580e
Showing
8 changed files
with
530 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.