diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt index b98ddb313e..41e007e3b0 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt @@ -9,6 +9,7 @@ import com.alibaba.android.arouter.facade.annotation.Route import com.mogo.commons.debug.DebugConfig import com.mogo.commons.storage.SharedPrefsMgr import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters +import com.mogo.eagle.core.data.autopilot.toAutoPilotCmdInfo import com.mogo.eagle.core.data.autopilot.toAutoPilotLine import com.mogo.eagle.core.data.autopilot.toRouteInfo import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult @@ -66,6 +67,7 @@ import com.zhidao.support.adas.high.chain.AdasChain import com.zhidao.support.adas.high.common.Constants import com.zhidao.support.adas.high.common.CupidLogUtils import com.zhjt.mogo.adas.common.MessageType +import com.zhjt.mogo.adas.common.power.PowerUnitChannel import com.zhjt.mogo.adas.data.Adas import com.zhjt.mogo.adas.data.AdasConstants import com.zhjt.mogo.adas.data.bean.MogoReport @@ -391,12 +393,12 @@ class MoGoAutopilotControlProvider : private fun startAutoPilotWithNoParameter(source: Int) { if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) { val invokeResult = AdasManager.getInstance() - .sendAutoPilotModeReq(1, source, null) + .sendAutoPilotModeReq(1, source, null, null) invokeAutoPilotResult(if (invokeResult > -1) "无参自动驾驶调用成功:${invokeResult}" else "自动驾驶调用失败, socket 或者 rawPack 可能为空") } else { if (AdasManager.getInstance().ipcConnectionStatus == AdasConstants.IpcConnectionStatus.CONNECTED) { val invokeResult = AdasManager.getInstance() - .sendAutoPilotModeReq(1, source, null) + .sendAutoPilotModeReq(1, source, null, null) invokeAutoPilotResult(if (invokeResult > -1) "无参自动驾驶调用成功:${invokeResult}" else "自动驾驶调用失败, socket 或者 rawPack 可能为空") } else { invokeAutoPilotResult("车机与工控机链接失败,无法开启自动驾驶 无参") @@ -407,13 +409,13 @@ class MoGoAutopilotControlProvider : private fun startAutoPilot(controlParameters: AutopilotControlParameters, source: Int): Long { if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) { val invokeResult = AdasManager.getInstance() - .sendAutoPilotModeReq(1, source, controlParameters.toRouteInfo()) + .sendAutoPilotModeReq(1, source, controlParameters.toRouteInfo(), controlParameters.toAutoPilotCmdInfo()) invokeAutoPilotResult(if (invokeResult > -1) "自动驾驶调用成功:${invokeResult}" else "自动驾驶调用失败, socket 或者 rawPack 可能为空") return invokeResult } else { if (AdasManager.getInstance().ipcConnectionStatus == AdasConstants.IpcConnectionStatus.CONNECTED) { val invokeResult = AdasManager.getInstance() - .sendAutoPilotModeReq(1, source, controlParameters.toRouteInfo()) + .sendAutoPilotModeReq(1, source, controlParameters.toRouteInfo(), controlParameters.toAutoPilotCmdInfo()) invokeAutoPilotResult(if (invokeResult > -1) "自动驾驶调用成功:${invokeResult}" else "自动驾驶调用失败, socket 或者 rawPack 可能为空") return invokeResult } else { @@ -463,7 +465,7 @@ class MoGoAutopilotControlProvider : override fun cancelAutoPilot() { if (AdasManager.getInstance().ipcConnectionStatus == AdasConstants.IpcConnectionStatus.CONNECTED) { - val invokeResult = AdasManager.getInstance().sendAutoPilotModeReq(0, 1, null) + val invokeResult = AdasManager.getInstance().sendAutoPilotModeReq(0, 1, null, null) invokeAutoPilotResult(if (invokeResult > -1) "取消自动驾驶调用成功:${invokeResult}" else "取消自动驾驶调用失败, socket 或者 rawPack 可能为空") } else { invokeAutoPilotResult("车机与工控机链接失败,无法取消自动驾驶") @@ -1032,11 +1034,11 @@ class MoGoAutopilotControlProvider : */ override fun setControlAutopilotCarAuto(isEnable: Boolean) { if (isEnable) { - AdasManager.getInstance().sendAutoPilotModeReq(1, 0, null) + AdasManager.getInstance().sendAutoPilotModeReq(1, 0, null, null) } else { // 司机屏才可关闭自动驾驶 if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) { - AdasManager.getInstance().sendAutoPilotModeReq(0, 0, null) + AdasManager.getInstance().sendAutoPilotModeReq(0, 0, null, null) } } } @@ -1269,6 +1271,82 @@ class MoGoAutopilotControlProvider : return AdasManager.getInstance().sendSweeperCloudSuspendResumeTaskResp(reqNo, bigTaskActionResp) > -1 } + /** + * 发送电源状态查询请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + override fun sendPowerUnitSTSRequest(): Long { + return AdasManager.getInstance().sendPowerUnitSTSRequest() + } + + /** + * 发送单通道电源控制请求 + * + * @param channel 通道 + * @param cmd 0:关闭;1:打开; + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + override fun sendPowerUnitSingleChannelControl(channel: PowerUnitChannel, cmd: Int): Long { + return AdasManager.getInstance().sendPowerUnitSingleChannelControl(channel,cmd) + } + + /** + * 发送电源控制重置请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + override fun sendPowerUnitReset(): Long { + return AdasManager.getInstance().sendPowerUnitReset() + } + + /** + * 查询冷启动状态 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + override fun sendSsmFuncQueryColdStartState(): Long { + return AdasManager.getInstance().sendSsmFuncQueryColdStartState() + } + + /** + * 查询自驾命令状态 + * 查询:是否首次进自驾、订单号、次数 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + override fun sendSsmFuncQueryAutoPilotInfo(): Long { + return AdasManager.getInstance().sendSsmFuncQueryAutoPilotInfo() + } + + /** + * 查询到站信息 + * + * @param orderId 订单号 + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + override fun sendSsmFuncQueryAutoPilotStation(orderId: String): Long { + return AdasManager.getInstance().sendSsmFuncQueryAutoPilotStation(orderId) + } + override fun sendParallelDrivingReq( reqNo: String, parallelRequest: ParallelDrivingRequest.ParallelRequest 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 ca38830dba..0701b49141 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 @@ -8,8 +8,11 @@ import com.mogo.eagle.core.data.app.AppConfigInfo import com.mogo.eagle.core.data.config.HdMapBuildConfig import com.mogo.eagle.core.data.deva.chain.ChainConstant import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_ARRIVE +import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_ARRIVE_QUERY +import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_AUTOPILOT_INFO import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_CAR_CONFIG 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_MSG import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_CODE_ADAS_GUARDIAN @@ -35,6 +38,8 @@ import com.mogo.eagle.core.data.msgbox.MsgBoxType import com.mogo.eagle.core.data.msgbox.SSMMsg import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.invokeArriveAtStation +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.invokeAutoPilotInfo +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.invokeAutoPilotStation import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.invokeAutopilotGuardian import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.invokeAutopilotSNRequest import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.invokeAutopilotStatusRespByQuery @@ -58,6 +63,7 @@ import com.mogo.eagle.core.function.call.autopilot.CallerBackCameraVideoListener import com.mogo.eagle.core.function.call.autopilot.CallerChassisDoorStateListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerChassisGnssListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerChassisStatesListenerManager +import com.mogo.eagle.core.function.call.autopilot.CallerColdStartStateListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerFaultManagementStateListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerFsm2024ListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerLocalizationStateListenerManager @@ -98,6 +104,7 @@ import com.zhjt.mogo.adas.data.bean.LaunchConditionData import com.zhjt.mogo.adas.data.bean.NodeStateInfo import com.zhjt.mogo.adas.data.bean.ReceivedAck import com.zhjt.mogo.adas.data.bean.UnableLaunchReason +import com.zhjt.mogo.adas.data.bean.power.PowerData import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus @@ -414,6 +421,160 @@ class MoGoAdasListenerImpl : OnAdasListener { override fun onWarn(header: MessagePad.Header, warn: MessagePad.Warn?) { } + /** + * 冷启动状态变更上报以及查询状态 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param isQuery 是否是查询 ture:查询相应的结果 false:表示状态变动域控主动推送 + * @param coldStartState 数据 null表示 PadSsmMsg中的消息体为null + */ + override fun onColdStartState( + header: MessagePad.Header?, + token: Long, + timestamp: Long, + isQuery: Boolean, + coldStartState: SsmInfo.ColdStartState? + ) { + CallerColdStartStateListenerManager.invokeColdStartState( + token, + timestamp, + isQuery, + coldStartState + ) + if (coldStartState == null) { + coldStartStateError( + token, + timestamp, + isQuery, + "PadSsmMsg中的消息体为null" + ) + } else { + coldStartState( + token, + timestamp, + isQuery, + coldStartState + ) + } + } + + @ChainLog( + linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT, + linkCode = CHAIN_SOURCE_ADAS, + nodeAliasCode = CHAIN_CODE_ADAS_COLD_START_STATE, + paramIndexes = [0, 1, 2, 3] + ) + private fun coldStartState( + token: Long, + timestamp: Long, + isQuery: Boolean, + coldStartState: SsmInfo.ColdStartState, + ) { + } + + @ChainLog( + linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT, + linkCode = CHAIN_SOURCE_ADAS, + nodeAliasCode = CHAIN_CODE_ADAS_COLD_START_STATE, + paramIndexes = [0, 1, 2, 3] + ) + private fun coldStartStateError( + token: Long, + timestamp: Long, + isQuery: Boolean, + autoPilotInfo: String, + ) { + } + + /** + * 自驾命令状态查询响应 + * 返回 是否首次进自驾、订单号、次数 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param autoPilotInfo 数据 null表示 PadSsmMsg中的消息体为null + */ + override fun onAutoPilotInfo( + header: MessagePad.Header?, + token: Long, + timestamp: Long, + autoPilotInfo: SsmInfo.AutoPilotInfo? + ) { + invokeAutoPilotInfo(token, timestamp, autoPilotInfo) + val msg: String + if (autoPilotInfo == null) { + msg = "PadSsmMsg中的消息体为null" + } else { + val temB: String = autoPilotInfo.firstAutopilotFlag.toString() + val temS: String = autoPilotInfo.orderId ?: "" + msg = "firstAutopilotFlag:" + temB + "orderId:" + temS + "count:" + autoPilotInfo.count + } + autoPilotInfoResponse( + token, + timestamp, + msg + ) + } + + @ChainLog( + linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT, + linkCode = CHAIN_SOURCE_ADAS, + nodeAliasCode = CHAIN_CODE_ADAS_AUTOPILOT_INFO, + paramIndexes = [0, 1, 2] + ) + private fun autoPilotInfoResponse( + token: Long, + timestamp: Long, + autoPilotInfo: String, + ) { + } + + /** + * 到站信息查询响应 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param autoPilotStation 数据 null表示 PadSsmMsg中的消息体为null + */ + override fun onAutoPilotStation( + header: MessagePad.Header?, + token: Long, + timestamp: Long, + autoPilotStation: SsmInfo.AutoPilotStation? + ) { + invokeAutoPilotStation(token, timestamp, autoPilotStation) + val msg: String + if (autoPilotStation == null) { + msg = "PadSsmMsg中的消息体为null" + } else { + val temB: String = autoPilotStation.arrivedStationFlag.toString() + val temS: String = autoPilotStation.orderId ?: "" + msg = "arrivedStationFlag:" + temB + "orderId:" + temS + } + autoPilotStationResponse( + token, + timestamp, + msg + ) + } + + @ChainLog( + linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT, + linkCode = CHAIN_SOURCE_ADAS, + nodeAliasCode = CHAIN_CODE_ADAS_ARRIVE_QUERY, + paramIndexes = [0, 1, 2] + ) + private fun autoPilotStationResponse( + token: Long, + timestamp: Long, + autoPilotStation: String, + ) { + } + //到站回调 @ChainLog( linkChainLog = CHAIN_TYPE_SOCKET_AUTOPILOT, @@ -1052,6 +1213,20 @@ class MoGoAdasListenerImpl : OnAdasListener { } + /** + * 电源盒协议接口 + *

+ * {@link PowerData}使用方法 + * 1.先判断数据中的{@link PowerData#protocolStatus} 是否是 {@link PowerProtocolStatus#SUCCEED} 如果是则表示数据解析正常可以正常使用,进行下一步 + * 2.判断 {@link PowerData#frameType} 数据类型 + * + * @param header 头 + * @param data 数据 + */ + override fun onPowerUnit(header: MessagePad.Header, data: PowerData) { + + } + /** * 所连接的域控的节点状态信息 * 目前包含状态 节点是否存在;节点是否超时; diff --git a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/autopilot/AutopilotControlParameters.kt b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/autopilot/AutopilotControlParameters.kt index 6e65ee612a..46940aecc6 100644 --- a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/autopilot/AutopilotControlParameters.kt +++ b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/autopilot/AutopilotControlParameters.kt @@ -86,6 +86,12 @@ fun AutopilotControlParameters.toRouteInfo(): MessagePad.RouteInfo { return routeInfo.build() } +fun AutopilotControlParameters.toAutoPilotCmdInfo(): MessagePad.CmdInfo { + val cmdInfo = MessagePad.CmdInfo.newBuilder() + cmdInfo.setFirstAutopilotFlag(firstAutopilotFlag).setOrderId(orderId) + return cmdInfo.build() +} + fun AutopilotControlParameters.AutoPilotLine.toAutoPilotLine(): MessagePad.Line { val line = MessagePad.Line.newBuilder() line.lineId = this.lineId @@ -145,6 +151,12 @@ class AutopilotControlParameters { @JvmField var autoPilotLine: AutoPilotLine? = null // 自动驾驶路线 + @JvmField + var firstAutopilotFlag = true//是否首次进自驾 + + @JvmField + var orderId = ""//订单号 + class AutoPilotLine { var lineId = 0L 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 8eeabaea5b..e2820b7d97 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_FM_MSG = "CHAIN_CODE_ADAS_FM_MSG" const val CHAIN_CODE_ADAS_FSM_MSG = "CHAIN_CODE_ADAS_FSM_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" const val CHAIN_CODE_ADAS_ROUTE_REQ = "CHAIN_CODE_ADAS_ROUTE_REQ" const val CHAIN_CODE_ADAS_TRAJECTORY = "CHAIN_CODE_ADAS_ROUTE_REQ" @@ -73,6 +74,8 @@ class ChainConstant { const val CHAIN_CODE_ADAS_V2N_EVENT = "CHAIN_CODE_ADAS_V2N_EVENT" const val CHAIN_CODE_ADAS_POWER_OFF = "CHAIN_CODE_ADAS_POWER_OFF" const val CHAIN_CODE_ADAS_IPC_REBOOT = "CHAIN_CODE_ADAS_IPC_REBOOT" + const val CHAIN_CODE_ADAS_AUTOPILOT_INFO = "CHAIN_CODE_ADAS_AUTOPILOT_INFO" + const val CHAIN_CODE_ADAS_COLD_START_STATE = "CHAIN_CODE_ADAS_COLD_START_STATE" const val CHAIN_CODE_RECORD_NATIVE_LEAK = "CHAIN_CODE_RECORD_NATIVE_LEAK" const val CHAIN_CODE_RECORD_ANR = "CHAIN_CODE_RECORD_ANR" diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotControlProvider.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotControlProvider.kt index 6370402b6c..a00b103231 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotControlProvider.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotControlProvider.kt @@ -5,7 +5,7 @@ import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult import com.mogo.eagle.core.data.deva.badcase.BagManagerEntity import com.mogo.eagle.core.function.api.base.IMoGoFunctionServerProvider -import com.zhjt.mogo.adas.data.Adas +import com.zhjt.mogo.adas.common.power.PowerUnitChannel import com.zhjt.mogo.adas.data.AdasConstants import com.zhjt.mogo.adas.data.bean.NodeStateInfo import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable.IsBootable @@ -551,6 +551,70 @@ interface IMoGoAutopilotControlProvider : IMoGoFunctionServerProvider { */ fun sendSweeperCloudSuspendResumeTaskResp(reqNo: String, bigTaskActionResp: BigTaskActionResp): Boolean + /** + * 发送电源状态查询请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendPowerUnitSTSRequest(): Long + + /** + * 发送单通道电源控制请求 + * + * @param channel 通道 + * @param cmd 0:关闭;1:打开; + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendPowerUnitSingleChannelControl(channel: PowerUnitChannel, cmd: Int): Long + + /** + * 发送电源控制重置请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendPowerUnitReset(): Long + + /** + * 查询冷启动状态 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendSsmFuncQueryColdStartState(): Long + + /** + * 查询自驾命令状态 + * 查询:是否首次进自驾、订单号、次数 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendSsmFuncQueryAutoPilotInfo(): Long + + /** + * 查询到站信息 + * + * @param orderId 订单号 + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendSsmFuncQueryAutoPilotStation(orderId: String): Long + /** * 打开点云绘制 * diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotStatusListener.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotStatusListener.kt index ee52f9c5de..24c51c006d 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotStatusListener.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotStatusListener.kt @@ -34,6 +34,32 @@ interface IMoGoAutopilotStatusListener { */ fun onAutopilotDockerInfo(dockerVersion:String){} + /** + * 自驾命令状态查询响应 + * 返回 是否首次进自驾、订单号、次数 + * 查询调用:CallerAutoPilotControlManager.sendSsmFuncQueryAutoPilotInfo() + * + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param autoPilotInfo 数据 null表示 PadSsmMsg中的消息体为null + */ + fun onAutoPilotInfo(token: Long, timestamp: Long, autoPilotInfo: SsmInfo.AutoPilotInfo?) {} + + /** + * 到站信息查询响应 + * 查询调用:CallerAutoPilotControlManager.sendSsmFuncQueryAutoPilotStation(orderId: String) + * + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param autoPilotStation 数据 null表示 PadSsmMsg中的消息体为null + */ + fun onAutoPilotStation( + token: Long, + timestamp: Long, + autoPilotStation: SsmInfo.AutoPilotStation? + ) { + } + /** * 自动驾驶到站 * diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoColdStartStateListener.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoColdStartStateListener.kt new file mode 100644 index 0000000000..824d37d843 --- /dev/null +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoColdStartStateListener.kt @@ -0,0 +1,25 @@ +package com.mogo.eagle.core.function.api.autopilot + +import system_master.SsmInfo + + +/** + * 冷启动状态变更上报以及查询状态 + */ +interface IMoGoColdStartStateListener { + + /** + * 冷启动状态变更上报以及查询状态 + * + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param isQuery 是否是查询 ture:查询相应的结果 false:表示状态变动域控主动推送 + * @param coldStartState 数据 null表示 PadSsmMsg中的消息体为null + */ + fun onColdStartState( + token: Long, + timestamp: Long, + isQuery: Boolean, + coldStartState: SsmInfo.ColdStartState? + ) +} \ No newline at end of file diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotControlManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotControlManager.kt index 44e8ce8e7a..28e7280bca 100644 --- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotControlManager.kt +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotControlManager.kt @@ -22,6 +22,7 @@ import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.mogo.eagle.core.utilcode.util.AppStateManager import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.zhjt.mogo.adas.common.power.PowerUnitChannel import com.zhjt.mogo.adas.data.Adas import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable.IsBootable import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask.GetTaskReq @@ -845,6 +846,82 @@ object CallerAutoPilotControlManager { return providerApi?.sendParallelDrivingReq(reqNo, parallelRequest) ?: false } + /** + * 发送电源状态查询请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendPowerUnitSTSRequest(): Long { + return providerApi?.sendPowerUnitSTSRequest() ?: -1L + } + + /** + * 发送单通道电源控制请求 + * + * @param channel 通道 + * @param cmd 0:关闭;1:打开; + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendPowerUnitSingleChannelControl(channel: PowerUnitChannel, cmd: Int): Long { + return providerApi?.sendPowerUnitSingleChannelControl(channel, cmd) ?: -1L + } + + /** + * 发送电源控制重置请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendPowerUnitReset(): Long { + return providerApi?.sendPowerUnitReset() ?: -1L + } + + /** + * 查询冷启动状态 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendSsmFuncQueryColdStartState(): Long { + return providerApi?.sendSsmFuncQueryColdStartState() ?: -1L + } + + /** + * 查询自驾命令状态 + * 查询:是否首次进自驾、订单号、次数 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendSsmFuncQueryAutoPilotInfo(): Long { + return providerApi?.sendSsmFuncQueryAutoPilotInfo() ?: -1L + } + + /** + * 查询到站信息 + * + * @param orderId 订单号 + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + fun sendSsmFuncQueryAutoPilotStation(orderId: String): Long { + return providerApi?.sendSsmFuncQueryAutoPilotStation(orderId) ?: -1L + } + /** * 打开点云绘制 */ diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotStatusListenerManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotStatusListenerManager.kt index c96fde4939..a9cdb83b1e 100644 --- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotStatusListenerManager.kt +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutoPilotStatusListenerManager.kt @@ -190,6 +190,42 @@ object CallerAutoPilotStatusListenerManager : CallerBase() { + + /** + * 冷启动状态变更上报以及查询状态 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param isQuery 是否是查询 ture:查询相应的结果 false:表示状态变动域控主动推送 + * @param coldStartState 数据 null表示 PadSsmMsg中的消息体为null + */ + @Synchronized + fun invokeColdStartState( + token: Long, + timestamp: Long, + isQuery: Boolean, + coldStartState: SsmInfo.ColdStartState? + ) { + M_LISTENERS.forEach { + val listener = it.value + listener.onColdStartState(token, timestamp, isQuery, coldStartState) + } + } +} \ No newline at end of file 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 6985e1d840..f0771035b6 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 @@ -88,6 +88,13 @@ public enum MessageType { TYPE_RECEIVE_V2N_NIO_OTHER_RETROGRADE_EVENT(MessagePad.MessageType.MsgTypeV2nNioOtherRetrogradeEvent, "V2N NIO他车逆行(路侧)"), TYPE_RECEIVE_V2N_NIO_CONGESTION_EVENT(MessagePad.MessageType.MsgTypeV2nNioCongestionEvent, "V2N NIO拥堵事件"), TYPE_RECEIVE_LANE_MARKS_TRAN(MessagePad.MessageType.MsgTypeLaneMarksTran, "车道线"), + TYPE_SEND_COLLISION_REPORT(MessagePad.MessageType.MsgTypeCollisionReport, "碰撞上报"), + TYPE_SEND_POWER_UNIT(MessagePad.MessageType.MsgTypePowerUnit, "电源模块请求"), + TYPE_RECEIVE_POWER_UNIT(MessagePad.MessageType.MsgTypePowerUnit, "电源模块响应"), + TYPE_SEND_SSM_FUNC_MSG(MessagePad.MessageType.MsgTypeSSMFuncMsg, "SSM功能控制"), + TYPE_RECEIVE_SSM_FUNC_MSG(MessagePad.MessageType.MsgTypeSSMFuncMsg, "SSM功能响应"), + TYPE_SEND_SSM_FUNC_STATUS_QUERY(MessagePad.MessageType.MsgTypeSSMFuncStatusQuery, "SSM功能状态查询"), + TYPE_RECEIVE_SSM_FUNC_STATUS_QUERY(MessagePad.MessageType.MsgTypeSSMFuncStatusQuery, "SSM功能状态响应"), //TODO 透传原始pb文件中不存在以下type。由于Java中无法强转,所以在mogo-adas-data/message_pad.proto中放开注释 TYPE_RECEIVE_PLANNING_DECISION_STATE(MessagePad.MessageType.MsgTypePlanningDecisionState, "Planning决策状态"), TYPE_RECEIVE_SWEEPER_TASK_INDEX_DATA(MessagePad.MessageType.MsgTypeSweeperTaskIndexData, "清扫车指标数据"), diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerControlType.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerControlType.java new file mode 100644 index 0000000000..778153f0ea --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerControlType.java @@ -0,0 +1,34 @@ +package com.zhjt.mogo.adas.common.power; + +/** + * 电源控制类型 + */ +public enum PowerControlType { + UNKNOWN(-1),//未知 + SINGLE_CHANNEL_CONTROL(0x0011),//单通道控制 + SINGLE_CHANNEL_CONTROL_RESPONSE(0x0811),//单通道控制响应 + MULTI_CHANNEL_CONTROL(0x00FF),//多通道控制 + MULTI_CHANNEL_CONTROL_RESPONSE(0x08FF),//多通道控制响应 + RESET_CONTROL(0x0044),//复位控制 + RESET_CONTROL_RESPONSE(0x0844),//复位控制响应 + ; + + + public final int value; + + PowerControlType(int value) { + this.value = value; + } + + + public static PowerControlType getPowerControlType(int value) { + PowerControlType[] data = PowerControlType.values(); + for (PowerControlType type : data) { + if (type.value == value) { + return type; + } + } + return UNKNOWN; + } + +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerError.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerError.java new file mode 100644 index 0000000000..8eac2492af --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerError.java @@ -0,0 +1,55 @@ +package com.zhjt.mogo.adas.common.power; + +public enum PowerError { + + UNKNOWN(-1, "未知"), + ERR0(0x00, "其它未识别异常"), + ERR1(0x01, "帧校验值验证失败或帧类型不支持"), + ERR2(0x02, "STS帧长度“不是12”异常"), + ERR3(0x03, "帧长度“小于16”异常"), + ERR4(0x04, "帧类型不支持(合并处理)"), + ERR5(0x05, "底层控制“CAN”中断异常"), + ERR6(0x06, "底层控制“未就绪”异常"), + ERR7(0x07, "CMD帧的“控制方式”不支持或未定义"), + ERR8(0x08, "CMD帧、单通道控制、通道索引号未注册使用"), + ERR9(0x09, "CMD帧、单通道控制、通道索引号超出范围"), + ; + public final int value; + + /** + * 描述 + */ + public final String desc; + + PowerError(int value, String desc) { + this.value = value; + this.desc = desc; + } + + public static PowerError getPowerError(int value) { + if (value == ERR0.value) { + return ERR0; + } else if (value == ERR1.value) { + return ERR1; + } else if (value == ERR2.value) { + return ERR2; + } else if (value == ERR3.value) { + return ERR3; + } else if (value == ERR4.value) { + return ERR4; + } else if (value == ERR5.value) { + return ERR5; + } else if (value == ERR6.value) { + return ERR6; + } else if (value == ERR7.value) { + return ERR7; + } else { + return UNKNOWN; + } + } + + @Override + public String toString() { + return desc; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerFrameType.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerFrameType.java new file mode 100644 index 0000000000..55d7f4c7b5 --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerFrameType.java @@ -0,0 +1,39 @@ +package com.zhjt.mogo.adas.common.power; + +public enum PowerFrameType { + + UNKNOWN(-1, "未知"), + STS_REQUEST(0x0040, "STS请求"), + STS_RESPONSE(0x0840, "STS响应"), + CMD_REQUEST(0x0044, "CMD请求"), + CMD_RESPONSE(0x0844, "CMD响应"), + ERROR_RESPONSE(0x0800, "服务器异常响应"),//客户端发送的数据服务端检测到异常 + ; + public final int type; + + /** + * 描述 + */ + public final String desc; + + PowerFrameType(int type, String desc) { + this.type = type; + this.desc = desc; + } + + public static PowerFrameType getPowerFrameType(int type) { + if (type == STS_REQUEST.type) { + return STS_REQUEST; + } else if (type == STS_RESPONSE.type) { + return STS_RESPONSE; + } else if (type == CMD_REQUEST.type) { + return CMD_REQUEST; + } else if (type == CMD_RESPONSE.type) { + return CMD_RESPONSE; + } else if (type == ERROR_RESPONSE.type) { + return ERROR_RESPONSE; + } else { + return UNKNOWN; + } + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerProtocolStatus.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerProtocolStatus.java new file mode 100644 index 0000000000..9fbbd85691 --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerProtocolStatus.java @@ -0,0 +1,35 @@ +package com.zhjt.mogo.adas.common.power; + +/** + * 数据协议解析状态 + */ +public enum PowerProtocolStatus { + + + SUCCEED(0x00, "数据解析成功"), + CHECK_FAILED_PACKAGE_LENGTH(0x01, "数据包长度校验失败"), + DATA_LENGTH_NOT_NOTE_OF4(0x02, "数据长度非4的倍数"), + XOR_CHECK_FAILED(0x03, "异域校验失败"), + DATA_PARSE_FAILED(0x04, "数据解析失败"), + CHECK_FAILED_FRAME_HEADER(0x05, "数据头校验失败"), + POWER_FRAME_TYPE_UNKNOWN(0x06, "帧类型未知"), + PAYLOAD_DATA_PARSE_FAILED(0x07, "负载数据解析失败"), + + ; + public final int code; + + /** + * 描述 + */ + public final String desc; + + PowerProtocolStatus(int code, String desc) { + this.code = code; + this.desc = desc; + } + + @Override + public String toString() { + return desc; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerUnitChannel.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerUnitChannel.java new file mode 100644 index 0000000000..e0b2bf98d9 --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/common/power/PowerUnitChannel.java @@ -0,0 +1,96 @@ +package com.zhjt.mogo.adas.common.power; + +/** + * 单元通道 + */ +public enum PowerUnitChannel { + + UNKNOWN(-1, null, -1, null), + AIO_PASSENGER_SCREEN(1, "OUT1", 15, "乘客屏一体机(含主控)"), + EB5_DEVICE(2, "OUT2", 15, "EB5主机(工程样车)"), + VERIFICATION_DEVICE(3, "OUT3", 5, "核销设备"), + DASHCAM(4, "OUT4", 5, "行车记录仪"), + VOICE_MODULE(5, "OUT5", 10, "语音模块"), + CALL_KEY(6, "OUT6", 10, "呼叫按键"), + FRONT_LED_SCREEN(7, "OUT7", 10, "前LED屏"), + BACK_LED_SCREEN(8, "OUT8", 10, "后LED屏"), + POWER_AMPLIFIER(9, "OUT9", 10, "功放"), + AIO_DRIVER_SCREEN(10, "OUT10", 10, "司机屏一体机"), + RTK(27, "OUT27", 5, "RTK定位设备"), + VTBOX(28, "OUT28", 5, "VTBOX"), + FRONT_MILLIMETER_WAVE_RADAR(29, "OUT29", 10, "前毫米波雷达"), + BACK_MILLIMETER_WAVE_RADAR(30, "OUT30", 10, "后毫米波雷达"), + LEFT_FRONT_MILLIMETER_WAVE_RADAR(31, "OUT31", 10, "左前毫米波雷达"), + RIGHT_FRONT_MILLIMETER_WAVE_RADAR(32, "OUT32", 10, "右前毫米波雷达"), + LEFT_BACK_MILLIMETER_WAVE_RADAR(33, "OUT33", 10, "左后毫米波雷达"), + RIGHT_BACK_MILLIMETER_WAVE_RADAR(34, "OUT34", 10, "右后毫米波雷达"), + FRONT_BLIND_LASER_RADAR(35, "OUT35", 5, "前补盲激光雷达"), + LEFT_BLIND_LASER_RADAR(36, "OUT36", 5, "左补盲激光雷达"), + RIGHT_BLIND_LASER_RADAR(37, "OUT37", 5, "右补盲激光雷达"), + BACK_BLIND_LASER_RADAR(38, "OUT38", 5, "后补盲激光雷达"), + FRONT_LASER_RADAR(39, "OUT39", 5, "前激光雷达"), + LEFT_LASER_RADAR(40, "OUT40", 5, "左激光雷达"), + RIGHT_LASER_RADAR(41, "OUT41", 5, "右激光雷达"), + BACK_LASER_RADAR(42, "OUT42", 5, "后激光雷达"), + SWITCH(43, "OUT43", 5, "交换机"), + ROUTER_5G(44, "OUT44", 5, "5G路由器"), + OBU(45, "OUT45", 5, "OBU"), + FRONT_RIGHT_CAMERA_120(52, "M-Video1", 0.6F, "120°前右摄像头(2M)"), + FRONT_CENTRE_CAMERA_60(53, "M-Video2", 0.6F, "60°前中摄像头(8M)"), + LEFT_FRONT_CAMERA_120(54, "M-Video3", 0.6F, "120°左前摄像头(2M)"), + LEFT_BACK_CAMERA_120(55, "M-Video4", 0.6F, "120°左后摄像头(2M)"), + RIGHT_FRONT_CAMERA_120(56, "M-Video5", 0.6F, "120°右前摄像头(2M)"), + RIGHT_BACK_CAMERA_120(57, "M-Video6", 0.6F, "120°右后摄像头(2M)"), + BACK_CAMERA_60(58, "M-Video7", 0.6F, "120°后摄像头(2M)"), + FRONT_SURROUND_VIEW_CAMERA(63, "S-Video4", 0.6F, "前环视摄像头(2M)"), + LEFT_SURROUND_VIEW_CAMERA(64, "S-Video5", 0.6F, "左环视摄像头(2M)"), + RIGHT_SURROUND_VIEW_CAMERA(65, "S-Video6", 0.6F, "右环视摄像头(2M)"), + BACK_SURROUND_VIEW_CAMERA(66, "S-Video7", 0.6F, "后环视摄像头(2M)"), + ; + + /** + * 通道编号 + */ + public final int index; + + /** + * 物理连接通道 + */ + + public final String physicalChannel; + /** + * 电流保护阈值 单位:A + */ + public final float currentProtectionThreshold; + + /** + * 驱动单元 + */ + public final String driverElement; + + + PowerUnitChannel(int index, String physicalChannel, float currentProtectionThreshold, String driverElement) { + this.index = index; + this.physicalChannel = physicalChannel; + this.currentProtectionThreshold = currentProtectionThreshold; + this.driverElement = driverElement; + } + + public static PowerUnitChannel getPowerUnitChannel(int index) { + PowerUnitChannel[] data = PowerUnitChannel.values(); + for (PowerUnitChannel channel : data) { + if (channel.index == index) { + return channel; + } + } + return UNKNOWN; + } + + @Override + public String toString() { + return "PowerUnitChannel{" + + "index=" + index + + ", driverElement='" + driverElement + '\'' + + '}'; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerCommandExecuteState.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerCommandExecuteState.java new file mode 100644 index 0000000000..ab29f581cb --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerCommandExecuteState.java @@ -0,0 +1,68 @@ +package com.zhjt.mogo.adas.data.bean.power; + +import com.zhjt.mogo.adas.common.power.PowerControlType; +import com.zhjt.mogo.adas.common.power.PowerUnitChannel; + +/** + * 命令执行状态 包括:单通道控制;多通道控制;复位控制; + */ +public class PowerCommandExecuteState { + /** + * 控制方式 + */ + public final PowerControlType controlType; + + /** + * 命令是否执行成功 + */ + public final boolean isSucceed; + /** + * 单元索引 + * 单通道控制存在此字段 + */ + public final PowerUnitChannel channel; + + /** + * 下发命令的开关状态 + * 单通道控制存在此字段 + * 索引1~46表示通电状态 0:关闭;1:打开; + */ + public final int sendPowerState; + + /** + * 实际开关状态 + * 单通道控制存在此字段 + * 索引1~46表示通电状态 0:关闭;1:打开; + */ + public final int actualPowerState; + + /** + * 故障状态 + * 单通道控制存在此字段 + * 索引1~46表示故障状态 0:无故障;1:对地短路;2:过流;3:故障; + * 索引51~66表示故障状态 0:无故障;8:过温;4:过流;2:过压;1:欠压;可能出现多故障 + *

+ * 整体判断是否有无故障使用{@link PowerUnitState#isNoneFault()}} + *

+ * 索引为51~66时调用 以下方法判断存在哪些故障 + * {@link PowerUnitState#isTS()}} + * {@link PowerUnitState#isOC()}} + * {@link PowerUnitState#isOV()}} + * {@link PowerUnitState#isUV()}} + * 详情参见{@link PowerUnitState#getFaultState()}} + */ + public final int faultState; + + public PowerCommandExecuteState(PowerControlType controlType, boolean isSucceed) { + this(controlType, isSucceed, null, -1, -1, -1); + } + + public PowerCommandExecuteState(PowerControlType controlType, boolean isSucceed, PowerUnitChannel channel, int sendPowerState, int actualPowerState, int faultState) { + this.controlType = controlType; + this.isSucceed = isSucceed; + this.channel = channel; + this.sendPowerState = sendPowerState; + this.actualPowerState = actualPowerState; + this.faultState = faultState; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerData.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerData.java new file mode 100644 index 0000000000..2f126a488f --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerData.java @@ -0,0 +1,101 @@ +package com.zhjt.mogo.adas.data.bean.power; + +import com.zhjt.mogo.adas.common.power.PowerFrameType; +import com.zhjt.mogo.adas.common.power.PowerProtocolStatus; + +import java.util.List; + + +/** + * 电源原始数据协议 + */ +public class PowerData { + /** + * 原始数据 + */ + public final byte[] originalData; + /** + * 数据拆包状态 + */ + public final PowerProtocolStatus protocolStatus; + + /** + * 帧头 用于检查数据是否为正确数据 + * mg=0xAA55 + */ + public final int frameHead; + /** + * 帧总长度 + */ + public final int totalLength; + /** + * 帧类型 + */ + public final PowerFrameType frameType; + /** + * 保留字节 + */ + public final int reserved; + /** + * 负载数据 + */ + public final byte[] dataBlocks; + /** + * 帧校验值 + */ + public final int checkValue; + + + private List powerUnitStates; + private PowerErrorData powerErrorData; + private PowerCommandExecuteState executeState; + + /** + * 拆包失败的构造 + */ + public static PowerData createError(byte[] originalData, PowerProtocolStatus protocolStatus) { + return new PowerData(originalData, protocolStatus, 0, 0, null, 0, null, 0); + } + + /** + * 拆包成功的构造 + */ + public static PowerData create(byte[] originalData, int frameHead, int totalLength, PowerFrameType frameType, int reserved, byte[] dataBlocks, int checkValue) { + return new PowerData(originalData, PowerProtocolStatus.SUCCEED, frameHead, totalLength, frameType, reserved, dataBlocks, checkValue); + } + + private PowerData(byte[] originalData, PowerProtocolStatus protocolStatus, int frameHead, int totalLength, PowerFrameType frameType, int reserved, byte[] dataBlocks, int checkValue) { + this.originalData = originalData; + this.protocolStatus = protocolStatus; + this.frameHead = frameHead; + this.totalLength = totalLength; + this.frameType = frameType; + this.reserved = reserved; + this.dataBlocks = dataBlocks; + this.checkValue = checkValue; + } + + public List getPowerUnitStates() { + return powerUnitStates; + } + + public void setPowerUnitStates(List powerUnitStates) { + this.powerUnitStates = powerUnitStates; + } + + public PowerErrorData getPowerErrorData() { + return powerErrorData; + } + + public void setPowerErrorData(PowerErrorData powerErrorData) { + this.powerErrorData = powerErrorData; + } + + public PowerCommandExecuteState getExecuteState() { + return executeState; + } + + public void setExecuteState(PowerCommandExecuteState executeState) { + this.executeState = executeState; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerErrorData.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerErrorData.java new file mode 100644 index 0000000000..f6753c9bc5 --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerErrorData.java @@ -0,0 +1,29 @@ +package com.zhjt.mogo.adas.data.bean.power; + +import com.zhjt.mogo.adas.common.power.PowerError; +import com.zhjt.mogo.adas.common.power.PowerFrameType; + +/** + * 服务端输出的异常信息 对应帧类型{@link PowerFrameType#ERROR_RESPONSE} + */ +public class PowerErrorData { + + /** + * 客户端请求类型 + */ + public final PowerFrameType frameType; + /** + * 异常信息 + */ + public final PowerError error; + + public PowerErrorData(PowerFrameType frameType, PowerError error) { + this.frameType = frameType; + this.error = error; + } + + @Override + public String toString() { + return "异常响应,帧类型:" + frameType + " 错误代码:" + error; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerUnitState.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerUnitState.java new file mode 100644 index 0000000000..e1e03c5d39 --- /dev/null +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/data/bean/power/PowerUnitState.java @@ -0,0 +1,171 @@ +package com.zhjt.mogo.adas.data.bean.power; + +import com.zhjt.mogo.adas.common.power.PowerUnitChannel; + +import java.util.Objects; + +/** + * 个单元电源状态 + */ +public class PowerUnitState { + /** + * 单元索引 + */ + private final PowerUnitChannel channel; + + /** + * 单元状态 + * 索引1~46表示通电状态 0:关闭;1:打开;2:底边打开; + * 索引51~66表示连接状态 0:未连接;1:已连接; + */ + private int powerState; + + /** + * 故障状态 + * 索引1~46表示故障状态 0:无故障;1:对地短路;2:过流;3:故障; + * 索引51~66表示故障状态 0:无故障;8:过温;4:过流;2:过压;1:欠压;可能出现多故障 + *

+ * 整体判断是否有无故障使用{@link PowerUnitState#isNoneFault()}} + *

+ * 索引为51~66时调用 以下方法判断存在哪些故障 + * {@link PowerUnitState#isTS()}} + * {@link PowerUnitState#isOC()}} + * {@link PowerUnitState#isOV()}} + * {@link PowerUnitState#isUV()}} + */ + private int faultState; + + /** + * 索引1~46电流保护状态 null表示没有此参数 + * ture:电流保护;false:为保护; + */ + private Boolean currentProtectionState; + + /** + * 索引1~46电流值 null表示没有此参数 + * 单位:A + */ + private Float currentValue; + + public PowerUnitState(PowerUnitChannel channel) { + this.channel = channel; + } + + public PowerUnitChannel getChannel() { + return channel; + } + + public int getPowerState() { + return powerState; + } + + public void setPowerState(int powerState) { + this.powerState = powerState; + } + + public int getFaultState() { + return faultState; + } + + public void setFaultState(int faultState) { + this.faultState = faultState; + } + + public Boolean getCurrentProtectionState() { + return currentProtectionState; + } + + public void setCurrentProtectionState(Boolean currentProtectionState) { + this.currentProtectionState = currentProtectionState; + } + + public Float getCurrentValue() { + return currentValue; + } + + public void setCurrentValue(Float currentValue) { + this.currentValue = currentValue; + } + + /** + * 是否打开 + * 索引1~46表示通电状态 false:关闭;ture:打开或底边打开 + * 索引51~66表示连接状态 false:未连接;ture:已连接; + * + * @return 状态 + */ + public boolean isPowerOpen() { + return powerState != 0; + } + + /** + * 是否无故障 + * 索引1~46表示通电状态 true:无故障;false:对地短路或过流或故障; + * 索引51~66表示连接状态 true:无故障;false:过温或过流或过压或欠压; + * + * @return 有无故障 + */ + public boolean isNoneFault() { + return faultState == 0; + } + + /** + * 索引51~66是否过温故障 + * + * @return 是否过温故障 + */ + public boolean isTS() { + return (faultState & 8) == 8; + } + + /** + * 索引51~66是否过流故障 + * + * @return 是否过流故障 + */ + public boolean isOC() { + return (faultState & 4) == 4; + } + + /** + * 索引51~66是否过压故障 + * + * @return 是否过压故障 + */ + public boolean isOV() { + return (faultState & 2) == 2; + } + + /** + * 索引51~66是否欠压故障 + * + * @return 是否欠压故障 + */ + public boolean isUV() { + return (faultState & 1) == 1; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PowerUnitState that = (PowerUnitState) o; + return channel == that.channel; + } + + @Override + public int hashCode() { + return Objects.hashCode(channel); + } + + @Override + public String toString() { + return "PowerUnitState{" + + "channel=" + channel + + ", powerState=" + powerState + + ", faultState=" + faultState + + ", currentProtectionState=" + currentProtectionState + + ", currentValue=" + currentValue + + '}'; + } +} diff --git a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/utils/ByteUtil.java b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/utils/ByteUtil.java index 015f877f82..c450e03f87 100644 --- a/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/utils/ByteUtil.java +++ b/libraries/mogo-adas-data/src/main/java/com/zhjt/mogo/adas/utils/ByteUtil.java @@ -18,6 +18,13 @@ public class ByteUtil { return bytes; } + public static byte[] set16bitUnsignedValueLittleEndian(int num) { + byte[] bytes = new byte[2]; + bytes[1] = (byte) (num >> 8); + bytes[0] = (byte) num; + return bytes; + } + public static byte[] set32bitUnsignedValue(long num) { byte[] bytes = new byte[4]; bytes[0] = (byte) (num >> 24); @@ -27,6 +34,15 @@ public class ByteUtil { return bytes; } + public static byte[] set32bitUnsignedValueValueLittleEndian(long num) { + byte[] bytes = new byte[4]; + bytes[0] = (byte) num; + bytes[1] = (byte) (num >> 8); + bytes[2] = (byte) (num >> 16); + bytes[3] = (byte) (num >> 24); + return bytes; + } + public static byte[] set64bitUnsignedValue(long num) { byte[] bytes = new byte[8]; bytes[0] = (byte) (num >> 56); @@ -81,6 +97,25 @@ public class ByteUtil { return value; } + /** + * 无符号 + * 合并 2 byte + * 使用后将 Index中的index移动到下一个数据的开始位 + * + * @param data + * @return + */ + + public static int get16bitUnsignedValueLittleEndian(byte[] data) { + int value = 0; + if (data.length > 1) { + value = data[1] & 0xFF; + value = value << 8; + value = value | (data[0] & 0xFF); + } + return value; + } + /** * 无符号 * 合并 4 byte @@ -106,6 +141,30 @@ public class ByteUtil { return value; } + /** + * 无符号 + * 合并 4 byte + * 使用后将 Index中的index移动到下一个数据的开始位 + * * + * + * @param data + * @return + */ + + public static int get32bitUnsignedValueLittleEndian(byte[] data) { + int value = 0; + if (data.length > 3) { + value = data[3] & 0xFF; + value = value << 8; + value = value | (data[2] & 0xFF); + value = value << 8; + value = value | (data[1] & 0xFF); + value = value << 8; + value = value | (data[0] & 0xFF); + } + return value; + } + /** * 无符号 * 合并 8 byte @@ -374,4 +433,11 @@ public class ByteUtil { (byte) ((b >> 6) & 0x1) + (byte) ((b >> 7) & 0x1); } + + + //b为传入的字节,i为第几位(范围0-7),如要获取bit0,则i=0 + public static int getBit(byte b, int i) { + return (b >> i) & 0x1; + } + } 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 560b6fd351..b9f77fc20f 100644 --- a/libraries/mogo-adas-data/src/main/proto/message_pad.proto +++ b/libraries/mogo-adas-data/src/main/proto/message_pad.proto @@ -93,6 +93,10 @@ enum MessageType MsgTypeV2nNioOtherRetrogradeEvent = 0x1012a; //他车逆行(路侧)事件推送, 透传 MsgTypeV2nNioCongestionEvent = 0x1012b; //拥堵事件推送, 透传 MsgTypeLaneMarksTran = 0x1012c;//车道线上传 + MsgTypeCollisionReport = 0x1012d;//碰撞上报 + MsgTypePowerUnit = 0x1012e;//电源模块通信 + MsgTypeSSMFuncMsg = 0x1012f;//SSM功能(上下行) + MsgTypeSSMFuncStatusQuery = 0x10130;//SSM功能状态查询及返回(上下行) } message Header @@ -292,7 +296,7 @@ message TrackedSource message TrackedObject { - uint32 type = 1; //物体类型, 0:Background, 1:Person, 2:Bicycle, 3:Car, 4:MotorCycle, + uint32 type = 1; //物体类型, 0:Background, 1:Person, 2:Bicycle, 3:Car, 4:MotorCycle, //5:TrafficSign, 6:Bus, 7:CellPhone, 8:Truck, 9:Bottle, 10:TrafficLight, //11:Rider, 12:TriangleRoadblock, 13:WarningTriangle, 100:Unknown, //447:TAILBACK 501:RoadWork_occupy_0501, 502:RoadWork_break_0502, @@ -351,7 +355,7 @@ message TrackedObjects // message definition for MsgTypeGnssInfo message GnssInfo { - double longitude = 1; //经度 + double longitude = 1; //经度 double latitude = 2; //纬度 double altitude = 3; //海拔 double heading = 4; //航向角 @@ -393,7 +397,7 @@ message AutopilotState // message definition for MessageType: MsgTypePlanningObjects message PlanningObject { - uint32 uuid = 1; + uint32 uuid = 1; uint32 type = 2; //影响自车决策的类型, 和感知的障碍物类型不是一回事 0是leading障碍物,1是避障和择机的障碍物 } @@ -434,7 +438,7 @@ message TrajectoryDownloadReq } // message definition for MessageType: MsgTypeBasicInfoReq -message BasicInfoReq +message BasicInfoReq { bytes certification = 1;//域控ssl证书 } @@ -462,7 +466,7 @@ message Location message RouteInfo { - Location startLocation = 1; + Location startLocation = 1; string startName = 2; Location endLocation = 3; string endName = 4; @@ -478,12 +482,18 @@ message RouteInfo bool isStation = 13; //20240523 用于表示判断是否是站点下单。默认false:起点下单,接管下单; true: 中间站点下单 } +message CmdInfo { + bool first_autopilot_flag = 1; // 是否首次进自驾 + string order_id = 2; // 订单号 +} + message SetAutopilotModeReq { uint32 mode = 1; //1: enter autopilot mode, 0: quit autopilot mode uint32 source = 2; //命令来源: 0: pad模拟, 1: pad业务, 2:aicloud, 3:魔方(清扫车MAP Version==332以及MAP Version>=350,其他车型目前未上线) RouteInfo routeInfo = 3; //自动驾驶路径信息 uint64 sessionId = 4; //autopilot cmd session ID + CmdInfo cmd_info = 5; //自驾命令信息 } // message definition for MsgTypeSetDemoModeReq @@ -505,7 +515,7 @@ message CarConfigResp string macAddress = 3; ProtocolVersion protocolVersion = 4; //通信协议版本 double speedLimit = 5; //自动驾驶限速, 单位:m/s - double maxSpeedLimit = 6; //最大自动驾驶限速, 单位:m/s + double maxSpeedLimit = 6; //最大自动驾驶限速, 单位:m/s double minAcceleration = 7; //最小加速度, 单位:m/s² double maxAcceleration = 8; //最大加速度, 单位:m/s² string carType = 9; //车辆类型 @@ -582,7 +592,7 @@ message TrafficLightDetail message TrafficLightData { string crossID = 1; //roadID - double latitude = 2; + double latitude = 2; double longitude = 3; string heading = 4; //红绿灯方向 string direction = 5; //路的航向角 @@ -794,7 +804,7 @@ message PlanningActionMsg //message definition for MsgTypeSetParamReq message SetOneParam { - uint32 type = 1; // 0:default 1:绕障类功能开关(bool) 2:变道绕障的目标障碍物速度阈值(double, m/s),针对低速绕行功能的 + uint32 type = 1; // 0:default 1:绕障类功能开关(bool) 2:变道绕障的目标障碍物速度阈值(double, m/s),针对低速绕行功能的 // 3:AEB开关(bool) 0:关闭自动紧急制动功能 1:启用自动紧急制动功能 // 4:限制绕障开关(bool) 0:正常绕障 1:限制绕障 默认0 // 5:停车让行线前避让等待开关(bool) 0:停车让行线前无需等待 1:停车让行线前需要等待 默认0 @@ -810,7 +820,7 @@ message SetOneParam // 15:座椅状态(int) 0:表示仅主驾位有人,1:表示仅副驾位有人,2:表示主驾和副驾同时有人,3:表示仅后排有人,4:表示主驾有人+后排有人,5:表示副驾有人+后排有人,6:表示主驾和副驾同时有人+后排有人,7: 所有座位都无人, 255:缺省 // 16: 超车的最大速度阈值(double, m/s) T1/T2: 范围[3, 12.5], 默认值10 // 17: 故障模拟指令(int) default:0, 1:线控失效 - // 18: 碰撞上报(null) + // 18: 碰撞上报(null) TODO 废弃,使用:message CollisionReport // 19: 会车开关(bool) 0: off 1:on 默认0 // 20: 超车开关(bool) 0: off 1:on 默认0 string value = 2; // 转成字符串的值 @@ -923,3 +933,11 @@ message SessionInfo //message definition for MsgTypeLocState //refer to loc_state.proto + +//message definition for MsgTypeCollisionReport +message CollisionReport +{ + double longitude = 1; + double latitude = 2; + double timestamp = 3;//时间, 单位:秒 +} \ No newline at end of file diff --git a/libraries/mogo-adas-data/src/main/proto/ssm_info.proto b/libraries/mogo-adas-data/src/main/proto/ssm_info.proto index 1d9653c267..7e738f60d2 100644 --- a/libraries/mogo-adas-data/src/main/proto/ssm_info.proto +++ b/libraries/mogo-adas-data/src/main/proto/ssm_info.proto @@ -52,3 +52,128 @@ message SsmStatusInf { optional string slam_map_ver = 22; //slam地图版本 optional string grid_map_ver = 23; //栅格地图版本 } + + +enum MessageType { + NOTIFICATION = 0; // ssm发送通知 msg:Notification + OTA_DOWNLOAD_REQUEST = 1; // ssm发送OTA升级提示请求 todo + OTA_DOWNLOAD_RESPONSE = 2; // pad下发OTA升级提示响应 todo + OTA_LOADING_PROGRESS = 3; // ssm上报OTA下载进度, 开始升级后定频上报 todo + OTA_STATUS = 4; // ssm 上报OTA状态 todo + OTA_STATUS_QUERY = 5; // pad查询OTA状态 req:OtaToken resp:OtaStatus + COLD_START_STATUS_REPORT = 6; // 冷启动状态上报 msg:ColdStartState + COLD_START_STATE_QUERY = 7; // 冷启动状态查询 req:None resp:ColdStartState + AUTO_PILOT_INFO = 8; // 自驾命令状态查询 resp:AutoPilotInfo + STATION_STATUS_QUERY = 9; //到站信息查询 req: OrderInfo resp:AutoPilotStation +} + +message PadSsmMsg { + required uint64 token = 1; //消息唯一id + required MessageType msg_type = 2; //消息类型 + required double timestamp = 3; //消息发送时间, 单位:秒 + optional bytes data = 6; // 消息体 +} + +enum Level { + INFO_MSG = 0; + WARNING_MSG = 1; + ERROR_MSG = 2; +} + +message Notification { + required Level level = 1; // 消息等级 0:info, 1:warning, 2:error + required string msg = 2; // 通知 +} + +enum OtaType { + IMAGE = 1; + FIRMWARE = 2; + MAP = 3; + PROFILE = 4; +} + +message OtaDownloadRequest { + required string ota_token = 1; // ota token 唯一标识 + required OtaType ota_type = 2; // ota type 1:镜像, 2:固件, 3:地图, 4:配置文件 + required bool need_restart = 3; // 是否需要重启 True:需要, False:不需要 + required string product_name = 4; // 制品名称 + optional double size = 5; // 文件大小 Mb +} + +enum IfUpgrade { + IMMEDIATELY = 1; + DELAY = 2; +} + +message OtaToken { + required string token = 1; // ota token +} + +message OtaDownloadResponse { + required string token = 1; // ota token + required IfUpgrade if_upgrade = 2; // 是否立即升级 1:立即升级 2:暂不升级 +} + +message OtaLoadingProgess { + required string ota_token = 1; // ota token + required double currentSize = 2; // 当前下载大小 + required double totalSize = 3; // 总大小 +} + +enum UpgradeStatus { + UPGRADE_DEFAULT = 0; + UPGRADE_DOWNLOADING = 1; + UPGRADE_DOWNLOAD_FINISH = 2; + UPGRADE_FINSH = 3; + UPGRADE_FAIL = 4; +} + +message OtaStatus { + required OtaDownloadRequest ota_info = 1; // 升级信息 + required UpgradeStatus status = 2; // 状态 0:默认(未开始), 1:下载中, 2:下载完成, 3:升级完成, 4:升级失败 + optional string reason = 3; // 失败原因 +} + +enum CSState { + COLD_START_DEFAULT = 0; // 未开始 + COLD_START_STARTING = 1; // 启动中 + COLD_START_READY = 2; // 就绪 + COLD_START_UNREADY = 3; // 有异常未就绪 + COLD_START_TIMEOUT = 4; // 超时 +} + +enum NodeStatus { + NODE_STARTING = 0; // 启动中 + NODE_FINISH = 1; // 启动成功 + NODE_FAILED = 2; // 启动失败 + NODE_TIMEOUT = 3; // 启动超时 +} + +message ColdStartNode { + required string node_name = 1; //节点名称 + required string event_code = 2; //上报事件 + required NodeStatus status = 3; //0:启动中, 1:启动成功, 2:启动失败, 3:启动超时 + required string desc = 4; //事件描述 +} + +message ColdStartState { + required CSState process_status = 1; //旧冷启动状态 + required CSState event_status = 2; //节点自上报冷启动状态 + repeated ColdStartNode node = 3; //冷启动关键节点信息 + optional string process_timeout_reason = 4; //旧冷启动超时原因 +} + +message AutoPilotInfo { + required bool first_autopilot_flag = 1; // 是否首次进自驾 + required string order_id = 2; // 订单号 + required uint32 count = 3; // 次数 +} + +message OrderInfo{ + required string order_id = 1; //订单号 +} + +message AutoPilotStation { + required bool arrived_station_flag = 1; //是否到站 + optional string order_id = 2; //订单号 +} \ No newline at end of file diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java index 03783708cc..7e184cad1c 100644 --- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasChannel.java @@ -39,6 +39,7 @@ import com.zhidao.support.adas.high.protocol.PackData; import com.zhidao.support.adas.high.protocol.RawData; import com.zhidao.support.adas.high.protocol.RawPack; import com.zhidao.support.adas.high.protocol.RawUnpack; +import com.zhidao.support.adas.high.protocol.power.PowerRawPack; import com.zhidao.support.adas.high.queue.WSByteQueueManager; import com.zhidao.support.adas.high.queue.WebSocketQueueManager; import com.zhidao.support.adas.high.socket.FpgaSocket; @@ -46,6 +47,9 @@ import com.zhidao.support.adas.high.subscribe.SubscribeInterface; import com.zhidao.support.adas.high.subscribe.SubscribeInterfaceOption; import com.zhidao.support.adas.high.thread.DispatchHandler; import com.zhjt.mogo.adas.common.MessageType; +import com.zhjt.mogo.adas.common.power.PowerControlType; +import com.zhjt.mogo.adas.common.power.PowerFrameType; +import com.zhjt.mogo.adas.common.power.PowerUnitChannel; import com.zhjt.mogo.adas.data.AdasConstants; import com.zhjt.mogo.adas.data.AiCloudTask; import com.zhjt.mogo.adas.data.bean.AdasParam; @@ -70,7 +74,6 @@ import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import bag_manager.BagManagerOuterClass; -import chassis.Chassis; import chassis.SpecialVehicleTaskCmdOuterClass; import common.HeaderOuterClass; import function_state_management.FSMStatusReasonQueryOuterClass; @@ -78,6 +81,7 @@ import mogo.telematics.ParamSetCmdOuterClass; import mogo.telematics.pad.MessagePad; import mogo.yycp.paralleldriving.protocol.ParallelDrivingRequest; import okio.ByteString; +import system_master.SsmInfo; /** * @ProjectName: lib-adas-fpga @@ -150,6 +154,7 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec private final ReceivedAckManager receivedAckManager = new ReceivedAckManager();//消息回执 private final AtomicBoolean isInitConfigure = new AtomicBoolean(false);//是否进行配置初始化 + private PowerRawPack powerRawPack; public void setOnMultiDeviceListener(OnMultiDeviceListener onMultiDeviceListener) { this.onMultiDeviceListener = onMultiDeviceListener; @@ -1177,13 +1182,14 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec * @param mode 1: enter autopilot mode, 0: quit autopilot mode * @param source 命令来源: 0: pad模拟, 1: pad业务, 2:aicloud, 3:魔方(清扫车MAP Version==332以及MAP Version>=350,其他车型目前未上线) * @param routeInfo 自动驾驶路径信息 + * @param cmdInfo 自驾命令信息(订单号,是否首次进自驾等) * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID和SessionID * * >=0:表示添加到WS发送消息队列 * * =0:表示乘客屏模式添加到WS发送消息队列 * * -1L:添加到WS发送消息队列失败 */ @Override - public long sendAutoPilotModeReq(int mode, int source, MessagePad.RouteInfo routeInfo) { + public long sendAutoPilotModeReq(int mode, int source, @Nullable MessagePad.RouteInfo routeInfo, @Nullable MessagePad.CmdInfo cmdInfo) { MessageId messageId = MessageId.build(MessageType.TYPE_SEND_SET_AUTOPILOT_MODE_REQ); MessagePad.SetAutopilotModeReq.Builder builder = MessagePad.SetAutopilotModeReq.newBuilder(); builder.setMode(mode); @@ -1191,6 +1197,9 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec if (routeInfo != null) builder.setRouteInfo(routeInfo); builder.setSessionId(messageId.id); + if (cmdInfo != null) { + builder.setCmdInfo(cmdInfo); + } MessagePad.SetAutopilotModeReq req = builder.build(); if (autopilotReview != null) autopilotReview.onAutopilotCommandTrigger(req); return sendPBMessage(MessageType.TYPE_SEND_SET_AUTOPILOT_MODE_REQ, req.toByteArray(), messageId); @@ -1642,9 +1651,9 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec * 发送 轨迹下载请求 * 此方法存在域控回执,监听{@link OnAdasListener#onReceiveReceivedAck(ReceivedAck)}回调.使用方法:将此方法的返回值与{@link ReceivedAck#getMsgId()}进行比较,如果相同判断{@link ReceivedAck#getStatus()}是否等于{@link ReceivedAck.Status#NORMAL},详情参见CheckSystemView中的onReceiveReceivedAck * - * @param line 线路相关参数详情见PB message_pad.proto -> Line - * @param downloadType 下载类型: 0:正常下载 1:预下载 - * @param routeInfo 20240523 进行自动算路,务必下单时候携带自动驾驶路径信息,否则可不填! + * @param line 线路相关参数详情见PB message_pad.proto -> Line + * @param downloadType 下载类型: 0:正常下载 1:预下载 + * @param routeInfo 20240523 进行自动算路,务必下单时候携带自动驾驶路径信息,否则可不填! * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID * * >=0:表示添加到WS发送消息队列 * * =0:表示乘客屏模式添加到WS发送消息队列 @@ -2874,5 +2883,117 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec return sendAiCloudTaskCmd(MessageType.TYPE_SEND_PARALLEL_DRIVING_REQ, AiCloudTask.MessageType.ParallelDrivingCmd, reqNo, parallelRequest.toByteString()); } + private long sendPowerUnit(PowerFrameType frameType, byte[] data) { + if (powerRawPack == null) { + powerRawPack = new PowerRawPack(); + } + byte[] temp = powerRawPack.pack(frameType, data); + return sendPBMessage(MessageType.TYPE_SEND_POWER_UNIT, temp); + } + + /** + * 发送电源状态查询请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendPowerUnitSTSRequest() { + return sendPowerUnit(PowerFrameType.STS_REQUEST, null); + } + + /** + * 发送单通道电源控制请求 + * + * @param channel 通道 + * @param cmd 0:关闭;1:打开; + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendPowerUnitSingleChannelControl(PowerUnitChannel channel, int cmd) { + byte[] type = ByteUtil.set16bitUnsignedValueLittleEndian(PowerControlType.SINGLE_CHANNEL_CONTROL.value); + byte[] channelB = ByteUtil.set8bitUnsignedValue(channel.index); + byte[] cmdB = ByteUtil.set8bitUnsignedValue(cmd); + byte[] temp = ByteUtil.concatBytes(type, channelB); + temp = ByteUtil.concatBytes(temp, cmdB); + return sendPowerUnit(PowerFrameType.CMD_REQUEST, temp); + } + + @Override + public long sendPowerUnitReset() { + byte[] type = ByteUtil.set16bitUnsignedValueLittleEndian(PowerControlType.RESET_CONTROL.value); + byte[] reserved = ByteUtil.set16bitUnsignedValueLittleEndian(0); + byte[] temp = ByteUtil.concatBytes(type, reserved); + return sendPowerUnit(PowerFrameType.CMD_REQUEST, temp); + } + + /** + * 发送SSM功能消息 + * + * @param isQuery 是否是查询功能 + * @param data 数据 + * @return + */ + private long sendSsmFuncMsg(boolean isQuery, system_master.SsmInfo.MessageType type, @Nullable com.google.protobuf.ByteString data) { + MessageType messageType = isQuery ? MessageType.TYPE_SEND_SSM_FUNC_STATUS_QUERY : MessageType.TYPE_SEND_SSM_FUNC_MSG; + MessageId messageId = MessageId.build(messageType); + SsmInfo.PadSsmMsg.Builder builder = SsmInfo.PadSsmMsg.newBuilder(); + builder.setToken(messageId.id); + builder.setMsgType(type); + builder.setTimestamp(System.currentTimeMillis() / 1000D); + if (data != null && !data.isEmpty()) { + builder.setData(data); + } + SsmInfo.PadSsmMsg req = builder.build(); + return sendPBMessage(messageType, req.toByteArray(), messageId); + } + + /** + * 查询冷启动状态 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendSsmFuncQueryColdStartState() { + return sendSsmFuncMsg(true, system_master.SsmInfo.MessageType.COLD_START_STATE_QUERY, null); + } + + /** + * 查询自驾命令状态 + * 查询:是否首次进自驾、订单号、次数 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendSsmFuncQueryAutoPilotInfo() { + return sendSsmFuncMsg(true, system_master.SsmInfo.MessageType.AUTO_PILOT_INFO, null); + } + + /** + * 查询到站信息 + * + * @param orderId 订单号 + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendSsmFuncQueryAutoPilotStation(@NonNull String orderId) { + return sendSsmFuncMsg(true, system_master.SsmInfo.MessageType.STATION_STATUS_QUERY, SsmInfo.OrderInfo.newBuilder().setOrderId(orderId).build().toByteString()); + } + + } diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java index 49e3723e69..0796d7dd15 100644 --- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/AdasManager.java @@ -16,6 +16,7 @@ import com.zhidao.support.adas.high.common.MessageIdGenerator; import com.zhidao.support.adas.high.common.ReceiveTimeoutManager; import com.zhidao.support.adas.high.common.autopilot.ability.AutopilotAbilityManager; import com.zhjt.mogo.adas.common.MessageType; +import com.zhjt.mogo.adas.common.power.PowerUnitChannel; import com.zhjt.mogo.adas.data.Adas; import com.zhjt.mogo.adas.data.AdasConstants; import com.zhjt.mogo.adas.data.bean.AdasParam; @@ -397,14 +398,15 @@ public class AdasManager implements IAdasNetCommApi { * @param mode 1: enter autopilot mode, 0: quit autopilot mode * @param source 命令来源: 0: pad模拟, 1: pad业务, 2:aicloud, 3:魔方(清扫车MAP Version==332以及MAP Version>=350,其他车型目前未上线) * @param routeInfo 自动驾驶路径信息 + * @param cmdInfo 自驾命令信息(订单号,是否首次进自驾等) * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID和SessionID * * >=0:表示添加到WS发送消息队列 * * =0:表示乘客屏模式添加到WS发送消息队列 * * -1L:添加到WS发送消息队列失败 */ @Override - public long sendAutoPilotModeReq(int mode, int source, MessagePad.RouteInfo routeInfo) { - return mChannel == null ? -1L : mChannel.sendAutoPilotModeReq(mode, source, routeInfo); + public long sendAutoPilotModeReq(int mode, int source, @Nullable MessagePad.RouteInfo routeInfo, @Nullable MessagePad.CmdInfo cmdInfo) { + return mChannel == null ? -1L : mChannel.sendAutoPilotModeReq(mode, source, routeInfo, cmdInfo); } /** @@ -1731,6 +1733,81 @@ public class AdasManager implements IAdasNetCommApi { return mChannel == null ? -1L : mChannel.sendParallelDrivingReq(reqNo, parallelRequest); } + + /** + * 发送电源状态查询请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendPowerUnitSTSRequest() { + return mChannel == null ? -1L : mChannel.sendPowerUnitSTSRequest(); + } + + /** + * 发送单通道电源控制请求 + * + * @param channel 通道 + * @param cmd 0:关闭;1:打开; + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendPowerUnitSingleChannelControl(PowerUnitChannel channel, int cmd) { + return mChannel == null ? -1L : mChannel.sendPowerUnitSingleChannelControl(channel, cmd); + } + + @Override + public long sendPowerUnitReset() { + return mChannel == null ? -1L : mChannel.sendPowerUnitReset(); + } + + /** + * 查询冷启动状态 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendSsmFuncQueryColdStartState() { + return mChannel == null ? -1L : mChannel.sendSsmFuncQueryColdStartState(); + } + + /** + * 查询自驾命令状态 + * 查询:是否首次进自驾、订单号、次数 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendSsmFuncQueryAutoPilotInfo() { + return mChannel == null ? -1L : mChannel.sendSsmFuncQueryAutoPilotInfo(); + } + + /** + * 查询到站信息 + * + * @param orderId 订单号 + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + @Override + public long sendSsmFuncQueryAutoPilotStation(@NonNull String orderId) { + return mChannel == null ? -1L : mChannel.sendSsmFuncQueryAutoPilotStation(orderId); + } + /** * 查询节点状态 * diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java index 2fdfa84f0d..5aecae3df7 100644 --- a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/IAdasNetCommApi.java @@ -7,6 +7,7 @@ import com.zhidao.support.adas.high.bean.VersionCompatibility; import com.zhidao.support.adas.high.common.Constants; import com.zhidao.support.adas.high.common.Define; import com.zhjt.mogo.adas.common.MessageType; +import com.zhjt.mogo.adas.common.power.PowerUnitChannel; import com.zhjt.mogo.adas.data.AdasConstants; import com.zhjt.mogo.adas.data.bean.AdasParam; import com.zhjt.mogo.adas.data.bean.ReceivedAck; @@ -22,7 +23,6 @@ import java.util.Map; import java.util.Set; import bag_manager.BagManagerOuterClass; -import chassis.Chassis; import chassis.SpecialVehicleTaskCmdOuterClass; import mogo.telematics.pad.MessagePad; import mogo.yycp.paralleldriving.protocol.ParallelDrivingRequest; @@ -169,12 +169,13 @@ public interface IAdasNetCommApi { * @param mode 1: enter autopilot mode, 0: quit autopilot mode * @param source 命令来源: 0: pad模拟, 1: pad业务, 2:aicloud, 3:魔方(清扫车MAP Version==332以及MAP Version>=350,其他车型目前未上线) * @param routeInfo 自动驾驶路径信息 + * @param cmdInfo 自驾命令信息(订单号,是否首次进自驾等) * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID和SessionID * * >=0:表示添加到WS发送消息队列 * * =0:表示乘客屏模式添加到WS发送消息队列 * * -1L:添加到WS发送消息队列失败 */ - long sendAutoPilotModeReq(int mode, int source, MessagePad.RouteInfo routeInfo); + long sendAutoPilotModeReq(int mode, int source, @Nullable MessagePad.RouteInfo routeInfo, @Nullable MessagePad.CmdInfo cmdInfo); /** @@ -468,15 +469,15 @@ public interface IAdasNetCommApi { * 发送 轨迹下载请求 * 此方法存在域控回执,监听{@link OnAdasListener#onReceiveReceivedAck(ReceivedAck)}回调.使用方法:将此方法的返回值与{@link ReceivedAck#getMsgId()}进行比较,如果相同判断{@link ReceivedAck#getStatus()}是否等于{@link ReceivedAck.Status#NORMAL},详情参见CheckSystemView中的onReceiveReceivedAck * - * @param line 线路相关参数详情见PB message_pad.proto -> Line - * @param downloadType 下载类型: 0:正常下载 1:预下载 - * @param routeInfo 20240523 进行自动算路,务必下单时候携带自动驾驶路径信息,否则可不填! + * @param line 线路相关参数详情见PB message_pad.proto -> Line + * @param downloadType 下载类型: 0:正常下载 1:预下载 + * @param routeInfo 20240523 进行自动算路,务必下单时候携带自动驾驶路径信息,否则可不填! * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID * * >=0:表示添加到WS发送消息队列 * * =0:表示乘客屏模式添加到WS发送消息队列 * * -1L:添加到WS发送消息队列失败 */ - long sendTrajectoryDownloadReq(MessagePad.Line line, int downloadType, MessagePad.RouteInfo routeInfo); + long sendTrajectoryDownloadReq(MessagePad.Line line, int downloadType, MessagePad.RouteInfo routeInfo); /** * 发送 状态查询请求 @@ -1241,6 +1242,70 @@ public interface IAdasNetCommApi { */ long sendParallelDrivingReq(@NonNull String reqNo, @NonNull ParallelDrivingRequest.ParallelRequest parallelRequest); + /** + * 发送电源状态查询请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + long sendPowerUnitSTSRequest(); + + /** + * 发送单通道电源控制请求 + * + * @param channel 通道 + * @param cmd 0:关闭;1:打开; + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + long sendPowerUnitSingleChannelControl(PowerUnitChannel channel, int cmd); + + /** + * 发送电源控制重置请求 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + long sendPowerUnitReset(); + + /** + * 查询冷启动状态 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + long sendSsmFuncQueryColdStartState(); + + /** + * 查询自驾命令状态 + * 查询:是否首次进自驾、订单号、次数 + * + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + long sendSsmFuncQueryAutoPilotInfo(); + + /** + * 查询到站信息 + * + * @param orderId 订单号 + * @return 消息是否添加到WS消息发送队列,返回值为非0的正整数时表示下发消息的消息ID + * * >=0:表示添加到WS发送消息队列 + * * =0:表示乘客屏模式添加到WS发送消息队列 + * * -1L:添加到WS发送消息队列失败 + */ + long sendSsmFuncQueryAutoPilotStation(@NonNull String orderId); + // TODO 需求暂停 待讨论 // boolean getRoutes(); 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 091535c69a..c58a5e6180 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 @@ -7,6 +7,7 @@ import com.google.protobuf.ByteString; import com.mogo.support.obu.ObuScene; import com.zhidao.support.adas.high.common.ProtocolStatus; import com.zhjt.mogo.adas.common.MessageType; +import com.zhjt.mogo.adas.common.power.PowerProtocolStatus; import com.zhjt.mogo.adas.data.AdasConstants; import com.zhjt.mogo.adas.data.AiCloudTask; import com.zhjt.mogo.adas.data.bean.AdasParam; @@ -15,6 +16,7 @@ import com.zhjt.mogo.adas.data.bean.LaunchConditionData; import com.zhjt.mogo.adas.data.bean.NodeStateInfo; import com.zhjt.mogo.adas.data.bean.ReceivedAck; import com.zhjt.mogo.adas.data.bean.UnableLaunchReason; +import com.zhjt.mogo.adas.data.bean.power.PowerData; import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable; import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask; import com.zhjt.mogo.adas.data.sweeper.task.big.SweeperBigTaskStatus; @@ -205,6 +207,38 @@ public interface OnAdasListener { @Deprecated void onWarn(MessagePad.Header header, MessagePad.Warn warn); + /** + * 冷启动状态变更上报以及查询状态 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param isQuery 是否是查询 ture:查询相应的结果 false:表示状态变动域控主动推送 + * @param coldStartState 数据 null表示 PadSsmMsg中的消息体为null + */ + void onColdStartState(MessagePad.Header header, long token, long timestamp, boolean isQuery, @Nullable SsmInfo.ColdStartState coldStartState); + + /** + * 自驾命令状态查询响应 + * 返回 是否首次进自驾、订单号、次数 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param autoPilotInfo 数据 null表示 PadSsmMsg中的消息体为null + */ + void onAutoPilotInfo(MessagePad.Header header, long token, long timestamp, @Nullable SsmInfo.AutoPilotInfo autoPilotInfo); + + /** + * 到站信息查询响应 + * + * @param header 头 + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param autoPilotStation 数据 null表示 PadSsmMsg中的消息体为null + */ + void onAutoPilotStation(MessagePad.Header header, long token, long timestamp, @Nullable SsmInfo.AutoPilotStation autoPilotStation); + /** * 到站提醒 自动驾驶站点 * @@ -538,11 +572,23 @@ public interface OnAdasListener { /** * 车道线 * - * @param header 头 + * @param header 头 * @param laneMarks 数据 */ void onLaneMarksTran(@NonNull MessagePad.Header header, @NonNull LaneMarkOuterClass.LaneMarks laneMarks); + /** + * 电源盒协议接口 + *

+ * {@link PowerData}使用方法 + * 1.先判断数据中的{@link PowerData#protocolStatus} 是否是 {@link PowerProtocolStatus#SUCCEED} 如果是则表示数据解析正常可以正常使用,进行下一步 + * 2.判断 {@link PowerData#frameType} 数据类型 + * + * @param header 头 + * @param data 数据 + */ + void onPowerUnit(@NonNull MessagePad.Header header, @NonNull PowerData data); + /** * 所连接的域控的节点状态信息 * 目前包含状态 节点是否存在;节点是否超时; 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 1dc44cf498..b221e7746c 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 @@ -53,6 +53,8 @@ public class MyMessageFactory implements IMyMessageFactory { private IMsg v2nNioOtherRetrogradeEventMessage;//V2N NIO他车逆行(路侧) private IMsg v2nNioCongestionEventMessage;//V2N NIO拥堵事件 private IMsg laneMarksTranMessage;//车道线 + private IMsg powerUnitMessage;//电源模块 + private IMsg padSsmFuncMsgMessage;//SSM功能 private final AutopilotReview autopilotReview; private final TurnLightState lightLeft = new TurnLightState(); @@ -303,6 +305,18 @@ public class MyMessageFactory implements IMyMessageFactory { laneMarksTranMessage = new LaneMarksTranMessage(); } return laneMarksTranMessage; + } else if (messageType == MessageType.TYPE_RECEIVE_POWER_UNIT.typeCode) { + //电源模块响应 + if (powerUnitMessage == null) { + powerUnitMessage = new PowerUnitMessage(); + } + return powerUnitMessage; + } else if (messageType == MessageType.TYPE_RECEIVE_SSM_FUNC_MSG.typeCode || messageType == MessageType.TYPE_RECEIVE_SSM_FUNC_STATUS_QUERY.typeCode) { + //SSM功能 + if (padSsmFuncMsgMessage == null) { + padSsmFuncMsgMessage = new PadSsmFuncMsgMessage(); + } + return padSsmFuncMsgMessage; } else { //MessageType.TYPE_DEFAULT.typeCode return null; diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/PadSsmFuncMsgMessage.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/PadSsmFuncMsgMessage.java new file mode 100644 index 0000000000..f9df0a5746 --- /dev/null +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/PadSsmFuncMsgMessage.java @@ -0,0 +1,59 @@ +package com.zhidao.support.adas.high.msg; + +import android.os.SystemClock; + +import com.google.protobuf.ByteString; +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 system_master.SsmInfo; + +/** + * SSM功能相关 + */ +public class PadSsmFuncMsgMessage extends MyAbstractMessageHandler { + + @Override + public void handlerMsg(RawData raw, OnAdasListener adasListener) throws InvalidProtocolBufferException { + SsmInfo.PadSsmMsg padSsmMsg = SsmInfo.PadSsmMsg.parser().parseFrom(raw.originalData.toByteArray(), raw.getOffsetValue(), raw.getPackageLengthValue() - raw.getOffsetValue()); + AdasChannel.calculateTimeConsumingOnDispatchRaw("SSM功能", raw.receiveTime); + long nowTime = 0; + if (CupidLogUtils.isEnableLog()) + nowTime = SystemClock.elapsedRealtime(); + SsmInfo.MessageType type = padSsmMsg.getMsgType(); + ByteString data = padSsmMsg.getData(); + long timestamp = (long) (padSsmMsg.getTimestamp() * 1000L); + if (type == SsmInfo.MessageType.COLD_START_STATUS_REPORT || type == SsmInfo.MessageType.COLD_START_STATE_QUERY) { + //冷启动状态上报 + SsmInfo.ColdStartState coldStartState = null; + if (!data.isEmpty()) { + coldStartState = SsmInfo.ColdStartState.parseFrom(data); + } + if (adasListener != null) { + adasListener.onColdStartState(raw.getHeader(), padSsmMsg.getToken(), timestamp, type == SsmInfo.MessageType.COLD_START_STATE_QUERY, coldStartState); + } + } else if (type == SsmInfo.MessageType.AUTO_PILOT_INFO) { + //自驾命令状态查询响应 + SsmInfo.AutoPilotInfo autoPilotInfo = null; + if (!data.isEmpty()) { + autoPilotInfo = SsmInfo.AutoPilotInfo.parseFrom(data); + } + if (adasListener != null) { + adasListener.onAutoPilotInfo(raw.getHeader(), padSsmMsg.getToken(), timestamp, autoPilotInfo); + } + } else if (type == SsmInfo.MessageType.STATION_STATUS_QUERY) { + //到站信息查询响应 + SsmInfo.AutoPilotStation autoPilotStation = null; + if (!data.isEmpty()) { + autoPilotStation = SsmInfo.AutoPilotStation.parseFrom(data); + } + if (adasListener != null) { + adasListener.onAutoPilotStation(raw.getHeader(), padSsmMsg.getToken(), timestamp, autoPilotStation); + } + } + AdasChannel.calculateTimeConsumingBusiness("SSM功能", nowTime); + } +} diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/PowerUnitMessage.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/PowerUnitMessage.java new file mode 100644 index 0000000000..6723331fe1 --- /dev/null +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/msg/PowerUnitMessage.java @@ -0,0 +1,38 @@ +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 com.zhidao.support.adas.high.protocol.power.PowerRawUnpack; +import com.zhjt.mogo.adas.data.bean.power.PowerData; + +import okio.ByteString; + +/** + * 电源管理 + */ +public class PowerUnitMessage extends MyAbstractMessageHandler { + private static final String TAG = PowerUnitMessage.class.getSimpleName(); + private final PowerRawUnpack unpack = new PowerRawUnpack(); + + public PowerUnitMessage() { + } + + @Override + public void handlerMsg(RawData raw, OnAdasListener adasListener) throws InvalidProtocolBufferException { + ByteString data = ByteString.of(raw.originalData.toByteArray(), raw.getOffsetValue(), raw.getPackageLengthValue() - raw.getOffsetValue()); + PowerData rawData = unpack.unpack(data); + AdasChannel.calculateTimeConsumingOnDispatchRaw("电源盒", raw.receiveTime); + long nowTime = 0; + if (CupidLogUtils.isEnableLog()) + nowTime = SystemClock.elapsedRealtime(); + if (adasListener != null) { + adasListener.onPowerUnit(raw.getHeader(), rawData); + } + AdasChannel.calculateTimeConsumingBusiness("电源盒", nowTime); + } +} diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerMessageProtocol.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerMessageProtocol.java new file mode 100644 index 0000000000..53ec9a9c64 --- /dev/null +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerMessageProtocol.java @@ -0,0 +1,92 @@ +package com.zhidao.support.adas.high.protocol.power; + + +/** + * 电源管理协议 + */ +public class PowerMessageProtocol { + public static final int FRAME_HEAD = 0xAA55; + public static final int CHANNEL_NORMAL_END_INDEX = 46;//普通通道最大索引值(包含46) + public static final int CHANNEL_CAMERA_START_INDEX = 51;//相机通道最小索引值(包含51) + public static final byte KEY_SEND = 0x4D; + public static final byte KEY_RECEIVE = 0x47; + + public static void xor(byte[] data,byte key) { + for (int i = 0; i < data.length; i++) { + data[i] ^= key; + } + } + + + /** + * 帧头长度 + * 固定为:0xAA55 + * + * @return 字节个数 + */ + + public int getFrameHeaderLength() { + return 2; + } + + + /** + * 帧总长度长度 + * 最小值:12,对应于数据区长度为0的帧 + * + * @return 字节个数 + */ + + public int getTotalLengthLength() { + return 2; + } + + /** + * 帧类型长度,(0x0000:保留,0xFFFF:保留) + * 客户端STS请求帧:0x0040,服务器响应正常帧:0x0840 + * 客户端CMD请求帧:0x0044,服务器响应正常帧:0x0844 + * 服务器检测到帧异常,响应异常ERR帧:0x0800 + * + * @return 字节个数 + */ + + public int getFrameTypeLength() { + return 2; + } + + + /** + * 保留字节长度 + * 定为:0x0000 + * + * @return 字节个数 + */ + public int getReservedLength() { + return 2; + } + + /** + * 数据区长度 + * 数据区长度必须为4的整倍数,可为0字节 + * + * @param totalLength 数据包总长度 + * @return 字节个数 + */ + + public int getDataBlocksLength(int totalLength) { + return totalLength - getFrameHeaderLength() - getTotalLengthLength() - getFrameTypeLength() - getReservedLength() - getCheckValueLength(); + } + + /** + * 帧校验值长度,对校验值之前的所有数据进行校验, + * 校验值计算初步定为: + * 1:帧所有数据分割成32位长(4字节)的块; + * 2:对这些32位长的块进行二进制"异或"操作; + * 3:取"异或"操作的结果作为校验值。 + * + * @return 字节个数 + */ + public int getCheckValueLength() { + return 4; + } +} diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerRawPack.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerRawPack.java new file mode 100644 index 0000000000..e5e757fc1e --- /dev/null +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerRawPack.java @@ -0,0 +1,72 @@ +package com.zhidao.support.adas.high.protocol.power; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.zhjt.mogo.adas.common.power.PowerFrameType; +import com.zhjt.mogo.adas.utils.ByteUtil; + +/** + * 数据打包 + */ +public class PowerRawPack { + private static final String TAG = PowerRawPack.class.getSimpleName(); + private final PowerMessageProtocol messageProtocol; + private final byte[] reservedData; + + + public PowerRawPack() { + messageProtocol = new PowerMessageProtocol(); + reservedData = new byte[messageProtocol.getReservedLength()]; + } + + + public synchronized byte[] pack(@NonNull PowerFrameType frameType, @Nullable byte[] data) { + if (frameType == PowerFrameType.UNKNOWN) return null; + int dataBlocksLength = 0; + if (data != null && data.length != 0) { + dataBlocksLength = data.length; + } + //除校验位4个字节所有的长度 + int packageLength = messageProtocol.getFrameHeaderLength() + messageProtocol.getTotalLengthLength() + messageProtocol.getFrameTypeLength() + messageProtocol.getReservedLength() + dataBlocksLength; + byte[] msg = new byte[packageLength]; + byte[] frameHeadData = ByteUtil.set16bitUnsignedValueLittleEndian(PowerMessageProtocol.FRAME_HEAD); + //添加帧头 + System.arraycopy(frameHeadData, 0, msg, 0, messageProtocol.getFrameHeaderLength()); + + byte[] packageLengthData = ByteUtil.set16bitUnsignedValueLittleEndian(packageLength + messageProtocol.getCheckValueLength()); + //添加总长度 + System.arraycopy(packageLengthData, 0, msg, messageProtocol.getFrameHeaderLength(), messageProtocol.getTotalLengthLength()); + + byte[] type = ByteUtil.set16bitUnsignedValueLittleEndian(frameType.type); + //添加帧类型 + System.arraycopy(type, 0, msg, messageProtocol.getFrameHeaderLength() + messageProtocol.getTotalLengthLength(), messageProtocol.getFrameTypeLength()); + + //添加保留位 + System.arraycopy(reservedData, 0, msg, messageProtocol.getFrameHeaderLength() + messageProtocol.getTotalLengthLength() + messageProtocol.getFrameTypeLength(), messageProtocol.getReservedLength()); + + if (data != null && data.length != 0) { + PowerMessageProtocol.xor(data, PowerMessageProtocol.KEY_SEND); + System.arraycopy(data, 0, msg, messageProtocol.getFrameHeaderLength() + messageProtocol.getTotalLengthLength() + messageProtocol.getFrameTypeLength() + messageProtocol.getReservedLength(), data.length); + } + int xor = xorCheck(msg); + + return ByteUtil.concatBytes(msg, ByteUtil.set32bitUnsignedValueValueLittleEndian(xor)); + } + + //异或校验 + private int xorCheck(byte[] bytes) { + int xorChecksum = 0; + //异或校验 + for (int i = 0; i < bytes.length; i += 4) { + byte[] tInt = new byte[4]; + tInt[0] = bytes[i]; + tInt[1] = bytes[i + 1]; + tInt[2] = bytes[i + 2]; + tInt[3] = bytes[i + 3]; + int datum = ByteUtil.get32bitUnsignedValueLittleEndian(tInt); + xorChecksum ^= datum; // 对每个字节进行异或操作 + } + return xorChecksum; + } +} diff --git a/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerRawUnpack.java b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerRawUnpack.java new file mode 100644 index 0000000000..6b5d2f2e0f --- /dev/null +++ b/libraries/mogo-adas/src/main/java/com/zhidao/support/adas/high/protocol/power/PowerRawUnpack.java @@ -0,0 +1,290 @@ +package com.zhidao.support.adas.high.protocol.power; + + +import androidx.annotation.NonNull; + +import com.zhjt.mogo.adas.common.power.PowerControlType; +import com.zhjt.mogo.adas.common.power.PowerError; +import com.zhjt.mogo.adas.common.power.PowerFrameType; +import com.zhjt.mogo.adas.common.power.PowerProtocolStatus; +import com.zhjt.mogo.adas.common.power.PowerUnitChannel; +import com.zhjt.mogo.adas.data.bean.power.PowerCommandExecuteState; +import com.zhjt.mogo.adas.data.bean.power.PowerData; +import com.zhjt.mogo.adas.data.bean.power.PowerErrorData; +import com.zhjt.mogo.adas.data.bean.power.PowerUnitState; +import com.zhjt.mogo.adas.utils.ByteUtil; + +import java.util.ArrayList; +import java.util.List; + +import okio.ByteString; + +/** + * 电源管理数据拆包 + */ +public class PowerRawUnpack { + private static final String TAG = PowerRawUnpack.class.getSimpleName(); + private final PowerMessageProtocol messageProtocol; + + + public PowerRawUnpack() { + messageProtocol = new PowerMessageProtocol(); + } + + public PowerData unpack(@NonNull ByteString bytes) { + byte[] data = bytes.toByteArray(); + int size = bytes.size(); + if (size == 0) { + return PowerData.createError(data, PowerProtocolStatus.CHECK_FAILED_PACKAGE_LENGTH); + } + if (size % 4 != 0) { + return PowerData.createError(data, PowerProtocolStatus.DATA_LENGTH_NOT_NOTE_OF4); + } + int frameHeaderLength = messageProtocol.getFrameHeaderLength(); + int totalLengthLength = messageProtocol.getTotalLengthLength(); + int frameTypeLength = messageProtocol.getFrameTypeLength(); + int reservedLength = messageProtocol.getReservedLength(); + int checkValueLength = messageProtocol.getCheckValueLength(); + try { + int localXor = xorCheck(bytes, checkValueLength); +// Log.i(TAG, "计算得出的异域校验值=" + localXor); + ByteString xor = bytes.substring(size - checkValueLength, size); + int serverXor = ByteUtil.get32bitUnsignedValueLittleEndian(xor.toByteArray()); +// Log.i(TAG, "数据中的异域校验值=" + serverXor); + if (localXor != serverXor) { + return PowerData.createError(data, PowerProtocolStatus.XOR_CHECK_FAILED); + } + //读取FrameHeader + ByteString frameHeaderByteString; + if (size < frameHeaderLength) { + frameHeaderByteString = bytes; + } else { + frameHeaderByteString = bytes.substring(0, frameHeaderLength); + } + int frameHeader = ByteUtil.get16bitUnsignedValueLittleEndian(frameHeaderByteString.toByteArray()); +// Log.w(TAG, "WS frameHeader=" + frameHeaderByteString.hex()); +// Log.w(TAG, "WS frameHeader=" + frameHeader); + if (frameHeader == PowerMessageProtocol.FRAME_HEAD) { + ByteString totalLengthByteString = bytes.substring(frameHeaderLength, frameHeaderLength + totalLengthLength); + int totalLength = ByteUtil.get16bitUnsignedValueLittleEndian(totalLengthByteString.toByteArray()); +// Log.w(TAG, "WS TotalLength=" + totalLength); + if (size != totalLength) { + return PowerData.createError(data, PowerProtocolStatus.CHECK_FAILED_PACKAGE_LENGTH); + } + ByteString frameTypeByteString = bytes.substring(frameHeaderLength + totalLengthLength, frameHeaderLength + totalLengthLength + frameTypeLength); + int typeValue = ByteUtil.get16bitUnsignedValueLittleEndian(frameTypeByteString.toByteArray()); + PowerFrameType frameType = PowerFrameType.getPowerFrameType(typeValue); +// Log.w(TAG, "WS FrameType=" + frameType); + if (frameType == PowerFrameType.UNKNOWN) { + return PowerData.createError(data, PowerProtocolStatus.POWER_FRAME_TYPE_UNKNOWN); + } + ByteString reservedByteString = bytes.substring(frameHeaderLength + totalLengthLength + frameTypeLength, frameHeaderLength + totalLengthLength + frameTypeLength + reservedLength); + int reserved = ByteUtil.get16bitUnsignedValueLittleEndian(reservedByteString.toByteArray()); + int dataBlocksLength = messageProtocol.getDataBlocksLength(totalLength); + ByteString dataBlocksByteString = bytes.substring(frameHeaderLength + totalLengthLength + frameTypeLength + reservedLength, frameHeaderLength + totalLengthLength + frameTypeLength + reservedLength + dataBlocksLength); + byte[] dataBlocks = dataBlocksByteString.toByteArray(); + PowerMessageProtocol.xor(dataBlocks, PowerMessageProtocol.KEY_RECEIVE); + dataBlocksByteString = ByteString.of(dataBlocks); +// Log.i(TAG, dataBlocks.length + " 负载数据=" + ByteUtil.byteArrToHex(dataBlocks)); + PowerErrorData errorData = null; + List states = null; + PowerCommandExecuteState executeState = null; + if (frameType == PowerFrameType.ERROR_RESPONSE) { + errorData = unpackErrorData(dataBlocksByteString); + if (errorData == null) { + return PowerData.createError(data, PowerProtocolStatus.PAYLOAD_DATA_PARSE_FAILED); + } + } else if (frameType == PowerFrameType.STS_RESPONSE) { + states = unpackSTSResponseData(dataBlocksByteString); + if (states == null) { + return PowerData.createError(data, PowerProtocolStatus.PAYLOAD_DATA_PARSE_FAILED); + } + } else if (frameType == PowerFrameType.CMD_RESPONSE) { + executeState = unpackCommandExecuteState(dataBlocksByteString); + if (executeState == null) { + return PowerData.createError(data, PowerProtocolStatus.PAYLOAD_DATA_PARSE_FAILED); + } + } + PowerData powerData = PowerData.create(data, frameHeader, totalLength, frameType, reserved, dataBlocks, serverXor); + if (errorData != null) { + powerData.setPowerErrorData(errorData); + } + if (states != null) { + powerData.setPowerUnitStates(states); + } + if (executeState != null) { + powerData.setExecuteState(executeState); + } + return powerData; + } else { + return PowerData.createError(data, PowerProtocolStatus.CHECK_FAILED_FRAME_HEADER); + } + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return PowerData.createError(data, PowerProtocolStatus.DATA_PARSE_FAILED); + } + } + + private PowerCommandExecuteState unpackCommandExecuteState(ByteString bytes) { + try { + ByteString controlTypeByteString = bytes.substring(0, 2); + int controlTypeValue = ByteUtil.get16bitUnsignedValueLittleEndian(controlTypeByteString.toByteArray()); + PowerControlType controlType = PowerControlType.getPowerControlType(controlTypeValue); +// Log.w(TAG, "controlType=" + controlType); + if (controlType == PowerControlType.SINGLE_CHANNEL_CONTROL_RESPONSE) { + int channelIndex = ByteUtil.get8bitUnsignedValue(2, bytes.toByteArray()); + PowerUnitChannel channel = PowerUnitChannel.getPowerUnitChannel(channelIndex); + byte state = bytes.getByte(3); + int executeState = ByteUtil.getBit(state, 0); + int sendPowerState = ByteUtil.getBit(state, 1); + int actualPowerState = (state & 0x0c) >> 2; + int faultState = (state & 0xF0) >> 4; + return new PowerCommandExecuteState(controlType, executeState == 1, channel, sendPowerState, actualPowerState, faultState); + } else if (controlType == PowerControlType.MULTI_CHANNEL_CONTROL_RESPONSE || controlType == PowerControlType.RESET_CONTROL_RESPONSE) { + byte state = bytes.getByte(3); + int executeState = ByteUtil.getBit(state, 0); + return new PowerCommandExecuteState(controlType, executeState == 1); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private List unpackSTSResponseData(ByteString bytes) { + try { + List list = initPowerUnitStateList(); + int channelBeginIndex = 0;//通道1~46索引开始 + int channelEndIndex = channelBeginIndex + 8 * 3;//通道1~46索引结束 + + int currentProtectionStateBeginIndex = channelEndIndex;//1~46电流保护索引开始 + int currentProtectionStateEndIndex = currentProtectionStateBeginIndex + 8;//1~46电流保护索引结束 + int currentValueBeginIndex = currentProtectionStateEndIndex;//1~46电流值索引开始 + int currentValueEndIndex = currentProtectionStateEndIndex + 8 * 16;//1~46电流值索引结束 + int cameraChannelBeginIndex = currentValueEndIndex;//通道51~58索引开始 + int cameraChannelEndIndex = cameraChannelBeginIndex + 8 * 2;//通道51~66索引结束 + + //获取索引1~46的开关状态以及故障状态 + ByteString channelState = bytes.substring(channelBeginIndex, channelEndIndex); +// Log.i(TAG, channelState.size() + " 电源数据=" + ByteUtil.byteArrToHex(channelState.toByteArray())); + for (int i = 0; i < channelState.size(); i++) { + byte data = channelState.getByte(i); + int index = i * 2 + 1; + for (int j = 0; j < 2; j++) { + PowerUnitChannel channel = PowerUnitChannel.getPowerUnitChannel(index + j); + if (channel.index > PowerUnitChannel.UNKNOWN.index && channel.index <= PowerMessageProtocol.CHANNEL_NORMAL_END_INDEX) { + int faultState = (data >> j * 4) & 0x03; + int powerState = (data >> j * 4 + 2) & 0x03; + int pos = list.indexOf(new PowerUnitState(channel)); + if (pos != -1) { + PowerUnitState powerUnitState = list.get(pos); + powerUnitState.setFaultState(faultState); + powerUnitState.setPowerState(powerState); + } + } + } + } + + //获取索引1~46的电流保护状态 + ByteString currentProtectionState = bytes.substring(currentProtectionStateBeginIndex, currentProtectionStateEndIndex); +// Log.i(TAG, currentProtectionState.size() + " 电源保护数据=" + ByteUtil.byteArrToHex(currentProtectionState.toByteArray())); + for (int i = 0; i < currentProtectionState.size(); i++) { + byte b = currentProtectionState.getByte(i); + int index = i * 8 + 1; + for (int j = 0; j < 8; j++) { + PowerUnitChannel channel = PowerUnitChannel.getPowerUnitChannel(index + j); + if (channel.index > PowerUnitChannel.UNKNOWN.index && channel.index <= PowerMessageProtocol.CHANNEL_NORMAL_END_INDEX) { + int pos = list.indexOf(new PowerUnitState(channel)); + if (pos != -1) { + PowerUnitState powerUnitState = list.get(pos); + powerUnitState.setCurrentProtectionState(((b >> j) & 0x1) == 1); + } + } + } + } + + //获取索引1~46的电流值 + ByteString currentValue = bytes.substring(currentValueBeginIndex, currentValueEndIndex); +// Log.i(TAG, currentValue.size() + " 电流数据=" + ByteUtil.byteArrToHex(currentValue.toByteArray())); + for (int i = 0; i < currentValue.size(); i += 8) { + int idx = currentValue.getByte(i); + for (int j = 0; j < 3; j++) { + PowerUnitChannel channel = PowerUnitChannel.getPowerUnitChannel(idx * 3 + j + 1); + if (channel.index > PowerUnitChannel.UNKNOWN.index && channel.index <= PowerMessageProtocol.CHANNEL_NORMAL_END_INDEX) { + int pos = list.indexOf(new PowerUnitState(channel)); + if (pos != -1) { + PowerUnitState powerUnitState = list.get(pos); + int beginIndex = i + 2 + j * 2; + int endIndex = beginIndex + 2; + powerUnitState.setCurrentValue(ByteUtil.get16bitUnsignedValueLittleEndian(currentValue.substring(beginIndex, endIndex).toByteArray()) * 0.1F); + } + } + } + } + //获取索引51~66的相机状态 + ByteString cameraChannelState = bytes.substring(cameraChannelBeginIndex, cameraChannelEndIndex); +// Log.i(TAG, cameraChannelState.size() + " 相机通道数据=" + ByteUtil.byteArrToHex(cameraChannelState.toByteArray())); + for (int i = 0; i < cameraChannelState.size(); i++) { + PowerUnitChannel channel = PowerUnitChannel.getPowerUnitChannel(51 + i); + if (channel.index >= PowerMessageProtocol.CHANNEL_CAMERA_START_INDEX) { + byte b = cameraChannelState.getByte(i); +// Log.i(TAG, "相机" + channel + " 值=" + ByteUtil.byteToBit(b)); + int pos = list.indexOf(new PowerUnitState(channel)); + if (pos != -1) { + PowerUnitState powerUnitState = list.get(pos); + powerUnitState.setPowerState(b & 0x03); + int faultState = (b & 0x3C) >> 2; + powerUnitState.setFaultState(faultState); + } + } + } + return list; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private PowerErrorData unpackErrorData(ByteString bytes) { + try { + ByteString frameTypeByteString = bytes.substring(0, 2); + int frameTypeValue = ByteUtil.get16bitUnsignedValueLittleEndian(frameTypeByteString.toByteArray()); + PowerFrameType frameType = PowerFrameType.getPowerFrameType(frameTypeValue); +// Log.w(TAG, "Error FrameType=" + frameType); + int errorValue = ByteUtil.get8bitUnsignedValue(3, bytes.toByteArray()); + PowerError error = PowerError.getPowerError(errorValue); +// Log.w(TAG, "Error errorType=" + error); + return new PowerErrorData(frameType, error); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + //异或校验 + private int xorCheck(ByteString bytes, int checkValueLength) { + int xorChecksum = 0; + //异或校验 + for (int i = 0; i < bytes.size() - checkValueLength; i += 4) { + byte[] tInt = new byte[4]; + tInt[0] = bytes.getByte(i); + tInt[1] = bytes.getByte(i + 1); + tInt[2] = bytes.getByte(i + 2); + tInt[3] = bytes.getByte(i + 3); + int datum = ByteUtil.get32bitUnsignedValueLittleEndian(tInt); + xorChecksum ^= datum; // 对每个字节进行异或操作 + } + return xorChecksum; + } + + private List initPowerUnitStateList() { + List list = new ArrayList<>(); + PowerUnitChannel[] channels = PowerUnitChannel.values(); + for (PowerUnitChannel channel : channels) { + if (channel != PowerUnitChannel.UNKNOWN) { + list.add(new PowerUnitState(channel)); + } + } + return list; + } +}