smartware 0.1.30 → 0.2

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.
@@ -0,0 +1,29 @@
1
+ module Smartware
2
+ module Driver
3
+ module Watchdog
4
+
5
+ class Dummy
6
+
7
+ def initialize(config)
8
+
9
+ end
10
+
11
+ def model
12
+ "Dummy watchdog"
13
+ end
14
+
15
+ def version
16
+ ""
17
+ end
18
+
19
+ def reboot_modem
20
+
21
+ end
22
+
23
+ def error
24
+ nil
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,40 @@
1
+ module Smartware
2
+ module Driver
3
+ module Watchdog
4
+
5
+ class WatchdogDaemon
6
+
7
+ attr_reader :error
8
+
9
+ def initialize(config)
10
+ @error = nil
11
+ @config = config
12
+ end
13
+
14
+ def model
15
+ "watchdogd-controlled watchdog"
16
+ end
17
+
18
+ def version
19
+ ""
20
+ end
21
+
22
+ def reboot_modem
23
+ begin
24
+ File.open(@config["pidfile"], "r") do |io|
25
+ pid = io.read.to_i
26
+
27
+ Process.kill :USR1, pid
28
+ end
29
+
30
+ @error = nil
31
+ rescue => e
32
+ Smartware::Logging.logger.warn "Watchdog communication error: #{e}"
33
+
34
+ @error = Interface::Watchdog::WATCHDOG_NOT_AVAILABLE
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,142 +1,187 @@
1
- require 'drb'
2
-
3
1
  module Smartware
4
2
  module Interface
3
+ class CashAcceptor < Interface
4
+
5
+ DROP_CASETTE_FULL = 1
6
+ DROP_CASETTE_OUT_OF_POSITION = 2
7
+ VALIDATOR_JAMMED = 3
8
+ DROP_CASETTE_JAMMED = 4
9
+ CHEATED = 5
10
+ PAUSE = 6
11
+ BILL_VALIDATOR_FAILURE = 7
12
+ STACK_MOTOR_FAILURE = 8
13
+ TRANSPORT_MOTOR_SPEED_FAILURE = 9
14
+ TRANSPORT_MOTOR_FAILURE = 10
15
+ ALIGNING_MOTOR_FAILURE = 11
16
+ INITIAL_CASETTE_STATUS_FAILURE = 12
17
+ OPTIC_CANAL_FAILURE = 13
18
+ MAGNETIC_CANAL_FAILURE = 14
19
+ CAPACITANCE_CANAL_FAILURE = 15
20
+ COMMUNICATION_ERROR = 16
21
+
22
+ def initialize(config)
23
+ super
24
+
25
+ @limit = nil
26
+ @banknotes = {}
27
+ @banknotes.default = 0
5
28
 
6
- module CashAcceptor
7
-
8
- #
9
- # Init vars
10
- #
11
- @configured = false
12
- @no_limit = true
13
- @banknotes = {}
14
- @commands = %w(monitor)
15
- @status = { :cassette => true }
16
-
17
- #
18
- # (re)configure device
19
- #
20
- def self.configure!(port=nil, driver=nil)
21
- @device = Smartware::Driver::CashAcceptor.const_get(
22
- Smartware::Service.config['cash_acceptor_driver']).new(
23
- Smartware::Service.config['cash_acceptor_port'])
24
- @session.kill if @session and @session.alive?
25
- @commands = %w(monitor)
26
- @device.cancel_accept
27
- @session = self.start_poll!
29
+ update_status do
30
+ @status[:casette] = true
31
+ end
32
+
33
+ @accepting = false
34
+ @commands = Queue.new
35
+ @commands.push :close
36
+
37
+ Thread.new &method(:dispatch_commands)
38
+ Thread.new &method(:periodic)
28
39
  Smartware::Logging.logger.info "Cash acceptor monitor started"
29
- @configured = true
30
- rescue => e
31
- @configured = false
32
- Smartware::Logging.logger.error e.message
33
- Smartware::Logging.logger.error e.backtrace.join("\n")
34
40
  end
35
41
 
36
- def self.open_session(limit_min, limit_max)
37
- @commands << 'open'
38
- @banknotes = {}
39
- if !limit_min.nil? && !limit_max.nil?
40
- @no_limit = false
41
- @limit_min = limit_min
42
- @limit_max = limit_max
42
+ def open_session(limit_min, limit_max)
43
+ @banknotes.clear
44
+
45
+ if limit_min.nil? || limit_max.nil?
46
+ @limit = nil
47
+
48
+ Smartware::Logging.logger.info "Session open, unlimited"
43
49
  else
44
- @no_limit = true
50
+ @limit = limit_min..limit_max
51
+
52
+ Smartware::Logging.logger.info "Session open, limit: #{@limit}"
45
53
  end
54
+
55
+ @commands.push :open
56
+ @commands.push :get_money
46
57
  end
47
58
 
48
- def self.close_session
49
- @commands << 'close'
50
- @limit_min = nil
51
- @limit_max = nil
52
- @no_limit = true
59
+ def close_session
60
+ Smartware::Logging.logger.info "Session closed"
61
+
62
+ @commands.push :close
63
+ @limit = nil
53
64
  end
