zklib 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+ class Zklib
2
+ module DataManagement
3
+ # Free data for transmission
4
+ def free_data
5
+ execute_cmd(
6
+ command: CMD_FREE_DATA,
7
+ command_string: ''
8
+ ) do |opts|
9
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
10
+
11
+ data = opts[:data]
12
+ if data.length > 7
13
+ data.split("\u0000").pop
14
+ else
15
+ puts 'ERROR: Invalid free data response'
16
+ end
17
+ end
18
+ end
19
+
20
+ # Refresh data for transmission
21
+ def refresh_data
22
+ execute_cmd(
23
+ command: CMD_REFRESHDATA,
24
+ command_string: ''
25
+ ) do |opts|
26
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
27
+
28
+ data = opts[:data]
29
+ if data.length > 7
30
+ data.split("\u0000").pop
31
+ else
32
+ puts 'ERROR: Invalid refresh data response'
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,91 @@
1
+ class Zklib
2
+ module DeviceManagement
3
+ DEVICE_NAME_KEYWORD = '~DeviceName'
4
+ DISABLE_DEVICE_KEYWORD = "\u0000\u0000"
5
+
6
+ # Disable attendance machine
7
+ def disable_device
8
+ execute_cmd(
9
+ command: CMD_DISABLEDEVICE,
10
+ command_string: DISABLE_DEVICE_KEYWORD
11
+ ) do |opts|
12
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
13
+
14
+ data = opts[:data]
15
+ if data.length > 7
16
+ data.split("\u0000").pop
17
+ else
18
+ puts 'ERROR: Invalid disable device response'
19
+ end
20
+ end
21
+ end
22
+
23
+ # Enable attendance machine
24
+ def enable_device
25
+ execute_cmd(
26
+ command: CMD_ENABLEDEVICE,
27
+ command_string: ''
28
+ ) do |opts|
29
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
30
+
31
+ data = opts[:data]
32
+ if data.length > 7
33
+ data.split("\u0000").pop
34
+ else
35
+ puts 'ERROR: Invalid enable device response'
36
+ end
37
+ end
38
+ end
39
+
40
+ # Get device name
41
+ def get_device_name
42
+ execute_cmd(
43
+ command: CMD_DEVICE,
44
+ command_string: DEVICE_NAME_KEYWORD
45
+ ) do |opts|
46
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
47
+
48
+ data = opts[:data]
49
+ if data.length > 8
50
+ data.split("\u0000").pop.tr("#{DEVICE_NAME_KEYWORD}=", '')
51
+ else
52
+ puts 'ERROR: Invalid device name response'
53
+ end
54
+ end
55
+ end
56
+
57
+ # Turn off attendance machine
58
+ def power_off_device
59
+ execute_cmd(
60
+ command: CMD_POWEROFF,
61
+ command_string: ''
62
+ ) do |opts|
63
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
64
+
65
+ data = opts[:data]
66
+ if data.length > 7
67
+ data.split("\u0000").pop
68
+ else
69
+ puts 'ERROR: Invalid power off device response'
70
+ end
71
+ end
72
+ end
73
+
74
+ # Restart attendance machine
75
+ def restart_device
76
+ execute_cmd(
77
+ command: CMD_RESTART,
78
+ command_string: ''
79
+ ) do |opts|
80
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
81
+
82
+ data = opts[:data]
83
+ if data.length > 7
84
+ data.split("\u0000").pop
85
+ else
86
+ puts 'ERROR: Invalid restart device response'
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ class Zklib
2
+ module FaceManagement
3
+ TURN_FACE_OFF_KEYWORD = 'FaceFunOff'
4
+ TURN_FACE_ON_KEYWORD = 'FaceFunOn'
5
+
6
+ # Turn face off
7
+ def turn_face_off
8
+ execute_cmd(
9
+ command: CMD_DEVICE,
10
+ command_string: TURN_FACE_OFF_KEYWORD
11
+ ) do |opts|
12
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
13
+
14
+ data = opts[:data]
15
+ if data.length > 7
16
+ data.split("\u0000").pop
17
+ else
18
+ puts 'ERROR: Invalid turn face off response'
19
+ end
20
+ end
21
+ end
22
+
23
+ # Turn face on
24
+ def turn_face_on
25
+ execute_cmd(
26
+ command: CMD_DEVICE,
27
+ command_string: TURN_FACE_ON_KEYWORD
28
+ ) do |opts|
29
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
30
+
31
+ data = opts[:data]
32
+ if data.length > 7
33
+ data.split("\u0000").pop
34
+ else
35
+ puts 'ERROR: Invalid turn face on response'
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,181 @@
1
+ class Zklib
2
+ module Helper
3
+ # Check validity of response
4
+ #
5
+ # param options
6
+ # |_ data Data to check validity
7
+ def check_valid(options)
8
+ BinData::Uint16le.read(options[:data][0..-1]).snapshot == CMD_ACK_OK
9
+ end
10
+
11
+ # Create checksum for execution
12
+ #
13
+ # param options
14
+ # |_ data Data to create checksum
15
+ def create_checksum(options)
16
+ data = options[:data]
17
+ checksum = 0
18
+
19
+ (0...data.length).step(2) do |i|
20
+ checksum += (i == data.length - 1) ?
21
+ BinData::Uint8le.read(data[i]).snapshot :
22
+ BinData::Uint16le.read(data[i..-1]).snapshot
23
+ checksum %= USHRT_MAX
24
+ end
25
+
26
+ chksum = USHRT_MAX - checksum - 1
27
+ chksum
28
+ end
29
+
30
+ # Create header for execution
31
+ #
32
+ # param options
33
+ # |_ command Command value
34
+ # |_ checksum Checksum
35
+ # |_ session_id Session ID
36
+ # |_ reply_id Reply ID
37
+ # |_ command_string Command string
38
+ def create_header(options)
39
+ header_buffer = StringIO.new
40
+ binary_writer = BinData::Uint16le.new
41
+
42
+ # Write command header
43
+ binary_writer.value = options[:command]
44
+ header_buffer.pos = 0
45
+ binary_writer.write(header_buffer)
46
+
47
+ # Write checksum header
48
+ binary_writer.value = options[:checksum]
49
+ header_buffer.pos = 2
50
+ binary_writer.write(header_buffer)
51
+
52
+ # Write session ID header
53
+ binary_writer.value = options[:session_id]
54
+ header_buffer.pos = 4
55
+ binary_writer.write(header_buffer)
56
+
57
+ # Write reply ID header
58
+ binary_writer.value = options[:reply_id]
59
+ header_buffer.pos = 6
60
+ binary_writer.write(header_buffer)
61
+
62
+ # Write command string header
63
+ header_buffer.pos = 8
64
+ header_buffer.write(options[:command_string])
65
+
66
+ # Rewrite checksum header
67
+ binary_writer.value = create_checksum(data: header_buffer.string)
68
+ header_buffer.pos = 2
69
+ binary_writer.write(header_buffer)
70
+
71
+ # Rewrite reply ID header
72
+ binary_writer.value = (options[:reply_id] + 1) % USHRT_MAX
73
+ header_buffer.pos = 6
74
+ binary_writer.write(header_buffer)
75
+
76
+ header_buffer.string
77
+ end
78
+
79
+ # Convert number of seconds to time
80
+ #
81
+ # param options
82
+ # |_ seconds Time in seconds to decode
83
+ def decode_time(options)
84
+ time = options[:seconds]
85
+
86
+ # Calculate second value
87
+ second = time % 60
88
+ time = (time - second) / 60
89
+
90
+ # Calculate minute value
91
+ minute = time % 60
92
+ time = (time - minute) / 60
93
+
94
+ # Calculate hour value
95
+ hour = time % 24
96
+ time = (time - hour) / 24
97
+
98
+ # Calculate day value
99
+ day = time % 31 + 1
100
+ time = (time - day + 1) / 31
101
+
102
+ # Calculate month value
103
+ month = time % 12 + 1
104
+ time = (time - month + 1) / 12
105
+
106
+ # Calculate year value
107
+ year = time + 2000
108
+
109
+ Time.new(year, month, day, hour, minute, second)
110
+ end
111
+
112
+ def decode_user_data(options)
113
+ data = options[:data]
114
+
115
+ {
116
+ uid: BinData::Uint16be.read(data[0..1]).snapshot,
117
+ role: BinData::Uint16le.read(data[2..3]).snapshot,
118
+ password: nil,
119
+ name: nil,
120
+ cardno: nil,
121
+ userid: nil
122
+ }
123
+ end
124
+
125
+ # Convert time to number of seconds
126
+ #
127
+ # param options
128
+ # |_ time Time object to encode
129
+ def encode_time(options)
130
+ time = options[:time]
131
+
132
+ ((time.year % 100) * 12 * 31 + ((time.mon - 1) * 31) + time.day - 1) * (24 * 60 * 60) + (time.hour * 60 + time.min) * 60 + time.sec
133
+ end
134
+
135
+ # Execute command on attendance machine
136
+ #
137
+ # param options
138
+ # |_ command Command to execute
139
+ # |_ command_string Command string
140
+ def execute_cmd(options)
141
+ command = options[:command]
142
+ self.reply_id = USHRT_MAX - 1 if command == CMD_CONNECT
143
+ header = create_header(
144
+ command: command,
145
+ checksum: 0,
146
+ session_id: session_id,
147
+ reply_id: reply_id,
148
+ command_string: options[:command_string]
149
+ )
150
+
151
+ # Send command
152
+ socket = UDPSocket.new
153
+ socket.bind('0.0.0.0', inport)
154
+ socket.send(header, 0, ip, port)
155
+ self.data_recv = socket.recvfrom(USHRT_MAX)[0] if IO.select([socket], nil, nil, 10)
156
+ socket.close
157
+
158
+ # Callback
159
+ if data_recv && data_recv.length > 0
160
+ self.session_id = BinData::Uint16le.read(data_recv[4..-1]).snapshot
161
+ self.reply_id = BinData::Uint16le.read(data_recv[6..-1]).snapshot
162
+
163
+ yield(valid: true, data: data_recv) if block_given?
164
+ else
165
+ yield(valid: false, error: 'Empty response') if block_given?
166
+ end
167
+ end
168
+
169
+ # Receive data from non-blocking socket
170
+ #
171
+ # param options
172
+ # |_ socket Socket to receive data from
173
+ def receive_nonblock(options)
174
+ return options[:socket].recvfrom_nonblock(USHRT_MAX)
175
+ rescue IO::WaitReadable
176
+ IO.select([options[:socket]])
177
+
178
+ retry
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module PINManagement
3
+ PIN_WIDTH_KEYWORD = '~PIN2Width'
4
+
5
+ # Get PIN width
6
+ def get_pin_width
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: PIN_WIDTH_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{PIN_WIDTH_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid PIN width response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module PlatformManagement
3
+ PLATFORM_KEYWORD = '~Platform'
4
+
5
+ # Get platform
6
+ def get_platform
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: PLATFORM_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{PLATFORM_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid platform response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module SerialManagement
3
+ SERIAL_KEYWORD = '~SerialNumber'
4
+
5
+ # Get serial number of attendance machine
6
+ def get_serial_number
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: SERIAL_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{SERIAL_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid serial number response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module SSRManagement
3
+ SSR_KEYWORD = '~SSR'
4
+
5
+ # Get SSR
6
+ def get_ssr
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: SSR_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{SSR_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid SSR response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ class Zklib
2
+ module TimeManagement
3
+ # Get current time of attendance machine
4
+ def get_time
5
+ execute_cmd(
6
+ command: CMD_GET_TIME,
7
+ command_string: ''
8
+ ) do |opts|
9
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
10
+
11
+ data = opts[:data]
12
+ if data.length > 8
13
+ decode_time(seconds: BinData::Uint32le.read(data[8..-1]).snapshot)
14
+ else
15
+ puts 'ERROR: Invalid time response'
16
+ end
17
+ end
18
+ end
19
+
20
+ # Set current time for attendance machine
21
+ def set_time(time = Time.now)
22
+ seconds = encode_time(time: time)
23
+ command_buffer = StringIO.new
24
+ binary_writer = BinData::Uint32le.new
25
+
26
+ # Write command string
27
+ binary_writer.value = seconds
28
+ command_buffer.pos = 0
29
+ binary_writer.write(command_buffer)
30
+ command_string = command_buffer.string
31
+
32
+ execute_cmd(
33
+ command: CMD_SET_TIME,
34
+ command_string: command_string
35
+ ) do |opts|
36
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
37
+
38
+ data = opts[:data]
39
+ if data.length > 7
40
+ data.split("\u0000").pop
41
+ else
42
+ puts 'ERROR: Invalid time response'
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end