rbzk 0.1.6 → 0.1.8

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/lib/rbzk/zk.rb CHANGED
@@ -14,46 +14,45 @@ module RBZK
14
14
  end
15
15
 
16
16
  def test_ping
17
- begin
18
- Timeout.timeout(5) do
19
- s = TCPSocket.new(@ip, @port)
20
- s.close
21
- return true
22
- end
23
- rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError => e
24
- return false
25
- rescue => e
26
- return false
17
+ Timeout.timeout(5) do
18
+ s = TCPSocket.new(@ip, @port)
19
+ s.close
20
+ return true
27
21
  end
22
+ rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
23
+ false
24
+ rescue StandardError
25
+ false
28
26
  end
29
27
 
30
28
  def test_tcp
31
- begin
32
- client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
33
- client.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [ 10, 0 ].pack('l_*'))
29
+ client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
30
+ client.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [ 10, 0 ].pack('l_*'))
34
31
 
35
- sockaddr = Socket.pack_sockaddr_in(@port, @ip)
36
- begin
37
- client.connect(sockaddr)
38
- result = 0 # Success code
39
- rescue Errno::EISCONN
40
- result = 0 # Already connected
41
- rescue => e
42
- result = e.errno || 1 # Connection failed
43
- end
44
-
45
- client.close
46
- return result
47
- rescue => e
48
- return e.errno || 1
32
+ sockaddr = Socket.pack_sockaddr_in(@port, @ip)
33
+ begin
34
+ client.connect(sockaddr)
35
+ result = 0 # Success code
36
+ rescue Errno::EISCONN
37
+ result = 0 # Already connected
38
+ rescue StandardError => e
39
+ # Some exceptions (e.g., Socket::ResolutionError) don't provide errno
40
+ result = e.respond_to?(:errno) ? e.errno : 1 # Connection failed
49
41
  end
42
+
43
+ client.close
44
+ result
45
+ rescue StandardError => e
46
+ # Some exceptions (e.g., Socket::ResolutionError) don't provide errno
47
+ e.respond_to?(:errno) ? e.errno : 1
50
48
  end
51
49
  end
52
50
 
53
51
  class ZK
54
52
  include RBZK::Constants
55
53
 
56
- def initialize(ip, port: 4370, timeout: 60, password: 0, force_udp: false, omit_ping: false, verbose: false, encoding: 'UTF-8')
54
+ def initialize(ip, port: 4370, timeout: 60, password: 0, force_udp: false, omit_ping: false, verbose: false,
55
+ encoding: 'UTF-8')
57
56
  # Initialize the ZK device connection
58
57
  RBZK::User.encoding = encoding
59
58
  @address = [ ip, port ]
@@ -77,6 +76,8 @@ module RBZK
77
76
  @data = nil
78
77
  @connected = false
79
78
  @next_uid = 1
79
+ @next_user_id = '1'
80
+ @user_packet_size = 28
80
81
 
81
82
  # Storage for user and attendance data
82
83
  @users = {}
@@ -102,22 +103,20 @@ module RBZK
102
103
  # Create helper for ping and TCP tests
103
104
  @helper = ZKHelper.new(ip, port)
104
105
 
105
- if @verbose
106
- puts "ZK instance created for device at #{@ip}:#{@port}"
107
- puts "Using #{@force_udp ? 'UDP' : 'TCP'} mode"
108
- end
106
+ return unless @verbose
107
+
108
+ puts "ZK instance created for device at #{@ip}:#{@port}"
109
+ puts "Using #{@force_udp ? 'UDP' : 'TCP'} mode"
109
110
  end
110
111
 
111
112
  def connect
112
113
  return self if @connected
113
114
 
114
115
  # Skip ping check if requested
115
- if !@omit_ping && !@helper.test_ping
116
- raise RBZK::ZKNetworkError, "Can't reach device (ping #{@ip})"
117
- end
116
+ raise RBZK::ZKNetworkError, "Can't reach device (ping #{@ip})" if !@omit_ping && !@helper.test_ping
118
117
 
119
118
  # Set user packet size if TCP connection is available
120
- if !@force_udp && @helper.test_tcp == 0
119
+ if !@force_udp && @helper.test_tcp.zero?
121
120
  @user_packet_size = 72 # Default for ZK8
122
121
  end
123
122
 
@@ -127,9 +126,7 @@ module RBZK
127
126
  @session_id = 0
128
127
  @reply_id = USHRT_MAX - 1
129
128
 
130
- if @verbose
131
- puts "Sending connect command to device"
132
- end
129
+ puts 'Sending connect command to device' if @verbose
133
130
 
134
131
  begin
135
132
  cmd_response = send_command(CMD_CONNECT)
@@ -137,9 +134,7 @@ module RBZK
137
134
 
138
135
  # Authenticate if needed
139
136
  if cmd_response[:code] == CMD_ACK_UNAUTH
140
- if @verbose
141
- puts "try auth"
142
- end
137
+ puts 'try auth' if @verbose
143
138
 
144
139
  command_string = make_commkey(@password, @session_id)
145
140
  cmd_response = send_command(CMD_AUTH, command_string)
@@ -148,23 +143,17 @@ module RBZK
148
143
  # Check response status
149
144
  if cmd_response[:status]
150
145
  @connected = true
151
- return self
146
+ self
152
147
  else
153
- if cmd_response[:code] == CMD_ACK_UNAUTH
154
- raise RBZK::ZKErrorResponse, "Unauthenticated"
155
- end
148
+ raise RBZK::ZKErrorResponse, 'Unauthenticated' if cmd_response[:code] == CMD_ACK_UNAUTH
156
149
 
157
- if @verbose
158
- puts "Connect error response: #{cmd_response[:code]}"
159
- end
150
+ puts "Connect error response: #{cmd_response[:code]}" if @verbose
160
151
 
161
152
  raise RBZK::ZKErrorResponse, "Invalid response: Can't connect"
162
153
  end
163
- rescue => e
154
+ rescue StandardError => e
164
155
  @connected = false
165
- if @verbose
166
- puts "Connection error: #{e.message}"
167
- end
156
+ puts "Connection error: #{e.message}" if @verbose
168
157
  raise e
169
158
  end
170
159
  end
@@ -176,11 +165,11 @@ module RBZK
176
165
  def disconnect
177
166
  return unless @connected
178
167
 
179
- self.send_command(CMD_EXIT)
180
- self.recv_reply
168
+ send_command(CMD_EXIT)
169
+ recv_reply
181
170
 
182
171
  @connected = false
183
- @socket.close if @socket
172
+ @socket&.close
184
173
 
185
174
  @socket = nil
186
175
  @tcp = nil
@@ -189,32 +178,28 @@ module RBZK
189
178
  end
190
179
 
191
180
  def enable_device
192
- self.send_command(CMD_ENABLEDEVICE)
193
- self.recv_reply
181
+ send_command(CMD_ENABLEDEVICE)
182
+ recv_reply
194
183
  true
195
184
  end
196
185
 
197
186
  def disable_device
198
- cmd_response = self.send_command(CMD_DISABLEDEVICE)
199
- if cmd_response[:status]
200
- @is_enabled = false
201
- true
202
- else
203
- raise RBZK::ZKErrorResponse, "Can't disable device"
204
- end
187
+ cmd_response = send_command(CMD_DISABLEDEVICE)
188
+ raise RBZK::ZKErrorResponse, "Can't disable device" unless cmd_response[:status]
189
+
190
+ @is_enabled = false
191
+ true
205
192
  end
206
193
 
207
194
  def get_firmware_version
208
195
  command = CMD_GET_VERSION
209
196
  response_size = 1024
210
- response = self.send_command(command, "", response_size)
197
+ response = send_command(command, '', response_size)
211
198
 
212
- if response && response[:status]
213
- firmware_version = @data.split("\x00")[0]
214
- firmware_version.to_s
215
- else
216
- raise RBZK::ZKErrorResponse, "Can't read firmware version"
217
- end
199
+ raise RBZK::ZKErrorResponse, "Can't read firmware version" unless response && response[:status]
200
+
201
+ firmware_version = @data.split("\x00")[0]
202
+ firmware_version.to_s
218
203
  end
219
204
 
220
205
  def get_serialnumber
@@ -222,15 +207,14 @@ module RBZK
222
207
  command_string = "~SerialNumber\x00".b
223
208
  response_size = 1024
224
209
 
225
- response = self.send_command(command, command_string, response_size)
210
+ response = send_command(command, command_string, response_size)
226
211
 
227
- if response && response[:status]
228
- serialnumber = @data.split("=", 2)[1]&.split("\x00")[0] || ""
229
- serialnumber = serialnumber.gsub("=", "")
230
- serialnumber.to_s
231
- else
232
- raise RBZK::ZKErrorResponse, "Can't read serial number"
233
- end
212
+ raise RBZK::ZKErrorResponse, "Can't read serial number" unless response && response[:status]
213
+
214
+ serialnumber_field = @data.split('=', 2)[1]
215
+ serialnumber = serialnumber_field ? serialnumber_field.split("\x00")[0] : ''
216
+ serialnumber = serialnumber.gsub('=', '')
217
+ serialnumber.to_s
234
218
  end
235
219
 
236
220
  def get_mac
@@ -238,14 +222,12 @@ module RBZK
238
222
  command_string = "MAC\x00".b
239
223
  response_size = 1024
240
224
 
241
- response = self.send_command(command, command_string, response_size)
225
+ response = send_command(command, command_string, response_size)
242
226
 
243
- if response && response[:status]
244
- mac = @data.split("=", 2)[1]&.split("\x00")[0] || ""
245
- mac.to_s
246
- else
247
- raise RBZK::ZKErrorResponse, "Can't read MAC address"
248
- end
227
+ raise RBZK::ZKErrorResponse, "Can't read MAC address" unless response && response[:status]
228
+
229
+ mac = @data.split('=', 2)[1]&.split("\x00")&.[](0) || ''
230
+ mac.to_s
249
231
  end
250
232
 
251
233
  def get_device_name
@@ -253,13 +235,14 @@ module RBZK
253
235
  command_string = "~DeviceName\x00".b
254
236
  response_size = 1024
255
237
 
256
- response = self.send_command(command, command_string, response_size)
238
+ response = send_command(command, command_string, response_size)
257
239
 
258
240
  if response && response[:status]
259
- device = @data.split("=", 2)[1]&.split("\x00")[0] || ""
241
+ device_field = @data.split('=', 2)[1]
242
+ device = device_field ? device_field.split("\x00")[0] : ''
260
243
  device.to_s
261
244
  else
262
- ""
245
+ ''
263
246
  end
264
247
  end
265
248
 
@@ -268,13 +251,16 @@ module RBZK
268
251
  command_string = "ZKFaceVersion\x00".b
269
252
  response_size = 1024
270
253
 
271
- response = self.send_command(command, command_string, response_size)
254
+ response = send_command(command, command_string, response_size)
272
255
 
273
- if response && response[:status]
274
- version = @data.split("=", 2)[1]&.split("\x00")[0] || ""
275
- version.to_i rescue 0
276
- else
277
- nil
256
+ return unless response && response[:status]
257
+
258
+ version_field = @data.split('=', 2)[1]
259
+ version = version_field ? version_field.split("\x00")[0] : ''
260
+ begin
261
+ version.to_i
262
+ rescue StandardError
263
+ 0
278
264
  end
