hwping 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a6cbddb5d50553a985d48cda712b992ea667ede9
4
+ data.tar.gz: 72840576bfc2f86a92414f573f957ccdb040b4aa
5
+ SHA512:
6
+ metadata.gz: bbd0ea2f0c0f574e2d144601184c3c93c9f2bdd9bff8f85951164418ca2fce61be5a06441225545288d3cb725b9a3468d40d42d1d43f434f9fa60426959e4dce
7
+ data.tar.gz: af2ce63c355ff50cee63a95f92f60c786eb15b6e449339d5ab99ba6fdc5937f8e4996a6c46e8bad70b95a076e609a16a67c45a5a857b1733160f2fc7a349476d
data/bin/hwping ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'yaml'
5
+ require 'hwping'
6
+
7
+ # Parse arguments
8
+ options = {}
9
+ OptionParser.new do |opts|
10
+ opts.version = HWPing::VERSION
11
+ opts.program_name = HWPing::APP_NAME
12
+ opts.banner = 'Usage: hwping [options]'
13
+ opts.on('-c', '--config-file file.yml', "Specify which configuration file you want to use instead of the default config.yml") do |v|
14
+ options[:config] = v
15
+ end
16
+ end.parse!
17
+
18
+ # Open the configuration
19
+ file = options.fetch(:config, HWPing::CONFIG_FILE)
20
+ config = YAML.load_file(file)
21
+
22
+ # Run the application
23
+ app = HWPing::HWPing.new(config)
24
+ app.start
25
+
26
+ # Stop the bot and save the configuration file
27
+ at_exit do
28
+ app.stop
29
+ File.open(file, 'w') do |f|
30
+ YAML.dump(app.config, f)
31
+ end
32
+ end
data/lib/hwping/bot.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'cinch'
2
+
3
+ module HWPing
4
+ class Bot
5
+
6
+ MESSAGES = {
7
+ :unauthorized => "Sorry, you're unauthorized to use this bot!",
8
+ :firing => 'Firing rocket in 5 seconds!',
9
+ :notarget => 'Unknown target!',
10
+ :fire => 'Rocket launch initiated!',
11
+ :reset => 'Launcher set back to default position!',
12
+ :position => 'Current position: %d %d',
13
+ :target_list => 'Available targets: %s',
14
+ :target_get => "Target's position: %d %d",
15
+ :target_del => 'Target successfully deleted!',
16
+ :target_set => "Target's position saved at: %d %d",
17
+ :move => 'Move operation finished!',
18
+ :badcommand => "Unknown command, type 'help' for further information!",
19
+ :help => "Hardware Pinger\n
20
+ Usage in a channel: hwping <target>\n
21
+ Available commands in private:\n
22
+ help\n
23
+ fire\n
24
+ position\n
25
+ up|down|left|right\n
26
+ reset\n
27
+ target list\n
28
+ target set <nick> <right> <up>\n
29
+ target get <nick>\n
30
+ target del <nick>\n"
31
+ }
32
+
33
+ # Initialize a bot and return with its Cinch instance
34
+ def initialize(handler, config = {})
35
+ @nick = config.nick
36
+ @server = config.server
37
+ @port = config.port
38
+ @channels = config.channels.map { |m| "\##{m}"}
39
+ @handler = handler
40
+ return setup_bot()
41
+ end
42
+
43
+ private
44
+ def setup_bot
45
+ bot = Cinch::Bot.new do |b|
46
+ configure do |c|
47
+ c.nick = @nick
48
+ c.server = @server
49
+ c.port = @port
50
+ c.channels = @channels
51
+ end
52
+
53
+ # For channel mesages, just reply with the matching message
54
+ on :channel, /^hwping/ do |e|
55
+ r = @handler.channel(e)
56
+ e.reply(MESSAGES[r])
57
+ end
58
+
59
+ # For private messages, build a reply message from the format strinc and the passed variables
60
+ on :private do |e|
61
+ (r, *f) = @handler.message(e)
62
+ e.reply(MESSAGES[r] % f)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,24 @@
1
+ module HWPing
2
+ class Config
3
+
4
+ attr_reader :server
5
+ attr_reader :port
6
+ attr_reader :nick
7
+ attr_reader :channels
8
+ attr_reader :auth
9
+ attr_accessor :targets
10
+
11
+ def initialize(hash = {})
12
+ @server = hash.fetch(:server, 'irc.freenode.net')
13
+ @port = hash.fetch(:port, 6667)
14
+ @nick = hash.fetch(:nick, 'hwping')
15
+ @channels = hash.fetch(:channels, ['hwping-test'])
16
+ @auth = hash.fetch(:auth , [])
17
+ @targets = hash.fetch(:targets, [])
18
+ end
19
+
20
+ def to_hash
21
+ Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ module HWPing
2
+ VERSION = '0.0.1'
3
+ APP_NAME = 'hwping'
4
+ REPO_URL = 'http://github.com/skateman/hwping'
5
+ CONFIG_FILE = 'config.yml'
6
+ end
@@ -0,0 +1,68 @@
1
+ module HWPing
2
+ class Handler
3
+ # Set up the handler with the configuration
4
+ def initialize(launcher, config)
5
+ @targets = config.targets
6
+ @auth = config.auth
7
+ @nick = config.nick
8
+ @launcher = launcher
9
+ end
10
+
11
+ # If the event happened in a channel, return just with a symbol
12
+ def channel(event)
13
+ if event.message =~ /^hwping,?\s+(.*)\s*$/
14
+ if @auth.include?(event.user.to_s)
15
+ if @targets.include?($1)
16
+ @launcher.point_and_fire(@targets[$1])
17
+ return :firing
18
+ else
19
+ return :notarget
20
+ end
21
+ else
22
+ return :unauthorized
23
+ end
24
+ end
25
+ end
26
+
27
+ # If the event happened in a private window, return with an array
28
+ def private(event)
29
+ if @auth.include?(event.user.to_s)
30
+ case event.message
31
+ when "fire"
32
+ @launcher.fire
33
+ return [:fire]
34
+ when "position"
35
+ return @launcher.position.unshift(:position)
36
+ when "help"
37
+ return [:help]
38
+ when "reset"
39
+ @launcher.reset
40
+ return [:reset]
41
+ when "target list"
42
+ return [:target_list, @targets.keys.join(', ')]
43
+ when /^target set ([^\s]+)( (\d+) (\d+))?$/
44
+ @targets[$1] = $2 ? [$3.to_i, $4.to_i] : @launcher.position
45
+ return [:target_set, @targets[$1]].flatten
46
+ when /^target ((get)|(del)) ([^\s]+)$/
47
+ if @targets.has_key?($+)
48
+ if $1 == "del"
49
+ @targets.delete($+)
50
+ return [:target_del]
51
+ else
52
+ return [:target_get, @targets[$+]].flatten
53
+ end
54
+ else
55
+ return [:notarget]
56
+ end
57
+ when /^((up)|(down)|(left)|(right)) (\d+)$/
58
+ @launcher.send($1, $+.to_i)
59
+ return [:move]
60
+ else
61
+ return [:badcommand]
62
+ end
63
+ else
64
+ return [:unauthorized]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,26 @@
1
+ module HWPing
2
+ class HWPing
3
+
4
+ attr_reader :bot
5
+
6
+ def initialize(config = {})
7
+ @config = Config.new(config)
8
+ @launcher = Launcher.connect()
9
+ @handler = Handler.new(@launcher, @config)
10
+ @bot = Bot.new(@handler, @config)
11
+ end
12
+
13
+ def start
14
+ @bot.start
15
+ end
16
+
17
+ def stop
18
+ @bot.quit
19
+ end
20
+
21
+ # Return the configuration hash for an export
22
+ def config
23
+ @config.to_hash
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,136 @@
1
+ # Inspired by https://github.com/robhurring/thunder/blob/master/lib/launcher.rb
2
+ require 'libusb'
3
+
4
+ module HWPing
5
+ class Launcher
6
+
7
+ DeviceNotFoundError = Class.new(IOError)
8
+
9
+ DEVICE = {
10
+ :vendor_id => 0x2123,
11
+ :product_id => 0x1010
12
+ }
13
+
14
+ COMMANDS = {
15
+ :down => 0x01,
16
+ :up => 0x02,
17
+ :left => 0x04,
18
+ :right => 0x08,
19
+ :fire => 0x10,
20
+ :stop => 0x20,
21
+ :on => 0x01,
22
+ :off => 0x00
23
+ }
24
+
25
+ TARGETS = {
26
+ :launcher => 0x02,
27
+ :led => 0x03
28
+ }
29
+
30
+ REQUEST_TYPE = 0x21
31
+ REQUEST = 0x09
32
+
33
+ # Connect to the device
34
+ def self.connect
35
+ usb = LIBUSB::Context.new
36
+ launcher = usb.devices(
37
+ :idVendor => DEVICE[:vendor_id],
38
+ :idProduct => DEVICE[:product_id]
39
+ ).first
40
+
41
+ raise DeviceNotFoundError, 'Launcher was not found.' if launcher.nil?
42
+ new(launcher)
43
+ end
44
+
45
+ def initialize(device)
46
+ @device = device
47
+ @handle = @device.open
48
+ @handle.detach_kernel_driver(0) if @handle.kernel_driver_active?(0)
49
+ @x = 0
50
+ @y = 0
51
+ end
52
+
53
+ # Point at the given location and fire a rocket
54
+ def point_and_fire(arr)
55
+ led(:on)
56
+ reset
57
+ right arr[0]
58
+ up arr[1]
59
+ fire
60
+ led(:off)
61
+ end
62
+
63
+ # Get the relative position
64
+ def position
65
+ [@x, @y]
66
+ end
67
+
68
+ # Switch the LED on/off
69
+ def led(status)
70
+ send! :led, status
71
+ end
72
+
73
+ # Fire a rocket and wait for the device to reload
74
+ def fire
75
+ send! :launcher, :fire
76
+ Kernel.sleep 4.5
77
+ end
78
+
79
+ # Resets the launcher into the default position
80
+ def reset
81
+ down(1000)
82
+ left(6000) # should be enough
83
+ @x = 0
84
+ @y = 0
85
+ end
86
+
87
+ # Positioning functions
88
+ [:up, :down, :left, :right].each do |direction|
89
+ define_method direction do |duration|
90
+ move direction, duration
91
+ end
92
+ end
93
+
94
+ # Not really the best motor control
95
+ def move(direction, duration)
96
+ send! :launcher, direction
97
+ Kernel.sleep duration.to_f / 1000
98
+ send! :launcher, :stop
99
+ update_pos direction, duration
100
+ end
101
+
102
+ private
103
+ # Send data through USB
104
+ def send!(target, command)
105
+ payload = build_payload(target, COMMANDS[command.to_sym])
106
+
107
+ @handle.control_transfer(
108
+ bmRequestType: REQUEST_TYPE,
109
+ bRequest: REQUEST,
110
+ wValue: 0,
111
+ wIndex: 0,
112
+ dataOut: payload,
113
+ timeout: 0
114
+ )
115
+ end
116
+
117
+ def build_payload(target, command)
118
+ [TARGETS[target], command, 0, 0, 0, 0, 0, 0].pack('CCCCCCCC')
119
+ end
120
+
121
+ # Update inner position variables
122
+ def update_pos(direction, value)
123
+ value = value.to_i
124
+ case direction
125
+ when :up
126
+ @y = [1000, @y + value].min
127
+ when :down
128
+ @y = [0, @y - value].max
129
+ when :right
130
+ @x = [6000, @x + value].min
131
+ when :left
132
+ @x = [0, @x - value].max
133
+ end
134
+ end
135
+ end
136
+ end
data/lib/hwping.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'hwping/constants'
2
+ require 'hwping/config'
3
+ require 'hwping/launcher'
4
+ require 'hwping/handler'
5
+ require 'hwping/bot'
6
+ require 'hwping/hwping'
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hwping
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dávid Halász
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: libusb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: cinch
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 10.4.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 10.4.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: IRC bot for HW pinging with the Dream Cheeky Thunder missile launcher
70
+ email: skateman@skateman.eu
71
+ executables:
72
+ - hwping
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/hwping/handler.rb
77
+ - lib/hwping/launcher.rb
78
+ - lib/hwping/hwping.rb
79
+ - lib/hwping/bot.rb
80
+ - lib/hwping/config.rb
81
+ - lib/hwping/constants.rb
82
+ - lib/hwping.rb
83
+ - bin/hwping
84
+ homepage: http://github.com/skateman/hwping
85
+ licenses:
86
+ - GPL-2
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 2.0.0
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.0.14
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Hardware Pinger
108
+ test_files: []