From 582499595efd37cd6ab67540648b49223ae939ba Mon Sep 17 00:00:00 2001 From: xinfengkun Date: Mon, 22 Dec 2025 14:59:53 +0800 Subject: [PATCH] =?UTF-8?q?[8.3.0]=20FSM=20Event=E6=B6=88=E6=81=AF=20?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E8=B5=B7=E8=87=AA=E9=A9=BE=E5=92=8C=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E6=8E=A8=E8=87=AA=E9=A9=BE=E6=B6=88=E6=81=AF=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=88=B0=E6=B6=88=E6=81=AF=E7=9B=92=E5=AD=90=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../autopilot/adapter/MoGoAdasListenerImpl.kt | 11 + .../eagle/core/function/msgbox/DataManager.kt | 2 +- .../badcase/BadCaseManager.kt | 4 +- .../hmi/bone/tab/adapter/MsgBoxTabAdapter.kt | 357 +++++++++++------- .../hmi/ui/msgbox/DriverMsgBoxBubbleView.kt | 110 +++--- .../hmi/ui/msgbox/DriverMsgBoxListView.kt | 9 +- .../function/hmi/ui/msgbox/MsgBoxToastView.kt | 111 +++--- .../ui/msgbox/adapter/MsgBoxToastAdapter.kt | 14 +- .../drawable-xhdpi/icon_warning_fsm_event.png | Bin 0 -> 15127 bytes .../src/main/res/layout/view_msg_box_tab.xml | 4 +- .../src/main/res/values-en/strings.xml | 2 +- .../src/main/res/values/strings.xml | 2 +- .../core/data/deva/chain/ChainConstant.kt | 1 + .../eagle/core/data/msgbox/FSMEventMsg.kt | 14 + .../mogo/eagle/core/data/msgbox/MsgBoxType.kt | 2 +- .../api/autopilot/IMoGoFsm2024Listener.kt | 3 + .../autopilot/CallerFsm2024ListenerManager.kt | 85 ++++- .../src/main/res/values-en/string.xml | 3 + .../src/main/res/values/string.xml | 3 + .../zhjt/mogo/adas/common/MessageType.java | 1 + .../src/main/proto/fsm2024.proto | 54 ++- .../src/main/proto/message_pad.proto | 1 + .../src/main/res/values-en/strings.xml | 1 + .../src/main/res/values/strings.xml | 1 + .../support/adas/high/OnAdasListener.java | 8 + .../adas/high/msg/FSMEventMessage.java | 30 ++ .../adas/high/msg/MyMessageFactory.java | 7 + 27 files changed, 569 insertions(+), 271 deletions(-) create mode 100644 core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_warning_fsm_event.png create mode 100644 core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/FSMEventMsg.kt create mode 100644 libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/FSMEventMessage.java diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt index 27de31e663..bd958f8055 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt @@ -17,6 +17,7 @@ import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_AD import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_CAR_LOC import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_COLD_START_STATE import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_FM_MSG +import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_FSM_EVENT_MSG import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_FSM_MSG import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_GUARDIAN import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_MAP_PARAM @@ -884,6 +885,16 @@ class MoGoAdasListenerImpl : OnAdasListener { updateAutoPilotStatus(2, state, mode) } + @ChainLog( + linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT, + linkCode = CHAIN_SOURCE_ADAS, + nodeAliasCode = CHAIN_CODE_ADAS_FSM_EVENT_MSG, + paramIndexes = [0, 1] + ) + override fun onFSMEvent(header: MessagePad.Header, fsmEventMsg: Fsm2024.FsmEventMsg) { + CallerFsm2024ListenerManager.invokeFSMEvent(fsmEventMsg) + } + /** * 定位状态 * 定位呈现状态透传 用于pad图标显示 1hz 所有车型MAP440开始支持 diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/msgbox/DataManager.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/msgbox/DataManager.kt index 16c19b6505..2ea8487af0 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/msgbox/DataManager.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/msgbox/DataManager.kt @@ -141,7 +141,7 @@ object DataManager { CallerMsgBoxListenerManager.invokeListener(MsgCategory.NOTICE, msg) } - MsgBoxType.FMINFO -> { + MsgBoxType.FSM_EVENT, MsgBoxType.FMINFO -> { synchronized(this) { fmInfoList.add(msg) } diff --git a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt index 6f9010aa76..4a559b86b4 100644 --- a/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt +++ b/core/function-impl/mogo-core-function-devatools/src/main/java/com/zhjt/mogo_core_function_devatools/badcase/BadCaseManager.kt @@ -592,7 +592,9 @@ internal object BadCaseManager : LifecycleEventObserver, IMoGoAutopilotRecordLis } }else if(category == MsgCategory.FM_INFO){ //FM - BadCaseConfig.newFMInfoMsg = msgBoxList.bean as FMInfoMsg + if (msgBoxList.type== MsgBoxType.FMINFO) { + BadCaseConfig.newFMInfoMsg = msgBoxList.bean as FMInfoMsg + } } } diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/adapter/MsgBoxTabAdapter.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/adapter/MsgBoxTabAdapter.kt index 36fab10ca1..5c62bac1ce 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/adapter/MsgBoxTabAdapter.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/adapter/MsgBoxTabAdapter.kt @@ -50,6 +50,7 @@ class MsgBoxTabAdapter(private val activity: Activity) : private val nde = 22 //NDE消息车龙 private val ota = 23 //OTA升级消息 private val cloud = 24 //云控基础平台 + private val fsmEvent = 25 private val none = -1 @@ -165,6 +166,11 @@ class MsgBoxTabAdapter(private val activity: Activity) : .inflate(R.layout.item_tab_cloud,parent,false) return MsgBoxCloud(view) } + fsmEvent -> { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_tab_fm,parent,false) + return FSMEventInfoHolder(view) + } //V2X消息 else -> { val view = LayoutInflater.from(parent.context) @@ -202,170 +208,176 @@ class MsgBoxTabAdapter(private val activity: Activity) : //FM信息 is FmInfoHolder -> { data?.let { - val fmInfoMsg = it[position].bean as FMInfoMsg - //时间显示 - holder.tvFmTime.text = + val temp = it[position] + if (temp.type == MsgBoxType.FMINFO) { + val fmInfoMsg = temp.bean as FMInfoMsg + //时间显示 + holder.tvFmTime.text = // "时间:${fmInfoMsg.policyTime?.let { it1 -> TimeUtils.millis2String(it1) }}" - "${StringUtils.getString(R.string.module_core_time)}${fmInfoMsg.policyTime?.let { it1 -> TimeUtils.millis2String(it1) }}" - //建议操作 - if(fmInfoMsg.fmInfoList.isNullOrEmpty()){ - //建议操作暂无 + "${StringUtils.getString(R.string.module_core_time)}${fmInfoMsg.policyTime?.let { it1 -> TimeUtils.millis2String(it1) }}" + //建议操作 + if (fmInfoMsg.fmInfoList.isNullOrEmpty()) { + //建议操作暂无 // holder.tvFmAction.text = "建议操作:暂无" - holder.tvFmAction.text = StringUtils.getString(R.string.module_core_suggested_procedure_not_available) - //Title -// holder.tvFmTitle.text = "暂无建议操作" - holder.tvFmTitle.text = StringUtils.getString(R.string.module_core_not_available_suggested_procedure) - }else{ - val receiveFaultLevel = ArrayList() - fmInfoMsg.fmInfoList!!.forEach { info -> - if(info.faultActionCount != 0){ - info.faultActionList.forEach { action -> - //如果不包含此故障Level,则进行添加 - if(!receiveFaultLevel.contains(MsgFmData.FaultAction.getFaultLevel(action))){ - receiveFaultLevel.add(MsgFmData.FaultAction.getFaultLevel(action)) - } - } - } - } - //对faultLevel集合进行排序,按照顺序输出建议操作 - if(receiveFaultLevel.size > 0){ - val faultActionStr: StringBuilder = StringBuilder() -// faultActionStr.append("建议操作:") - faultActionStr.append(StringUtils.getString(R.string.module_core_suggested_procedure)) - receiveFaultLevel.sort() -// receiveFaultLevel.reverse() - //Title - holder.tvFmTitle.text = MsgFmData.FaultAction.getFaultTitle(receiveFaultLevel[0]) - //不同级别的Icon显示 - when(receiveFaultLevel[0]){ - 0->{ - //重度预警样式 - holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_severe_warning)) - } - 1,2,3->{ - //中度预警样式 - holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_moderate_warning)) - } - 4,5->{ - //轻度预警样式 - holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_mild_warning)) - } - } - receiveFaultLevel.forEach {level-> - if(MsgFmData.FaultAction.getFaultAction(level).isNotBlank()){ - faultActionStr.append(MsgFmData.FaultAction.getFaultAction(level)) - } - if(MsgFmData.FaultAction.getFaultActionCode(level).isNotBlank()){ - faultActionStr.append("(") - faultActionStr.append(MsgFmData.FaultAction.getFaultActionCode(level)) - faultActionStr.append(")") - } - if(MsgFmData.FaultAction.getFaultAction(level).isNotBlank() || MsgFmData.FaultAction.getFaultActionCode(level).isNotBlank()){ - faultActionStr.append(";") - } - } - if(faultActionStr.length > 5){ - if(faultActionStr.endsWith(";")){ - faultActionStr.deleteCharAt(faultActionStr.lastIndex) - } - holder.tvFmAction.text = faultActionStr.toString() - }else{ -// holder.tvFmAction.text = "建议操作:暂无" - holder.tvFmAction.text = StringUtils.getString(R.string.module_core_suggested_procedure_not_available) - } - }else{ -// holder.tvFmAction.text = "建议操作:暂无" holder.tvFmAction.text = StringUtils.getString(R.string.module_core_suggested_procedure_not_available) - //轻度预警样式 - holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_mild_warning)) - } - } - //故障策略 -// holder.tvFmFault.text = "故障策略:${MsgFmData.getFmPolicyName(fmInfoMsg.policyCode)}(${fmInfoMsg.policyCode})" - holder.tvFmFault.text = "${StringUtils.getString(R.string.module_core_fault_handling_strategy)}${MsgFmData.getFmPolicyName(fmInfoMsg.policyCode)}(${fmInfoMsg.policyCode})" - //故障原因 - if(fmInfoMsg.fmInfoList.isNullOrEmpty()){ -// holder.tvFmReason.text = "故障原因:暂无" - holder.tvFmReason.text = StringUtils.getString(R.string.module_core_failure_cause_not_available) - }else{ - val fmFaultReason = StringBuilder() -// fmFaultReason.append("故障原因:") - fmFaultReason.append(StringUtils.getString(R.string.module_core_failure_cause)) - for((index,info) in fmInfoMsg.fmInfoList!!.withIndex()){ - fmFaultReason.append(info.faultName) - if(info.faultId.isNotBlank()){ - fmFaultReason.append("(") - fmFaultReason.append(info.faultId) - fmFaultReason.append(")") - } - if(index!=(fmInfoMsg.fmInfoList!!.size-1)){ - fmFaultReason.append("/") - } - } - holder.tvFmReason.text = fmFaultReason.toString() - } - //故障后果 - if(fmInfoMsg.fmInfoList.isNullOrEmpty()){ -// holder.tvFmResult.text = "故障后果:暂无" - holder.tvFmResult.text = StringUtils.getString(R.string.module_core_consequences_failure_not_available) - }else{ - val fmFaultResult = StringBuilder() -// fmFaultResult.append("故障后果:") - fmFaultResult.append(StringUtils.getString(R.string.module_core_consequences_failure)) - fmInfoMsg.fmInfoList!!.forEach { info-> - if(info.faultResultCount != 0){ - info.faultResultList.forEach { result-> - if(MsgFmData.FaultResult.getResultDefine(result).isNotBlank()){ - fmFaultResult.append(MsgFmData.FaultResult.getResultDefine(result)) - } - if(result.isNotBlank()){ - fmFaultResult.append("(") - fmFaultResult.append(result) - fmFaultResult.append(")") - } - if(MsgFmData.FaultResult.getResultDefine(result).isNotBlank() || result.isNotBlank()){ - fmFaultResult.append("/") + //Title +// holder.tvFmTitle.text = "暂无建议操作" + holder.tvFmTitle.text = StringUtils.getString(R.string.module_core_not_available_suggested_procedure) + } else { + val receiveFaultLevel = ArrayList() + fmInfoMsg.fmInfoList!!.forEach { info -> + if (info.faultActionCount != 0) { + info.faultActionList.forEach { action -> + //如果不包含此故障Level,则进行添加 + if (!receiveFaultLevel.contains(MsgFmData.FaultAction.getFaultLevel(action))) { + receiveFaultLevel.add(MsgFmData.FaultAction.getFaultLevel(action)) + } } } } + //对faultLevel集合进行排序,按照顺序输出建议操作 + if (receiveFaultLevel.size > 0) { + val faultActionStr: StringBuilder = StringBuilder() +// faultActionStr.append("建议操作:") + faultActionStr.append(StringUtils.getString(R.string.module_core_suggested_procedure)) + receiveFaultLevel.sort() +// receiveFaultLevel.reverse() + //Title + holder.tvFmTitle.text = MsgFmData.FaultAction.getFaultTitle(receiveFaultLevel[0]) + //不同级别的Icon显示 + when (receiveFaultLevel[0]) { + 0 -> { + //重度预警样式 + holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_severe_warning)) + } + + 1, 2, 3 -> { + //中度预警样式 + holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_moderate_warning)) + } + + 4, 5 -> { + //轻度预警样式 + holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_mild_warning)) + } + } + receiveFaultLevel.forEach { level -> + if (MsgFmData.FaultAction.getFaultAction(level).isNotBlank()) { + faultActionStr.append(MsgFmData.FaultAction.getFaultAction(level)) + } + if (MsgFmData.FaultAction.getFaultActionCode(level).isNotBlank()) { + faultActionStr.append("(") + faultActionStr.append(MsgFmData.FaultAction.getFaultActionCode(level)) + faultActionStr.append(")") + } + if (MsgFmData.FaultAction.getFaultAction(level).isNotBlank() || MsgFmData.FaultAction.getFaultActionCode(level).isNotBlank()) { + faultActionStr.append(";") + } + } + if (faultActionStr.length > 5) { + if (faultActionStr.endsWith(";")) { + faultActionStr.deleteCharAt(faultActionStr.lastIndex) + } + holder.tvFmAction.text = faultActionStr.toString() + } else { +// holder.tvFmAction.text = "建议操作:暂无" + holder.tvFmAction.text = StringUtils.getString(R.string.module_core_suggested_procedure_not_available) + } + } else { +// holder.tvFmAction.text = "建议操作:暂无" + holder.tvFmAction.text = StringUtils.getString(R.string.module_core_suggested_procedure_not_available) + //轻度预警样式 + holder.ivFmImage.setImageDrawable(getDrawable(R.drawable.icon_fm_mild_warning)) + } } - if(fmFaultResult.endsWith("/")){ - holder.tvFmResult.text = fmFaultResult.deleteCharAt(fmFaultResult.lastIndex).toString() - }else{ -// holder.tvFmResult.text = "故障后果:暂无" + //故障策略 +// holder.tvFmFault.text = "故障策略:${MsgFmData.getFmPolicyName(fmInfoMsg.policyCode)}(${fmInfoMsg.policyCode})" + holder.tvFmFault.text = + "${StringUtils.getString(R.string.module_core_fault_handling_strategy)}${MsgFmData.getFmPolicyName(fmInfoMsg.policyCode)}(${fmInfoMsg.policyCode})" + //故障原因 + if (fmInfoMsg.fmInfoList.isNullOrEmpty()) { +// holder.tvFmReason.text = "故障原因:暂无" + holder.tvFmReason.text = StringUtils.getString(R.string.module_core_failure_cause_not_available) + } else { + val fmFaultReason = StringBuilder() +// fmFaultReason.append("故障原因:") + fmFaultReason.append(StringUtils.getString(R.string.module_core_failure_cause)) + for ((index, info) in fmInfoMsg.fmInfoList!!.withIndex()) { + fmFaultReason.append(info.faultName) + if (info.faultId.isNotBlank()) { + fmFaultReason.append("(") + fmFaultReason.append(info.faultId) + fmFaultReason.append(")") + } + if (index != (fmInfoMsg.fmInfoList!!.size - 1)) { + fmFaultReason.append("/") + } + } + holder.tvFmReason.text = fmFaultReason.toString() + } + //故障后果 + if (fmInfoMsg.fmInfoList.isNullOrEmpty()) { +// holder.tvFmResult.text = "故障后果:暂无" holder.tvFmResult.text = StringUtils.getString(R.string.module_core_consequences_failure_not_available) + } else { + val fmFaultResult = StringBuilder() +// fmFaultResult.append("故障后果:") + fmFaultResult.append(StringUtils.getString(R.string.module_core_consequences_failure)) + fmInfoMsg.fmInfoList!!.forEach { info -> + if (info.faultResultCount != 0) { + info.faultResultList.forEach { result -> + if (MsgFmData.FaultResult.getResultDefine(result).isNotBlank()) { + fmFaultResult.append(MsgFmData.FaultResult.getResultDefine(result)) + } + if (result.isNotBlank()) { + fmFaultResult.append("(") + fmFaultResult.append(result) + fmFaultResult.append(")") + } + if (MsgFmData.FaultResult.getResultDefine(result).isNotBlank() || result.isNotBlank()) { + fmFaultResult.append("/") + } + } + } + } + if (fmFaultResult.endsWith("/")) { + holder.tvFmResult.text = fmFaultResult.deleteCharAt(fmFaultResult.lastIndex).toString() + } else { +// holder.tvFmResult.text = "故障后果:暂无" + holder.tvFmResult.text = StringUtils.getString(R.string.module_core_consequences_failure_not_available) + } } - } - //对布局进行展开折叠操作 - if(fmInfoMsg.isShow){ + //对布局进行展开折叠操作 + if (fmInfoMsg.isShow) { // holder.tvFmShowStatus.text = "收起" - holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_pack_up) - holder.tvFmFault.visibility = View.VISIBLE - holder.tvFmReason.visibility = View.VISIBLE - holder.tvFmResult.visibility = View.VISIBLE - }else{ -// holder.tvFmShowStatus.text = "展开" - holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_unfold) - holder.tvFmFault.visibility = View.GONE - holder.tvFmReason.visibility = View.GONE - holder.tvFmResult.visibility = View.GONE - } - holder.tvFmShowStatus.setOnClickListener{ - if(!fmInfoMsg.isShow){ - fmInfoMsg.isShow = true -// holder.tvFmShowStatus.text = "收起" holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_pack_up) holder.tvFmFault.visibility = View.VISIBLE holder.tvFmReason.visibility = View.VISIBLE holder.tvFmResult.visibility = View.VISIBLE - }else{ - fmInfoMsg.isShow = false -// holder.tvFmShowStatus.text = "展开" + } else { +// holder.tvFmShowStatus.text = "展开" holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_unfold) holder.tvFmFault.visibility = View.GONE holder.tvFmReason.visibility = View.GONE holder.tvFmResult.visibility = View.GONE } + holder.tvFmShowStatus.setOnClickListener { + if (!fmInfoMsg.isShow) { + fmInfoMsg.isShow = true +// holder.tvFmShowStatus.text = "收起" + holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_pack_up) + holder.tvFmFault.visibility = View.VISIBLE + holder.tvFmReason.visibility = View.VISIBLE + holder.tvFmResult.visibility = View.VISIBLE + } else { + fmInfoMsg.isShow = false +// holder.tvFmShowStatus.text = "展开" + holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_unfold) + holder.tvFmFault.visibility = View.GONE + holder.tvFmReason.visibility = View.GONE + holder.tvFmResult.visibility = View.GONE + } + } } } } @@ -627,6 +639,47 @@ class MsgBoxTabAdapter(private val activity: Activity) : holder.tvCloudTime.text = TimeUtils.millis2String(it[position].timestamp,getHourMinFormat()) } } + is FSMEventInfoHolder -> { + data?.let { + val temp = it[position] + if (temp.type == MsgBoxType.FSM_EVENT) { + holder.ivFmImage.setImageResource(R.drawable.icon_warning_fsm_event) + holder.tvFmReason.visibility = View.GONE + holder.tvFmResult.visibility = View.GONE + holder.tvFmFault.visibility = View.GONE + val fsmEventMsg = temp.bean as FSMEventMsg + //时间显示 + holder.tvFmTime.text = + "${StringUtils.getString(R.string.module_core_time)}${fsmEventMsg.timestamp.let { it1 -> TimeUtils.millis2String(it1) }}" + + holder.tvFmTitle.text = fsmEventMsg.title + holder.tvFmShowStatus.visibility = if (fsmEventMsg.content.contains(';') || fsmEventMsg.content.contains(';')) View.VISIBLE else View.GONE + //对布局进行展开折叠操作 + if (fsmEventMsg.isShow) { +// holder.tvFmShowStatus.text = "收起" + holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_pack_up) + holder.tvFmAction.text = StringUtils.getString(R.string.module_core_failure_cause) + fsmEventMsg.content + } else { +// holder.tvFmShowStatus.text = "展开" + holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_unfold) + holder.tvFmAction.text = StringUtils.getString(R.string.module_core_failure_cause) + fsmEventMsg.summaryContent + } + holder.tvFmShowStatus.setOnClickListener { + if (!fsmEventMsg.isShow) { + fsmEventMsg.isShow = true +// holder.tvFmShowStatus.text = "收起" + holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_pack_up) + holder.tvFmAction.text = StringUtils.getString(R.string.module_core_failure_cause) + fsmEventMsg.content + } else { + fsmEventMsg.isShow = false +// holder.tvFmShowStatus.text = "展开" + holder.tvFmShowStatus.text = StringUtils.getString(R.string.module_core_unfold) + holder.tvFmAction.text = StringUtils.getString(R.string.module_core_failure_cause) + fsmEventMsg.summaryContent + } + } + } + } + } } } @@ -677,6 +730,8 @@ class MsgBoxTabAdapter(private val activity: Activity) : cloud } else if(data!![position].type == MsgBoxType.V2X || data!![position].type == MsgBoxType.OBU){ v2x + }else if (data!![position].type == MsgBoxType.FSM_EVENT){ + fsmEvent } else { none } @@ -805,5 +860,15 @@ class MsgBoxTabAdapter(private val activity: Activity) : var tvCloudTime: TextView = itemView.findViewById(R.id.tvCloudTime) var tvCloudContent: TextView = itemView.findViewById(R.id.tvCloudContent) } - + //FSM Evet + class FSMEventInfoHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ + var ivFmImage: ImageView = itemView.findViewById(R.id.ivFmImage) //故障级别图标 + var tvFmTitle: TextView = itemView.findViewById(R.id.tvFmTitle) //标题展示故障策略 + var tvFmShowStatus: TextView = itemView.findViewById(R.id.tvFmShowStatus) //折叠状态 + var tvFmTime: TextView = itemView.findViewById(R.id.tvFmTime) //发生时间 + var tvFmAction: TextView = itemView.findViewById(R.id.tvFmAction) //建议操作 + var tvFmFault: TextView = itemView.findViewById(R.id.tvFmFault) //故障策略 + var tvFmReason: TextView = itemView.findViewById(R.id.tvFmReason) //故障原因 + var tvFmResult: TextView = itemView.findViewById(R.id.tvFmResult) //后果 + } } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxBubbleView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxBubbleView.kt index 2158333f0d..363830485b 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxBubbleView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxBubbleView.kt @@ -154,8 +154,9 @@ class DriverMsgBoxBubbleView @JvmOverloads constructor( } } } else if (category == MsgCategory.FM_INFO) { - CallerMsgBoxEventListenerManager.invokeUpdateTipListener(true) - if (FunctionBuildConfig.isTakeoverRemind) { + if (msgBoxBean.type == MsgBoxType.FMINFO) { + CallerMsgBoxEventListenerManager.invokeUpdateTipListener(true) + if (FunctionBuildConfig.isTakeoverRemind) { // //属于停车警示(包括择机靠边停车、立即舒适停车、就地紧急停车)时,需要弹出消息气泡并伴有提示音 // var curFaultLevel = 5 //默认级别,遍历数组找出级别最高的(level数越小,级别越高) @@ -192,64 +193,63 @@ class DriverMsgBoxBubbleView @JvmOverloads constructor( // } // } - /** - * 8.2.0需求:定义三种不同提示强度的异常提示交互 - * 不判断驾驶状态,发生相应故障时立即有相应的提醒 - * 若同一时间触发多个多种级别异常,则按照最高级别的异常交互元素做提醒,低级别的异常不做特殊提醒 - * 若同一时间触发多个同一级别异常,则同一时刻只提醒一次,不互相打断 - * 除此以外不做其他提示频率限制 - * - * 一级:安全停车 - * FM_DP_EMERGENCY_STOP(就地紧急停车)、FM_DP_COMFORTABLE_STOP(立刻舒适停车)、FM_DP_PNC_CHOOSE_STOP(择机靠边停车) - * 交互:图像、TTS、消息盒子 - * - * 二级:降速行驶 - * FM_DP_SPEED_LIMIT3(三级降速)、FM_DP_SPEED_LIMIT2(二级降速)、FM_DP_SPEED_LIMIT1(一级降速) - * 交互:TTS、消息盒子 - * - * 三级:无操作 - * FM_DP_ONLY_WARNING(警示)、FM_DP_NO_ACTION(报告) - * ps:以上异常提醒受司机屏工具箱-运营面板-美化模式-接管提醒开关控制,默认开启有全量提示,关闭后无语音/图像提示,只有消息盒子红点展示 - */ - val fmInfoMsg = msgBoxBean.bean as FMInfoMsg - when(MsgFmData.getFmPolicyLevel(fmInfoMsg.policyCode)){ - //一级 - MsgFmData.LEVEL_ONE->{ - //接管图像提示、语音提示 - CallerDevaToolsManager.takeOver(TAKE_OVER_REQUEST) - CallerHmiManager.warningV2X( - EventTypeEnumNew.TAKE_OVER_EVENT.poiType, - EventTypeEnumNew.TAKE_OVER_EVENT.content, + /** + * 8.2.0需求:定义三种不同提示强度的异常提示交互 + * 不判断驾驶状态,发生相应故障时立即有相应的提醒 + * 若同一时间触发多个多种级别异常,则按照最高级别的异常交互元素做提醒,低级别的异常不做特殊提醒 + * 若同一时间触发多个同一级别异常,则同一时刻只提醒一次,不互相打断 + * 除此以外不做其他提示频率限制 + * + * 一级:安全停车 + * FM_DP_EMERGENCY_STOP(就地紧急停车)、FM_DP_COMFORTABLE_STOP(立刻舒适停车)、FM_DP_PNC_CHOOSE_STOP(择机靠边停车) + * 交互:图像、TTS、消息盒子 + * + * 二级:降速行驶 + * FM_DP_SPEED_LIMIT3(三级降速)、FM_DP_SPEED_LIMIT2(二级降速)、FM_DP_SPEED_LIMIT1(一级降速) + * 交互:TTS、消息盒子 + * + * 三级:无操作 + * FM_DP_ONLY_WARNING(警示)、FM_DP_NO_ACTION(报告) + * ps:以上异常提醒受司机屏工具箱-运营面板-美化模式-接管提醒开关控制,默认开启有全量提示,关闭后无语音/图像提示,只有消息盒子红点展示 + */ + val fmInfoMsg = msgBoxBean.bean as FMInfoMsg + when (MsgFmData.getFmPolicyLevel(fmInfoMsg.policyCode)) { + //一级 + MsgFmData.LEVEL_ONE -> { + //接管图像提示、语音提示 + CallerDevaToolsManager.takeOver(TAKE_OVER_REQUEST) + CallerHmiManager.warningV2X( + EventTypeEnumNew.TAKE_OVER_EVENT.poiType, + EventTypeEnumNew.TAKE_OVER_EVENT.content, // "识别车辆故障,建议安全停车并查看操作建议", - StringUtils.getString(R.string.module_core_warning_vehicle_fault_safe_park), - object : IMoGoWarningStatusListener { - override fun onShow() { - CallerTakeOverManager.invokeTakeOverEvent(true) - } + StringUtils.getString(R.string.module_core_warning_vehicle_fault_safe_park), + object : IMoGoWarningStatusListener { + override fun onShow() { + CallerTakeOverManager.invokeTakeOverEvent(true) + } - override fun onDismiss() { - CallerTakeOverManager.invokeTakeOverEvent(false) - } - },expireTime =3000L, isFromObu = false - ) - //展示消息盒子消息 - showData(msgBoxBean) - } - //二级 - MsgFmData.LEVEL_TWO->{ - //语音提示 + override fun onDismiss() { + CallerTakeOverManager.invokeTakeOverEvent(false) + } + }, expireTime = 3000L, isFromObu = false + ) + //展示消息盒子消息 + showData(msgBoxBean) + } + //二级 + MsgFmData.LEVEL_TWO -> { + //语音提示 // AIAssist.getInstance(context).speakTTSVoice("识别车辆异常,建议尽快安全停车,查看操作建议") - AIAssist.getInstance(context).speakTTSVoice(StringUtils.getString(R.string.module_core_warning_vehicle_abnormal_safe_park)) - //展示消息盒子消息 - showData(msgBoxBean) - } - //三级 - MsgFmData.LEVEL_THREE->{ - //在消息盒子图标上,可查看到红点标记,无其他元素特殊提醒;点进消息盒子可查看到详细信息 + AIAssist.getInstance(context).speakTTSVoice(StringUtils.getString(R.string.module_core_warning_vehicle_abnormal_safe_park)) + //展示消息盒子消息 + showData(msgBoxBean) + } + //三级 + MsgFmData.LEVEL_THREE -> { + //在消息盒子图标上,可查看到红点标记,无其他元素特殊提醒;点进消息盒子可查看到详细信息 + } } } - - } } else { if (msgBoxBean.sourceType == DataSourceType.SUMMARY) { diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxListView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxListView.kt index 68f858319e..15c66116b3 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxListView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/DriverMsgBoxListView.kt @@ -9,6 +9,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.LinearLayoutManager import com.mogo.eagle.core.data.enums.DataSourceType import com.mogo.eagle.core.data.msgbox.MsgBoxBean +import com.mogo.eagle.core.data.msgbox.MsgBoxType import com.mogo.eagle.core.data.msgbox.MsgCategory import com.mogo.eagle.core.function.api.datacenter.IDataCenterBizListener import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxEventListener @@ -249,9 +250,11 @@ class DriverMsgBoxListView @JvmOverloads constructor( } //FM信息 MsgCategory.FM_INFO -> { - fmList?.add(0,msgBoxList) - if(MsgBoxConfig.getUserRecord() == 1){ - fmList?.let { driverMsgBoxListAdapter?.setData(it) } + if (msgBoxList.type == MsgBoxType.FMINFO) { + fmList?.add(0, msgBoxList) + if (MsgBoxConfig.getUserRecord() == 1) { + fmList?.let { driverMsgBoxListAdapter?.setData(it) } + } } } //系统信息 diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/MsgBoxToastView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/MsgBoxToastView.kt index f6443039d7..4a4e787d56 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/MsgBoxToastView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/MsgBoxToastView.kt @@ -146,8 +146,9 @@ class MsgBoxToastView @JvmOverloads constructor( } } } else if (category == MsgCategory.FM_INFO) { - CallerMsgBoxEventListenerManager.invokeUpdateTipListener(true) - if (FunctionBuildConfig.isTakeoverRemind) { + if (msgBoxBean.type == MsgBoxType.FMINFO) { + CallerMsgBoxEventListenerManager.invokeUpdateTipListener(true) + if (FunctionBuildConfig.isTakeoverRemind) { // //属于停车警示(包括择机靠边停车、立即舒适停车、就地紧急停车)时,需要弹出消息气泡并伴有提示音 // var curFaultLevel = 5 //默认级别,遍历数组找出级别最高的(level数越小,级别越高) // fmInfoMsg.fmInfoList?.forEach { faultInfo -> @@ -183,63 +184,65 @@ class MsgBoxToastView @JvmOverloads constructor( // } // } - /** - * 8.2.0需求:定义三种不同提示强度的异常提示交互 - * 不判断驾驶状态,发生相应故障时立即有相应的提醒 - * 若同一时间触发多个多种级别异常,则按照最高级别的异常交互元素做提醒,低级别的异常不做特殊提醒 - * 若同一时间触发多个同一级别异常,则同一时刻只提醒一次,不互相打断 - * 除此以外不做其他提示频率限制 - * - * 一级:安全停车 - * FM_DP_EMERGENCY_STOP(就地紧急停车)、FM_DP_COMFORTABLE_STOP(立刻舒适停车)、FM_DP_PNC_CHOOSE_STOP(择机靠边停车) - * 交互:图像、TTS、消息盒子 - * - * 二级:降速行驶 - * FM_DP_SPEED_LIMIT3(三级降速)、FM_DP_SPEED_LIMIT2(二级降速)、FM_DP_SPEED_LIMIT1(一级降速) - * 交互:TTS、消息盒子 - * - * 三级:无操作 - * FM_DP_ONLY_WARNING(警示)、FM_DP_NO_ACTION(报告) - * ps:以上异常提醒受司机屏工具箱-运营面板-美化模式-接管提醒开关控制,默认开启有全量提示,关闭后无语音/图像提示,只有消息盒子红点展示 - */ - val fmInfoMsg = msgBoxBean.bean as FMInfoMsg - when(MsgFmData.getFmPolicyLevel(fmInfoMsg.policyCode)){ - //一级 - MsgFmData.LEVEL_ONE->{ - //接管图像提示、语音提示 - CallerDevaToolsManager.takeOver(TAKE_OVER_REQUEST) - CallerHmiManager.warningV2X( - EventTypeEnumNew.TAKE_OVER_EVENT.poiType, - EventTypeEnumNew.TAKE_OVER_EVENT.content, + /** + * 8.2.0需求:定义三种不同提示强度的异常提示交互 + * 不判断驾驶状态,发生相应故障时立即有相应的提醒 + * 若同一时间触发多个多种级别异常,则按照最高级别的异常交互元素做提醒,低级别的异常不做特殊提醒 + * 若同一时间触发多个同一级别异常,则同一时刻只提醒一次,不互相打断 + * 除此以外不做其他提示频率限制 + * + * 一级:安全停车 + * FM_DP_EMERGENCY_STOP(就地紧急停车)、FM_DP_COMFORTABLE_STOP(立刻舒适停车)、FM_DP_PNC_CHOOSE_STOP(择机靠边停车) + * 交互:图像、TTS、消息盒子 + * + * 二级:降速行驶 + * FM_DP_SPEED_LIMIT3(三级降速)、FM_DP_SPEED_LIMIT2(二级降速)、FM_DP_SPEED_LIMIT1(一级降速) + * 交互:TTS、消息盒子 + * + * 三级:无操作 + * FM_DP_ONLY_WARNING(警示)、FM_DP_NO_ACTION(报告) + * ps:以上异常提醒受司机屏工具箱-运营面板-美化模式-接管提醒开关控制,默认开启有全量提示,关闭后无语音/图像提示,只有消息盒子红点展示 + */ + val fmInfoMsg = msgBoxBean.bean as FMInfoMsg + when (MsgFmData.getFmPolicyLevel(fmInfoMsg.policyCode)) { + //一级 + MsgFmData.LEVEL_ONE -> { + //接管图像提示、语音提示 + CallerDevaToolsManager.takeOver(TAKE_OVER_REQUEST) + CallerHmiManager.warningV2X( + EventTypeEnumNew.TAKE_OVER_EVENT.poiType, + EventTypeEnumNew.TAKE_OVER_EVENT.content, // "识别车辆故障,建议安全停车并查看操作建议", - StringUtils.getString(R.string.module_core_warning_vehicle_fault_safe_park), - object : IMoGoWarningStatusListener { - override fun onShow() { - CallerTakeOverManager.invokeTakeOverEvent(true) - } + StringUtils.getString(R.string.module_core_warning_vehicle_fault_safe_park), + object : IMoGoWarningStatusListener { + override fun onShow() { + CallerTakeOverManager.invokeTakeOverEvent(true) + } - override fun onDismiss() { - CallerTakeOverManager.invokeTakeOverEvent(false) - } - },expireTime =3000L, isFromObu = false - ) - //展示消息盒子消息 - showData(msgBoxBean) - } - //二级 - MsgFmData.LEVEL_TWO->{ - //语音提示 + override fun onDismiss() { + CallerTakeOverManager.invokeTakeOverEvent(false) + } + }, expireTime = 3000L, isFromObu = false + ) + //展示消息盒子消息 + showData(msgBoxBean) + } + //二级 + MsgFmData.LEVEL_TWO -> { + //语音提示 // AIAssist.getInstance(context).speakTTSVoice("识别车辆异常,建议尽快安全停车,查看操作建议") - AIAssist.getInstance(context).speakTTSVoice(StringUtils.getString(R.string.module_core_warning_vehicle_abnormal_safe_park)) - //展示消息盒子消息 - showData(msgBoxBean) - } - //三级 - MsgFmData.LEVEL_THREE->{ - //在消息盒子图标上,可查看到红点标记,无其他元素特殊提醒;点进消息盒子可查看到详细信息 + AIAssist.getInstance(context).speakTTSVoice(StringUtils.getString(R.string.module_core_warning_vehicle_abnormal_safe_park)) + //展示消息盒子消息 + showData(msgBoxBean) + } + //三级 + MsgFmData.LEVEL_THREE -> { + //在消息盒子图标上,可查看到红点标记,无其他元素特殊提醒;点进消息盒子可查看到详细信息 + } } } - + } else { + showData(msgBoxBean) } } else { if (msgBoxBean.sourceType == DataSourceType.SUMMARY) { diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/adapter/MsgBoxToastAdapter.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/adapter/MsgBoxToastAdapter.kt index 34a3533978..75ce11d835 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/adapter/MsgBoxToastAdapter.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/msgbox/adapter/MsgBoxToastAdapter.kt @@ -19,6 +19,7 @@ import com.mogo.eagle.core.data.enums.EventTypeEnumNew import com.mogo.eagle.core.data.msgbox.AutopilotMsg import com.mogo.eagle.core.data.msgbox.CloudControlMsg import com.mogo.eagle.core.data.msgbox.FMInfoMsg +import com.mogo.eagle.core.data.msgbox.FSMEventMsg import com.mogo.eagle.core.data.msgbox.FSMMsg import com.mogo.eagle.core.data.msgbox.MsgBoxCountDownBean import com.mogo.eagle.core.data.msgbox.MsgBoxType @@ -331,7 +332,18 @@ class MsgBoxToastAdapter(private val activity: Activity) : RecyclerView.Adapter< )) } } - }else{ + }else if(it[position].msgBoxBean.type == MsgBoxType.FSM_EVENT){ + //FSM Event信息 + //FSM消息 + val fsmMsg = it[position].msgBoxBean.bean as FSMEventMsg + holder.tvV2XTitle.text = fsmMsg.title + holder.tvV2XContent.text = fsmMsg.summaryContent + holder.ivV2XImage.setImageDrawable( + ContextCompat.getDrawable( + activity, + R.drawable.icon_warning_fsm_event + )) + } else{ //V2X消息 val msgBoxBean = it[position].msgBoxBean val v2XMsg = msgBoxBean.bean as V2XMsg diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_warning_fsm_event.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_warning_fsm_event.png new file mode 100644 index 0000000000000000000000000000000000000000..513ca5bf60e402a4bccde2d42448362922bef610 GIT binary patch literal 15127 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 Notice - FM Info + Fault Info System Info Record Record Icon diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml index 22402495fc..a5e3a1c48d 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml @@ -181,7 +181,7 @@ 通知 - FM信息 + 故障信息 系统信息 录包 录包图标 diff --git a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/chain/ChainConstant.kt b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/chain/ChainConstant.kt index 9f95285af3..4afab84a7d 100644 --- a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/chain/ChainConstant.kt +++ b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/deva/chain/ChainConstant.kt @@ -56,6 +56,7 @@ class ChainConstant { const val CHAIN_CODE_ADAS_SEND = "CHAIN_CODE_ADAS_SEND" const val CHAIN_CODE_ADAS_FM_MSG = "CHAIN_CODE_ADAS_FM_MSG" const val CHAIN_CODE_ADAS_FSM_MSG = "CHAIN_CODE_ADAS_FSM_MSG" + const val CHAIN_CODE_ADAS_FSM_EVENT_MSG = "CHAIN_CODE_ADAS_FSM_EVENT_MSG" const val CHAIN_CODE_ADAS_ARRIVE = "CHAIN_CODE_ADAS_ARRIVE" const val CHAIN_CODE_ADAS_ARRIVE_QUERY = "CHAIN_CODE_ADAS_ARRIVE_QUERY" const val CHAIN_CODE_ADAS_ROUTE = "CHAIN_CODE_ADAS_ROUTE" diff --git a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/FSMEventMsg.kt b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/FSMEventMsg.kt new file mode 100644 index 0000000000..db040975ed --- /dev/null +++ b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/FSMEventMsg.kt @@ -0,0 +1,14 @@ +package com.mogo.eagle.core.data.msgbox + +import java.io.Serializable + +/** + * fsm event相关的消息 + */ +data class FSMEventMsg( + val title: String, + val summaryContent: String,//内容概况 + val content: String, + val timestamp: Long, + var isShow: Boolean = false +) : Serializable \ No newline at end of file diff --git a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/MsgBoxType.kt b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/MsgBoxType.kt index 4bb3b849fd..9af9f1dc06 100644 --- a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/MsgBoxType.kt +++ b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/msgbox/MsgBoxType.kt @@ -2,5 +2,5 @@ package com.mogo.eagle.core.data.msgbox enum class MsgBoxType { // 按功能划分为几大类:运营、通知、V2X模块、OBU模块、工控机Report、录制、交通、FM、语音、SSM、工控机相关等 - OPERATION, NOTICE, V2X, OBU, REPORT, RECORD, TRAFFIC, FMINFO, VOICE, SSMINFO, AUTOPILOT, FSM, NDE,OTA,CLOUD + OPERATION, NOTICE, V2X, OBU, REPORT, RECORD, TRAFFIC, FMINFO, VOICE, SSMINFO, AUTOPILOT, FSM, NDE, OTA, CLOUD, FSM_EVENT } \ No newline at end of file diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoFsm2024Listener.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoFsm2024Listener.kt index 3da37890b7..b88c19252a 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoFsm2024Listener.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoFsm2024Listener.kt @@ -1,5 +1,6 @@ package com.mogo.eagle.core.function.api.autopilot +import fault_management.FmInfo import fsm.Fsm2024 /** @@ -15,4 +16,6 @@ interface IMoGoFsm2024Listener { */ fun onFSM2024State(fsmState: Fsm2024.FSMStateMsg) +// fun onFSMEvent(fsmEventMsg: Fsm2024.FsmEventMsg){} + } \ No newline at end of file diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerFsm2024ListenerManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerFsm2024ListenerManager.kt index 530c7b8344..686abb2225 100644 --- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerFsm2024ListenerManager.kt +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerFsm2024ListenerManager.kt @@ -1,14 +1,40 @@ package com.mogo.eagle.core.function.call.autopilot +import android.os.Build +import com.mogo.commons.AbsMogoApplication +import com.mogo.eagle.core.data.R +import com.mogo.eagle.core.data.msgbox.FSMEventMsg +import com.mogo.eagle.core.data.msgbox.MsgBoxBean +import com.mogo.eagle.core.data.msgbox.MsgBoxType import com.mogo.eagle.core.function.api.autopilot.IMoGoFsm2024Listener import com.mogo.eagle.core.function.call.base.CallerBase +import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager +import com.mogo.eagle.core.utilcode.util.StringUtils import fsm.Fsm2024 -import mogo.telematics.pad.MessagePad +import java.util.Locale /** * 新版FSM状态 */ object CallerFsm2024ListenerManager : CallerBase() { + var fsmLocaleLanguage = "chs" + + init { + val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // API 24+ 获取语言列表中的第一个 + AbsMogoApplication.getApp().resources.configuration.locales[0] + } else { + // API 24 以下直接获取 locale 成员 + @Suppress("DEPRECATION") + AbsMogoApplication.getApp().resources.configuration.locale + } + val language = locale.language // 例如: "zh" + if (language == Locale.CHINESE.language) { + fsmLocaleLanguage = "chs" + } else if (language == Locale.ENGLISH.language) { + fsmLocaleLanguage = "eng" + } + } fun invokeFSM2024State(fsmState: Fsm2024.FSMStateMsg) { M_LISTENERS.forEach { @@ -17,5 +43,62 @@ object CallerFsm2024ListenerManager : CallerBase() { } } + fun invokeFSMEvent(fsmEventMsg: Fsm2024.FsmEventMsg) { +// M_LISTENERS.forEach { +// val listener = it.value +// listener.onFSMEvent(fsmEventMsg) +// } + if (fsmEventMsg.hasFsmEventInt()) { + val fsmEvent = fsmEventMsg.fsmEventInt + if (fsmEvent.activeMode == Fsm2024.ActiveMode.PILOT_ACTIVE) { + if (fsmEvent.event == Fsm2024.Event.FAIL_TO_ENTER_ACTIVE || fsmEvent.event == Fsm2024.Event.ABNORMAL_EXIT_ACTIVE) { + val title = + StringUtils.getString(if (fsmEvent.event == Fsm2024.Event.FAIL_TO_ENTER_ACTIVE) R.string.module_mogo_core_fail_to_enter_active else R.string.module_mogo_core_abnormal_exit_active) + var content = StringUtils.getString(R.string.module_mogo_core_unknown_cause_fault) + var summaryContent = "" + if (fsmEvent.transitionReasonsMultiLangCount > 0) { + fsmEvent.transitionReasonsMultiLangList.forEach { + if (it.language == fsmLocaleLanguage) { + val tem = StringBuilder() + it.transitionReasonsList.forEach { msg -> + if (!msg.isNullOrEmpty()) { + if (summaryContent.isEmpty()) { + summaryContent = msg + } + tem.append(msg).append(if (fsmLocaleLanguage == "chs") ";" else "; ") + } + } + if (tem.endsWith(';') || tem.endsWith(' ')) { + val delLength = if (fsmLocaleLanguage == "chs") 1 else 2 + if (tem.length >= delLength) { + tem.delete(tem.length - delLength, tem.length) + } + content = tem.toString(); + } + return@forEach + } + } + } + if (summaryContent.isEmpty()) { + summaryContent = StringUtils.getString(R.string.module_mogo_core_unknown_cause_fault) + } + val time = if (fsmEvent.hasTime()) { + fsmEvent.time.sec * 1000L + } else { + System.currentTimeMillis() + } + CallerMsgBoxManager.saveMsgBoxNoTrace( + MsgBoxBean( + MsgBoxType.FSM_EVENT, + FSMEventMsg(title, summaryContent, content, time) + ) + ) + } + } + + } + + + } } \ No newline at end of file diff --git a/core/mogo-core-res/src/main/res/values-en/string.xml b/core/mogo-core-res/src/main/res/values-en/string.xml index 6c1690b402..d17f07f108 100644 --- a/core/mogo-core-res/src/main/res/values-en/string.xml +++ b/core/mogo-core-res/src/main/res/values-en/string.xml @@ -172,6 +172,9 @@ Upgrading to new version, expected 5 minutes Upgrade failed, please contact operations personnel Already the latest version + Unable to start autonomous driving + Abnormal exit from autonomous driving + Unknown cause of fault Failed to enter roaming mode, code:%s diff --git a/core/mogo-core-res/src/main/res/values/string.xml b/core/mogo-core-res/src/main/res/values/string.xml index 264be2de27..54899b4b42 100644 --- a/core/mogo-core-res/src/main/res/values/string.xml +++ b/core/mogo-core-res/src/main/res/values/string.xml @@ -172,6 +172,9 @@ 新版本升级中,预计5分钟升级完成 升级失败,请联系运维人员 已是最新版本 + 无法起自驾 + 异常退出自驾 + 未知故障原因 进入漫游模式失败, code:%s diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/MessageType.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/MessageType.java index 519f77c5e1..c85e1a9202 100644 --- a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/MessageType.java +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/MessageType.java @@ -118,6 +118,7 @@ public enum MessageType { TYPE_SEND_OBU_UPLOAD_STATUS(MessagePad.MessageType.MsgTypeObuUploadStatus, R.string.adas_data_MsgTypeObuUploadStatus_SEND), TYPE_RECEIVE_OBU_UPLOAD_STATUS(MessagePad.MessageType.MsgTypeObuUploadStatus, R.string.adas_data_MsgTypeObuUploadStatus_RECEIVE), TYPE_RECEIVE_PLANNING_STOP_LINE(MessagePad.MessageType.MsgTypePlanningStopLine, R.string.adas_data_MsgTypePlanningStopLine), + TYPE_RECEIVE_FSM_EVENT(MessagePad.MessageType.MsgTypeFsmEvent, R.string.adas_data_MsgTypeFsmEvent), //TODO 透传原始pb文件中不存在以下type。由于Java中无法强转,所以在mogo-adas-data/message_pad.proto中放开注释 TYPE_RECEIVE_PLANNING_DECISION_STATE(MessagePad.MessageType.MsgTypePlanningDecisionState, R.string.adas_data_MsgTypePlanningDecisionState), diff --git a/libraries/mogo-adas-data/src/main/proto/fsm2024.proto b/libraries/mogo-adas-data/src/main/proto/fsm2024.proto index 1a4a708814..c6dc2cc774 100644 --- a/libraries/mogo-adas-data/src/main/proto/fsm2024.proto +++ b/libraries/mogo-adas-data/src/main/proto/fsm2024.proto @@ -40,12 +40,18 @@ enum SessionResult{ REQUEST_FAILED= 3; //请求失败 } -enum ExitType{ +enum ExitType{ //废弃 NO_EXIT =0; NORMAL_EXIT= 1; ABNORMAL_EXIT= 2; } +enum OrderStatus { + OLDER_SSM_VERSION = 0; + NO_ORDER = 1; + HAS_ORDER = 2; +} + message Session{ optional ActiveMode session_active_mode = 1 ; //这次点击是要进入哪个模式 optional uint64 session_id= 2; //最新收到的请求的session id, 暂时不区分 自驾,平行驾驶、方向盘驾驶以及发送源头。没收到或者请求不带id时置为0 @@ -75,6 +81,9 @@ message FSMStateMsg { required bool pilot_standby_flag = 11; required bool parallel_standby_flag = 12; required bool m1steer_standby_flag = 13; + + optional OrderStatus order_status = 16; + optional bool place_order_standby_flag = 17; optional string pilot_not_standby_reason= 21; //FSM 无法自驾无法就绪的原因。 optional string parallel_not_standby_reason= 22; //FSM 无法平行即使就绪原因 @@ -82,8 +91,8 @@ message FSMStateMsg { repeated string repeated_pilot_not_standby_reason= 26; // repeated reason repeated string repeated_parallel_not_standby_reason= 27; - repeated string repeated_m1steer_not_standby_reason= 28; - + repeated string repeated_m1steer_not_standby_reason= 28; + optional Session session = 30; //包含某次点击的所有信息 optional uint64 fail_to_pilot_session_id= 36; //2.0起废弃 @@ -92,6 +101,43 @@ message FSMStateMsg { optional string abnormal_state_trans_reason= 41; //2.0起废弃 - optional ExitActive exit_active= 42; //存储最近一次离开Active状态的情况 (包括正常退出,掉自驾,接管,停车) + optional ExitActive exit_active= 42; //(废弃)存储最近一次离开Active状态的情况 (包括正常退出,掉自驾,接管,停车) + repeated string pilot_not_standby_reasons_eng= 50; + repeated string parallel_not_standby_reasons_eng= 51; + repeated string m1steer_not_standby_reasons_eng= 52; + + repeated uint32 pilot_not_standby_reasons_int= 55; + repeated uint32 parallel_not_standby_reasons_int= 56; + repeated uint32 m1steer_not_standby_reasons_int= 57; +} + + +enum Event{ + NO_EVENT =0; //不会出现,出现则说明FSM有bug + SUCCEED_TO_ENTER_ACTIVE =1;//正常进入自驾/平行驾驶/M1方向盘驾驶/APP控车 等需要激活底盘线控的模式 (暂不会报出) + FAIL_TO_ENTER_ACTIVE =2; //进入失败 + NORMAL_EXIT_ACTIVE= 3; //正常退出(包括到终点和接管) + ABNORMAL_EXIT_ACTIVE= 4; //异常退出 +} + +message TransReasons{ + optional string language = 1; //chs, eng + repeated string transition_reasons = 2; +} + +message FsmEventInt{ //此事件非系统事件,而是一个FSM单次报出自驾状态变化关键信息的接口 + +optional ActiveMode active_mode = 1; //进入或退出的模式是自驾/平行驾驶/M1方向盘驾驶/APP控车 +optional Event event= 2; +repeated uint32 transition_reasons = 3; //正常进入不会有原因。进入失败,正常退出,异常退出都会有原因 +repeated string fm_faults = 4; //如果涉及故障,就存在这个字段里 +optional common.Time time = 5; //时间发生的时间点 +optional string broken_nodes = 6; //崩溃节点字符串 +repeated TransReasons transition_reasons_multi_lang = 10; +} + +message FsmEventMsg { + optional common.Header header = 1; + optional FsmEventInt fsm_event_int= 2; } diff --git a/libraries/mogo-adas-data/src/main/proto/message_pad.proto b/libraries/mogo-adas-data/src/main/proto/message_pad.proto index e826d5f81c..0647a5f0b7 100644 --- a/libraries/mogo-adas-data/src/main/proto/message_pad.proto +++ b/libraries/mogo-adas-data/src/main/proto/message_pad.proto @@ -113,6 +113,7 @@ enum MessageType MsgTypeSetObuUploadReq = 0x10139;//关闭或打开域控上报自车数据到OBU MsgTypeObuUploadStatus = 0x1013A;//obu上报状态查询以结果(上下行) MsgTypePlanningStopLine = 0x1013B;//决策停止线(自动驾驶决策呈现使用) 定频,理论是10hz,实际会有不同 + MsgTypeFsmEvent = 0x1013C;//fsm event msg } message Header diff --git a/libraries/mogo-adas-data/src/main/res/values-en/strings.xml b/libraries/mogo-adas-data/src/main/res/values-en/strings.xml index c326933535..ff8c670118 100644 --- a/libraries/mogo-adas-data/src/main/res/values-en/strings.xml +++ b/libraries/mogo-adas-data/src/main/res/values-en/strings.xml @@ -93,6 +93,7 @@ Domain control OBU upload status query Domain control OBU upload status response Planning Stop Line + FSM Event Planning decision state Sweeper index data OBU warning event diff --git a/libraries/mogo-adas-data/src/main/res/values/strings.xml b/libraries/mogo-adas-data/src/main/res/values/strings.xml index 34f31740ef..22900a9408 100644 --- a/libraries/mogo-adas-data/src/main/res/values/strings.xml +++ b/libraries/mogo-adas-data/src/main/res/values/strings.xml @@ -93,6 +93,7 @@ 域控上报OBU开关状态查询 域控上报OBU开关状态响应 决策停止线 + FSM事件 Planning决策状态 清扫车指标数据 OBU预警事件 diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/OnAdasListener.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/OnAdasListener.java index 423e3a28af..48d0baa23a 100644 --- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/OnAdasListener.java +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/OnAdasListener.java @@ -339,6 +339,14 @@ public interface OnAdasListener { */ void onFSM2024State(@NonNull MessagePad.Header header, @NonNull Fsm2024.FSMStateMsg fsmState, int autopilotState, int autopilotMode); + /** + * FSM事件 + * + * @param header 头 + * @param fsmEventMsg 数据 + */ + void onFSMEvent(@NonNull MessagePad.Header header, @NonNull Fsm2024.FsmEventMsg fsmEventMsg); + /** * 定位状态 * 定位呈现状态透传 用于pad图标显示 1hz 所有车型MAP440开始支持 diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/FSMEventMessage.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/FSMEventMessage.java new file mode 100644 index 0000000000..fa5a9f51f6 --- /dev/null +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/FSMEventMessage.java @@ -0,0 +1,30 @@ +package com.zhidao.support.adas.high.msg; + +import android.os.SystemClock; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.zhidao.support.adas.high.AdasChannel; +import com.zhidao.support.adas.high.OnAdasListener; +import com.zhidao.support.adas.high.common.CupidLogUtils; +import com.zhidao.support.adas.high.protocol.RawData; + +import fsm.Fsm2024; + +/** + * FSM事件 + */ +public class FSMEventMessage extends MyAbstractMessageHandler { + + @Override + public void handlerMsg(RawData raw, OnAdasListener adasListener) throws InvalidProtocolBufferException { + Fsm2024.FsmEventMsg fsmEventMsg = Fsm2024.FsmEventMsg.parser().parseFrom(raw.originalData.toByteArray(), raw.getOffsetValue(), raw.getPackageLengthValue() - raw.getOffsetValue()); + AdasChannel.calculateTimeConsumingOnDispatchRaw("FSM事件", raw.receiveTime); + long nowTime = 0; + if (CupidLogUtils.isEnableLog()) + nowTime = SystemClock.elapsedRealtime(); + if (adasListener != null) { + adasListener.onFSMEvent(raw.getHeader(), fsmEventMsg); + } + AdasChannel.calculateTimeConsumingBusiness("FSM事件", nowTime); + } +} diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/MyMessageFactory.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/MyMessageFactory.java index ce0c62b736..c3f3a91024 100644 --- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/MyMessageFactory.java +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/MyMessageFactory.java @@ -64,6 +64,7 @@ public class MyMessageFactory implements IMyMessageFactory { private IMsg vlmMessageImage;//视觉语言模型图像 private IMsg obuUploadStatusMessage;//域控上报OBU开关状态响应 private IMsg planningStopLineMessage;//决策停止线 + private IMsg fSMEventMessage;//FSM事件 private final AutopilotReview autopilotReview; private final TurnLightState lightLeft = new TurnLightState(); @@ -380,6 +381,12 @@ public class MyMessageFactory implements IMyMessageFactory { planningStopLineMessage = new PlanningStopLineMessage(); } return planningStopLineMessage; + } else if (messageType == MessageType.TYPE_RECEIVE_FSM_EVENT.typeCode) { + //决策停止线 + if (fSMEventMessage == null) { + fSMEventMessage = new FSMEventMessage(); + } + return fSMEventMessage; } else { //MessageType.TYPE_DEFAULT.typeCode return null;