Class: SML::BinaryTransport

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-sml/transport-binary.rb

Class Method Summary collapse

Class Method Details

.handle_escape(bytes) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/ruby-sml/transport-binary.rb', line 133

def self.handle_escape(bytes)
#      print "escape sequence: "
  if bytes[0] == 0x01 and bytes[1] == 0x01 and bytes[2] == 0x01 and bytes[3] == 0x01
#        puts "data transmission v1"
  elsif bytes[0] == 0x1a
#        puts "end of data transmission (padding: #{bytes[1]}, checksum: 0x#{bytes[2].to_s(16)}#{bytes[3].to_s(16)})"
    return "" << bytes[2] << bytes[3], bytes[1]
  elsif bytes[0] == 0x02
#        puts "data transmission v2"
  elsif bytes[0] == 0x03
#        puts "v2 set timeout"
  elsif bytes[0] == 0x04
#        puts "v2 set block size"
  elsif bytes[0] == 0x1b and bytes[1] == 0x1b and bytes[2] == 0x1b and bytes[3] == 0x1b
#        puts "literal escape :("
    return 1, 0
  else
#        print "unknown ["
#        print "0x%08x" % escape
#        puts "]"
  end
  return 0, 0
end

.readfile(io) ⇒ Object



9
10
11
12
13
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
47
48
49
50
# File 'lib/ruby-sml/transport-binary.rb', line 9

def self.readfile(io)
  file = String.new
  received_checksum_bytes = String.new
  raw = String.new
  
  while not io.eof?
    bytes_raw = io.read(4)
    raw << bytes_raw
    bytes = bytes_raw.unpack('N')[0]
    if bytes == 0x1b1b1b1b
      escape = []
      4.times do
        byte = io.read(1)
        raw << byte
        escape.push(byte.unpack('C')[0])
      end
      escape_return, padding_length = handle_escape(escape)
      case escape_return
      when 1
        4.times do
          file << [0x1b].pack('C')
        end
      when String
        received_checksum_bytes = escape_return
        break
      end
    else
      file << [bytes].pack('N')
    end
  end

  # calculate CRC16 over all received bytes (except last 2 - they contain the checksum itself)
  raw.chop!.chop!
  calculated_checksum = CRC16.crc16(raw)
  calculated_checksum = (calculated_checksum ^ 0xffff)
  calculated_checksum = ((calculated_checksum & 0xff00) >> 8) | ((calculated_checksum & 0x00ff) << 8)
  # unpack the checksum we received
  received_checksum = received_checksum_bytes.unpack('n')[0]

  return nil unless calculated_checksum == received_checksum
  return file[0..-(padding_length+1)]
end

.readstring(data) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/ruby-sml/transport-binary.rb', line 51

def self.readstring(data)
  io = StringIO.new(data)
  end_of_transmission_found = false
  file = String.new
  received_checksum_bytes = String.new
  raw = String.new
  
  while not io.eof?
    bytes_raw = io.read(4)
    raw << bytes_raw
    bytes = bytes_raw.unpack('N')[0]
    if bytes == 0x1b1b1b1b
      escape = []
      4.times do
        byte = io.read(1)
        raw << byte
        escape.push(byte.unpack('C')[0])
      end
      escape_return, padding_length = handle_escape(escape)
      case escape_return
      when 1
        4.times do
          file << [0x1b].pack('C')
        end
      when String
        received_checksum_bytes = escape_return
        end_of_transmission_found = true
        break
      end
    else
      file << [bytes].pack('N')
    end
  end

  return [nil, nil, data] unless end_of_transmission_found

  # calculate CRC16 over all received bytes (except last 2 - they contain the checksum itself)
  raw.chop!.chop!
  calculated_checksum = CRC16.crc16(raw)
  calculated_checksum = (calculated_checksum ^ 0xffff)
  calculated_checksum = ((calculated_checksum & 0xff00) >> 8) | ((calculated_checksum & 0x00ff) << 8)
  # unpack the checksum we received
  received_checksum = received_checksum_bytes.unpack('n')[0]

  return [nil, false, data[io.pos..-1]] unless calculated_checksum == received_checksum
  return [file[0..-(padding_length+1)], true, data[io.pos..-1]]
end

.writefile(io, file) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/ruby-sml/transport-binary.rb', line 98

def self.writefile(io, file)
  source = String.new(file)
  result = String.new

  # add transport begin header
  result << [0x1b1b1b1b, 0x01010101].pack('NN')

  while not source.empty?
    value = source.unpack('N')[0]
    if value == 0x1b1b1b1b
      result << [0x1b1b1b1b].pack('N')
      result << source.slice!(0,4)
    else
      result << source.slice!(0,1)
    end
  end

  # calculate padding length
  padding_length = (4-(file.length % 4)) % 4

  # add padding
  padding_length.times do
    result << 0x00
  end
  # add transmission end header
  result << [0x1b1b1b1b, 0x1a, padding_length].pack('NCC')

  # calculate checksum
  checksum = CRC16.crc16(result)
  checksum = (checksum ^ 0xffff)
  result << [(checksum & 0x00ff), ((checksum >> 8) & 0x00ff)].pack('CC')

  io << result
end