import common from '@ohos.app.ability.common'; import RealTime from '../components/RealTime'; import { MediaPlayer } from '../utils/MediaPlayer'; import { CommandType, MessageCallBackParams, SimulatorUdpClient } from '../utils/simulator/UdpClient'; import { BackMachineUdpClient } from '../utils/udp/UdpClient'; import { ConfigItemProps, ConfigProps, Status } from '../model/index'; import { getConfigFile } from '../utils/native/NativeUtils'; import promptAction from '@ohos.promptAction'; import { OutWireControl } from '../utils/wireControl/OutWireControl'; import { nativeLogCallback, nativeSDKInit, onTrack, registerControlCallback, registerSoundCallback, selectLineAndLib, setConfigFile, setImageSize } from '../utils/native/NativeSDK'; import { LogHelper } from '../utils/LogHelper'; import util from '@ohos.util'; import { CarInfo, GpsInfo, parseCar, parseGps } from '../utils/udp/Gps'; // 直角转弯 (0, 0) (0, 1) ... // 坡道起步 (1, 0) (1, 1) ... // 倒车入库 (2, 0) (2, 1) ... // 曲线行驶 (3, 0) (3, 1) ... // 侧方停车 (4, 0) (4, 1) ... const startImage: Resource[] = [$rawfile("images/start.png"), $rawfile("images/finish.png"), $rawfile("images/finish.png")] const resumeImage: Resource[] = [$rawfile("images/resume.png"), $rawfile("images/pause.png"), $rawfile("images/resume.png")] const audios = new Array(33).map((_, i) => { return "audio/output_" + i + ".mp3" }) const projectAudio = [ [4, 5], [0, 1, 2, 3], [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21], [29, 30, 31, 32], [22, 23, 24, 25, 26, 27, 28], ] @Component struct CustomButton { @Prop checked: boolean private text: string = "" build() { Button(this.text, { type: ButtonType.Normal }) .backgroundColor(this.checked ? 0xff5e69 : 0xffffff) .fontColor(this.checked ? 0xffffff : 0x557685) .borderRadius(8) .shadow({ offsetX: 3, offsetY: 3, color: 0xf1f1f1, radius: 10 }) .width("100%") } } @Entry @Component struct Index { @State status: Status = Status.Idle @State paths: ConfigItemProps>>[] = [] @State libraries: ConfigItemProps>[] = [] @State currentPath: number = 0 @State currentLibrary: number = 0 @State process: number = 1 private line: string private lib: string private carModel: string private fieldModel: string private teachPoint: string private teachPointParams: string private basePoint: string private player: MediaPlayer = new MediaPlayer(getContext(this) as common.UIAbilityContext) private simulatorUdpClient?: SimulatorUdpClient private backupUdpClient?: BackMachineUdpClient private outWireControl?: OutWireControl private carStatus: number = 0 async aboutToAppear() { try { await this.initWireControlUDP() await this.initPlatformUDP() await this.initAudioPlayer() await this.initBackMachineUDP() await getConfigFile().then(([fieldModel, carModel, line, lib, teachPoint, teachPointParams, basePoint]) => { this.fieldModel = fieldModel this.carModel = carModel this.teachPoint = teachPoint this.basePoint = basePoint this.teachPointParams = teachPointParams this.line = line this.lib = lib this.libraries = (JSON.parse(lib) as ConfigProps>).features this.paths = (JSON.parse(line) as ConfigProps>>).features }) await nativeSDKInit() await nativeLogCallback((message: string, _: number) => { LogHelper.I("NativeSDK", "[Log Callback]: ", message) }) await registerControlCallback((fxp: number, move: number) => { if (fxp > 0) { this.outWireControl.rightWheel(fxp) } else { this.outWireControl.leftWheel(fxp) } switch (move) { case -1000: break; case -1: this.outWireControl.moveDown() this.carStatus = move break; case 0: this.outWireControl.moveStop() this.carStatus = move break; case 1: this.outWireControl.moveUp() this.carStatus = move break; default: break; } LogHelper.I("NativeSDK", "[Control Callback]: ") }) await registerSoundCallback((project: number, idx: number) => { this.playAudio(project, idx) LogHelper.I("NativeSDK", "[Sound Callback]: ") }) await setImageSize(500, 300) await setConfigFile(this.basePoint, this.fieldModel, this.teachPoint, this.teachPointParams, this.carModel, this.line, this.lib) } catch (err) { promptAction.showToast({ message: JSON.stringify(err?.message || err), duration: 3000 }) LogHelper.E("View", JSON.stringify(err?.message || err)) } } // 播放语音 async playAudio(project: number, idx: number) { try { await this.player.setSource({ type: "raw", url: audios[projectAudio[project][idx]] }) } catch (err) { promptAction.showToast({ message: JSON.stringify(err?.message || err), duration: 3000 }) LogHelper.E("View", JSON.stringify(err?.message || err)) } } // 初始化语音播放器 async initAudioPlayer() { await this.player.create() this.player.on("prepared", () => { this.player.play() }) } // 初始化终端UDP async initPlatformUDP() { this.simulatorUdpClient = new SimulatorUdpClient("0.0.0.0", 8990, "88.22.10.118", 9001) try { await this.simulatorUdpClient.bindUdp() // this.simulatorUdpClient.heart() // setInterval(() => { // this.simulatorUdpClient.uploadPosition(new GpsInfo(), new CarInfo()) // }, 1000) this.simulatorUdpClient.onMessage(({type, data = [] }: MessageCallBackParams) => { if (type === CommandType.Start) { let path = this.paths.findIndex(item => { return item.properties.id === data[0] }) let lib = this.libraries.findIndex(item => { return item.properties.id === data[1] }) if (path === -1 || lib === -1) { promptAction.showToast({ message: "错误的路线或库位" }) this.simulatorUdpClient.sendPID26(CommandType.Failed) return } this.currentPath = path this.currentLibrary = lib this.status = Status.Running this.simulatorUdpClient.sendPID26(CommandType.Success) } else if (type === CommandType.Stop) { this.status = Status.Idle this.simulatorUdpClient.sendPID26(CommandType.Success) } }) } catch (err) { throw new Error(JSON.stringify(err)) } } // 初始化后置机UDP async initBackMachineUDP() { this.backupUdpClient = new BackMachineUdpClient("0.0.0.0", 8991, "", 0) try { await this.backupUdpClient.bindUdp() this.backupUdpClient.onMessage((arr) => { let gps = parseGps(arr) let car = parseCar(arr) this.simulatorUdpClient?.uploadPosition(gps, car) onTrack(gps.lng, gps.lat, gps.heading, gps.v) }) } catch (err) { throw new Error(JSON.stringify(err)) } } // 初始化车机控制UDP async initWireControlUDP() { this.outWireControl = new OutWireControl() await this.outWireControl.init("192.168.7.181", 30021) } // 上方按钮点击 onConfirm() { if (this.status === Status.Idle) { this.simulatorUdpClient?.setPathId(this.paths[this.currentPath].properties.id) this.simulatorUdpClient?.setLibId(this.libraries[this.currentLibrary].properties.id) this.simulatorUdpClient?.sendPID26(CommandType.Start) selectLineAndLib(this.paths[this.currentPath].properties.id, this.libraries[this.currentLibrary].properties.id) this.status = Status.Running this.outWireControl.apaStart() } else { this.simulatorUdpClient?.sendPID26(CommandType.Stop) this.status = Status.Idle this.outWireControl.moveStop() this.outWireControl.apaStop() } } // 下方按钮点击 onCancel() { if (this.status === Status.Running) { this.status = Status.Pause this.outWireControl.moveStop() } else if (this.status === Status.Pause) { switch (this.carStatus) { case -1: this.outWireControl.moveDown() break; case 0: this.outWireControl.moveStop() break; case 1: this.outWireControl.moveUp() break; default: break; } this.status = Status.Running } } build() { Row() { Stack() { RealTime() Row() { Column() { Row() { ForEach(["项目演示", "发车", "收车"], (item, index) => { Text(item) .padding(12) .backgroundColor(this.process === index ? 0xff5d69 : "rgba(240, 242, 246, 0.88)") .fontColor(this.process === index ? 0xffffff : 0x7f899f) .borderRadius(index === 0 ? { topLeft: 10, bottomLeft: 10 } : index === 2 ? { topRight: 10, bottomRight: 10 } : {}) .width(90) .textAlign(TextAlign.Center) .onClick(() => { if (index > 0) { this.process = index } }) }) }.borderRadius(10).margin({ bottom: 20 }) Column() { Column() { Row() { Image($rawfile("images/path.png")).width(42) Text("线路选择").fontColor(0x557685) }.margin({ bottom: 12 }) Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.paths, (item: ConfigItemProps>>, index: number) => { Row() { CustomButton({ text: item.properties.name, checked: this.currentPath === index }).onClick(() => { this.currentPath = index }).margin({ bottom: 12 }).width("100%") }.width("50%").padding({ left: index % 2 === 0 ? 0 : 5, right: index % 2 === 0 ? 5 : 0 }) }) } }.alignItems(HorizontalAlign.Start).width("100%") Column() { Row() { Image($rawfile("images/park.png")).width(42) Text("库位选择").fontColor(0x557685) }.margin({ bottom: 12 }) Flex({ wrap: FlexWrap.Wrap }) { ForEach(this.libraries, (item: ConfigItemProps>, index: number) => { Row() { CustomButton({ text: item.properties.name, checked: this.currentLibrary === index }) .onClick(() => { this.currentLibrary = index }) .margin({ bottom: 12 }) .width("100%") }.width("50%").padding({ left: index % 2 === 0 ? 0 : 5, right: index % 2 === 0 ? 5 : 0 }) }) } }.alignItems(HorizontalAlign.Start).width("100%") }.backgroundColor("rgba(240, 242, 246, 0.88)").borderRadius(10).padding(12).width(270) } Blank() Column() { Image(startImage[this.status]).width(74).onClick(() => { this.onConfirm() }) Image(resumeImage[this.status]).width(74).onClick(() => { this.onCancel() }) }.backgroundColor('rgba(228, 229, 233, 0.7)').borderRadius(10) }.width("100%").height("100%").padding(24).alignItems(VerticalAlign.Top) }.height('100%') .width("100%") } .height('100%') .width("100%") } }