279
265
  end
280
266
 
@@ -283,13 +269,16 @@ module RBZK
283
269
  command_string = "~ExtendFmt\x00".b
284
270
  response_size = 1024
285
271
 
286
- response = self.send_command(command, command_string, response_size)
272
+ response = send_command(command, command_string, response_size)
287
273
 
288
- if response && response[:status]
289
- fmt = @data.split("=", 2)[1]&.split("\x00")[0] || ""
290
- fmt.to_i rescue 0
291
- else
292
- nil
274
+ return unless response && response[:status]
275
+
276
+ fmt_field = @data.split('=', 2)[1]
277
+ fmt = fmt_field ? fmt_field.split("\x00")[0] : ''
278
+ begin
279
+ fmt.to_i
280
+ rescue StandardError
281
+ 0
293
282
  end
294
283
  end
295
284
 
@@ -298,15 +287,14 @@ module RBZK
298
287
  command_string = "~Platform\x00".b
299
288
  response_size = 1024
300
289
 
301
- response = self.send_command(command, command_string, response_size)
290
+ response = send_command(command, command_string, response_size)
302
291
 
303
- if response && response[:status]
304
- platform = @data.split("=", 2)[1]&.split("\x00")[0] || ""
305
- platform = platform.gsub("=", "")
306
- platform.to_s
307
- else
308
- raise RBZK::ZKErrorResponse, "Can't read platform name"
309
- end
292
+ raise RBZK::ZKErrorResponse, "Can't read platform name" unless response && response[:status]
293
+
294
+ platform_field = @data.split('=', 2)[1]
295
+ platform = platform_field ? platform_field.split("\x00")[0] : ''
296
+ platform = platform.gsub('=', '')
297
+ platform.to_s
310
298
  end
311
299
 
312
300
  def get_fp_version
@@ -314,32 +302,35 @@ module RBZK
314
302
  command_string = "~ZKFPVersion\x00".b
315
303
  response_size = 1024
316
304
 
317
- response = self.send_command(command, command_string, response_size)
305
+ response = send_command(command, command_string, response_size)
318
306
 
319
- if response && response[:status]
320
- version = @data.split("=", 2)[1]&.split("\x00")[0] || ""
321
- version = version.gsub("=", "")
322
- version.to_i rescue 0
323
- else
324
- raise RBZK::ZKErrorResponse, "Can't read fingerprint version"
307
+ raise RBZK::ZKErrorResponse, "Can't read fingerprint version" unless response && response[:status]
308
+
309
+ version_field = @data.split('=', 2)[1]
310
+ version = version_field ? version_field.split("\x00")[0] : ''
311
+ version = version.gsub('=', '')
312
+ begin
313
+ version.to_i
314
+ rescue StandardError
315
+ 0
325
316
  end
326
317
  end
327
318
 
328
319
  def restart
329
- self.send_command(CMD_RESTART)
330
- self.recv_reply
320
+ send_command(CMD_RESTART)
321
+ recv_reply
331
322
  true
332
323
  end
333
324
 
334
325
  def poweroff
335
- self.send_command(CMD_POWEROFF)
336
- self.recv_reply
326
+ send_command(CMD_POWEROFF)
327
+ recv_reply
337
328
  true
338
329
  end
339
330
 
340
331
  def test_voice(index = 0)
341
332
  command_string = [ index ].pack('L<')
342
- response = self.send_command(CMD_TESTVOICE, command_string)
333
+ response = send_command(CMD_TESTVOICE, command_string)
343
334
 
344
335
  if response && response[:status]
345
336
  true
@@ -352,20 +343,18 @@ module RBZK
352
343
  # @param time [Integer] define delay in seconds
353
344
  # @return [Boolean] true if successful, raises exception otherwise
354
345
  def unlock(time = 3)
355
- command_string = [time * 10].pack('L<')
356
- response = self.send_command(CMD_UNLOCK, command_string)
346
+ command_string = [ time * 10 ].pack('L<')
347
+ response = send_command(CMD_UNLOCK, command_string)
357
348
 
358
- if response && response[:status]
359
- true
360
- else
361
- raise RBZK::ZKErrorResponse, "Can't open door"
362
- end
349
+ raise RBZK::ZKErrorResponse, "Can't open door" unless response && response[:status]
350
+
351
+ true
363
352
  end
364
353
 
365
354
  # Get the lock state
366
355
  # @return [Boolean] true if door is open, false otherwise
367
356
  def get_lock_state
368
- response = self.send_command(CMD_DOORSTATE_RRQ)
357
+ response = send_command(CMD_DOORSTATE_RRQ)
369
358
 
370
359
  if response && response[:status]
371
360
  true
@@ -379,38 +368,32 @@ module RBZK
379
368
  # @param text [String] text to write
380
369
  # @return [Boolean] true if successful, raises exception otherwise
381
370
  def write_lcd(line_number, text)
382
- command_string = [line_number, 0].pack('s<c') + ' ' + text.encode(@encoding, invalid: :replace, undef: :replace)
383
- response = self.send_command(CMD_WRITE_LCD, command_string)
371
+ command_string = "#{[ line_number, 0 ].pack('s<c')} #{text.encode(@encoding, invalid: :replace, undef: :replace)}"
372
+ response = send_command(CMD_WRITE_LCD, command_string)
384
373
 
385
- if response && response[:status]
386
- true
387
- else
388
- raise RBZK::ZKErrorResponse, "Can't write lcd"
389
- end
374
+ raise RBZK::ZKErrorResponse, "Can't write lcd" unless response && response[:status]
375
+
376
+ true
390
377
  end
391
378
 
392
379
  # Clear LCD
393
380
  # @return [Boolean] true if successful, raises exception otherwise
394
381
  def clear_lcd
395
- response = self.send_command(CMD_CLEAR_LCD)
382
+ response = send_command(CMD_CLEAR_LCD)
396
383
 
397
- if response && response[:status]
398
- true
399
- else
400
- raise RBZK::ZKErrorResponse, "Can't clear lcd"
401
- end
384
+ raise RBZK::ZKErrorResponse, "Can't clear lcd" unless response && response[:status]
385
+
386
+ true
402
387
  end
403
388
 
404
389
  # Refresh the device data
405
390
  # @return [Boolean] true if successful, raises exception otherwise
406
391
  def refresh_data
407
- response = self.send_command(CMD_REFRESHDATA)
392
+ response = send_command(CMD_REFRESHDATA)
408
393
 
409
- if response && response[:status]
410
- true
411
- else
412
- raise RBZK::ZKErrorResponse, "Can't refresh data"
413
- end
394
+ raise RBZK::ZKErrorResponse, "Can't refresh data" unless response && response[:status]
395
+
396
+ true
414
397
  end
415
398
 
416
399
  # Create or update user by uid
@@ -423,23 +406,17 @@ module RBZK
423
406
  # @param card [Integer] card number
424
407
  # @return [Boolean] true if successful, raises exception otherwise
425
408
  def set_user(uid: nil, name: '', privilege: 0, password: '', group_id: '', user_id: '', card: 0)
426
- # If uid is not provided, use next_uid
427
409
  if uid.nil?
410
+ ensure_user_metadata!
428
411
  uid = @next_uid
429
- if user_id.empty?
430
- user_id = @next_user_id
431
- end
412
+ user_id = @next_user_id if user_id.empty? && @next_user_id
432
413
  end
433
414
 
434
- # If user_id is not provided, use uid as string
435
- if user_id.empty?
436
- user_id = uid.to_s # ZK6 needs uid2 == uid
437
- end
415
+ # If uid is not provided, use next_uid
416
+ user_id = uid.to_s if user_id.nil? || user_id.empty? # ZK6 needs uid2 == uid
438
417
 
439
418
  # Validate privilege
440
- if privilege != USER_DEFAULT && privilege != USER_ADMIN
441
- privilege = USER_DEFAULT
442
- end
419
+ privilege = USER_DEFAULT if privilege != USER_DEFAULT && privilege != USER_ADMIN
443
420
  privilege = privilege.to_i
444
421
 
445
422
  # Create command string based on user_packet_size
@@ -447,73 +424,79 @@ module RBZK
447
424
  group_id = 0 if group_id.empty?
448
425
 
449
426
  begin
450
- command_string = [uid, privilege].pack('S<C') +
451
- password.encode(@encoding, invalid: :replace, undef: :replace).ljust(5, "\x00")[0...5] +
452
- name.encode(@encoding, invalid: :replace, undef: :replace).ljust(8, "\x00")[0...8] +
453
- [card.to_i, 0, group_id.to_i, 0, user_id.to_i].pack('L<CS<S<L<')
454
- rescue => e
455
- if @verbose
456
- puts "Error packing user: #{e.message}"
457
- end
427
+ command_string = [ uid, privilege ].pack('S<C') +
428
+ password.encode(@encoding, invalid: :replace, undef: :replace).ljust(5, "\x00")[0...5] +
429
+ name.encode(@encoding, invalid: :replace, undef: :replace).ljust(8, "\x00")[0...8] +
430
+ [ card.to_i, 0, group_id.to_i, 0, user_id.to_i ].pack('L<CS<S<L<')
431
+ rescue StandardError => e
432
+ puts "Error packing user: #{e.message}" if @verbose
458
433
  raise RBZK::ZKErrorResponse, "Can't pack user"
459
434
  end
460
435
  else
461
436
  # For other firmware versions
462
437
  name_pad = name.encode(@encoding, invalid: :replace, undef: :replace).ljust(24, "\x00")[0...24]
463
- card_str = [card.to_i].pack('L<')[0...4]
464
- command_string = [uid, privilege].pack('S<C') +
465
- password.encode(@encoding, invalid: :replace, undef: :replace).ljust(8, "\x00")[0...8] +
466
- name_pad +
467
- card_str + "\x00" +
468
- group_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(7, "\x00")[0...7] +
469
- "\x00" +
470
- user_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(24, "\x00")[0...24]
438
+ card_str = [ card.to_i ].pack('L<')[0...4]
439
+ command_string = "#{[ uid,
440
+ privilege ].pack('S<C')}#{password.encode(@encoding, invalid: :replace, undef: :replace).ljust(8,
441
+ "\x00")[0...8]}#{name_pad}#{card_str}\u0000#{group_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(7,
442
+ "\x00")[0...7]}\u0000#{user_id.encode(@encoding, invalid: :replace, undef: :replace).ljust(
443
+ 24, "\x00"
444
+ )[0...24]}"
471
445
  end
472
446
 
473
447
  # Send command
474
- response = self.send_command(CMD_USER_WRQ, command_string, 1024)
448
+ response = send_command(CMD_USER_WRQ, command_string, 1024)
475
449
 
476
450
  if response && response[:status]
477
451
  # Update next_uid and next_user_id if necessary
