基于车载以太网的OTA升级
一. 简介
本人就职于北京的一家汽车电子科技公司,接到了广汽的订单。22年4月份接到一个订单:广汽乘用车M8,OTA升级的开发。OTA(Over-the-Air Technology),理解的话就是:无线传输技术。本次的开发,运用到的知识包括:TCP/IP协议,DoIP协议,UDS协议,开发语言为C语言,开发环境为Linux,gcc编译,Linux环境下调试,Make文件等等。
二. 协议简述
TCP/IP协议就不说了,它是互联网通信的最常用的一个通信协议,自我20年开始工作以来,首先负责的就是网络通信这一块。
DoIP是基于TCP/IP协议的一个通信协议,协议格式如下图:
这个协议栈,是公司买的AUTOSAR的软件,可以根据需求直接在软件上进行配置,然后直接生成代码。软件如下图:
UDS协议,本次OTA开发,运用了多种协议,协议之间的关系为嵌套。UDS嵌套入DoIP协议,DoIP协议嵌入TCP协议。下图简单介绍了,何为UDS协议,UDS具体划分为哪些功能。
三. 程序流程
整个升级流程分为两个阶段,预升级阶段,升级阶段。
第一阶段,为预升级阶段,验证版本号,会话模式切换,例程控制,DTC控制设置,通信控制。
第二阶段,到了实际的升级流程。其流程图如下:
会话模式切换,秘钥申请,写入ID,下载flash driver文件,例程控制
OTA的核心部分是下面三个步骤:
#34 请求下载
#36 传输数据
#37 下载结束
四. 程序简要
所有的程序都在INVO-OTA文件下面,整体的架构为,OTA功能,在整个工程中相当于线程;编译这个程序后,会生成静态库文件.so ,供其他地方调用。
工程文件如下图左侧
lib_ota.c ota初始化部分,及与上位机直接调用的接口。程序的设计思路是,写一个结构体,结构里面包含了上位机所需要调用到的函数接口。
#include "Network_DoIP_SoAd_Sys.h"
#include "Dcm/Dcm.h"
#include "Invo_Upgrade_Flag.h"
#include "invo_ota_lib.h"static InvoOtaObj ota_obj;
static doip_config_t g_config;static INVO_OTA_DATA_CALLBACK invo_ota_lib_get_data_callback_handler();
static INVO_OTA_UDS_MSG_CALLBACK invo_ota_lib_get_uds_msg_callback_handler();bool invo_ota_lib_init(doip_config_t *config)
{if (config){g_config = *config;}else{(void)memset(&g_config, 0, sizeof(g_config));}struct bl_mesg msg;bool ret = FALSE;bzero( &ota_obj, sizeof( ota_obj ) );ota_obj.dcmflag = TRUE;ota_obj.DoIPConfigObj = 1;if(1){TcpIp_Init();SoAd_Init();DoIP_Init( &ota_obj.DoIPConfigObj );Dcm_Init( NULL );DoIP_ActivationLineSwitchActive();ota_obj.inited = TRUE;ret = TRUE;PR_ERROR( "invo lib ota init successed!." );}else{ret = FALSE;}PR_ERROR("-----------------------------------------------");PR_ERROR("version :%d", 1);PR_ERROR("-----------------------------------------------");return ret;
}void invo_ota_lib_main()
{if ( ota_obj.inited ){SoAd_MainFunction();DoIP_MainFunction();Dcm_MainFunction();usleep(5000);}
}void invo_ota_lib_deinit()
{if ( ota_obj.inited ){TcpIp_DeInit();SoAd_DeInit();Dcm_DeInit();bzero( &ota_obj, sizeof( ota_obj ) );ota_obj.dcmstart = false;ota_obj.is_data_callback_inited = false;ota_obj.is_msg_callback_inited = false;ota_obj.inited = false;}
}/*------------------------------------------------------------------------------* doip_get_path-------------------------------------------------------------------------------*/
char *doip_get_path(void)
{return g_config.download_path;
}/*------------------------------------------------------------------------------* doip_space_check-------------------------------------------------------------------------------*/
int doip_space_check(uint64_t size)
{int ret = -1;if(1) // (g_config.do_install){ret = g_config.do_space_check(size);}return ret;
}/*------------------------------------------------------------------------------* doip_do_install-------------------------------------------------------------------------------*/
void doip_do_install(char *path)
{if (g_config.do_install){g_config.do_install(path);}
}/*------------------------------------------------------------------------------* doip_write_did ***************************Start Change************************-------------------------------------------------------------------------------*/
void doip_write_did(uint16_t did, uint8_t *data, uint32_t size)
{if (g_config.do_write_did){g_config.do_write_did(did, data, size);}
}/*------------------------------------------------------------------------------* doip_read_did-------------------------------------------------------------------------------*/
void doip_read_did(uint16_t did, uint8_t *data)
{if (g_config.do_read_did){g_config.do_read_did(did, data);}
}/*------------------------------------------------------------------------------* doip_do_reboot-------------------------------------------------------------------------------*/
void doip_do_reboot(void)
{if (g_config.do_reboot){g_config.do_reboot();}
}/*------------------------------------------------------------------------------* doip_get_update_state-------------------------------------------------------------------------------*/
doip_install_state_t doip_get_update_state(void)
{if (g_config.get_update_state){return g_config.get_update_state();}return INSTALL_STATE_ERR;
}
lib_ota_lib_if.h 头文件,包含了结构体类型的函数接口,宏定义数据,ENUM变量,函数引用
#ifndef _INVO_OTA_LIB_IF_H_
#define _INVO_OTA_LIB_IF_H_#ifdef __cplusplus
extern "C" {
#endif
/*
** ===================================================================
** Include files.
** ===================================================================
*/#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>/*
** ===================================================================
** Macro definition.
** ===================================================================
*/
typedef enum
{INVO_OTA_UDS_NORMAL_MSG_PROCESS = 0x1U,INVO_OTA_UDS_ERROR_MSG_PROCESS = 0x2U,INVO_OTA_BEING_DATA_PROCESS = 0x3U,INVO_OTA_SUSPEND_DATA_PROCESS = 0x4U,INVO_OTA_FINISH_DATA_PROCESS = 0x5U
} INVO_OTA_PROCESS_STATUS;typedef enum
{OTA_LIB_CMD_NONE = 0,OTA_LIB_CMD_UDS = 1U,OTA_LIB_CMD_RESET = 2U,OTA_LIB_CMD_RESERVED
} INVO_OTA_LIB_CMD;typedef struct
{INVO_OTA_PROCESS_STATUS status;INVO_OTA_LIB_CMD cmd;int length;unsigned char* data;
} ota_lib_message_t;typedef enum
{INSTALL_STATE_NOSTART,INSTALL_STATE_RUNNING,INSTALL_STATE_OK,INSTALL_STATE_ERR,
} doip_install_state_t;typedef enum
{STATE_ACTIVATE,STATE_NEGATIVE,
} doip_activeline_state_t;typedef struct
{char download_path[128];int (*do_space_check)(uint64_t size);int (*do_install)(char *path);int (*do_write_did)(uint16_t did, uint8_t *data, uint32_t size);int (*do_read_did)(uint16_t did, uint8_t *data);void (*do_reboot)(void);doip_install_state_t (*get_update_state)(void);doip_activeline_state_t (*get_activeline_state)(void);
} doip_config_t;typedef void ( *INVO_OTA_DATA_CALLBACK )( INVO_OTA_PROCESS_STATUS status,void* data, uint32_t data_size );typedef void ( *INVO_OTA_UDS_MSG_CALLBACK )( ota_lib_message_t msg );/*
** ===================================================================
** func definition.
** ===================================================================
*/
extern bool invo_ota_lib_init(doip_config_t *config);
extern void invo_ota_lib_main();
extern void invo_ota_lib_deinit();
extern bool invo_ota_lib_get_init_flag();
extern bool invo_ota_lib_get_dcm_flag();
extern bool invo_ota_lib_get_sys_flag();
extern int invo_ota_lib_get_upgrade_flag();extern void invo_ota_lib_set_uds_msg( unsigned char* usdmsg, int len );
extern void invo_ota_lib_register_data_callback( INVO_OTA_DATA_CALLBACK callback );
extern void invo_ota_lib_register_uds_msg_callback( INVO_OTA_UDS_MSG_CALLBACK callback );extern void invo_ota_lib_SndPragramSessResp( void );
extern void invo_ota_lib_SndRespPending( void );
extern void invo_ota_lib_DoIP_SndEcuResetResp( void );
extern void invo_ota_lib_SndEcuUpgradeFailure();#ifdef __cplusplus
}
#endif /* extern "C" */#endif /* INVO_OTA_IFS_H */
#34 写文件请求
/************************************************************************************
* Name : DiagServ_RequestDownload
* Called by : DiagServ_Task
* Preconditions: None
* Parameters : None
* Return code : TRUE - Request has been accepted.
* FALSE - Request is not allowed.
* Description : Request to start a download progress.
*************************************************************************************/boolean DiagServ_RequestDownload( uint32 uiMemAddr, unsigned long int uiMemSize )
{boolean ret = FALSE;do{//PR_INF("%s ucLogicType = %d", __func__, stSocUpdateInfo.ucLogicType);if ( ( TRUE == stSocUpdateInfo.bTransDataAllowed )|| ( LOGIC_TYPE_IDLE == stSocUpdateInfo.ucLogicType )|| ( LOGIC_TYPE_ERASING == stSocUpdateInfo.ucLogicType ) ){//PR_INF("%s, break", __func__);break;}stSocUpdateInfo.bTransDataAllowed = TRUE;stSocUpdateInfo.uiMemAddr = uiMemAddr;stSocUpdateInfo.uiMemSize = uiMemSize;stSocUpdateInfo.uiDataIdx = 0U;stSocUpdateInfo.uiDataLen = 0U;stSocUpdateInfo.ucSectionIdx = 0U;Dcm_WriteFileReq(uiMemSize);if ( LOGIC_TYPE_SOC_DRV == stSocUpdateInfo.ucLogicType ){PR_INF("LOGIC_TYPE_SOC_DRV == stSocUpdateInfo.ucLogicType");ret = TRUE;}else if ( LOGIC_TYPE_SOC_APP == stSocUpdateInfo.ucLogicType ){PR_INF("LOGIC_TYPE_SOC_APP == stSocUpdateInfo.ucLogicType");ret = TRUE;}else{//PR_INF("ret = FALSE");ret = FALSE;}}while ( 0 );if ( FALSE == ret ){_ClrSocUpdateInfo();}return ( ret );
}
#36 文件传输数据
/************************************************************************************
* Name : DiagServ_TransferData
* Called by : DiagServ_ProgramTask
* Preconditions: None
* Parameters : None
* Return code : None
* Description : Transfer data request, write data into RAM or FLASH.
*************************************************************************************/
boolean DiagServ_TransferData( uint8 ucSectionIdx, uint16 usDateSize, uint8* pucData )
{boolean ret = FALSE;//PR_INF("%s ucLogicType = %d************************", __func__, stSocUpdateInfo.ucLogicType);do{if ( ( FALSE == stSocUpdateInfo.bTransDataAllowed )|| ( usDateSize > TRANS_DATA_LEN_MAX )|| ( ucSectionIdx != ( stSocUpdateInfo.ucSectionIdx + 1 ) )|| ( ( stSocUpdateInfo.uiDataLen + usDateSize ) > stSocUpdateInfo.uiMemSize ) ){if ( stSocUpdateInfo.ucSectionIdx == 0xFF ){stSocUpdateInfo.ucSectionIdx = 0x01;}else{PR_DEBUG( 1U, " SOC condition falied! %d %d \n", usDateSize, stSocUpdateInfo.ucSectionIdx );break;}}stSocUpdateInfo.ucSectionIdx = ucSectionIdx;Ethernet_OTA_MemcpytoShmBufferData( &stSocUpdateInfo.ucDataBuffer, pucData, usDateSize );PR_DEBUG( 0U, "usDateSize:%u.\n", usDateSize );//uiCurrMemAddr = stSocUpdateInfo.uiMemAddr + stSocUpdateInfo.uiDataIdx;stSocUpdateInfo.uiDataIdx += usDateSize;stSocUpdateInfo.uiDataLen += usDateSize;stSocUpdateInfo.uiOldCrc32 = GetCrc32( stSocUpdateInfo.ucDataBuffer, usDateSize, stSocUpdateInfo.uiOldCrc32 );switch ( stSocUpdateInfo.ucLogicType ){case LOGIC_TYPE_SOC_DRV:{ret = TRUE;stSocUpdateInfo.count = 1;break;}case LOGIC_TYPE_SOC_APP:{if ( stSocUpdateInfo.count == 1 ){stSocUpdateInfo.count = 0;}//Ethernet_OTA_ProcessUpgradeData( stSocUpdateInfo.ucDataBuffer, usDateSize );Dcm_WriteDataToFile(stSocUpdateInfo.ucDataBuffer, usDateSize);ret = TRUE;break;}default:{PR_DEBUG( 1U, "SOC default falied! %d %d \n", usDateSize, stSocUpdateInfo.ucSectionIdx );break;}}}while ( 0 );if ( FALSE == ret ){_ClrSocUpdateInfo();}return ( ret );
}
#37 传输结束
/************************************************************************************
* Name : DiagServ_TransferExit
* Called by : DiagServ_ProgramTask
* Preconditions: None
* Parameters : None
* Return code : None
* Description : Transfer data end, new transfer request can be allowed.
*************************************************************************************/
boolean DiagServ_TransferExit( void )
{PR_INF(" %s start...", __func__);uint8 crc = 1;boolean ret = FALSE;do{PR_DEBUG( 0, "%s \n", __func__ );PR_DEBUG( 0, "%ld %ld \n", stSocUpdateInfo.uiDataLen, stSocUpdateInfo.uiMemSize );PR_INF("bTransDataAllowed %ld ", stSocUpdateInfo.bTransDataAllowed);// PR_INF("stSocUpdateInfo.uiDataLen = %ld uiMemSize %ld \n", stSocUpdateInfo.uiDataLen, stSocUpdateInfo.uiMemSize);if ( ( FALSE == stSocUpdateInfo.bTransDataAllowed )|| ( stSocUpdateInfo.uiDataLen != stSocUpdateInfo.uiMemSize )){PR_INF(" %s, break ", __func__);break;}stSocUpdateInfo.bTransDataAllowed = FALSE;if ( LOGIC_TYPE_SOC_DRV == stSocUpdateInfo.ucLogicType ){PR_INF("LOGIC_TYPE_SOC_DRV == stSocUpdateInfo.ucLogicType ");stSocUpdateInfo.ucLogicType = LOGIC_TYPE_ERASING;}else{//Ethernet_OTA_FinishUpgradeProcessing();Dcm_WriteFileEnd(&crc);PR_INF("%s else ",__func__);}ret = TRUE;PR_INF(" %s ret = TRUE", __func__);}while ( 0 );if ( FALSE == ret ){_ClrSocUpdateInfo();}PR_INF(" %s end...", __func__);return ( ret );
}
代码部分太多了,这里就不介绍了。
五. 总结
这个项目开发了三,四个月,并且后期也一直在维护。期间还去广州广汽研究院那边出过一次差。期间遇到了很多问题,比如需要找人协调调试设备,需要跟测试部沟通,然他们编写测试程序,需要组织讨论问题的解决方案;自己出差的时候要在实车上进行调试程序,需要给甲方讲解清问题原因,问题的解决方案等等。
这是我毕业两年多来,做的最有成就感的一个项目。
基于车载以太网的OTA升级相关推荐
- 车载以太网时间同步之EthTsync
车载以太网时间同步之EthTsync 前言 首先,请问大家几个小小问题,你清楚: 你知道EthTsync模块的主要作用是什么吗? EthTsync模块与其他AUTOSAR基础软件模块交互关系: Eth ...
- 基于AUTOSAR的车载以太网通信技术与实现
随着处理器运算能力和硬件的高速发展,汽车整车功能越来越多.越来越强.鉴于 ADAS 技术.高品质车载娱乐以及 OTA 远程升级等新增功能的需求,使得 ECU 的网络带宽需求也呈现爆发式增长.这一需求超 ...
- 乐鑫esp8266基于freeRtos实现私有服务器本地远程OTA升级
代码地址如下: http://www.demodashi.com/demo/13533.html 文章目录 一.前言: 二.回顾下`OTA`的流程: 三.`lwip`网络框架的知识的使用: 四.如何处 ...
- 基于 Marvell 88Q2112 车载以太网 物理层收发器
Marvell 88Q2112 车载以太网 物理层收发器 介绍 88Q2112 是一款基于 IEEE 802.3bw 和 IEEE 802.3bp 定义的 100/1000BASE-T1 以太网物理层 ...
- 基于OSI模型的车载以太网
一. 车载以太网是汽车内部使用的网络连接技术,支持各个电子设备之间的传输和通信. 车载以太网的实现功能:娱乐系统.导航系统.车辆诊断维护.驾驶辅助. 车载以太网较传统以太网的差异:根据使用环境,车载以 ...
- 乐鑫esp8266学习rtos3.0笔记第6篇:esp8266-12模块基于rtos3.1版本ota功能远程空中升级固件,官网之上增加dns域名解析!(附带demo)
本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个"hello ...
- Android 系统 '七夕'巨献 VIVO Xplay 基于ViVo官方稳定内核,完美root,适度美化,降噪点,完美支持官方OTA升级
ROM版本 VIVO-Xplay-PD2.13.2 ROM作者 大盛 http://weibo.com/DaShengdd Android版本 Android4.2.2 创建日期 2013.08.13 ...
- 车载以太网会是传统总线的末路吗?
今天我们不聊高深的技术问题,怿星带大家看看车载以太网是怎么走到今天的. 2013年宝马X5的正式量产标志着以太网正式进入到车载领域,粗略计算已有7年的时间,它究竟有什么魔力让我们一个又一个的汽车人前赴 ...
- AUTOSAR OTA升级
一.OTA技术概念 随着高级辅助驾驶的发展和自动驾驶的引入,汽车变得越来越智能,这些智能汽车被软件控制,装有巨量的软件程序,当出现一个软件程序问题或者更新时,如果 按照传统的解决方式 ,那都将是一项很 ...
最新文章
- python中的运算符举例_举例讲解Python中的身份运算符的使用方法
- 你的Windows电脑里有哪些效率翻倍的生产力软件?
- python爬虫可视化界面_python爬虫---垃圾分类可视化界面
- solrcloud集群搭建
- Linux下根据进程ID查看进程文件的路径
- ymodem协议c语言,STC单片机ISP-Demo-使用Y-Modem协议源码与库函数分享
- SVM基本思想及入门学习(转载+自己解释为什么minL(w)变成minmaxL(a,w))
- DataView的ToTable方法,类似数据库Distinct。
- 浅入浅出 Android 安全:第五章 Android 应用层安全
- 浅析SQL SERVER执行计划中的各类怪相
- 如何用MobaXterm查看日志信息以及xml
- 微软测试新工具:让Windows 10和Android设备文件同步更方便
- 分页组件change_javascript原生瀑布流+图片懒加载组件
- TML5 App 开发框架收集
- Java基础教程【第五章:Java数组】
- python自动检测网站_Web全自动化测试Python + Pytest+Selenium+ Saucelabs 转
- Hadoop的shell命令
- sublime使用LiveReload自动刷新
- 华为云文字识别服务关键技术、能力和产品落地需要注意的事宜(OCR系列二)
- 科普 | 金融衍生品系列——互换