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.
- data/bin/smartware +10 -3
- data/config/smartware.yml.sample +10 -0
- data/lib/smartware.rb +19 -0
- data/lib/smartware/clients/printer.rb +8 -2
- data/lib/smartware/clients/watchdog.rb +36 -0
- data/lib/smartware/connection_monitor.rb +25 -0
- data/lib/smartware/drivers/cash_acceptor/ccnet.rb +28 -24
- data/lib/smartware/drivers/cash_acceptor/dummy.rb +3 -3
- data/lib/smartware/drivers/modem/dummy.rb +2 -2
- data/lib/smartware/drivers/modem/standard.rb +3 -3
- data/lib/smartware/drivers/printer/dummy.rb +16 -5
- data/lib/smartware/drivers/printer/esc_pos.rb +272 -0
- data/lib/smartware/drivers/watchdog/dummy.rb +29 -0
- data/lib/smartware/drivers/watchdog/watchdog_daemon.rb +40 -0
- data/lib/smartware/interfaces/cash_acceptor.rb +154 -109
- data/lib/smartware/interfaces/interface.rb +47 -0
- data/lib/smartware/interfaces/modem.rb +29 -58
- data/lib/smartware/interfaces/printer.rb +78 -60
- data/lib/smartware/interfaces/watchdog.rb +26 -0
- data/lib/smartware/process_manager.rb +40 -0
- data/lib/smartware/service.rb +26 -70
- data/lib/smartware/version.rb +1 -1
- data/smartware.gemspec +3 -1
- metadata +44 -4
- data/lib/smartware/drivers/printer/tg24xx.rb +0 -64
@@ -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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
37
|
-
@
|
38
|
-
|
39
|
-
if
|
40
|
-
@
|
41
|
-
|
42
|
-
|
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
|
-
@
|
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
|
49
|
-
|
50
|
-
|
51
|
-
@
|
52
|
-
@
|
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
|
56
|
-
@
|
66
|
+
def banknotes
|
67
|
+
update_status { @banknotes }
|
57
68
|
end
|
58
69
|
|
59
|
-
def
|
60
|
-
|
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
|
-
|
64
|
-
|
76
|
+
private
|
77
|
+
|
78
|
+
def limit_satisfied(sum)
|
79
|
+
@limit.nil? or @limit.include? sum
|
65
80
|
end
|
66
81
|
|
67
|
-
def
|
68
|
-
@
|
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
|
72
|
-
@
|
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
|
76
|
-
@
|
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
|
80
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
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
|
-
|
7
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
9
|
+
update_status do
|
10
|
+
@status[:balance] = ''
|
11
|
+
@status[:signal_level] = ''
|
12
|
+
end
|
38
13
|
|
39
|
-
|
40
|
-
|
14
|
+
@session = Thread.new &method(:poll)
|
15
|
+
Smartware::Logging.logger.info 'Modem monitor started'
|
41
16
|
end
|
42
17
|
|
43
|
-
def
|
44
|
-
|
18
|
+
def balance
|
19
|
+
self.status[:balance]
|
45
20
|
end
|
46
21
|
|
47
|
-
def
|
48
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|