478
- self.refresh_data
479
- if @next_uid == uid
480
- @next_uid += 1
481
- end
482
- if @next_user_id == user_id
483
- @next_user_id = @next_uid.to_s
484
- end
452
+ refresh_data
453
+ @next_uid += 1 if @next_uid == uid
454
+ @next_user_id = @next_uid.to_s if @next_user_id == user_id
485
455
  true
486
456
  else
487
- raise RBZK::ZKErrorResponse, "Can't set user"
457
+ code = response[:code] if response
458
+ data_msg = @data && !@data.empty? ? " Data: #{format_as_python_bytes(@data)}" : ''
459
+ raise RBZK::ZKErrorResponse, "Can't set user (device response: #{code || 'NO_CODE'})#{data_msg}"
488
460
  end
489
461
  end
490
462
 
463
+ def ensure_user_metadata!
464
+ @next_uid ||= 1
465
+ @next_user_id ||= '1'
466
+ @user_packet_size ||= 28
467
+
468
+ return unless @next_uid <= 1 || @next_user_id.nil? || @user_packet_size.nil?
469
+
470
+ get_users
471
+ rescue StandardError => e
472
+ puts "Warning: unable to refresh user metadata before creating user: #{e.message}" if @verbose
473
+ @next_uid ||= 1
474
+ @next_user_id ||= '1'
475
+ @user_packet_size ||= 28
476
+ end
477
+ private :ensure_user_metadata!
478
+
491
479
  # Delete user by uid
492
480
  # @param uid [Integer] user ID that are generated from device
493
481
  # @return [Boolean] true if successful, raises exception otherwise
494
482
  def delete_user(uid: 0)
495
483
  # Send command
496
- command_string = [uid].pack('S<')
497
- response = self.send_command(CMD_DELETE_USER, command_string)
484
+ command_string = [ uid ].pack('S<')
485
+ response = send_command(CMD_DELETE_USER, command_string)
498
486
 
499
- if response && response[:status]
500
- self.refresh_data
501
- # Update next_uid if necessary
502
- if uid == (@next_uid - 1)
503
- @next_uid = uid
504
- end
505
- true
506
- else
507
- raise RBZK::ZKErrorResponse, "Can't delete user"
487
+ unless response && response[:status]
488
+ raise RBZK::ZKErrorResponse, "Can't delete user. User not found or other error."
508
489
  end
490
+
491
+ refresh_data
492
+ # Update next_uid if necessary
493
+ @next_uid = uid if uid == (@next_uid - 1)
494
+ true
509
495
  end
510
496
 
511
497
  # Helper method to read data with buffer (ZK6: 1503)
512
498
  def read_with_buffer(command, fct = 0, ext = 0)
513
-
514
- if @verbose
515
- puts "Reading data with buffer: command=#{command}, fct=#{fct}, ext=#{ext}"
516
- end
499
+ puts "Reading data with buffer: command=#{command}, fct=#{fct}, ext=#{ext}" if @verbose
517
500
 
518
501
  # Set max chunk size based on connection type
519
502
  max_chunk = @tcp ? 0xFFc0 : 16 * 1024
@@ -523,54 +506,39 @@ module RBZK
523
506
  # All in little-endian format
524
507
  command_string = [ 1, command, fct, ext ].pack('cs<l<l<')
525
508
 
526
- if @verbose
527
- puts "Command string: #{python_format(command_string)}"
528
- end
509
+ puts "Command string: #{python_format(command_string)}" if @verbose
529
510
 
530
511
  # Send the command to prepare the buffer
531
512
  response_size = 1024
532
- data = []
533
- start = 0
534
- response = self.send_command(CMD_PREPARE_BUFFER, command_string, response_size)
513
+ # local variables
514
+ response = send_command(CMD_PREPARE_BUFFER, command_string, response_size)
535
515
 
536
- if !response || !response[:status]
537
- raise RBZK::ZKErrorResponse, "Read with buffer not supported"
538
- end
516
+ raise RBZK::ZKErrorResponse, 'Read with buffer not supported' if !response || !response[:status]
539
517
 
540
518
  # Get data from the response
541
519
  data = @data
542
520
 
543
- if @verbose
544
- puts "Received #{data.size} bytes of data"
545
- end
521
+ puts "Received #{data.size} bytes of data" if @verbose
546
522
 
547
523
  # Check if we need more data
548
524
  if response[:code] == CMD_DATA
549
525
  if @tcp
550
- if @verbose
551
- puts "DATA! is #{data.size} bytes, tcp length is #{@tcp_length}"
552
- end
526
+ puts "DATA! is #{data.size} bytes, tcp length is #{@tcp_length}" if @verbose
553
527
 
554
528
  if data.size < (@tcp_length - 8)
555
529
  need = (@tcp_length - 8) - data.size
556
- if @verbose
557
- puts "need more data: #{need}"
558
- end
530
+ puts "need more data: #{need}" if @verbose
559
531
 
560
532
  # Receive more data to complete the buffer
561
533
  more_data = receive_raw_data(need)
562
534
 
563
- if @verbose
564
- puts "Read #{more_data.size} more bytes"
565
- end
535
+ puts "Read #{more_data.size} more bytes" if @verbose
566
536
 
567
537
  # Combine the data
568
538
  result = data + more_data
569
539
  return result, data.size + more_data.size
570
540
  else
571
- if @verbose
572
- puts "Enough data"
573
- end
541
+ puts 'Enough data' if @verbose
574
542
  size = data.size
575
543
  return data, size
576
544
  end
@@ -581,38 +549,30 @@ module RBZK
581
549
  end
582
550
 
583
551
  # Get the size from the first 4 bytes (unsigned long, little-endian)
584
- size = data[1..4].unpack('L<')[0]
552
+ size = data[1..4].unpack1('L<')
585
553
 
586
- if @verbose
587
- puts "size fill be #{size}"
588
- end
554
+ puts "size fill be #{size}" if @verbose
589
555
 
590
556
  # Calculate chunks
591
557
  remain = size % max_chunk
592
558
  # Calculate number of full-sized packets (integer division)
593
559
  packets = (size - remain).div(max_chunk)
594
560
 
595
- if @verbose
596
- puts "rwb: ##{packets} packets of max #{max_chunk} bytes, and extra #{remain} bytes remain"
597
- end
561
+ puts "rwb: ##{packets} packets of max #{max_chunk} bytes, and extra #{remain} bytes remain" if @verbose
598
562
 
599
563
  # Read chunks
600
564
  result_data = []
601
565
  start = 0
602
566
 
603
567
  packets.times do
604
- if @verbose
605
- puts "recieve chunk: prepare data size is #{max_chunk}"
606
- end
568
+ puts "recieve chunk: prepare data size is #{max_chunk}" if @verbose
607
569
  chunk = read_chunk(start, max_chunk)
608
570
  result_data << chunk
609
571
  start += max_chunk
610
572
  end
611
573
 
612
- if remain > 0
613
- if @verbose
614
- puts "recieve chunk: prepare data size is #{remain}"
615
- end
574
+ if remain.positive?
575
+ puts "recieve chunk: prepare data size is #{remain}" if @verbose
616
576
  chunk = read_chunk(start, remain)
617
577
  result_data << chunk
618
578
  start += remain
@@ -621,9 +581,7 @@ module RBZK
621
581
  # Free data (equivalent to Python's self.free_data())
622
582
  free_data
623
583
 
624
- if @verbose
625
- puts "_read w/chunk #{start} bytes"
626
- end
584
+ puts "_read w/chunk #{start} bytes" if @verbose
627
585
 
628
586
  # In Python: return b''.join(data), start
629
587
  result = result_data.join
@@ -633,8 +591,8 @@ module RBZK
633
591
  # Helper method to get data size from the current data
634
592
  def get_data_size
635
593
  if @data && @data.size >= 4
636
- size = @data[0...4].unpack('L<')[0]
637
- size
594
+ @data[0...4].unpack1('L<')
595
+
638
596
  else
639
597
  0
640
598
  end
@@ -648,12 +606,12 @@ module RBZK
648
606
  puts "tcp_length #{tcp_length}, size #{size}" if @verbose
649
607
 
650
608
  if tcp_length <= 0
651
- puts "Incorrect tcp packet" if @verbose
652
- return nil, "".b
609
+ puts 'Incorrect tcp packet' if @verbose
610
+ return nil, ''.b
653
611
  end
654
612
 
655
613
  if (tcp_length - 8) < size
656
- puts "tcp length too small... retrying" if @verbose
614
+ puts 'tcp length too small... retrying' if @verbose
657
615
 
658
616
  # Recursive call to handle smaller packet
659
617
  resp, bh = receive_tcp_data(data_recv, tcp_length - 8)
@@ -682,7 +640,7 @@ module RBZK
682
640
 
683
641
  # In Python: response = unpack('HHHH', data_recv[8:16])[0]
684
642
  # This unpacks 4 shorts (8 bytes) but only uses the first one
685
- response = data_recv[8...16].unpack('S<S<S<S<')[0]
643
+ response = data_recv[8...16].unpack1('S<S<S<S<')
686
644
 
687
645
  if received >= (size + 32)
688
646
  if response == CMD_DATA
@@ -690,28 +648,26 @@ module RBZK
690
648
 
691
649
  puts "resp complete len #{resp.size}" if @verbose
692
650
 
693
- return resp, data_recv[(size + 16)..]
651
+ [ resp, data_recv[(size + 16)..-1] ]
694
652
  else
695
653
  puts "incorrect response!!! #{response}" if @verbose
696
654
 
697
- return nil, "".b
655
+ [ nil, ''.b ]
698
656
  end
699
657
  else
700
658
  puts "try DATA incomplete (actual valid #{received - 16})" if @verbose
701
659
 
702
660
  data << data_recv[16...(size + 16)]
703
661
  size -= received - 16
704
- broken_header = "".b
662
+ broken_header = ''.b
705
663
 
706
- if size < 0
707
- broken_header = data_recv[size..]
664
+ if size.negative?
665
+ broken_header = data_recv[size..-1]
708
666
 
709
- if @verbose
710
- puts "broken: #{broken_header.bytes.map { |b| format('%02x', b) }.join}"
711
- end
667
+ puts "broken: #{broken_header.bytes.map { |b| format('%02x', b) }.join}" if @verbose
712
668
  end
713
669
 
714
- if size > 0
670
+ if size.positive?
715
671
  data_recv = receive_raw_data(size)
716
672
  data << data_recv
717
673
  end
@@ -730,14 +686,14 @@ module RBZK
730
686
  need = (@tcp_length - 8) - @data.size
731
687
  puts "need more data: #{need}" if @verbose
732
688
  more_data = receive_raw_data(need)
733
- return @data + more_data
689
+ @data + more_data
734
690
  else
735
- puts "Enough data" if @verbose
736
- return @data
691
+ puts 'Enough data' if @verbose
692
+ @data
737
693
  end
738
694
  else
739
695
  puts "_rc len is #{@data.size}" if @verbose
740
- return @data
696
+ @data
741
697
  end
742
698
  elsif @response == CMD_PREPARE_DATA
743
699
  data = []
@@ -747,10 +703,10 @@ module RBZK
747
703
 
748
704
  if @tcp
749
705
  if @data.size >= (8 + size)
750
- data_recv = @data[8..]
706
+ data_recv = @data[8..-1]
751
707
  else
