USB偏好设置-Android13

USB偏好设置

  • 1、USB偏好设置界面和入口
  • 2、USB功能设置
    • 2.1 USB功能对应模式
    • 2.2 点击设置
    • 2.3 广播监听刷新
  • 3、日志开关
    • 3.1 Evet日志
    • 3.2 代码中日志开关
    • 3.3 关键日志
  • 4、异常

1、USB偏好设置界面和入口

设置》已连接的设备》USB
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
packages/apps/Settings/res/xml/usb_details_fragment.xml
在这里插入图片描述

private static List<UsbDetailsController> createControllerList(Context context,
        UsbBackend usbBackend, UsbDetailsFragment fragment) {
    List<UsbDetailsController> ret = new ArrayList<>();
    ret.add(new UsbDetailsHeaderController(context, fragment, usbBackend));
    ret.add(new UsbDetailsDataRoleController(context, fragment, usbBackend));
    ret.add(new UsbDetailsFunctionsController(context, fragment, usbBackend));
    ret.add(new UsbDetailsPowerRoleController(context, fragment, usbBackend));
    ret.add(new UsbDetailsTranscodeMtpController(context, fragment, usbBackend));
    return ret;
}

2、USB功能设置

packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

2.1 USB功能对应模式

FWK模式对应值字符串显示节点
FUNCTION_NONE = 0NONE = 0
FUNCTION_MTP = GadgetFunction.MTPMTP = 1 << 2“文件传输”
FUNCTION_PTP = GadgetFunction.PTPPTP = 1 << 4“PTP”
FUNCTION_RNDIS = GadgetFunction.RNDISRNDIS = 1 << 5“USB 网络共享”
FUNCTION_MIDI = GadgetFunction.MIDIMIDI = 1 << 3“MIDI”
FUNCTION_ACCESSORY = GadgetFunction.ACCESSORYACCESSORY = 1 << 1
FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCEAUDIO_SOURCE = 1 << 6
FUNCTION_ADB = GadgetFunction.ADBADB = 1 << 0“不用于数据传输”

frameworks/base/core/java/android/hardware/usb/UsbManager.java
hardware/interfaces/usb/gadget/1.0/types.hal
frameworks/base/core/proto/android/service/usb.proto

/* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */
enum Function {
    FUNCTION_ADB = 1;
    FUNCTION_ACCESSORY = 2;
    FUNCTION_MTP = 4;
    FUNCTION_MIDI = 8;
    FUNCTION_PTP = 16;
    FUNCTION_RNDIS = 32;
    FUNCTION_AUDIO_SOURCE = 64;
}

2.2 点击设置

mUsbBackend 通过UsbManager.java、UsbService.java、UsbDeviceManager.java设置

packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

@Override
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
    final long function = UsbBackend.usbFunctionsFromString(preference.getKey());
    final long previousFunction = mUsbBackend.getCurrentFunctions();
    if (DEBUG) {
        Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : "
                + UsbManager.usbFunctionsToString(function) + ", previousFunction : "
                + previousFunction + ", toString() : "
                + UsbManager.usbFunctionsToString(previousFunction));
    }
    if (function != previousFunction && !Utils.isMonkeyRunning()
            && !isClickEventIgnored(function, previousFunction)) {
        mPreviousFunction = previousFunction;

        //Update the UI in advance to make it looks smooth
        final SelectorWithWidgetPreference prevPref =
                (SelectorWithWidgetPreference) mProfilesContainer.findPreference(
                        UsbBackend.usbFunctionsToString(mPreviousFunction));
        if (prevPref != null) {
            prevPref.setChecked(false);
            preference.setChecked(true);
        }

        if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) {
            // We need to have entitlement check for usb tethering, so use API in
            // TetheringManager.
            mTetheringManager.startTethering(
                    TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler),
                    mOnStartTetheringCallback);
        } else {
            mUsbBackend.setCurrentFunctions(function);
        }
    }
}

frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java

