AUTOSAR SOME/IP: Ruby parsing library

SOME/IP (Scalable service-Oriented MiddlewarE over IP) is an automotive/embedded communication protocol which supports remoteprocedure calls, event notifications and the underlying serialization/wire format.

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.9

This page hosts a formal specification of AUTOSAR SOME/IP using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for Ruby generated by Kaitai Struct depends on the Ruby runtime library. You have to install it before you can parse data.

The Ruby runtime library can be installed from RubyGems:

gem install kaitai-struct

Code

Parse a local file and get structure in memory:

data = SomeIp.from_file("path/to/local/file.bin")

Or parse structure from a string of bytes:

bytes = "\x00\x01\x02..."
data = SomeIp.new(Kaitai::Struct::Stream.new(bytes))

After that, one can get various attributes from the structure by invoking getter methods like:

data.header # => get header

Ruby source code to parse AUTOSAR SOME/IP

some_ip.rb

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

require 'kaitai/struct/struct'

unless Gem::Version.new(Kaitai::Struct::VERSION) >= Gem::Version.new('0.9')
  raise "Incompatible Kaitai Struct Ruby API: 0.9 or later is required, but you have #{Kaitai::Struct::VERSION}"
end


##
# SOME/IP (Scalable service-Oriented MiddlewarE over IP) is an automotive/embedded
# communication protocol which supports remoteprocedure calls, event notifications
# and the underlying serialization/wire format.
# @see https://www.autosar.org/fileadmin/standards/foundation/19-11/AUTOSAR_PRS_SOMEIPProtocol.pdf Source
class SomeIp < Kaitai::Struct::Struct
  def initialize(_io, _parent = nil, _root = self)
    super(_io, _parent, _root)
    _read
  end

  def _read
    @header = Header.new(@_io, self, @_root)
    case header.message_id.value
    when 4294934784
      @_raw_payload = @_io.read_bytes((header.length - 8))
      _io__raw_payload = Kaitai::Struct::Stream.new(@_raw_payload)
      @payload = SomeIpSd.new(_io__raw_payload)
    else
      @payload = @_io.read_bytes((header.length - 8))
    end
    self
  end
  class Header < Kaitai::Struct::Struct

    MESSAGE_TYPE_ENUM = {
      0 => :message_type_enum_request,
      1 => :message_type_enum_request_no_return,
      2 => :message_type_enum_notification,
      64 => :message_type_enum_request_ack,
      65 => :message_type_enum_request_no_return_ack,
      66 => :message_type_enum_notification_ack,
      128 => :message_type_enum_response,
      129 => :message_type_enum_error,
      192 => :message_type_enum_response_ack,
      193 => :message_type_enum_error_ack,
    }
    I__MESSAGE_TYPE_ENUM = MESSAGE_TYPE_ENUM.invert

    RETURN_CODE_ENUM = {
      0 => :return_code_enum_ok,
      1 => :return_code_enum_not_ok,
      2 => :return_code_enum_unknown_service,
      3 => :return_code_enum_unknown_method,
      4 => :return_code_enum_not_ready,
      5 => :return_code_enum_not_reachable,
      6 => :return_code_enum_time_out,
      7 => :return_code_enum_wrong_protocol_version,
      8 => :return_code_enum_wrong_interface_version,
      9 => :return_code_enum_malformed_message,
      10 => :return_code_enum_wrong_message_type,
    }
    I__RETURN_CODE_ENUM = RETURN_CODE_ENUM.invert
    def initialize(_io, _parent = nil, _root = self)
      super(_io, _parent, _root)
      _read
    end

    def _read
      @_raw_message_id = @_io.read_bytes(4)
      _io__raw_message_id = Kaitai::Struct::Stream.new(@_raw_message_id)
      @message_id = MessageId.new(_io__raw_message_id, self, @_root)
      @length = @_io.read_u4be
      @_raw_request_id = @_io.read_bytes(4)
      _io__raw_request_id = Kaitai::Struct::Stream.new(@_raw_request_id)
      @request_id = RequestId.new(_io__raw_request_id, self, @_root)
      @protocol_version = @_io.read_u1
      @interface_version = @_io.read_u1
      @message_type = Kaitai::Struct::Stream::resolve_enum(MESSAGE_TYPE_ENUM, @_io.read_u1)
      @return_code = Kaitai::Struct::Stream::resolve_enum(RETURN_CODE_ENUM, @_io.read_u1)
      self
    end

    ##
    # [PRS_SOMEIP_00035] The assignment of the Message ID shall be up to
    # the user. However, the Message ID shall be unique for the whole
    # system (i.e. the vehicle). TheMessage ID is similar to a CAN ID and
    # should be handled via a comparable process.
    # [PRS_SOMEIP_00038] Message IDs of method calls shall be structured in
    # the ID with 2^16 services with 2^15 methods.
    # @see '' AUTOSAR_PRS_SOMEIPProtocol.pdf 4.1.1.1  Message ID
    class MessageId < Kaitai::Struct::Struct
      def initialize(_io, _parent = nil, _root = self)
        super(_io, _parent, _root)
        _read
      end

      def _read
        @service_id = @_io.read_u2be
        @sub_id = @_io.read_bits_int_be(1) != 0
        if sub_id == false
          @method_id = @_io.read_bits_int_be(15)
        end
        if sub_id == true
          @event_id = @_io.read_bits_int_be(15)
        end
        self
      end

      ##
      # The value provides the undissected Message ID
      def value
        return @value unless @value.nil?
        _pos = @_io.pos
        @_io.seek(0)
        @value = @_io.read_u4be
        @_io.seek(_pos)
        @value
      end

      ##
      # Service ID
      attr_reader :service_id

      ##
      # Single bit to flag, if there is a Method or a Event ID
      attr_reader :sub_id

      ##
      # Method ID
      # @see '' AUTOSAR_PRS_SOMEIPProtocol.pdf - Table 4.1.
      attr_reader :method_id

      ##
      # Event ID
      # @see '' AUTOSAR_PRS_SOMEIPProtocol.pdf - Table 4.6
      attr_reader :event_id
    end

    ##
    # The Request ID allows a provider and subscriber to differentiate
    # multiple parallel usesof the same method, event, getter or setter.
    # @see '' AUTOSAR_PRS_SOMEIPProtocol.pdf - section 4.1.1.3  Request ID
    class RequestId < Kaitai::Struct::Struct
      def initialize(_io, _parent = nil, _root = self)
        super(_io, _parent, _root)
        _read
      end

      def _read
        @client_id = @_io.read_u2be
        @session_id = @_io.read_u2be
        self
      end

      ##
      # The value provides the undissected Request ID
      def value
        return @value unless @value.nil?
        _pos = @_io.pos
        @_io.seek(0)
        @value = @_io.read_u4be
        @_io.seek(_pos)
        @value
      end
      attr_reader :client_id
      attr_reader :session_id
    end

    ##
    # auxillary value
    # @see '' AUTOSAR_PRS_SOMEIPServiceDiscoveryProtocol.pdf - section 4.1.2.1 General Requirements
    def is_valid_service_discovery
      return @is_valid_service_discovery unless @is_valid_service_discovery.nil?
      @is_valid_service_discovery =  ((message_id.value == 4294934784) && (protocol_version == 1) && (interface_version == 1) && (message_type == :message_type_enum_notification) && (return_code == :return_code_enum_ok)) 
      @is_valid_service_discovery
    end

    ##
    # The Message ID shall be a 32 Bit identifier that is used to identify
    # the RPC call to a method of an application or to identify an event.
    attr_reader :message_id

    ##
    # [PRS_SOMEIP_00042] Length field shall contain the length in Byte
    # starting from Request ID/Client ID until the end of the SOME/IP message.
    attr_reader :length

    ##
    # The Request ID allows a provider and subscriber to differentiate
    # multiple parallel uses of the same method, event, getter or setter.
    attr_reader :request_id

    ##
    # The Protocol Version identifies the used SOME/IP Header format
    # (not including the Payload format).
    attr_reader :protocol_version

    ##
    # Interface Version shall be an 8 Bit field that contains the
    # MajorVersion of the Service Interface.
    attr_reader :interface_version

    ##
    # The Message Type field is used to differentiate different types of
    # messages.
    # @see '' AUTOSAR_PRS_SOMEIPProtocol.pdf - Table 4.4
    attr_reader :message_type

    ##
    # The Return Code shall be used to signal whether a request was
    # successfully processed.
    # @see '' AUTOSAR_PRS_SOMEIPProtocol.pdf - Table 4.5
    attr_reader :return_code
    attr_reader :_raw_message_id
    attr_reader :_raw_request_id
  end
  attr_reader :header
  attr_reader :payload
  attr_reader :_raw_payload
end