752
708
  # [80, 80, 130, 125, 92, 7, 0, 0, 221, 5, 142, 172, 0, 0, 4, 0, 80, 7, 0, 0, 1, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 65, 98, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 2, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 65, 110, 97, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 110, 100, 111, 115, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 51, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 116, 97, 0, 111, 115, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 97, 121, 115, 0, 115, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 53, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 97, 119, 97, 110, 0, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 54, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 101, 110, 97, 110, 0, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 55, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 97, 114, 97, 104, 0, 44, 65, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 56, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 98, 114, 101, 101, 110, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 57, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 101, 101, 100, 0, 110, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 48, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 111, 102, 114, 97, 110, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 49, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 97, 110, 105, 97, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 50, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 109, 105, 97, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 51, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 101, 101, 109, 0, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 52, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 97, 108, 97, 97, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 53, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 97, 110, 101, 101, 109, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 54, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 108, 97, 0, 101, 109, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 55, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 97, 114, 97, 104, 0, 0, 0, 98, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 56, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 111, 110, 100, 111, 115, 72, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 57, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 111, 0, 100, 111, 115, 72, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 52, 53, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 119, 115, 0, 111, 115, 72, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 49, 52, 54, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 109, 97, 114, 97, 0, 65, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 52, 53, 50, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 97, 115, 110, 101, 101, 109, 0, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 48, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 115, 114, 97, 97, 0, 109, 0, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 49, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 97, 114, 97, 106, 0, 109, 0, 0, 117, 107, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 49, 51, 53, 0, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 108, 97, 97, 110, 97, 115, 115, 101, 114, 0, 104, 100, 97, 105, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 50, 50, 0, 53, 0, 0, 0, 0, 25, 0, 0, 0, 0, 254, 6, 119, 255, 255, 255, 255, 212, 10, 159, 127, 80, 80, 130, 125, 8, 0, 0, 0, 208, 7, 73, 81, 226, 166, 4, 0]
753
- data_recv = @data[8..] + @socket.recv(size + 32)
709
+ data_recv = @data[8..-1] + @socket.recv(size + 32)
754
710
  end
755
711
 
756
712
  puts "data_recv: #{python_format(data_recv)}" if @verbose
@@ -760,36 +716,30 @@ module RBZK
760
716
  data << resp if resp
761
717
 
762
718
  # get CMD_ACK_OK
763
- if broken_header.size < 16
764
- data_recv = broken_header + @socket.recv(16)
765
- else
766
- data_recv = broken_header
767
- end
719
+ data_recv = if broken_header.size < 16
720
+ broken_header + @socket.recv(16)
721
+ else
722
+ broken_header
723
+ end
768
724
 
769
725
  if data_recv.size < 16
770
726
  puts "trying to complete broken ACK #{data_recv.size} /16"
771
- if @verbose
772
- puts "data_recv: #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
773
- end
727
+ puts "data_recv: #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}" if @verbose
774
728
  data_recv += @socket.recv(16 - data_recv.size) # TODO: CHECK HERE_!
775
729
  end
776
730
 
777
- if !test_tcp_top(data_recv)
778
- if @verbose
779
- puts "invalid chunk tcp ACK OK"
780
- end
731
+ unless test_tcp_top(data_recv)
732
+ puts 'invalid chunk tcp ACK OK' if @verbose
781
733
  return nil
782
734
  end
783
735
 
784
736
  # In Python: response = unpack('HHHH', data_recv[8:16])[0]
785
737
  # This unpacks 4 shorts (8 bytes) but only uses the first one
786
738
  # In Ruby, we need to use 'S<4' to unpack 4 shorts in little-endian format
787
- response = data_recv[8...16].unpack('S<4')[0]
739
+ response = data_recv[8...16].unpack1('S<4')
788
740
 
789
741
  if response == CMD_ACK_OK
790
- if @verbose
791
- puts "chunk tcp ACK OK!"
792
- end
742
+ puts 'chunk tcp ACK OK!' if @verbose
793
743
  return data.join
794
744
  end
795
745
 
@@ -798,40 +748,32 @@ module RBZK
798
748
  puts "data: #{data.map { |d| format_as_python_bytes(d) }.join(', ')}"
799
749
  end
800
750
 
801
- return nil
751
+ nil
802
752
  else
803
753
  # Non-TCP implementation
804
754
  loop do
805
755
  data_recv = @socket.recv(1024 + 8)
806
- response = data_recv[0...8].unpack('S<S<S<S<')[0]
756
+ response = data_recv[0...8].unpack1('S<S<S<S<')
807
757
 
808
- if @verbose
809
- puts "# packet response is: #{response}"
810
- end
758
+ puts "# packet response is: #{response}" if @verbose
811
759
 
812
760
  if response == CMD_DATA
813
- data << data_recv[8..]
761
+ data << data_recv[8..-1]
814
762
  size -= 1024
815
763
  elsif response == CMD_ACK_OK
816
764
  break
817
765
  else
818
- if @verbose
819
- puts "broken!"
820
- end
766
+ puts 'broken!' if @verbose
821
767
  break
822
768
  end
823
769
 
824
- if @verbose
825
- puts "still needs #{size}"
826
- end
770
+ puts "still needs #{size}" if @verbose
827
771
  end
828
772
 
829
- return data.join
773
+ data.join
830
774
  end
831
775
  else
832
- if @verbose
833
- puts "invalid response #{@response}"
834
- end
776
+ puts "invalid response #{@response}" if @verbose
835
777
  nil
836
778
  end
837
779
  end
@@ -839,27 +781,21 @@ module RBZK
839
781
  # Helper method to receive raw data (like Python's __recieve_raw_data)
840
782
  def receive_raw_data(size)
841
783
  data = []
842
- if @verbose
843
- puts "expecting #{size} bytes raw data"
844
- end
784
+ puts "expecting #{size} bytes raw data" if @verbose
845
785
 
846
- while size > 0
786
+ while size.positive?
847
787
  data_recv = @socket.recv(size)
848
788
  received = data_recv.size
849
789
 
850
790
  if @verbose
851
791
  puts "partial recv #{received}"
852
- if received < 100
853
- puts " recv #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
854
- end
792
+ puts " recv #{data_recv.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}" if received < 100
855
793
  end
856
794
 
857
795
  data << data_recv
858
796
  size -= received
859
797
 
860
- if @verbose
861
- puts "still need #{size}"
862
- end
798
+ puts "still need #{size}" if @verbose
863
799
  end
864
800
 
865
801
  data.join
@@ -868,13 +804,11 @@ module RBZK
868
804
  # Helper method to clear buffer (like Python's free_data)
869
805
  def free_data
870
806
  command = CMD_FREE_DATA
871
- response = self.send_command(command)
807
+ response = send_command(command)
872
808
 
873
- if response && response[:status]
874
- true
875
- else
876
- raise RBZK::ZKErrorResponse, "Can't free data"
877
- end
809
+ raise RBZK::ZKErrorResponse, "Can't free data" unless response && response[:status]
810
+
811
+ true
878
812
  end
879
813
 
880
814
  # Send data with buffer
@@ -883,15 +817,13 @@ module RBZK
883
817
  def send_with_buffer(buffer)
884
818
  max_chunk = 1024
885
819
  size = buffer.size
886
- self.free_data
820
+ free_data
887
821
 
888
822
  command = CMD_PREPARE_DATA
889
- command_string = [size].pack('L<')
890
- response = self.send_command(command, command_string)
823
+ command_string = [ size ].pack('L<')
824
+ response = send_command(command, command_string)
891
825
 
892
- if !response || !response[:status]
893
- raise RBZK::ZKErrorResponse, "Can't prepare data"
894
- end
826
+ raise RBZK::ZKErrorResponse, "Can't prepare data" if !response || !response[:status]
895
827
 
896
828
  remain = size % max_chunk
897
829
  packets = (size - remain) / max_chunk
@@ -902,7 +834,7 @@ module RBZK
902
834
  start += max_chunk
903
835
  end
904
836
 
905
- send_chunk(buffer[start, remain]) if remain > 0
837
+ send_chunk(buffer[start, remain]) if remain.positive?
906
838
 
907
839
  true
908
840
  end
@@ -912,22 +844,18 @@ module RBZK
912
844
  # @return [Boolean] true if successful, raises exception otherwise
913
845
  def send_chunk(command_string)
914
846
  command = CMD_DATA
915
- response = self.send_command(command, command_string)
847
+ response = send_command(command, command_string)
916
848
 
917
- if response && response[:status]
918
- true
919
- else
920
- raise RBZK::ZKErrorResponse, "Can't send chunk"
921
- end
849
+ raise RBZK::ZKErrorResponse, "Can't send chunk" unless response && response[:status]
850
+
851
+ true
922
852
  end
923
853
 
924
854
  # Helper method to read a chunk of data
925
855
  def read_chunk(start, size)
926
- if @verbose
927
- puts "Reading chunk: start=#{start}, size=#{size}"
928
- end
856
+ puts "Reading chunk: start=#{start}, size=#{size}" if @verbose
929
857
 
930
- 3.times do |_retries|
858
+ 3.times do |attempt|
931
859
  # In Python: command = const._CMD_READ_BUFFER (which is 1504)
932
860
  # In Ruby, we should use CMD_READ_BUFFER (1504) instead of CMD_READFILE_DATA (81)
933
861
  command = 1504 # CMD_READ_BUFFER
@@ -939,25 +867,21 @@ module RBZK
939
867
  response_size = @tcp ? size + 32 : 1024 + 8
940
868
 
941
869
  # In Python: cmd_response = self.__send_command(command, command_string, response_size)
942
- response = self.send_command(command, command_string, response_size)
870
+ response = send_command(command, command_string, response_size)
943
871
 
944
872
  if !response || !response[:status]
945
- if @verbose
946
- puts "Failed to read chunk on attempt #{_retries + 1}"
947
- end
873
+ puts "Failed to read chunk on attempt #{attempt + 1}" if @verbose
948
874
  next
949
875
  end
950
876
 
951
877
  # In Python: data = self.__recieve_chunk()
952
878
  data = receive_chunk
953
879
 
954
- if data
955
- if @verbose
956
- puts "Received chunk of #{data.size} bytes"
957
- end
880
+ next unless data
958
881
 
959
- return data
960
- end
882
+ puts "Received chunk of #{data.size} bytes" if @verbose
883
+
884
+ return data
961
885
  end
962
886
 
963
887
  # If we get here, all retries failed
@@ -966,12 +890,12 @@ module RBZK
966
890
 
967
891
  def get_users
968
892
  # Read sizes
969
- self.read_sizes
893
+ read_sizes
970
894
 
971
895
  puts "Device has #{@users} users" if @verbose
972
896
 
973
897
  # If no users, return empty array
974
- if @users == 0
898
+ if @users.zero?
975
899
  @next_uid = 1
976
900
  @next_user_id = '1'
977
901
  return []
@@ -979,46 +903,48 @@ module RBZK
979
903
 
980
904
  users = []
981
905
  max_uid = 0
