张世豪
2 天以前 c9b1d33979b3972fe6a82fa427b4ba9a20989112
src/gecaoji/Device.java
@@ -1,8 +1,12 @@
package gecaoji;
import baseStation.BaseStation;
import set.Setsys;
import zhuye.MowerLocationData;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Properties;
@@ -64,14 +68,37 @@
    // 航向角
    private String pitch;
    // 俯仰角
    private String battery;
    // 实时电量
    private String roll; // 横滚角 角度
    private String yaw; // 偏航角 角度
    private String battery_level; // 电池电量百分比
    private String battery_voltage; // 电池电压
    private String operation_mode; // 操作模式:manual, auto, emergency_stop
    private String motor_status; // 电机状态:stopped, running, error
    private String blade_status; // 刀片状态:stopped, rotating
    private String path_id_saved; // 存储的路径ID
    private String error_code; // 错误代码
    private String error_message; // 错误信息
    private String positioningStatus;
    // 定位状态
    private String satelliteCount;
    // 卫星可数
    private String differentialAge;
    // 差分时间
    private String self_check_status = "-1"; // 新增自检状态:1-完成,0-未完成
    // 割草机自检状态
    private String mowerStartStatus = "-1";
    // 割草机启动状态:1开启,0熄火,-1未知
    private String mowerLightStatus = "-1";
    // 割草机灯开关状态:1开启,0关闭,-1未知
    private String blade_height = "-1"; // 刀盘高度 厘米
    // 割草机刀盘高度:-1未知
    private String mowerWidth;
    // 割草机宽度,单位米
    private String mowerLength;
    // 割草机长度,单位米
    private String mowingSafetyDistance;
    // 割草安全距离,单位米
    private static final double METERS_PER_DEGREE_LAT = 111320.0d;
    