54
65
 
55
- def self.configured?
56
- @configured
66
+ def banknotes
67
+ update_status { @banknotes }
57
68
  end
58
69
 
59
- def self.error
60
- @status[:error] || ''
70
+ def cashsum
71
+ self.banknotes.inject(0) do |result, (key, value)|
72
+ result + key.to_i * value.to_i
73
+ end
61
74
  end
62
75
 
63
- def self.status
64
- @status
76
+ private
77
+
78
+ def limit_satisfied(sum)
79
+ @limit.nil? or @limit.include? sum
65
80
  end
66
81
 
67
- def self.model
68
- @status[:model]
82
+ def execute_open
83
+ @device.reset
84
+ @device.accept
85
+ Smartware::Logging.logger.info "Cash acceptor open"
86
+
87
+ @accepting = true
69
88
  end
70
89
 
71
- def self.version
72
- @status[:version]
90
+ def execute_get_money
91
+ res = @device.current_banknote
92
+
93
+ case res
94
+ when Integer
95
+ if limit_satisfied(self.cashsum + res)
96
+ @device.stack
97
+ update_status do
98
+ @banknotes[res] += 1
99
+ end
100
+ Smartware::Logging.logger.info "Cash acceptor bill stacked, #{res}"
101
+ else
102
+ @device.return
103
+ Smartware::Logging.logger.info "Cash acceptor limit violation, return #{res}"
104
+ end
105
+
106
+ when String
107
+ Smartware::Logging.logger.error "Cash acceptor error #{res}"
108
+
109
+ update_status do
110
+ @status[:error] = res
111
+ end
112
+ end
113
+
114
+ if !@limit.nil? && @limit.end > 0 && @limit.end == self.cashsum
115
+ # Close cash acceptor if current cashsum equal max-limit
116
+
117
+ execute_close
118
+ end
73
119
  end
74
120
 
75
- def self.cashsum
76
- @banknotes.inject(0){ |result, (key, value)| result + key.to_i*value.to_i }
121
+ def execute_close
122
+ @device.cancel_accept
123
+ Smartware::Logging.logger.info "Cash acceptor close"
124
+
125
+ @accepting = false
77
126
  end
78
127
 
79
- def self.banknotes
80
- @banknotes
128
+ def execute_monitor
129
+
130
+ error = @device.error || ''
131
+ model = @device.model
132
+ version = @device.version
133
+ cassette = @device.cassette?
134
+
135
+ update_status do
136
+ @status[:error] = error
137
+ @status[:model] = model
138
+ @status[:version] = version
139
+ @status[:cassette] = cassette
140
+ end
81
141
  end
82
142
 
83
- #
84
- # Session private method
85
- #
86
- private
87
- def self.start_poll!
88
- t = Thread.new do
89
- loop do
90
- case @commands[0]
91
- when 'open'
92
- @device.reset
93
- @device.accept
94
- Smartware::Logging.logger.info "Cash acceptor open: #{@commands}"
95
-
96
- @commands.shift
97
- @commands << 'get_money'
98
- when 'get_money'
99
- res = @device.current_banknote
100
- if res.is_a? Integer # Have a banknote
101
- if @no_limit or (@limit_min..@limit_max).include?(self.cashsum + res)
102
- @device.stack
103
- @banknotes[res] = (@banknotes[res]||0) + 1
104
- Smartware::Logging.logger.info "Cash acceptor bill stacked, #{res}"
105
- else
106
- @device.return
107
- Smartware::Logging.logger.info "Cash acceptor limit violation, return #{res}"
108
- end
109
- elsif res.is_a? String # Have a error, errors always as String
110
- Smartware::Logging.logger.error "Cash acceptor error #{res}"
111
- @status[:error] = res
112
- end
113
- @device.cancel_accept if !@no_limit && (@limit_max == self.cashsum and @limit_max > 0) # Close cash acceptor if current cashsum equal max-limit
114
-
115
- @commands.shift
116
- @commands << 'get_money' if @commands.empty?
117
- when 'close'
118
- @device.cancel_accept
119
- Smartware::Logging.logger.info "Cash acceptor close: #{@commands}"
120
-
121
- @commands.shift
122
- when 'monitor'
123
- @status[:error] = @device.error || ''
124
- @status[:model] = @device.model
125
- @status[:version] = @device.version
126
- @status[:cassette] = @device.cassette?
127
- @commands.shift
128
- else
129
- @commands << 'monitor'
130
- end
131
- sleep 0.5
143
+ def dispatch_commands
144
+ loop do
145
+ command = @commands.pop
146
+
147
+ begin
148
+ start = Time.now
149
+
150
+ send :"execute_#{command}"
151
+
152
+ complete = Time.now
153
+ if complete - start > 1
154
+ Smartware::Logging.logger.warn "#{command} has been running for #{complete - start} seconds."
155
+ end
156
+
157
+ rescue => e
158
+ Smartware::Logging.logger.error "Execution of #{command} failed:"
159
+ Smartware::Logging.logger.error e.to_s
160
+ e.backtrace.each do |line|
161
+ Smartware::Logging.logger.error line
132
162
  end
