Android基于vsomeIp3与VDC或者VIU通信

背景

部门需要开发一款App用于演示VDC或者VIU的功能,进一步控制汽车部件做出反应

方案1

作为一个对硬件,甚至对汽车没一丝了解的Android开发,第一时间并不想跳出舒适圈,脑子里立马浮现出一个场景,同一局域网内直接使用Socket通信。说干就干,啪啪啪,编码完成,一个基于C/S架构的Demo完成,领导看了看,有没有一种可能,板子上不需要重新写程序,直接使用板子已有的someIp协议进行通讯。what?

什么是someIp协议

SOME/IP全称Scalableservice-Oriented Middleware over IP,基于IP的可扩展面向服务的中间件,是一种专用于汽车嵌入式的客户端/服务器通信机制,访问方式分别为事件通知event和RPC远程调用

someip的数据结构

Message ID(Server ID) :16bit,服务的ID,标识出一个服务;
Message ID(Method ID) :16bit,方法的ID,表示出一个方法;
Length:报文长度,32bit,标识从request ID到报文结束的总长度;
Request ID(Client ID) :客户端ID,16bit。区分不同的客户端;
Request ID(Session ID) :会话ID,区分同一个客户端的多次调用;
Protocol Version :协议的版本号,固定值为x01;
Interface Version:服务接口版本;
Message Type :报文类型,在AUTOSAR中,总共包含五种,包括REQUEST,REQUEST_NO_RETURN,NOTIFICATION,RESPONSE,ERROR;
Return Code :返回码,包括四种,REQUEST,REQUEST_NO_RETURN,NOTIFICATION,RESPONSE;
Payload :数据段,用于放置需要传输的数据

Android开发是否支持Someip协议

平时开发App,Android的主要的开发语言是java和kotlin,那如果我们能通过java直接构建Someip消息体是否就能正常通信了?然后悲哀的发现光是按标准组建消息体 就是一个难度不小的挑战,更别说还要能构建通信通道,正常解析数据。又是一顿google search,发现BMW开源了一个实现someip的库vSomeIp

https://github.com/COVESA/vsomeip

查看这个库的过程中,我发现了一个名字非常数据的文件CMakeLists.txt,Android开发中使用JNI的方式调用函数,通过Cmake构建so库好像都跟这个文件有关,那是不是意味着Android可以通过JNI 的方式调用vSomeIp库,从而实现与硬件的通讯

开整

1.环境

  • Android Studio 4.1.2 (Gradle 6.5, JDK 1.8)
  • CMake 3.18.1 (for boost-cmake)

2.依赖

  • boost 1.71.0 (https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/)
  • vsomeip3 : (https://github.com/GENIVI/vsomeip.git).
  • boost-cmake: Used CMake adapted boost (https://github.com/Orphis/boost-cmake).

3.项目结构和配置

项目结构1
项目结构2
具体配置 可以参考 : (https://github.com/lixiaolia/ndk-someiplib)

4.延伸

基于上个git项目,其实已经能够完成单个应用内的someip通讯了,所以对于那个git项目已有的配置就不多做描述了。
但是要想与VDC或者VIU在一个局域网环境内通讯还要另外做配置。

4.1配置json文件
{
  "unicast" : "192.168.56.101",
  "netmask" : "255.255.255.0",
  "logging" : 
  {
      "level" : "debug",
      "console" : "true",
      "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" },
      "dlt" : "true"
  },
  "applications" :
  [
      {
          "name" : "World",
          "id" : "0x1314"
      }
  ],
  "clients" :
  [
      {
          "service" : "0x1234",
          "instance" : "0x5678",
          "unreliable" : [ 40000, 40002 ]
      }
  ],
  "routing" : "World",
  "service-discovery" :
  {
      "enable" : "true",
      "multicast" : "239.255.0.255",
      "port" : "30490",
      "protocol" : "udp",
      "initial_delay_min" : "10",
      "initial_delay_max" : "100",
      "repetitions_base_delay" : "200",
      "repetitions_max" : "3",
      "ttl" : "3",
      "cyclic_offer_delay" : "2000",
      "request_response_delay" : "1500"
  }
}
需要注意的几个点
1.unicast 主机地址,这个是你连上wifi后动态分配的IP地址
2.applications,这里定义你的clientId和你的项目名,注意routing和name和你调用jni函数传递的name需要保持一致,不然会找不到路由
3.clients 这里定义板子提供的serviceId,instance,和定义的端口,Client端和Service端必须对齐。否则无法订阅事件,也无法接收到单播事件
4.multicast 定义组播地址和端口号,以及一些其他配置
4.2定义配置文件的路径
      File someipConfig=new File(getCacheDir(),"demosomeip.json");
      try {
          if (someipConfig.exists()){
              someipConfig.delete();
          }
          someipConfig.createNewFile();
          writeConfigToFile(someipConfig);
      }catch (Exception e){
                 sendLog(e.toString());
      }
      try {
          Os.setenv("VSOMEIP_CONFIGURATION", someipConfig.getAbsolutePath(), true);
      } catch (ErrnoException e) {
          e.printStackTrace();
      }

 private void writeConfigToFile(File file) throws Exception {
      FileOutputStream fileOutputStream=new FileOutputStream(file);
      String value=getJson("vsomeip-udp-client.json");
      JSONObject jsonObject=new JSONObject(value);
      jsonObject.put("unicast",getIP());
      value=jsonObject.toString();
      sendLog("配置文件信息:"+value);
      byte[] bytes=value.getBytes();
      fileOutputStream.write(bytes);
      fileOutputStream.close();
  }

private String getJson(String fileName){
      StringBuffer stringBuffer=new StringBuffer();
      AssetManager assetManager=getAssets();
      try {
          BufferedReader reader=new BufferedReader(new InputStreamReader(assetManager.open(fileName)));
          String line;
          while ((line=reader.readLine())!=null){
              stringBuffer.append(line);
          }
      }catch (Exception e){

      }
      return stringBuffer.toString();
  }

5.调用函数

public void requestService(String serviceId,String instanceId) 请求服务,会回调onAvailability

public void requestEvent(String serviceId,String instanceId,String groupId,String eventId)  请求事件 

public void subscribeEventGroup(String serviceId,String instanceId,String groupId) 订阅事件组,注意订阅事件组之前务必先请求事件,不然可能会存在找不到事件组

public void sendSampleRequest(String serviceId,String instanceId,String methodId,byte[] payload) 发送RR请求
数据回调,和服务端发起的Notification都会回调
public void onMessage(int service_id, int instance_id, int method_id, int client_id, byte[] bytes)

结束

以上是Android作为client端 基于someip协议与硬件通讯的一个大致配置,本人已验证,可行,撒花~~

你可能感兴趣的:(Android基于vsomeIp3与VDC或者VIU通信)