@@ -102,6 +129,71 @@
        applyDefaults(gecaoji);
    }
    /**
     * 保存所有属性到device.properties文件
     */
    public void saveToProperties() {
        Properties properties = new Properties();
        // 加载现有属性(保留其他属性)
        try (FileInputStream input = new FileInputStream("device.properties")) {
            properties.load(input);
        } catch (IOException e) {
            // 如果文件不存在,继续创建新文件
        }
        // 设置所有设备属性
        if (mowerName != null) properties.setProperty("mowerName", mowerName);
        if (mowerModel != null) properties.setProperty("mowerModel", mowerModel);
        if (mowerNumber != null) properties.setProperty("mowerNumber", mowerNumber);
        if (mowingWidth != null) properties.setProperty("mowingWidth", mowingWidth);
        if (mowingHeight != null) properties.setProperty("mowingHeight", mowingHeight);
        if (baseStationNumber != null) properties.setProperty("baseStationNumber", baseStationNumber);
        if (baseStationCardNumber != null) properties.setProperty("baseStationCardNumber", baseStationCardNumber);
        if (baseStationCoordinates != null) properties.setProperty("baseStationCoordinates", baseStationCoordinates);
        if (deviceCardnumber != null) properties.setProperty("deviceCardnumber", deviceCardnumber);
        if (createTime != null) properties.setProperty("createTime", createTime);
        if (GupdateTime != null) properties.setProperty("GupdateTime", GupdateTime);
        if (BupdateTime != null) properties.setProperty("BupdateTime", BupdateTime);
        if (realtimeLatitude != null) properties.setProperty("realtimeLatitude", realtimeLatitude);
        if (realtimeLongitude != null) properties.setProperty("realtimeLongitude", realtimeLongitude);
        if (realtimeAltitude != null) properties.setProperty("realtimeAltitude", realtimeAltitude);
        if (realtimeX != null) properties.setProperty("realtimeX", realtimeX);
        if (realtimeY != null) properties.setProperty("realtimeY", realtimeY);
        if (realtimeSpeed != null) properties.setProperty("realtimeSpeed", realtimeSpeed);
        if (heading != null) properties.setProperty("heading", heading);
        if (pitch != null) properties.setProperty("pitch", pitch);
        if (roll != null) properties.setProperty("roll", roll);
        if (yaw != null) properties.setProperty("yaw", yaw);
        if (battery_level != null) properties.setProperty("battery_level", battery_level);
        if (battery_voltage != null) properties.setProperty("battery_voltage", battery_voltage);
        if (operation_mode != null) properties.setProperty("operation_mode", operation_mode);
        if (motor_status != null) properties.setProperty("motor_status", motor_status);
        if (blade_status != null) properties.setProperty("blade_status", blade_status);
        if (path_id_saved != null) properties.setProperty("path_id_saved", path_id_saved);
        if (error_code != null) properties.setProperty("error_code", error_code);
        if (error_message != null) properties.setProperty("error_message", error_message);
        if (positioningStatus != null) properties.setProperty("positioningStatus", positioningStatus);
        if (satelliteCount != null) properties.setProperty("satelliteCount", satelliteCount);
        if (differentialAge != null) properties.setProperty("differentialAge", differentialAge);
        if (self_check_status != null) properties.setProperty("self_check_status", self_check_status);
        if (mowerStartStatus != null) properties.setProperty("mowerStartStatus", mowerStartStatus);
        if (mowerLightStatus != null) properties.setProperty("mowerLightStatus", mowerLightStatus);
        if (blade_height != null) properties.setProperty("blade_height", blade_height);
        if (mowerWidth != null) properties.setProperty("mowerWidth", mowerWidth);
        if (mowerLength != null) properties.setProperty("mowerLength", mowerLength);
        if (mowingSafetyDistance != null) properties.setProperty("mowingSafetyDistance", mowingSafetyDistance);
        // 保存到文件
        try (FileOutputStream output = new FileOutputStream("device.properties");
             OutputStreamWriter writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
            properties.store(writer, "Updated device properties");
        } catch (IOException ex) {
            System.err.println("无法保存 device.properties: " + ex.getMessage());
        }
    }
    private void loadPropertiesInto(Device target, Properties properties) {
        if (target == null) {
            return;
@@ -127,10 +219,27 @@
        target.realtimeSpeed = properties.getProperty("realtimeSpeed", "-1");
        target.heading = properties.getProperty("heading", "-1");
        target.pitch = properties.getProperty("pitch", "-1");
        target.battery = properties.getProperty("battery", "-1");
        target.roll = properties.getProperty("roll", "-1");
        target.yaw = properties.getProperty("yaw", "-1");
        target.battery_level = properties.getProperty("battery_level", "-1");
        target.battery_voltage = properties.getProperty("battery_voltage", "-1");
        target.operation_mode = properties.getProperty("operation_mode", "-1");
        target.motor_status = properties.getProperty("motor_status", "-1");
        target.blade_status = properties.getProperty("blade_status", "-1");
        target.path_id_saved = properties.getProperty("path_id_saved", "-1");
        target.error_code = properties.getProperty("error_code", "-1");
        target.error_message = properties.getProperty("error_message", "-1");
        target.positioningStatus = properties.getProperty("positioningStatus", "-1");
        target.satelliteCount = properties.getProperty("satelliteCount", "-1");
        target.differentialAge = properties.getProperty("differentialAge", "-1");
        target.self_check_status = properties.getProperty("self_check_status", "-1");
        target.mowerStartStatus = properties.getProperty("mowerStartStatus", "-1");
        target.mowerLightStatus = properties.getProperty("mowerLightStatus", "-1");
        target.blade_height = properties.getProperty("blade_height", "-1");
        target.mowerWidth = properties.getProperty("mowerWidth", "-1");
        target.mowerLength = properties.getProperty("mowerLength", "-1");
        target.mowingSafetyDistance = properties.getProperty("mowingSafetyDistance", "-1");
    }
    private void applyDefaults(Device target) {
@@ -158,10 +267,27 @@
        target.realtimeSpeed = "-1";
        target.heading = "-1";
        target.pitch = "-1";
        target.battery = "-1";
        target.roll = "-1";
        target.yaw = "-1";
        target.battery_level = "-1";
        target.battery_voltage = "-1";
        target.operation_mode = "-1";
        target.motor_status = "-1";
        target.blade_status = "-1";
        target.path_id_saved = "-1";
        target.error_code = "-1";
        target.error_message = "-1";
        target.positioningStatus = "-1";
        target.satelliteCount = "-1";
        target.differentialAge = "-1";
        target.self_check_status = "-1";
        target.mowerStartStatus = "-1";
        target.mowerLightStatus = "-1";
        target.blade_height = "-1";
        target.mowerWidth = "-1";
        target.mowerLength = "-1";
        target.mowingSafetyDistance = "-1";
    }
    public static synchronized Device initializeActiveDevice(String mowerId) { // 根据设备ID初始化活跃设备
@@ -248,8 +374,35 @@
            case "pitch":
                this.pitch = value;
                return true;
            case "battery":
                this.battery = value;
            case "roll":
                this.roll = value;
                return true;
            case "yaw":
                this.yaw = value;
                return true;
            case "battery_level":
                this.battery_level = value;
                return true;
            case "battery_voltage":
                this.battery_voltage = value;
                return true;
            case "operation_mode":
                this.operation_mode = value;
                return true;
            case "motor_status":
                this.motor_status = value;
                return true;
            case "blade_status":
                this.blade_status = value;
                return true;
            case "path_id_saved":
                this.path_id_saved = value;
                return true;
            case "error_code":
                this.error_code = value;
                return true;
            case "error_message":
                this.error_message = value;
                return true;
            case "positioningStatus":
                this.positioningStatus = value;
@@ -260,6 +413,27 @@
            case "differentialAge":
                this.differentialAge = value;
                return true;
            case "self_check_status":
                this.self_check_status = value;
                return true;
            case "mowerStartStatus":
                this.mowerStartStatus = value;
                return true;
            case "mowerLightStatus":
                this.mowerLightStatus = value;
                return true;
            case "blade_height":
                this.blade_height = value;
                return true;
            case "mowerWidth":
                this.mowerWidth = value;
                return true;
            case "mowerLength":
                this.mowerLength = value;
                return true;
            case "mowingSafetyDistance":
                this.mowingSafetyDistance = value;
                return true;
            default:
                System.err.println("未知字段: " + fieldName);
                return false;
@@ -309,35 +483,51 @@
            mowerNumber = incomingDeviceId;
        }
        // 检查是否正在导航预览模式
        boolean isNavigating = checkIfNavigating();
        String latitudeValue = sanitizeField(fields, 2);
        String latitudeHemisphere = sanitizeField(fields, 3);
        String longitudeValue = sanitizeField(fields, 4);
        String longitudeHemisphere = sanitizeField(fields, 5);
        String combinedLatitude = combineCoordinate(latitudeValue, latitudeHemisphere);
        if (hasMeaningfulValue(combinedLatitude)) {
            realtimeLatitude = combinedLatitude;
        }
        String combinedLongitude = combineCoordinate(longitudeValue, longitudeHemisphere);
        if (hasMeaningfulValue(combinedLongitude)) {
            realtimeLongitude = combinedLongitude;
        // 只有在非导航预览模式下才更新位置相关数据
        if (!isNavigating) {
            String combinedLatitude = combineCoordinate(latitudeValue, latitudeHemisphere);
            if (hasMeaningfulValue(combinedLatitude)) {
                realtimeLatitude = combinedLatitude;
            }
            String combinedLongitude = combineCoordinate(longitudeValue, longitudeHemisphere);
            if (hasMeaningfulValue(combinedLongitude)) {
                realtimeLongitude = combinedLongitude;
            }
            String altitudeValue = sanitizeField(fields, 9);
            if (hasMeaningfulValue(altitudeValue)) {
                realtimeAltitude = altitudeValue;
            }
            // 更新位置坐标
            updateRelativeCoordinates(latitudeValue, latitudeHemisphere, longitudeValue, longitudeHemisphere);
            // 更新航向角(位置相关)
            heading = defaultIfEmpty(sanitizeField(fields, 19));
        }
        String altitudeValue = sanitizeField(fields, 9);
        if (hasMeaningfulValue(altitudeValue)) {
            realtimeAltitude = altitudeValue;
        }
        // 其他数据(电量、卫星数等)始终更新
        positioningStatus = defaultIfEmpty(sanitizeField(fields, 6));
        // 同步到绘制模块的数据源,保证往返绘制定时器能识别定位质量
        try {
            MowerLocationData.updateProperty("positioningQuality", positioningStatus);
        } catch (Throwable ignored) {
            // 防御式:即使更新失败也不影响设备数据处理
        }
        satelliteCount = defaultIfEmpty(sanitizeField(fields, 7));
        differentialAge = defaultIfEmpty(sanitizeField(fields, 13));
        battery = defaultIfEmpty(sanitizeField(fields, 16));
        battery_level = defaultIfEmpty(sanitizeField(fields, 16));
        pitch = defaultIfEmpty(sanitizeField(fields, 17));
        realtimeSpeed = defaultIfEmpty(sanitizeField(fields, 18));
        heading = defaultIfEmpty(sanitizeField(fields, 19));
        GupdateTime = String.valueOf(System.currentTimeMillis());
        updateRelativeCoordinates(latitudeValue, latitudeHemisphere, longitudeValue, longitudeHemisphere);
    }
    
    /**串口更新GNGGA数据*/
@@ -357,33 +547,86 @@
            return;
        }
        // 检查是否正在导航预览模式
        boolean isNavigating = checkIfNavigating();
        String latitudeValue = sanitizeField(fields, 2);
        String latitudeHemisphere = sanitizeField(fields, 3);
        String longitudeValue = sanitizeField(fields, 4);
        String longitudeHemisphere = sanitizeField(fields, 5);
        String combinedLatitude = combineCoordinate(latitudeValue, latitudeHemisphere);
        if (hasMeaningfulValue(combinedLatitude)) {
            realtimeLatitude = combinedLatitude;
        }
        String combinedLongitude = combineCoordinate(longitudeValue, longitudeHemisphere);
        if (hasMeaningfulValue(combinedLongitude)) {
            realtimeLongitude = combinedLongitude;
        // 只有在非导航预览模式下才更新位置相关数据
        if (!isNavigating) {
            String combinedLatitude = combineCoordinate(latitudeValue, latitudeHemisphere);
            if (hasMeaningfulValue(combinedLatitude)) {
                realtimeLatitude = combinedLatitude;
            }
            String combinedLongitude = combineCoordinate(longitudeValue, longitudeHemisphere);
            if (hasMeaningfulValue(combinedLongitude)) {
                realtimeLongitude = combinedLongitude;
            }
            String altitudeValue = sanitizeField(fields, 9);
            if (hasMeaningfulValue(altitudeValue)) {
                realtimeAltitude = altitudeValue;
            }
            // 更新位置坐标
            updateRelativeCoordinates(latitudeValue, latitudeHemisphere, longitudeValue, longitudeHemisphere);
            // 串口收到GNGGA数据后,触发拖尾更新
            notifyMowerTrailUpdate();
        }
        String altitudeValue = sanitizeField(fields, 9);
        if (hasMeaningfulValue(altitudeValue)) {
            realtimeAltitude = altitudeValue;
        }
        // 其他数据(电量、卫星数等)始终更新
        positioningStatus = defaultIfEmpty(sanitizeField(fields, 6));
        // 同步到绘制模块的数据源,保证往返绘制定时器能识别定位质量
        try {
            MowerLocationData.updateProperty("positioningQuality", positioningStatus);
        } catch (Throwable ignored) {
            // 防御式:即使更新失败也不影响设备数据处理
        }
        satelliteCount = defaultIfEmpty(sanitizeField(fields, 7));
        differentialAge = defaultIfEmpty(sanitizeField(fields, 13));       
        realtimeSpeed ="0";        
        GupdateTime = String.valueOf(System.currentTimeMillis());
        updateRelativeCoordinates(latitudeValue, latitudeHemisphere, longitudeValue, longitudeHemisphere);
    }
    /**
     * 通知地图渲染器更新割草机拖尾
     * 当串口收到GNGGA数据并更新位置后调用
     */
    /**
     * 检查是否正在导航预览模式
     * @return 如果正在导航预览返回true,否则返回false
     */
    private boolean checkIfNavigating() {
        try {
            dikuai.daohangyulan nav = dikuai.daohangyulan.getInstance();
            if (nav != null) {
                return nav.isNavigating();
            }
        } catch (Exception e) {
            // 如果获取导航实例失败,返回false(不影响主要功能)
        }
        return false;
    }
    private void notifyMowerTrailUpdate() {
        try {
            // 通过Shouye.getInstance()获取实例,避免循环依赖
            zhuye.Shouye shouye = zhuye.Shouye.getInstance();
            if (shouye != null) {
                zhuye.MapRenderer mapRenderer = shouye.getMapRenderer();
                if (mapRenderer != null) {
                    // 调用更新拖尾方法
                    mapRenderer.forceUpdateIdleMowerTrail();
                }
            }
        } catch (Exception e) {
            // 如果调用失败,静默处理(不影响主要功能)
            // System.err.println("通知拖尾更新失败: " + e.getMessage());
        }
    }
    private void updateRelativeCoordinates(String latValue, String latHemisphere,
@@ -415,6 +658,9 @@
        if (Double.isFinite(eastMeters) && Double.isFinite(northMeters)) {
            realtimeX = formatMeters(eastMeters);
            realtimeY = formatMeters(northMeters);
            // 保存坐标到工具类
            lujing.SavaXyZuobiao.addCoordinate(eastMeters, northMeters);
        }
    }