982
- userdata, size = self.read_with_buffer(CMD_USERTEMP_RRQ, FCT_USER)
906
+ userdata, size = read_with_buffer(CMD_USERTEMP_RRQ, FCT_USER)
983
907
  puts "user size #{size} (= #{userdata.length})" if @verbose
984
908
 
985
909
  if size <= 4
986
- puts "WRN: missing user data"
910
+ puts 'WRN: missing user data'
987
911
  return []
988
912
  end
989
913
 
990
914
  total_size = userdata[0, 4].unpack1('L<')
991
915
  @user_packet_size = total_size / @users
992
916
 
993
- if ![ 28, 72 ].include?(@user_packet_size)
994
- puts "WRN packet size would be #{@user_packet_size}" if @verbose
995
- end
917
+ puts "WRN packet size would be #{@user_packet_size}" if ![ 28, 72 ].include?(@user_packet_size) && @verbose
996
918
 
997
919
  userdata = userdata[4..-1]
998
920
 
999
921
  if @user_packet_size == 28
1000
922
  while userdata.length >= 28
1001
- uid, privilege, password, name, card, group_id, timezone, user_id = userdata.ljust(28, "\x00")[0, 28].unpack('S<Ca5a8L<xCs<L<')
923
+ uid, privilege, password, name, card, group_id, timezone, user_id = userdata.ljust(28, "\x00")[0,
924
+ 28].unpack('S<Ca5a8L<xCs<L<')
1002
925
  max_uid = uid if uid > max_uid
1003
926
  password = password.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)
1004
927
  name = name.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)&.strip
1005
928
  group_id = group_id.to_s
1006
929
  user_id = user_id.to_s
1007
- name = "NN-#{user_id}" if !name
930
+ name ||= "NN-#{user_id}"
1008
931
  user = User.new(uid, name, privilege, password, group_id, user_id, card)
1009
932
  users << user
1010
- puts "[6]user: #{uid}, #{privilege}, #{password}, #{name}, #{card}, #{group_id}, #{timezone}, #{user_id}" if @verbose
933
+ if @verbose
934
+ puts "[6]user: #{uid}, #{privilege}, #{password}, #{name}, #{card}, #{group_id}, #{timezone}, #{user_id}"
935
+ end
1011
936
  userdata = userdata[28..-1]
1012
937
  end
1013
938
  else
1014
939
  while userdata.length >= 72
1015
- uid, privilege, password, name, card, group_id, user_id = userdata.ljust(72, "\x00")[0, 72].unpack('S<Ca8a24L<xa7xa24')
940
+ uid, privilege, password, name, card, group_id, user_id = userdata.ljust(72, "\x00")[0,
941
+ 72].unpack('S<Ca8a24L<xa7xa24')
1016
942
  max_uid = uid if uid > max_uid
1017
943
  password = password.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)
1018
944
  name = name.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)&.strip
1019
945
  group_id = group_id.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)&.strip
1020
946
  user_id = user_id.split("\x00").first&.force_encoding(@encoding)&.encode('UTF-8', invalid: :replace)
1021
- name = "NN-#{user_id}" if !name
947
+ name ||= "NN-#{user_id}"
1022
948
  user = User.new(uid, name, privilege, password, group_id, user_id, card)
1023
949
  users << user
1024
950
  userdata = userdata[72..-1]
@@ -1030,12 +956,10 @@ module RBZK
1030
956
  @next_user_id = max_uid.to_s
1031
957
 
1032
958
  loop do
1033
- if users.any? { |u| u.user_id == @next_user_id }
1034
- max_uid += 1
1035
- @next_user_id = max_uid.to_s
1036
- else
1037
- break
1038
- end
959
+ break unless users.any? { |u| u.user_id == @next_user_id }
960
+
961
+ max_uid += 1
962
+ @next_user_id = max_uid.to_s
1039
963
  end
1040
964
 
1041
965
  users
@@ -1043,41 +967,33 @@ module RBZK
1043
967
 
1044
968
  def get_attendance_logs
1045
969
  # First, read device sizes to get record count
1046
- self.read_sizes
970
+ read_sizes
1047
971
 
1048
972
  # If no records, return empty array
1049
- if @records == 0
1050
- return []
1051
- end
973
+ return [] if @records.zero?
1052
974
 
1053
975
  # Get users for lookup
1054
- users = self.get_users
976
+ users = get_users
1055
977
 
1056
- if @verbose
1057
- puts "Found #{users.size} users"
1058
- end
978
+ puts "Found #{users.size} users" if @verbose
1059
979
 
1060
980
  logs = []
1061
981
 
1062
982
  # Read attendance data with buffer
1063
- attendance_data, size = self.read_with_buffer(CMD_ATTLOG_RRQ)
983
+ attendance_data, size = read_with_buffer(CMD_ATTLOG_RRQ)
1064
984
 
1065
985
  if size < 4
1066
- if @verbose
1067
- puts "WRN: no attendance data"
1068
- end
986
+ puts 'WRN: no attendance data' if @verbose
1069
987
  return []
1070
988
  end
1071
989
 
1072
990
  # Get total size from first 4 bytes
1073
- total_size = attendance_data[0...4].unpack('I')[0]
991
+ total_size = attendance_data[0...4].unpack1('I')
1074
992
 
1075
993
  # Calculate record size
1076
- record_size = @records > 0 ? total_size / @records : 0
994
+ record_size = @records.positive? ? total_size / @records : 0
1077
995
 
1078
- if @verbose
1079
- puts "record_size is #{record_size}"
1080
- end
996
+ puts "record_size is #{record_size}" if @verbose
1081
997
 
1082
998
  # Remove the first 4 bytes (total size)
1083
999
  attendance_data = attendance_data[4..-1]
@@ -1089,18 +1005,20 @@ module RBZK
1089
1005
  uid, status, timestamp_raw, punch = attendance_data[0...8].ljust(8, "\x00".b).unpack('S<C4sC')
1090
1006
 
1091
1007
  if @verbose
1092
- puts "Attendance data (hex): #{attendance_data[0...8].bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1008
+ puts "Attendance data (hex): #{attendance_data[0...8].bytes.map do |b|
1009
+ "0x#{b.to_s(16).rjust(2, '0')}"
1010
+ end.join(' ')}"
1093
1011
  end
1094
1012
 
1095
1013
  attendance_data = attendance_data[8..-1]
1096
1014
 
1097
1015
  # Look up user by uid
1098
1016
  tuser = users.find { |u| u.uid == uid }
1099
- if !tuser
1100
- user_id = uid.to_s
1101
- else
1102
- user_id = tuser.user_id
1103
- end
1017
+ user_id = if !tuser
1018
+ uid.to_s
1019
+ else
1020
+ tuser.user_id
1021
+ end
1104
1022
 
1105
1023
  # Decode timestamp
1106
1024
  timestamp = decode_time(timestamp_raw)
@@ -1113,10 +1031,13 @@ module RBZK
1113
1031
  # Handle 16-byte records
1114
1032
  while attendance_data && attendance_data.size >= 16
1115
1033
  # In Python: user_id, timestamp, status, punch, reserved, workcode = unpack('<I4sBB2sI', attendance_data.ljust(16, b'\x00')[:16])
1116
- user_id_raw, timestamp_raw, status, punch, reserved, workcode = attendance_data[0...16].ljust(16, "\x00".b).unpack('L<4sCCa2L<')
1034
+ user_id_raw, timestamp_raw, status, punch, _reserved, _workcode = attendance_data[0...16].ljust(16,
1035
+ "\x00".b).unpack('L<4sCCa2L<')
1117
1036
 
1118
1037
  if @verbose
1119
- puts "Attendance data (hex): #{attendance_data[0...16].bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1038
+ puts "Attendance data (hex): #{attendance_data[0...16].bytes.map do |b|
1039
+ "0x#{b.to_s(16).rjust(2, '0')}"
1040
+ end.join(' ')}"
1120
1041
  end
1121
1042
 
1122
1043
  attendance_data = attendance_data[16..-1]
@@ -1127,9 +1048,7 @@ module RBZK
1127
1048
  # Look up user by user_id and uid
1128
1049
  tuser = users.find { |u| u.user_id == user_id }
1129
1050
  if !tuser
1130
- if @verbose
1131
- puts "no uid #{user_id}"
1132
- end
1051
+ puts "no uid #{user_id}" if @verbose
1133
1052
  uid = user_id
1134
1053
  tuser = users.find { |u| u.uid.to_s == user_id }
1135
1054
  if !tuser
@@ -1153,10 +1072,13 @@ module RBZK
1153
1072
  # Handle 40-byte records (default)
1154
1073
  while attendance_data && attendance_data.size >= 40
1155
1074
  # In Python: uid, user_id, status, timestamp, punch, space = unpack('<H24sB4sB8s', attendance_data.ljust(40, b'\x00')[:40])
1156
- uid, user_id_raw, status, timestamp_raw, punch, space = attendance_data[0...40].ljust(40, "\x00".b).unpack('S<a24Ca4Ca8')
1075
+ uid, user_id_raw, status, timestamp_raw, punch, _space = attendance_data[0...40].ljust(40,
1076
+ "\x00".b).unpack('S<a24Ca4Ca8')
1157
1077
 
1158
1078
  if @verbose
1159
- puts "Attendance data (hex): #{attendance_data[0...40].bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1079
+ puts "Attendance data (hex): #{attendance_data[0...40].bytes.map do |b|
1080
+ "0x#{b.to_s(16).rjust(2, '0')}"
1081
+ end.join(' ')}"
1160
1082
  end
1161
1083
 
1162
1084
  # Extract user_id from null-terminated string
@@ -1178,23 +1100,23 @@ module RBZK
1178
1100
 
1179
1101
  def decode_time(t)
1180
1102
  # Convert binary timestamp to integer
1181
- t = t.unpack("L<")[0]
1103
+ t = t.unpack1('L<')
1182
1104
 
1183
1105
  # Extract time components
1184
1106
  second = t % 60
1185
- t = t / 60
1107
+ t /= 60
1186
1108
 
1187
1109
  minute = t % 60
1188
- t = t / 60
1110
+ t /= 60
1189
1111
 
1190
1112
  hour = t % 24
1191
- t = t / 24
1113
+ t /= 24
1192
1114
 
1193
1115
  day = t % 31 + 1
1194
- t = t / 31
1116
+ t /= 31
1195
1117
 
1196
1118
  month = t % 12 + 1
1197
- t = t / 12
1119
+ t /= 12
1198
1120
 
1199
1121
  year = t + 2000
1200
1122
 
@@ -1206,7 +1128,7 @@ module RBZK
1206
1128
  # Match Python's __decode_timehex method
1207
1129
  def decode_timehex(timehex)
1208
1130
  # Extract time components
1209
- year, month, day, hour, minute, second = timehex.unpack("C6")
1131
+ year, month, day, hour, minute, second = timehex.unpack('C6')
1210
1132
  year += 2000
1211
1133
 
1212
1134
  # Create Time object
@@ -1215,23 +1137,20 @@ module RBZK
1215
1137
 
1216
1138
  def encode_time(t)
1217
1139
  # Calculate encoded timestamp