public void setCurrentFunctions(long functions) {
        if (DEBUG) {
            Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
        }
        if (functions == UsbManager.FUNCTION_NONE) {
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_CHARGING);
        } else if (functions == UsbManager.FUNCTION_MTP) {
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);
        } else if (functions == UsbManager.FUNCTION_PTP) {
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_PTP);
        } else if (functions == UsbManager.FUNCTION_MIDI) {
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MIDI);
        } else if (functions == UsbManager.FUNCTION_RNDIS) {
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_RNDIS);
        } else if (functions == UsbManager.FUNCTION_ACCESSORY) {
            MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
        }
        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
    }

        private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) {
            String functions = null;
            if (usbFunctions != UsbManager.FUNCTION_NONE) {
                functions = UsbManager.usbFunctionsToString(usbFunctions);
            }
            mCurrentFunctions = usbFunctions;
            if (functions == null || applyAdbFunction(functions)
                    .equals(UsbManager.USB_FUNCTION_NONE)) {
                functions = UsbManager.usbFunctionsToString(getChargingFunctions());
            }
            functions = applyAdbFunction(functions);

            String oemFunctions = applyOemOverrideFunction(functions);

            if (!isNormalBoot() && !mCurrentFunctionsStr.equals(functions)) {
                setSystemProperty(getPersistProp(true), functions);
            }

            if ((!functions.equals(oemFunctions)
                    && !mCurrentOemFunctions.equals(oemFunctions))
                    || !mCurrentFunctionsStr.equals(functions)
                    || !mCurrentFunctionsApplied
                    || forceRestart) {
                Slog.i(TAG, "Setting USB config to " + functions);
                mCurrentFunctionsStr = functions;
                mCurrentOemFunctions = oemFunctions;
                mCurrentFunctionsApplied = false;

                /**
                 * Kick the USB stack to close existing connections.
                 */
                setUsbConfig(UsbManager.USB_FUNCTION_NONE);

                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
                    Slog.e(TAG, "Failed to kick USB config");
                    return false;
                }

                /**
                 * Set the new USB configuration.
                 */
                setUsbConfig(oemFunctions);

                if (mBootCompleted
                        && (containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
                        || containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
                    /**
                     * Start up dependent services.
                     */
                    updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
                }

                if (!waitForState(oemFunctions)) {
                    Slog.e(TAG, "Failed to switch USB config to " + functions);
                    return false;
                }

                mCurrentFunctionsApplied = true;
            }
            return true;
        }

hardware/interfaces/usb/gadget/1.2/default/UsbGadget.cpp

V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
                                       const sp<V1_0::IUsbGadgetCallback>& callback,
                                       uint64_t timeout) {
    bool ffsEnabled = false;
    int i = 0;

    if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
        V1_0::Status::SUCCESS)
        return V1_0::Status::ERROR;

    if ((functions & V1_2::GadgetFunction::ADB) != 0) {
        ffsEnabled = true;
        if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
    }

    // Pull up the gadget right away when there are no ffs functions.
    if (!ffsEnabled) {
        if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
        mCurrentUsbFunctionsApplied = true;
        if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
        return V1_0::Status::SUCCESS;
    }

    monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
    // Monitors the ffs paths to pull up the gadget when descriptors are written.
    // Also takes of the pulling up the gadget again if the userspace process
    // dies and restarts.
    monitorFfs.startMonitor();

    if (kDebug) ALOGI("Mainthread in Cv");

    if (callback) {
        bool pullup = monitorFfs.waitForPullUp(timeout);
        Return<void> ret = callback->setCurrentUsbFunctionsCb(
                functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
        if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
    }

    return V1_0::Status::SUCCESS;
}

Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
                                               const sp<V1_0::IUsbGadgetCallback>& callback,
                                               uint64_t timeout) {
    std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);

    mCurrentUsbFunctions = functions;
    mCurrentUsbFunctionsApplied = false;

    // Unlink the gadget and stop the monitor if running.
    V1_0::Status status = tearDownGadget();
    if (status != V1_0::Status::SUCCESS) {
        goto error;
    }

    ALOGI("Returned from tearDown gadget");

    // Leave the gadget pulled down to give time for the host to sense disconnect.
    usleep(kDisconnectWaitUs);

    if (functions == static_cast<uint64_t>(V1_2::GadgetFunction::NONE)) {
        if (callback == NULL) return Void();
        Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
        if (!ret.isOk())
            ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
        return Void();
    }

    status = validateAndSetVidPid(functions);

    if (status != V1_0::Status::SUCCESS) {
        goto error;
    }

    status = setupFunctions(functions, callback, timeout);
    if (status != V1_0::Status::SUCCESS) {
        goto error;
    }

    ALOGI("Usb Gadget setcurrent functions called successfully");
    return Void();

error:
    ALOGI("Usb Gadget setcurrent functions failed");
    if (callback == NULL) return Void();
    Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
    if (!ret.isOk())
        ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
    return Void();
}

