class SML::BinaryTransport

Public Class Methods

handle_escape(bytes) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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