133
163
  end
134
164
  end
165
+ end
166
+
167
+ def periodic
168
+ loop do
169
+ begin
170
+ if @commands.empty?
171
+ @commands.push :monitor
172
+ @commands.push :get_money if @accepting
173
+ end
135
174
 
136
- self.configure!
175
+ sleep 0.5
176
+ rescue => e
177
+ Smartware::Logging.logger.error "Error in periodic failed:"
178
+ Smartware::Logging.logger.error e.to_s
179
+ e.backtrace.each do |line|
180
+ Smartware::Logging.logger.error line
181
+ end
182
+ end
183
+ end
184
+ end
137
185
  end
138
186
  end
139
187
  end
140
-
141
- DRb.start_service('druby://localhost:6001', Smartware::Interface::CashAcceptor)
142
- DRb.thread.join
@@ -0,0 +1,47 @@
1
+ module Smartware
2
+ module Interface
3
+ class Interface
4
+ attr_reader :config
5
+
6
+ def initialize(config)
7
+ @config = config
8
+ @status_mutex = Mutex.new
9
+ @status = {
10
+ model: '',
11
+ version: ''
12
+ }
13
+
14
+ iface = @config["name"]
15
+ driver = @config["driver"]
16
+
17
+ require "smartware/drivers/#{iface.underscore}/#{driver.underscore}"
18
+
19
+ @device = Smartware::Driver.const_get(iface.to_s)
20
+ .const_get(driver.to_s)
21
+ .new(config)
22
+ end
23
+
24
+ def error
25
+ self.status[:error]
26
+ end
27
+
28
+ def model
29
+ self.status[:model]
30
+ end
31
+
32
+ def version
33
+ self.status[:version]
34
+ end
35
+
36
+ def status
37
+ @status_mutex.synchronize { @status }
38
+ end
39
+
40
+ protected
41
+
42
+ def update_status(&block)
43
+ @status_mutex.synchronize &block
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,78 +1,49 @@
1
- require 'drb'
2
-
3
1
  module Smartware
4
2
  module Interface
3
+ class Modem < Interface
4
+ MODEM_NOT_AVAILABLE = 1
5
5
 
6
- module Modem
7
- @configured = false
8
- @status = {}
9
-
10
- def self.configure!
11
- Smartware::Logging.logger.debug "Creating modem"
12
- @device = Smartware::Driver::Modem.const_get(
13
- Smartware::Service.config['modem_driver']).new(
14
- Smartware::Service.config['modem_config'])
15
- Smartware::Logging.logger.debug "Starting modem"
16
- @session.kill if @session
17
- @session = self.poll_status!
18
- @configured = true
19
- Smartware::Logging.logger.info 'Modem monitor started'
20
- @status = {}
21
- rescue => e
22
- Smartware::Logging.logger.error e.message
23
- Smartware::Logging.logger.error e.backtrace.join("\n")
24
- @configured = false
25
- end
26
-
27
- def self.configured?
28
- @configured
29
- end
30
-
31
- def self.error
32
- @status[:error]
33
- end
6
+ def initialize(config)
7
+ super
34
8
 
35
- def self.model
36
- @status[:model]
37
- end
9
+ update_status do
10
+ @status[:balance] = ''
11
+ @status[:signal_level] = ''
12
+ end
38
13
 
39
- def self.version
40
- @status[:version]
14
+ @session = Thread.new &method(:poll)
15
+ Smartware::Logging.logger.info 'Modem monitor started'
41
16
  end
42
17
 
43
- def self.balance
44
- @status[:balance]
18
+ def balance
19
+ self.status[:balance]
45
20
  end
46
21
 
47
- def self.signal_level
48
- @status[:signal_level]
22
+ def signal_level
23
+ self.status[:signal_level]
49
24
  end
50
25
 
51
26
  private
52
- def self.poll_status!
53
- t = Thread.new do
54
- begin
55
- loop do
56
- @device.tick
57
27
 
58
- @status[:signal_level] = @device.signal_level
59
- @status[:model] = @device.model
60
- @status[:version] = @device.version
61
- @status[:error] = @device.error || ''
62
- @status[:balance] = @device.balance
63
- end
64
- rescue => e
65
- Smartware::Logging.logger.error e.message
66
- Smartware::Logging.logger.error e.backtrace.join("\n")
28
+ def poll
29
+ begin
30
+ loop do
31
+ @device.tick
32
+
33
+ update_status do
34
+ @status[:signal_level] = @device.signal_level
35
+ @status[:model] = @device.model
36
+ @status[:version] = @device.version
37
+ @status[:error] = @device.error || ''
38
+ @status[:balance] = @device.balance
67
39
  end
68
40
  end
41
+ rescue => e
42
+ Smartware::Logging.logger.error e.message
43
+ Smartware::Logging.logger.error e.backtrace.join("\n")
69
44
  end
70
-
71
- self.configure!
45
+ end
72
46
  end
73
47
  end
74
48
  end
75
49
 
76
- DRb.start_service('druby://localhost:6002', Smartware::Interface::Modem)
77
- DRb.thread.join
78
-