hardware/interfaces/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp

Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
                                  int* functionCount) {
    if (((functions & GadgetFunction::MTP) != 0)) {
        *ffsEnabled = true;
        ALOGI("setCurrentUsbFunctions mtp");
        if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;

        if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;

        if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;

        // Add endpoints to be monitored.
        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
    } else if (((functions & GadgetFunction::PTP) != 0)) {
        *ffsEnabled = true;
        ALOGI("setCurrentUsbFunctions ptp");
        if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;

        if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;

        if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;

        // Add endpoints to be monitored.
        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
    }

    if ((functions & GadgetFunction::MIDI) != 0) {
        ALOGI("setCurrentUsbFunctions MIDI");
        if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
    }

    if ((functions & GadgetFunction::ACCESSORY) != 0) {
        ALOGI("setCurrentUsbFunctions Accessory");
        if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
    }

    if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
        ALOGI("setCurrentUsbFunctions Audio Source");
        if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
    }

    if ((functions & GadgetFunction::RNDIS) != 0) {
        ALOGI("setCurrentUsbFunctions rndis");
        if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
        std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
        if (rndisFunction != "") {
            if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
        } else {
            // link gsi.rndis for older pixel projects
            if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
        }
    }

    if ((functions & GadgetFunction::NCM) != 0) {
        ALOGI("setCurrentUsbFunctions ncm");
        if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;
    }

    return Status::SUCCESS;
}

了解 USB Gadget HAL API 架构
在这里插入图片描述

2.3 广播监听刷新

广播监听刷新 onUsbConnectionChanged > refresh
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

/**
 * Interface definition for a callback to be invoked when usb connection is changed.
 */
interface UsbConnectionListener {
    void onUsbConnectionChanged(boolean connected, long functions, int powerRole, int dataRole,
            boolean isUsbConfigured);
}
private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
            (connected, functions, powerRole, dataRole, isUsbFigured) -> {
                for (UsbDetailsController controller : mControllers) {
                    controller.refresh(connected, functions, powerRole, dataRole);
                }
            };

3、日志开关

3.1 Evet日志

如:MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);

frameworks/base/core/java/com/android/internal/logging/MetricsLogger.java
frameworks/base/core/java/android/metrics/LogMaker.java
frameworks/base/proto/src/metrics_constants/metrics_constants.proto

   // The view or control was activated.
   TYPE_ACTION = 4;
 
   // These values should never appear in log outputs - they are reserved for
   // internal platform metrics use.
   RESERVED_FOR_LOGBUILDER_CATEGORY = 757;
   RESERVED_FOR_LOGBUILDER_TYPE = 758;
   RESERVED_FOR_LOGBUILDER_SUBTYPE = 759;
 
   // ACTION: Usb config has been changed to charging
   // CATEGORY: SETTINGS
   // OS: P
   ACTION_USB_CONFIG_CHARGING = 1275;
 
   // ACTION: Usb config has been changed to mtp (file transfer)
   // CATEGORY: SETTINGS
   // OS: P
   ACTION_USB_CONFIG_MTP = 1276;
 
   // ACTION: Usb config has been changed to ptp (photo transfer)
   // CATEGORY: SETTINGS
   // OS: P
   ACTION_USB_CONFIG_PTP = 1277;
 
   // ACTION: Usb config has been changed to rndis (usb tethering)
   // CATEGORY: SETTINGS
   // OS: P
   ACTION_USB_CONFIG_RNDIS = 1278;
 
   // ACTION: Usb config has been changed to midi
   // CATEGORY: SETTINGS
   // OS: P
   ACTION_USB_CONFIG_MIDI = 1279;
 
   // ACTION: Usb config has been changed to accessory
   // CATEGORY: SETTINGS
   // OS: P
   ACTION_USB_CONFIG_ACCESSORY = 1280;

3.2 代码中日志开关

adb 打开:需要重启Settings进程

adb shell setprop log.tag.UsbFunctionsCtrl D
adb shell setprop log.tag.UsbBroadcastReceiver D

packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

private static final String TAG = "UsbFunctionsCtrl";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

3.3 关键日志

start u|SettingsActivity: Switching to|UsbFunctionsCtrl:|UsbDetailsFragment:|UsbBroadcastReceiver:|UsbDeviceManager:|sysui_multi_action: [757,.*,758,4]

android.hardware.usb.gadget@1.1-service-qti:|libusbconfigfs:

4、异常

symlink失败:"Cannot create symlink %s -> %s errno:%d"

hardware/interfaces/usb/gadget/1.2/default/lib/include/UsbGadgetCommon.h