1218
- d = (
1140
+ (
1219
1141
  ((t.year % 100) * 12 * 31 + ((t.month - 1) * 31) + t.day - 1) *
1220
1142
  (24 * 60 * 60) + (t.hour * 60 + t.minute) * 60 + t.second
1221
1143
  )
1222
- d
1223
1144
  end
1224
1145
 
1225
1146
  def get_time
1226
1147
  command = CMD_GET_TIME
1227
1148
  response_size = 1032
1228
- response = self.send_command(command, "", response_size)
1149
+ response = send_command(command, '', response_size)
1229
1150
 
1230
- if response && response[:status]
1231
- decode_time(@data[0...4])
1232
- else
1233
- raise RBZK::ZKErrorResponse, "Can't get time"
1234
- end
1151
+ raise RBZK::ZKErrorResponse, "Can't get time" unless response && response[:status]
1152
+
1153
+ decode_time(@data[0...4])
1235
1154
  end
1236
1155
 
1237
1156
  def set_time(timestamp = nil)
@@ -1240,24 +1159,22 @@ module RBZK
1240
1159
 
1241
1160
  command = CMD_SET_TIME
1242
1161
  command_string = [ encode_time(timestamp) ].pack('L<')
1243
- response = self.send_command(command, command_string)
1162
+ response = send_command(command, command_string)
1244
1163
 
1245
- if response && response[:status]
1246
- true
1247
- else
1248
- raise RBZK::ZKErrorResponse, "Can't set time"
1249
- end
1164
+ raise RBZK::ZKErrorResponse, "Can't set time" unless response && response[:status]
1165
+
1166
+ true
1250
1167
  end
1251
1168
 
1252
1169
  def clear_attendance_logs
1253
- self.send_command(CMD_CLEAR_ATTLOG)
1254
- self.recv_reply
1170
+ send_command(CMD_CLEAR_ATTLOG)
1171
+ recv_reply
1255
1172
  true
1256
1173
  end
1257
1174
 
1258
1175
  def clear_data
1259
- self.send_command(CMD_CLEAR_DATA)
1260
- self.recv_reply
1176
+ send_command(CMD_CLEAR_DATA)
1177
+ recv_reply
1261
1178
  true
1262
1179
  end
1263
1180
 
@@ -1267,33 +1184,33 @@ module RBZK
1267
1184
 
1268
1185
  result = "b'"
1269
1186
  binary_string.each_byte do |byte|
1270
- case byte
1271
- when 0x0d # Carriage return - Python shows as \r
1272
- result += "\\r"
1273
- when 0x0a # Line feed - Python shows as \n
1274
- result += "\\n"
1275
- when 0x09 # Tab - Python shows as \t
1276
- result += "\\t"
1277
- when 0x07 # Bell - Python can show as \a or \x07
1278
- result += "\\x07"
1279
- when 0x08 # Backspace - Python shows as \b
1280
- result += "\\b"
1281
- when 0x0c # Form feed - Python shows as \f
1282
- result += "\\f"
1283
- when 0x0b # Vertical tab - Python shows as \v
1284
- result += "\\v"
1285
- when 0x5c # Backslash - Python shows as \\
1286
- result += "\\\\"
1287
- when 0x27 # Single quote - Python shows as \'
1288
- result += "\\'"
1289
- when 0x22 # Double quote - Python shows as \"
1290
- result += "\\\""
1291
- when 32..126 # Printable ASCII
1292
- result += byte.chr
1293
- else
1294
- # All other bytes - Python shows as \xHH
1295
- result += "\\x#{byte.to_s(16).rjust(2, '0')}"
1296
- end
1187
+ result += case byte
1188
+ when 0x0d # Carriage return - Python shows as \r
1189
+ '\\r'
1190
+ when 0x0a # Line feed - Python shows as \n
1191
+ '\\n'
1192
+ when 0x09 # Tab - Python shows as \t
1193
+ '\\t'
1194
+ when 0x07 # Bell - Python can show as \a or \x07
1195
+ '\\x07'
1196
+ when 0x08 # Backspace - Python shows as \b
1197
+ '\\b'
1198
+ when 0x0c # Form feed - Python shows as \f
1199
+ '\\f'
1200
+ when 0x0b # Vertical tab - Python shows as \v
1201
+ '\\v'
1202
+ when 0x5c # Backslash - Python shows as \\
1203
+ '\\\\'
1204
+ when 0x27 # Single quote - Python shows as \'
1205
+ "\\'"
1206
+ when 0x22 # Double quote - Python shows as \"
1207
+ '\"'
1208
+ when 32..126 # Printable ASCII
1209
+ byte.chr
1210
+ else
1211
+ # All other bytes - Python shows as \xHH
1212
+ "\\x#{byte.to_s(16).rjust(2, '0')}"
1213
+ end
1297
1214
  end
1298
1215
  result += "'"
1299
1216
  result
@@ -1308,7 +1225,7 @@ module RBZK
1308
1225
  puts "Python expected: #{python_expected}"
1309
1226
 
1310
1227
  if ruby_formatted != python_expected
1311
- puts "DIFFERENCE DETECTED!"
1228
+ puts 'DIFFERENCE DETECTED!'
1312
1229
  # Show byte-by-byte comparison
1313
1230
  ruby_bytes = binary_string.bytes
1314
1231
  # Parse Python bytes string (format: b'\x01\x02')
@@ -1344,16 +1261,27 @@ module RBZK
1344
1261
  end
1345
1262
 
1346
1263
  # Show differences
1347
- puts "Byte-by-byte comparison:"
1264
+ puts 'Byte-by-byte comparison:'
1348
1265
  max_len = [ ruby_bytes.length, python_bytes.length ].max
1349
1266
  (0...max_len).each do |j|
1350
1267
  ruby_byte = j < ruby_bytes.length ? ruby_bytes[j] : nil
1351
1268
  python_byte = j < python_bytes.length ? python_bytes[j] : nil
1352
- match = ruby_byte == python_byte ? "" : ""
1353
- puts " Byte #{j}: Ruby=#{ruby_byte.nil? ? 'nil' : "0x#{ruby_byte.to_s(16).rjust(2, '0')}"}, Python=#{python_byte.nil? ? 'nil' : "0x#{python_byte.to_s(16).rjust(2, '0')}"} #{match}"
1269
+ match = ruby_byte == python_byte ? '' : ''
1270
+ puts " Byte #{j}: Ruby=#{if ruby_byte.nil?
1271
+ 'nil'
1272
+ else
1273
+ "0x#{ruby_byte.to_s(16).rjust(2,
1274
+ '0')}"
1275
+ end}, Python=#{if python_byte.nil?
1276
+ 'nil'
1277
+ else
1278
+ "0x#{python_byte.to_s(16).rjust(
1279
+ 2, '0'
1280
+ )}"
1281
+ end} #{match}"
1354
1282
  end
1355
1283
  else
1356
- puts "Binary data matches exactly!"
1284
+ puts 'Binary data matches exactly!'
1357
1285
  end
1358
1286
  end
1359
1287
 
@@ -1371,70 +1299,62 @@ module RBZK
1371
1299
  def read_sizes
1372
1300
  command = CMD_GET_FREE_SIZES
1373
1301
  response_size = 1024
1374
- cmd_response = self.send_command(command, "", response_size)
1302
+ cmd_response = send_command(command, '', response_size)
1375
1303
 
1376
- if cmd_response && cmd_response[:status]
1377
- if @verbose
1378
- puts "Data hex: #{@data.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1379
- puts "Data Python format: #{python_format(@data)}"
1304
+ raise RBZK::ZKErrorResponse, "Can't read sizes" unless cmd_response && cmd_response[:status]
1305
+
1306
+ if @verbose
1307
+ puts "Data hex: #{@data.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1308
+ puts "Data Python format: #{python_format(@data)}"
1309
+ end
1310
+
1311
+ size = @data.size
1312
+ puts "Data size: #{size} bytes" if @verbose
1313
+
1314
+ if @data.size >= 80
1315
+ # In Python: fields = unpack('20i', self.__data[:80])
1316
+ # In Ruby, 'l<' is a signed 32-bit integer (4 bytes) in little-endian format, which matches Python's 'i'
1317
+ fields = @data[0...80].unpack('l<20')
1318
+
1319
+ puts "Unpacked fields: #{fields.inspect}" if @verbose
1320
+
1321
+ @users = fields[4]
1322
+ @fingers = fields[6]
1323
+ @records = fields[8]
1324
+ @dummy = fields[10] # ???
1325
+ @cards = fields[12]
1326
+ @fingers_cap = fields[14]
1327
+ @users_cap = fields[15]
1328
+ @rec_cap = fields[16]
1329
+ @fingers_av = fields[17]
1330
+ @users_av = fields[18]
1331
+ @rec_av = fields[19]
1332
+ @data = @data[80..-1]
1333
+
1334
+ # Check for face information (added to match Python implementation)
1335
+ if @data.size >= 12 # face info
1336
+ # In Python: fields = unpack('3i', self.__data[:12]) #dirty hack! we need more information
1337
+ face_fields = @data[0...12].unpack('l<3')
1338
+ @faces = face_fields[0]
1339
+ @faces_cap = face_fields[2]
1340
+
1341
+ puts "Face info: faces=#{@faces}, capacity=#{@faces_cap}" if @verbose
1380
1342
  end
1381
1343
 
1382
- size = @data.size
1383
1344
  if @verbose
1384
- puts "Data size: #{size} bytes"
1345
+ puts "Device info: users=#{@users}, fingers=#{@fingers}, records=#{@records}"
1346
+ puts "Capacity: users=#{@users_cap}, fingers=#{@fingers_cap}, records=#{@rec_cap}"
1385
1347
  end
1386
1348
 
1387
- if @data.size >= 80
1388
- # In Python: fields = unpack('20i', self.__data[:80])
1389
- # In Ruby, 'l<' is a signed 32-bit integer (4 bytes) in little-endian format, which matches Python's 'i'
1390
- fields = @data[0...80].unpack('l<20')
1391
-
1392
- if @verbose
1393
- puts "Unpacked fields: #{fields.inspect}"
1394
- end
1395
-
1396
- @users = fields[4]
1397
- @fingers = fields[6]
1398
- @records = fields[8]
1399
- @dummy = fields[10] # ???
1400
- @cards = fields[12]
1401
- @fingers_cap = fields[14]
1402
- @users_cap = fields[15]
1403
- @rec_cap = fields[16]
1404
- @fingers_av = fields[17]
1405
- @users_av = fields[18]
1406
- @rec_av = fields[19]
1407
- @data = @data[80..-1]
1408
-
1409
- # Check for face information (added to match Python implementation)
1410
- if @data.size >= 12 # face info
1411
- # In Python: fields = unpack('3i', self.__data[:12]) #dirty hack! we need more information
1412
- face_fields = @data[0...12].unpack('l<3')
1413
- @faces = face_fields[0]
1414
- @faces_cap = face_fields[2]
1415
-
1416
- if @verbose
1417
- puts "Face info: faces=#{@faces}, capacity=#{@faces_cap}"
1418
- end
1419
- end
1420
-
1421
- if @verbose
1422
- puts "Device info: users=#{@users}, fingers=#{@fingers}, records=#{@records}"
1423
- puts "Capacity: users=#{@users_cap}, fingers=#{@fingers_cap}, records=#{@rec_cap}"
1424
- end
1425
-
1426
- return true
1427
- end
1428
- else
1429
- raise RBZK::ZKErrorResponse, "Can't read sizes"
1349
+ return true
1430
1350
  end
