17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
# File 'lib/meshtastic/admin/firmware/nordic_dfu.rb', line 17
public_class_method def self.install(opts = {})
unknown = opts.keys - %i[package package_bytes gatt address adapter timeout protocol]
raise ArgumentError, "Unsupported Nordic DFU options: #{unknown.join(', ')}" unless unknown.empty?
raise ArgumentError, 'protocol must be :nordic_dfu' unless opts.fetch(:protocol, :nordic_dfu) == :nordic_dfu
raise ArgumentError, 'Supply exactly one of package or package_bytes' unless opts.key?(:package) ^ opts.key?(:package_bytes)
image, init = package(opts.merge({}))
timeout = opts.fetch(:timeout, 30)
raise ArgumentError, 'timeout must be finite and positive' unless timeout.is_a?(Numeric) && timeout.positive? && timeout.finite?
gatt = opts[:gatt]
unless gatt
require_relative 'ble'
gatt = BLE::BlueZ.new(address: opts.fetch(:address), adapter: opts.fetch(:adapter, 'hci0'),
timeout: timeout, service_uuid: '00001530-1212-efde-1523-785feabcd123').connect
end
session = { gatt: gatt, timeout: timeout }
gatt.subscribe(uuid: CONTROL_UUID)
control(session.merge(bytes: [1, 4].pack('C*')))
packet(session.merge(bytes: [0, 0, image.bytesize].pack('V3')))
response(session.merge(opcode: 1))
control(session.merge(bytes: [2, 0].pack('C*')))
init.bytes.each_slice(20) { |chunk| packet(session.merge(bytes: chunk.pack('C*'))) }
control(session.merge(bytes: [2, 1].pack('C*')))
response(session.merge(opcode: 2))
control(session.merge(bytes: [8, 1].pack('Cv')))
control(session.merge(bytes: [3].pack('C')))
offset = 0
image.bytes.each_slice(20) do |chunk|
packet(session.merge(bytes: chunk.pack('C*')))
offset += chunk.length
if offset == image.bytesize
response(session.merge(opcode: 3))
else
receipt = notification(session)
raise IOError, 'DFU packet receipt offset mismatch' unless receipt == [17, offset].pack('CV')
end
end
control(session.merge(bytes: [4].pack('C')))
response(session.merge(opcode: 4))
control(session.merge(bytes: [5].pack('C')))
{ status: :verified, protocol: :nordic_dfu, bytes: image.bytesize,
sha256: Digest::SHA256.hexdigest(image), reboot_verified: false }
ensure
gatt&.close
end
|