#define GADGET_PATH "/config/usb_gadget/g1/"
#define PULLUP_PATH GADGET_PATH "UDC"
#define PERSISTENT_BOOT_MODE "ro.bootmode"
#define VENDOR_ID_PATH GADGET_PATH "idVendor"
#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
#define DESC_USE_PATH GADGET_PATH "os_desc/use"
#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
#define CONFIG_PATH GADGET_PATH "configs/b.1/"
#define FUNCTIONS_PATH GADGET_PATH "functions/"
#define FUNCTION_NAME "function"
#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"

在这里插入图片描述
hardware/interfaces/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp

int linkFunction(const char* function, int index) {
    char functionPath[kMaxFilePathLength];
    char link[kMaxFilePathLength];

    sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);
    sprintf(link, "%s%d", FUNCTION_PATH, index);
    if (symlink(functionPath, link)) {
        ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);
        return -1;
    }
    return 0;
}

Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
                                  int* functionCount) {
    if (((functions & GadgetFunction::MTP) != 0)) {
        *ffsEnabled = true;
        ALOGI("setCurrentUsbFunctions mtp");
        if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;

        if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;

        if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;

        // Add endpoints to be monitored.
        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
    } else if (((functions & GadgetFunction::PTP) != 0)) {
        *ffsEnabled = true;
        ALOGI("setCurrentUsbFunctions ptp");
        if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;

        if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;

        if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;

        // Add endpoints to be monitored.
        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
    }

    if ((functions & GadgetFunction::MIDI) != 0) {
        ALOGI("setCurrentUsbFunctions MIDI");
        if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
    }

    if ((functions & GadgetFunction::ACCESSORY) != 0) {
        ALOGI("setCurrentUsbFunctions Accessory");
        if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
    }

    if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
        ALOGI("setCurrentUsbFunctions Audio Source");
        if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
    }

    if ((functions & GadgetFunction::RNDIS) != 0) {
        ALOGI("setCurrentUsbFunctions rndis");
        if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
        std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
        if (rndisFunction != "") {
            if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
        } else {
            // link gsi.rndis for older pixel projects
            if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
        }
    }

    if ((functions & GadgetFunction::NCM) != 0) {
        ALOGI("setCurrentUsbFunctions ncm");
        if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;
    }

    return Status::SUCCESS;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/130164.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS 移动端 1px(线条/边框) 不同机型上显示粗细不同,解决办法

由于不同的手机有不同的像素密度导致的。如果移动显示屏的分辨率始终是普通屏幕的2倍&#xff0c;1px的边框在devicePixelRatio2的移动显示屏下会显示成2px&#xff0c;所以在高清瓶下看着1px总是感觉变胖了 <!DOCTYPE html> <html lang"en"> <head&g…

快速修复因相机断电导致视频文件打不开的问题

3-5 本文主要解决因相机突然断电导致拍摄的视频文件打不开的问题。 在日常工作中&#xff0c;有时候需要使用相机拍摄视频&#xff0c;比如现在有不少短视频拍摄的需求&#xff0c;如果因电池突然断电的原因&#xff0c;导致拍出来的视频播放不了&#xff0c;这时候就容易出大…

自适应模糊PID控制器在热交换器温度控制中的应用

热交换器是一种常见的热能传递设备&#xff0c;广泛应用于各个工业领域。对热交换器温度进行有效控制具有重要意义&#xff0c;可以提高能源利用效率和产品质量。然而&#xff0c;受到热传导特性和外部环境变化等因素的影响&#xff0c;热交换器温度控制难度较大。本文提出一种…

个人怎么投资伦敦金?

伦敦金是一种被广泛交易的黄金合约&#xff0c;是投资者参与黄金市场的一种交易方式。伦敦金投资也是黄金交易中最为方便快捷的一个种类&#xff0c;在黄金交易市场中占有较大的比例&#xff0c;每天都有来自全球各地的投资者参与买卖&#xff0c;是实现财富增益的一个有效途径…

数据库数据恢复—MSSQL报错“附加数据库错误823”如何恢复数据?

数据库故障&分析&#xff1a; MSSQL Server数据库比较常见的报错是“附加数据库错误823”。如果数据库有备份&#xff0c;只需要还原备份即可&#xff1b;如果无备份或者备份不可用&#xff0c;则需要使用专业的数据恢复手段去恢复数据。 MSSQL Server数据库出现“823”的报…

宠物医院信息展示预约小程序的效果如何

养宠家庭越来越多&#xff0c;随之带来的就是宠物健康问题&#xff0c;生活条件稍微好点的家庭&#xff0c;只要宠物生病或洗护、寄养、美容等就会前往宠物医院&#xff0c;而近些年来&#xff0c;市场中的宠物医院也在连年增加&#xff0c;可以预见市场需求度较高。 而对宠物…