1431
1351
 
1432
1352
  false
1433
1353
  end
1434
1354
 
1435
1355
  def get_free_sizes
1436
- self.send_command(CMD_GET_FREE_SIZES)
1437
- reply = self.recv_reply
1356
+ send_command(CMD_GET_FREE_SIZES)
1357
+ reply = recv_reply
1438
1358
 
1439
1359
  if reply && reply.size >= 8
1440
1360
  sizes_data = reply[8..-1].unpack('S<*')
@@ -1454,11 +1374,11 @@ module RBZK
1454
1374
  def get_templates
1455
1375
  fingers = []
1456
1376
 
1457
- self.send_command(CMD_PREPARE_DATA, [ FCT_FINGERTMP ].pack('C'))
1458
- self.recv_reply
1377
+ send_command(CMD_PREPARE_DATA, [ FCT_FINGERTMP ].pack('C'))
1378
+ recv_reply
1459
1379
 
1460
- data_size = self.recv_long
1461
- templates_data = self.recv_chunk(data_size)
1380
+ data_size = recv_long
1381
+ templates_data = recv_chunk(data_size)
1462
1382
 
1463
1383
  if templates_data && !templates_data.empty?
1464
1384
  offset = 0
@@ -1478,8 +1398,8 @@ module RBZK
1478
1398
  end
1479
1399
 
1480
1400
  def get_user_template(uid, finger_id)
1481
- self.send_command(CMD_GET_USERTEMP, [ uid, finger_id ].pack('S<S<'))
1482
- reply = self.recv_reply
1401
+ send_command(CMD_GET_USERTEMP, [ uid, finger_id ].pack('S<S<'))
1402
+ reply = recv_reply
1483
1403
 
1484
1404
  if reply && reply.size >= 8
1485
1405
  template_data = reply[8..-1]
@@ -1510,9 +1430,7 @@ module RBZK
1510
1430
  # Use connect_ex like Python (returns error code instead of raising exception)
1511
1431
  sockaddr = Socket.pack_sockaddr_in(@port, @ip)
1512
1432
  @socket.connect_nonblock(sockaddr)
1513
- if @verbose
1514
- puts "TCP socket connected successfully"
1515
- end
1433
+ puts 'TCP socket connected successfully' if @verbose
1516
1434
  rescue IO::WaitWritable
1517
1435
  # Socket is in progress of connecting
1518
1436
  ready = IO.select(nil, [ @socket ], nil, @timeout)
@@ -1521,42 +1439,30 @@ module RBZK
1521
1439
  @socket.connect_nonblock(sockaddr)
1522
1440
  rescue Errno::EISCONN
1523
1441
  # Already connected, which is fine
1524
- if @verbose
1525
- puts "TCP socket connected successfully"
1526
- end
1527
- rescue => e
1442
+ puts 'TCP socket connected successfully' if @verbose
1443
+ rescue StandardError => e
1528
1444
  # Connection failed
1529
- if @verbose
1530
- puts "TCP socket connection failed: #{e.message}"
1531
- end
1445
+ puts "TCP socket connection failed: #{e.message}" if @verbose
1532
1446
  raise e
1533
1447
  end
1534
1448
  else
1535
1449
  # Connection timed out
1536
- if @verbose
1537
- puts "TCP socket connection timed out"
1538
- end
1450
+ puts 'TCP socket connection timed out' if @verbose
1539
1451
  raise Errno::ETIMEDOUT
1540
1452
  end
1541
1453
  rescue Errno::EISCONN
1542
1454
  # Already connected, which is fine
1543
- if @verbose
1544
- puts "TCP socket already connected"
1545
- end
1455
+ puts 'TCP socket already connected' if @verbose
1546
1456
  end
1547
1457
  else
1548
1458
  # Create UDP socket (like Python's socket(AF_INET, SOCK_DGRAM))
1549
1459
  @socket = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM)
1550
1460
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [ @timeout, 0 ].pack('l_*'))
1551
1461
 
1552
- if @verbose
1553
- puts "UDP socket created successfully"
1554
- end
1555
- end
1556
- rescue => e
1557
- if @verbose
1558
- puts "Socket creation failed: #{e.message}"
1462
+ puts 'UDP socket created successfully' if @verbose
1559
1463
  end
1464
+ rescue StandardError => e
1465
+ puts "Socket creation failed: #{e.message}" if @verbose
1560
1466
  raise RBZK::ZKNetworkError, "Failed to create socket: #{e.message}"
1561
1467
  end
1562
1468
 
@@ -1582,24 +1488,18 @@ module RBZK
1582
1488
  end
1583
1489
 
1584
1490
  def ping
1585
- if @verbose
1586
- puts "Pinging device at #{@ip}:#{@port}..."
1587
- end
1491
+ puts "Pinging device at #{@ip}:#{@port}..." if @verbose
1588
1492
 
1589
1493
  # Try TCP ping first
1590
1494
  begin
1591
1495
  Timeout.timeout(5) do
1592
1496
  s = TCPSocket.new(@ip, @port)
1593
1497
  s.close
1594
- if @verbose
1595
- puts "TCP ping successful"
1596
- end
1498
+ puts 'TCP ping successful' if @verbose
1597
1499
  return true
1598
1500
  end
1599
1501
  rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
1600
- if @verbose
1601
- puts "TCP ping failed: #{e.message}"
1602
- end
1502
+ puts "TCP ping failed: #{e.message}" if @verbose
1603
1503
  end
1604
1504
 
1605
1505
  # If TCP ping fails, try UDP ping
@@ -1610,23 +1510,17 @@ module RBZK
1610
1510
  ready = IO.select([ udp_socket ], nil, nil, 5)
1611
1511
 
1612
1512
  if ready
1613
- if @verbose
1614
- puts "UDP ping successful"
1615
- end
1513
+ puts 'UDP ping successful' if @verbose
1616
1514
  udp_socket.close
1617
- return true
1515
+ true
1618
1516
  else
1619
- if @verbose
1620
- puts "UDP ping timed out"
1621
- end
1517
+ puts 'UDP ping timed out' if @verbose
1622
1518
  udp_socket.close
1623
- return false
1624
- end
1625
- rescue => e
1626
- if @verbose
1627
- puts "UDP ping failed: #{e.message}"
1519
+ false
1628
1520
  end
1629
- return false
1521
+ rescue StandardError => e
1522
+ puts "UDP ping failed: #{e.message}" if @verbose
1523
+ false
1630
1524
  end
1631
1525
  end
1632
1526
 
@@ -1645,24 +1539,18 @@ module RBZK
1645
1539
 
1646
1540
  # In Python: if checksum > const.USHRT_MAX: checksum -= const.USHRT_MAX
1647
1541
  # Handle overflow immediately after each addition
1648
- if checksum > USHRT_MAX
1649
- checksum -= USHRT_MAX
1650
- end
1542
+ checksum -= USHRT_MAX if checksum > USHRT_MAX
1651
1543
 
1652
1544
  l -= 2
1653
1545
  end
1654
1546
 
1655
1547
  # Handle odd byte if present
1656
1548
  # In Python: if l: checksum = checksum + p[-1]
1657
- if l > 0
1658
- checksum += buf[i]
1659
- end
1549
+ checksum += buf[i] if l.positive?
1660
1550
 
1661
1551
  # Handle overflow
1662
1552
  # In Python: while checksum > const.USHRT_MAX: checksum -= const.USHRT_MAX
1663
- while checksum > USHRT_MAX
1664
- checksum -= USHRT_MAX
1665
- end
1553
+ checksum -= USHRT_MAX while checksum > USHRT_MAX
1666
1554
 
1667
1555
  # Bitwise complement
1668
1556
  # In Python: checksum = ~checksum
@@ -1670,9 +1558,7 @@ module RBZK
1670
1558
 
1671
1559
  # Handle negative values
1672
1560
  # In Python: while checksum < 0: checksum += const.USHRT_MAX
1673
- while checksum < 0
1674
- checksum += USHRT_MAX
1675
- end
1561
+ checksum += USHRT_MAX while checksum.negative?
1676
1562
 
1677
1563
  # Return the checksum
1678
1564
  checksum
@@ -1681,6 +1567,7 @@ module RBZK
1681
1567
  # Helper method to debug binary data in both Python and Ruby formats
1682
1568
  def debug_binary(name, data)
1683
1569
  return unless @verbose
1570
+
1684
1571
  puts "#{name} (hex): #{data.bytes.map { |b| "\\x#{b.to_s(16).rjust(2, '0')}" }.join('')}"
1685
1572
  puts "#{name} (Ruby): #{data.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
1686
1573
  puts "#{name} (Python): #{format_as_python_bytes(data)}"
@@ -1692,18 +1579,18 @@ module RBZK
1692
1579
  top = [ MACHINE_PREPARE_DATA_1, MACHINE_PREPARE_DATA_2, length ].pack('S<S<I<')
1693
1580
 
1694
1581
  if @verbose
1695
- puts "TCP header components:"
1582
+ puts 'TCP header components:'
1696
1583
  puts " MACHINE_PREPARE_DATA_1: 0x#{MACHINE_PREPARE_DATA_1.to_s(16)}"
1697
1584
  puts " MACHINE_PREPARE_DATA_2: 0x#{MACHINE_PREPARE_DATA_2.to_s(16)}"
1698
1585
  puts " packet length: #{length}"
1699
- debug_binary("TCP header", top)
1700
- debug_binary("Full TCP packet", top + packet)
1586
+ debug_binary('TCP header', top)
1587
+ debug_binary('Full TCP packet', top + packet)
1701
1588
  end
1702
1589
 
1703
1590
  top + packet
1704
1591
  end
1705
1592
 
1706
- def create_header(command, command_string = "".b, session_id = 0, reply_id = 0)
1593
+ def create_header(command, command_string = ''.b, session_id = 0, reply_id = 0)
1707
1594
  # Ensure command_string is a binary string
1708
1595
  command_string = command_string.to_s.b
1709
1596
 
@@ -1718,35 +1605,33 @@ module RBZK
1718
1605
 
1719
1606
  # Update reply_id
1720
1607
  reply_id += 1
1721
- if reply_id >= USHRT_MAX
1722
- reply_id -= USHRT_MAX
1723
- end
1608
+ reply_id -= USHRT_MAX if reply_id >= USHRT_MAX
1724
1609
 
1725
1610
  # Create final header with updated values
1726
1611
  buf = [ command, checksum, session_id, reply_id ].pack('v4')
1727
1612
 
1728
1613
  if @verbose
1729
- puts "Header components:"
1614
+ puts 'Header components:'
1730
1615
  puts " Command: #{command}"
1731
1616
  puts " Checksum: #{checksum}"
1732
1617
  puts " Session ID: #{session_id}"
1733
1618
  puts " Reply ID: #{reply_id}"
1734
1619
 
1735
1620
  if !command_string.empty?
