14
15
16
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
|
# File 'lib/meshtastic/admin/firmware/serial_bootloader.rb', line 14
public_class_method def self.install(opts = {})
bytes = validate(opts.merge({}))
chip = opts.fetch(:chip)
offset = opts.fetch(:offset)
port = UART.open(opts.fetch(:port), 115_200, '8N1')
attrs = Termios.tcgetattr(port)
attrs.cflag &= ~(Termios::CRTSCTS | Termios::HUPCL)
Termios.tcsetattr(port, Termios::TCSANOW, attrs)
reset_lines(io: port, bootloader: true) if opts.fetch(:reset, :classic) == :classic
context = { io: port, timeout: opts.fetch(:timeout, 120) }
synchronize(context.merge({}))
identify(context.merge(chip: chip))
command(context.merge(op: 13, payload: [0, 0].pack('V2')))
command(context.merge(op: 11, payload: [0, opts.fetch(:flash_size), 65_536, 4096, 256, 65_535].pack('V6')))
blocks = (bytes.bytesize + 1023) / 1024
params = [bytes.bytesize, blocks, 1024, offset]
params << 0 unless chip == :esp32
command(context.merge(op: 2, payload: params.pack('V*')))
blocks.times do |sequence|
block = bytes.byteslice(sequence * 1024, 1024).ljust(1024, "\xff".b)
payload = [1024, sequence, 0, 0].pack('V4') + block
command(context.merge(op: 3, payload: payload, checksum: block.bytes.reduce(0xef, :^)))
end
md5 = command(context.merge(op: 19, payload: [offset, bytes.bytesize, 0, 0].pack('V4'), response_size: 32)).fetch(:data)
raise IOError, 'ROM flash MD5 mismatch' unless md5.downcase == Digest::MD5.hexdigest(bytes)
command(context.merge(op: 4, payload: [0].pack('V')))
reset_lines(io: port, bootloader: false) if opts.fetch(:reset, :classic) == :classic
{ status: :verified, chip: chip, bytes: bytes.bytesize, offset: offset, md5: md5.downcase, sha256: Digest::SHA256.hexdigest(bytes), reboot_requested: true, boot_verified: false }
ensure
port&.close
end
|