基于遗传算法优化的直流电机PID控制器设计

PID控制器是工业控制中常用的一种控制算法&#xff0c;通过不断调节比例、积分和微分部分来实现对系统的稳定控制。然而&#xff0c;在一些复杂系统中&#xff0c;传统的PID参数调节方法可能存在局限性。本文将介绍一种基于遗传算法优化的直流电机PID控制器设计方法&#xff0c…

[极客大挑战 2019]BuyFlag 1(两种解法)

题目环境&#xff1a; FLAG NEED YOUR 100000000 MONEY flag需要你的100000000元 F12瞅瞅源代码&#xff1a; if (isset($_POST[password])){ $password $_POST[password]; if (is_numeric($password)) { echo "password cant be number" } elseif ($pas…

Android RxJava3 原理浅析

使用 val retrofit Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build()val api retrofit.create(API::class.java)api.getRepo("…

数据结构之单链表

大家好&#xff0c;我们今天来简单的认识下单链表。 链表的概念及结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。 单链表就像图中的火车一样&#xff0c;是由一节一节车厢链接起来…

第12章 PyTorch图像分割代码框架-3:推理与部署

推理模块 模型训练完成后&#xff0c;需要单独再写一个推理模块来供用户测试或者使用&#xff0c;该模块可以命名为test.py或者inference.py&#xff0c;导入训练好的模型文件和待测试的图像&#xff0c;输出该图像的分割结果。inference.py主体部分如代码11-7所示。 代码11-7 …

Linux imu6ull驱动- led

一、GPIO模块结构 开始来啃手册了&#xff0c;打开我们的imx6ull手册。本章我们编写的是GPIO的&#xff0c;打开手册的第28章&#xff0c;这一章就有关于IMX6ULL 的 GPIO 模块结构。 mx6ull一共有5 组 GPIO&#xff08;GPIO1&#xff5e;GPIO5&#xff09; GPIO1 有 32 个引脚&…

C/C++输出硬币翻转 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C硬币翻转 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C硬币翻转 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 假设有N个硬币(N为不大于5000的正整数)&#xff0c;从1…

C语言--汉诺塔【内容超级详细】

今天与大家分享一下如何用C语言解决汉诺塔问题。 目录 一.前言 二.找规律⭐ 三.总结⭐⭐⭐ 四.代码实现⭐⭐ 一.前言 有一部很好看的电影《猩球崛起》⭐&#xff0c;说呀&#xff0c;人类为了抗击癌症发明了一种药物&#x1f357;&#xff0c;然后给猩猩做了实验&#xff0…

2020年五一杯数学建模A题煤炭价格预测问题解题全过程文档及程序

2020年五一杯数学建模 A题 煤炭价格预测问题 原题再现 煤炭属于大宗商品&#xff0c;煤炭价格既受国家相关部门的监管&#xff0c;又受国内煤炭市场的影响。除此之外&#xff0c;气候变化、出行方式、能源消耗方式、国际煤炭市场等其他因素也会影响煤炭价格。请完成如下问题。…

canvas 简单直线轨迹运动与线性插值计算

canvas 简单直线轨迹运动与线性插值计算 一、canvas 直线轨迹运行 添加 canvas 语法提示 通过/** type {HTMLCanvasElement} */代码块 来添加canvas的语法提示 <body><canvas id"canvas"></canvas> </body> <script>/** type {HTM…

软件模拟SPI协议的理解和使用编写W25Q64

SPI软件模拟的时序 SPI协议中&#xff0c;NSS、SCK、MOSI由主机产生&#xff0c;MISO由从机产生&#xff0c;在SCK每个时钟周期MOSI、MISO传输一位数据&#xff0c;数据的输入输出是同时进行的&#xff0c;所以读写数据也可以视作交换数据。所以读写时对数据位的控制都是用同一…

ke10javaweb停更

<jsp:getProperty property"isval" name "username"/> property来修改属性,name是类 所以如果调用tip在前面那么就是没有设置值 证明是先到java里面去运转

AI编程工具:一站式编程解决方案,引领AI编程新时代

在人工智能的巨浪之下&#xff0c;编程领域正在经历一场深刻的转型。这场转型的核心&#xff0c;就是AI智能编程工具的出现。它们为开发者提供了一种全新的编程方式&#xff0c;极大地提高了编程效率。在这场变革中&#xff0c;DevChat无疑是引领者之一。 一、DevChat&#xf…

计算机毕业设计 基于SpringBoot高校毕业与学位资格审核系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…
最新文章