1736
- debug_binary("Command string", command_string)
1621
+ debug_binary('Command string', command_string)
1737
1622
  else
1738
- puts "Command string: (empty)"
1623
+ puts 'Command string: (empty)'
1739
1624
  end
1740
- debug_binary("Final header", buf)
1625
+ debug_binary('Final header', buf)
1741
1626
  end
1742
1627
 
1743
1628
  buf + command_string
1744
1629
  end
1745
1630
 
1746
- def send_command(command, command_string = "".b, response_size = 8)
1631
+ def send_command(command, command_string = ''.b, response_size = 8)
1747
1632
  # Check connection status (except for connect and auth commands)
1748
1633
  if command != CMD_CONNECT && command != CMD_AUTH && !@connected
1749
- raise RBZK::ZKErrorConnection, "Instance are not connected."
1634
+ raise RBZK::ZKErrorConnection, 'Instance are not connected.'
1750
1635
  end
1751
1636
 
1752
1637
  # In Python, command_string is a bytes object (b'')
@@ -1780,9 +1665,9 @@ module RBZK
1780
1665
  if @verbose
1781
1666
  puts "\nSending TCP packet:"
1782
1667
  puts "Note: In send_command, 'top' variable contains the full packet (header + command packet)"
1783
- puts "This is because create_tcp_top returns the full packet, not just the header"
1784
- debug_binary("Command packet (buf)", buf)
1785
- debug_binary("Full TCP packet (top)", top) # 'top' contains the full packet here
1668
+ puts 'This is because create_tcp_top returns the full packet, not just the header'
1669
+ debug_binary('Command packet (buf)', buf)
1670
+ debug_binary('Full TCP packet (top)', top) # 'top' contains the full packet here
1786
1671
  end
1787
1672
 
1788
1673
  @socket.send(top, 0)
@@ -1791,12 +1676,10 @@ module RBZK
1791
1676
 
1792
1677
  if @verbose
1793
1678
  puts "\nReceived TCP response:"
1794
- debug_binary("TCP response", @tcp_data_recv)
1679
+ debug_binary('TCP response', @tcp_data_recv)
1795
1680
  end
1796
1681
 
1797
- if @tcp_length == 0
1798
- raise RBZK::ZKNetworkError, "TCP packet invalid"
1799
- end
1682
+ raise RBZK::ZKNetworkError, 'TCP packet invalid' if @tcp_length.zero?
1800
1683
 
1801
1684
  @header = @tcp_data_recv[8..15].unpack('v4')
1802
1685
  @data_recv = @tcp_data_recv[8..-1]
@@ -1806,10 +1689,8 @@ module RBZK
1806
1689
  @data_recv = @socket.recv(response_size)
1807
1690
  @header = @data_recv[0..7].unpack('S<4')
1808
1691
  end
1809
- rescue => e
1810
- if @verbose
1811
- puts "Connection error during send: #{e.message}"
1812
- end
1692
+ rescue StandardError => e
1693
+ puts "Connection error during send: #{e.message}" if @verbose
1813
1694
  raise RBZK::ZKNetworkError, e.message
1814
1695
  end
1815
1696
 
@@ -1834,9 +1715,7 @@ module RBZK
1834
1715
 
1835
1716
  def recv_reply
1836
1717
  begin
1837
- if @verbose
1838
- puts "Waiting for TCP reply"
1839
- end
1718
+ puts 'Waiting for TCP reply' if @verbose
1840
1719
 
1841
1720
  # Set a timeout for the read operation
1842
1721
  Timeout.timeout(5) do
@@ -1847,15 +1726,11 @@ module RBZK
1847
1726
  # Parse TCP header
1848
1727
  tcp_format1, tcp_format2, tcp_length = tcp_header.unpack('S<S<I<')
1849
1728
 
1850
- if @verbose
1851
- puts "TCP header: format1=#{tcp_format1}, format2=#{tcp_format2}, length=#{tcp_length}"
1852
- end
1729
+ puts "TCP header: format1=#{tcp_format1}, format2=#{tcp_format2}, length=#{tcp_length}" if @verbose
1853
1730
 
1854
1731
  # Verify TCP header format
1855
1732
  if tcp_format1 != MACHINE_PREPARE_DATA_1 || tcp_format2 != MACHINE_PREPARE_DATA_2
1856
- if @verbose
1857
- puts "Invalid TCP header format: #{tcp_format1}, #{tcp_format2}"
1858
- end
1733
+ puts "Invalid TCP header format: #{tcp_format1}, #{tcp_format2}" if @verbose
1859
1734
  return nil
1860
1735
  end
1861
1736
 
@@ -1874,30 +1749,24 @@ module RBZK
1874
1749
  data_size = tcp_length - 8
1875
1750
 
1876
1751
  # Read data if available
1877
- data = ""
1878
- if data_size > 0
1879
- if @verbose
1880
- puts "Reading #{data_size} bytes of data"
1881
- end
1752
+ data = ''
1753
+ if data_size.positive?
1754
+ puts "Reading #{data_size} bytes of data" if @verbose
1882
1755
 
1883
1756
  # Read data in chunks to handle large responses (like Python implementation)
1884
1757
  remaining = data_size
1885
- while remaining > 0
1758
+ while remaining.positive?
1886
1759
  chunk_size = [ remaining, 4096 ].min
1887
1760
  chunk = @socket.read(chunk_size)
1888
1761
  if chunk.nil? || chunk.empty?
1889
- if @verbose
1890
- puts "Failed to read data chunk, got #{chunk.inspect}"
1891
- end
1762
+ puts "Failed to read data chunk, got #{chunk.inspect}" if @verbose
1892
1763
  break
1893
1764
  end
1894
1765
 
1895
1766
  data += chunk
1896
1767
  remaining -= chunk.size
1897
1768
 
1898
- if @verbose && remaining > 0
1899
- puts "Read #{chunk.size} bytes, #{remaining} remaining"
1900
- end
1769
+ puts "Read #{chunk.size} bytes, #{remaining} remaining" if @verbose && remaining.positive?
1901
1770
  end
1902
1771
  end
1903
1772
 
@@ -1908,47 +1777,33 @@ module RBZK
1908
1777
  @session_id = session_id
1909
1778
 
1910
1779
  # Check command type and handle accordingly (like Python implementation)
1911
- if command == CMD_ACK_OK
1912
- if @verbose
1913
- puts "Received ACK_OK"
1914
- end
1780
+ case command
1781
+ when CMD_ACK_OK
1782
+ puts 'Received ACK_OK' if @verbose
1915
1783
  return cmd_header + data
1916
- elsif command == CMD_ACK_ERROR
1917
- if @verbose
1918
- puts "Received ACK_ERROR"
1919
- end
1784
+ when CMD_ACK_ERROR
1785
+ puts 'Received ACK_ERROR' if @verbose
1920
1786
  return nil
1921
- elsif command == CMD_ACK_DATA
1922
- if @verbose
1923
- puts "Received ACK_DATA"
1924
- end
1925
- if data_size > 0
1926
- return cmd_header + data
1927
- else
1928
- return nil
1929
- end
1787
+ when CMD_ACK_DATA
1788
+ puts 'Received ACK_DATA' if @verbose
1789
+ return cmd_header + data if data_size.positive?
1790
+
1791
+ return nil
1792
+
1930
1793
  else
1931
- if @verbose
1932
- puts "Received unknown command: #{command}"
1933
- end
1794
+ puts "Received unknown command: #{command}" if @verbose
1934
1795
  return cmd_header + data
1935
1796
  end
1936
1797
  end
1937
1798
  rescue Timeout::Error => e
1938
- if @verbose
1939
- puts "Timeout waiting for response: #{e.message}"
1940
- end
1941
- raise RBZK::ZKErrorResponse, "Timeout waiting for response"
1799
+ puts "Timeout waiting for response: #{e.message}" if @verbose
1800
+ raise RBZK::ZKErrorResponse, 'Timeout waiting for response'
1942
1801
  rescue Errno::ECONNRESET, Errno::EPIPE => e
1943
- if @verbose
1944
- puts "Connection error during receive: #{e.message}"
1945
- end
1802
+ puts "Connection error during receive: #{e.message}" if @verbose
1946
1803
  raise RBZK::ZKNetworkError, "Connection error: #{e.message}"
1947
1804
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK => e
1948
- if @verbose
1949
- puts "Timeout waiting for response: #{e.message}"
1950
- end
1951
- raise RBZK::ZKErrorResponse, "Timeout waiting for response"
1805
+ puts "Timeout waiting for response: #{e.message}" if @verbose
1806
+ raise RBZK::ZKErrorResponse, 'Timeout waiting for response'
1952
1807
  end
1953
1808
 
1954
1809
  nil
@@ -1958,31 +1813,25 @@ module RBZK
1958
1813
  if @data_recv && @data_recv.size >= 4
1959
1814
  data = @data_recv[0..3]
1960
1815
  @data_recv = @data_recv[4..-1]
1961
- return data.unpack('L<')[0]
1816
+ return data.unpack1('L<')
1962
1817
  end
1963
1818
 
1964
1819
  0
1965
1820
  end
1966
1821
 
1967
1822
  def recv_chunk(size)
1968
- if @verbose
1969
- puts "Receiving chunk of #{size} bytes"
1970
- end
1823
+ puts "Receiving chunk of #{size} bytes" if @verbose
1971
1824
 
1972
1825
  if @data_recv && @data_recv.size >= size
1973
1826
  data = @data_recv[0...size]
1974
1827
  @data_recv = @data_recv[size..-1]
1975
1828
 
1976
- if @verbose
1977
- puts "Received #{data.size} bytes from buffer"
1978
- end
1829
+ puts "Received #{data.size} bytes from buffer" if @verbose
1979
1830
 
1980
1831
  return data
1981
1832
  end
1982
1833
 
1983
- if @verbose
1984
- puts "Warning: No data available in buffer"
1985
- end
1834
+ puts 'Warning: No data available in buffer' if @verbose
1986
1835
 
1987
1836
  # Return empty string if no data is available
1988
1837
  ''
@@ -1999,11 +1848,11 @@ module RBZK
1999
1848
  k = 0
2000
1849
 
2001
1850
  32.times do |i|
2002
- if (key & (1 << i)) != 0
2003
- k = (k << 1 | 1)
2004
- else
2005
- k = k << 1
2006
- end
1851
+ k = if (key & (1 << i)) != 0
1852
+ (k << 1 | 1)
1853
+ else
1854
+ k << 1
1855
+ end
2007
1856
  end
2008
1857
 
2009
1858
  k += session_id
@@ -2036,9 +1885,7 @@ module RBZK
2036
1885
  # Note: The third byte is just B, not k[2] ^ B
2037
1886
  result = [ k_bytes[0] ^ b, k_bytes[1] ^ b, b, k_bytes[3] ^ b ].pack('C4')
2038
1887
 
2039
- if @verbose
2040
- puts "Final commkey bytes: #{result.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}"
2041
- end
1888
+ puts "Final commkey bytes: #{result.bytes.map { |b| "0x#{b.to_s(16).rjust(2, '0')}" }.join(' ')}" if @verbose
2042
1889
 
2043
1890
  result
2044
1891
  end