@@ -664,12 +910,84 @@
        this.pitch = pitch;
    }
    public String getBattery() { // 获取实时电量
        return battery;
    public String getRoll() {
        return roll;
    }
    public void setBattery(String battery) { // 设置实时电量
        this.battery = battery;
    public void setRoll(String roll) {
        this.roll = roll;
    }
    public String getYaw() {
        return yaw;
    }
    public void setYaw(String yaw) {
        this.yaw = yaw;
    }
    public String getBattery_level() {
        return battery_level;
    }
    public void setBattery_level(String battery_level) {
        this.battery_level = battery_level;
    }
    public String getBattery_voltage() {
        return battery_voltage;
    }
    public void setBattery_voltage(String battery_voltage) {
        this.battery_voltage = battery_voltage;
    }
    public String getOperation_mode() {
        return operation_mode;
    }
    public void setOperation_mode(String operation_mode) {
        this.operation_mode = operation_mode;
    }
    public String getMotor_status() {
        return motor_status;
    }
    public void setMotor_status(String motor_status) {
        this.motor_status = motor_status;
    }
    public String getBlade_status() {
        return blade_status;
    }
    public void setBlade_status(String blade_status) {
        this.blade_status = blade_status;
    }
    public String getPath_id_saved() {
        return path_id_saved;
    }
    public void setPath_id_saved(String path_id_saved) {
        this.path_id_saved = path_id_saved;
    }
    public String getError_code() {
        return error_code;
    }
    public void setError_code(String error_code) {
        this.error_code = error_code;
    }
    public String getError_message() {
        return error_message;
    }
    public void setError_message(String error_message) {
        this.error_message = error_message;
    }
    public String getPositioningStatus() { // 获取定位状态
@@ -696,6 +1014,62 @@
        this.differentialAge = differentialAge;
    }
    public String getSelf_check_status() { // 获取自检状态
        return self_check_status;
    }
    public void setSelf_check_status(String self_check_status) { // 设置自检状态
        this.self_check_status = self_check_status;
    }
    public String getMowerStartStatus() { // 获取割草机启动状态
        return mowerStartStatus;
    }
    public void setMowerStartStatus(String mowerStartStatus) { // 设置割草机启动状态
        this.mowerStartStatus = mowerStartStatus;
    }
    public String getMowerLightStatus() { // 获取割草机灯开关状态
        return mowerLightStatus;
    }
    public void setMowerLightStatus(String mowerLightStatus) { // 设置割草机灯开关状态
        this.mowerLightStatus = mowerLightStatus;
    }
    public String getBlade_height() { // 获取割草机刀盘高度
        return blade_height;
    }
    public void setBlade_height(String blade_height) { // 设置割草机刀盘高度
        this.blade_height = blade_height;
    }
    public String getMowerWidth() { // 获取割草机宽度
        return mowerWidth;
    }
    public void setMowerWidth(String mowerWidth) { // 设置割草机宽度
        this.mowerWidth = mowerWidth;
    }
    public String getMowerLength() { // 获取割草机长度
        return mowerLength;
    }
    public void setMowerLength(String mowerLength) { // 设置割草机长度
        this.mowerLength = mowerLength;
    }
    public String getMowingSafetyDistance() { // 获取割草安全距离
        return mowingSafetyDistance;
    }
    public void setMowingSafetyDistance(String mowingSafetyDistance) { // 设置割草安全距离
        this.mowingSafetyDistance = mowingSafetyDistance;
    }
    @Override
    public String toString() { // 输出对象信息
        return "Device{" +
@@ -719,10 +1093,26 @@
                ", realtimeSpeed='" + realtimeSpeed + '\'' +
                ", heading='" + heading + '\'' +
                ", pitch='" + pitch + '\'' +
                ", battery='" + battery + '\'' +
                ", roll='" + roll + '\'' +
                ", yaw='" + yaw + '\'' +
                ", battery_level='" + battery_level + '\'' +
                ", battery_voltage='" + battery_voltage + '\'' +
                ", operation_mode='" + operation_mode + '\'' +
                ", motor_status='" + motor_status + '\'' +
                ", blade_status='" + blade_status + '\'' +
                ", path_id_saved='" + path_id_saved + '\'' +
                ", error_code='" + error_code + '\'' +
                ", error_message='" + error_message + '\'' +
                ", positioningStatus='" + positioningStatus + '\'' +
                ", satelliteCount='" + satelliteCount + '\'' +
                ", differentialAge='" + differentialAge + '\'' +
                ", self_check_status='" + self_check_status + '\'' +
                ", mowerStartStatus='" + mowerStartStatus + '\'' +
                ", mowerLightStatus='" + mowerLightStatus + '\'' +
                ", blade_height='" + blade_height + '\'' +
                ", mowerWidth='" + mowerWidth + '\'' +
                ", mowerLength='" + mowerLength + '\'' +
                ", mowingSafetyDistance='" + mowingSafetyDistance + '\'' +
                '}';
    }
}