当前位置: 首页 > news >正文

ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks使用分析

ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks使用分析

  • 1 ATF的下载链接
  • 2 ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks处理流程
    • 2.1 ATF BL1/BL2 ufs_read_blocks
    • 2.2 ATF BL1/BL2 ufs_write_blocks
  • 3 UFS System Model
  • 4 ufs_read_blocks/ufs_write_blocks详细分析
    • 4.1 ufs_read_blocks
    • 4.2 ufs_write_blocks
    • 4.3 ufs_send_cmd
    • 4.4 get_utrd
    • 4.5 ufs_prepare_cmd
      • 4.5.1 COMMAND UPIU
      • 4.5.2 READ (10) Command
      • 4.5.3RESPONSE UPIU
      • 4.5.4 WRITE (10) Command
      • 4.5.5 ufs_prepare_cmd
    • 4.6 ufs_send_request
    • 4.7 ufs_check_resp

ATF BL1 UFS初始化简单分析
ATF bl1 ufshc_dme_get/set处理流程分析

1 ATF的下载链接

https://github.com/ARM-software/arm-trusted-firmware

可以通过下面的命令来下载ATF的代码,或者通过打包下载的方式也可以。

git clone git@github.com:ARM-software/arm-trusted-firmware.git

2 ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks处理流程

ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks的处理流程是类似的,只ufs_send_cmd下传的命令是有区别的,在ufs_prepare_cmd的时候需要依据ufs_send_cmd传递的命令参数去组织cmd UPIU。

2.1 ATF BL1/BL2 ufs_read_blocks

在这里插入图片描述

2.2 ATF BL1/BL2 ufs_write_blocks

在这里插入图片描述

3 UFS System Model

It shows how a UFS host is connected to a UFS device, the position of UFS host controller and its related UFS HCI interface.
它显示了 UFS 主机与 UFS 设备的连接方式、UFS 主机控制器的位置及其相关的 UFS HCI 接口。
The UFS host consists of the application which wishes to communicate with the UFS device. It communicates with the device using the UFS driver. The UFS driver is meant for managing the UFS host controller through the UFS HCI (UFS Host Controller Interface). The UFS HCI is basically a set of registers exposed by the host controller.
UFS 主机由希望与 UFS 设备通信的应用程序组成。它使用 UFS 驱动程序与设备通信。UFS 驱动程序用于通过 UFS 主控制器接口(UFS HCI)管理 UFS 主控制器。UFS HCI 基本上是主控制器公开的一组寄存器。
## 3.2

4 ufs_read_blocks/ufs_write_blocks详细分析

4.1 ufs_read_blocks

  • ufs_send_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
{utp_utrd_t utrd;resp_upiu_t *resp;assert((ufs_params.reg_base != 0) &&(ufs_params.desc_base != 0) &&(ufs_params.desc_size >= UFS_DESC_SIZE));ufs_send_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
#ifdef UFS_RESP_DEBUGdump_upiu(&utrd);
#endif/** Invalidate prefetched cache contents before cpu* accesses the buf.*/inv_dcache_range(buf, size);resp = (resp_upiu_t *)utrd.resp_upiu;return size - resp->res_trans_cnt;
}

4.2 ufs_write_blocks

  • ufs_send_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size)
{utp_utrd_t utrd;resp_upiu_t *resp;assert((ufs_params.reg_base != 0) &&(ufs_params.desc_base != 0) &&(ufs_params.desc_size >= UFS_DESC_SIZE));ufs_send_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
#ifdef UFS_RESP_DEBUGdump_upiu(&utrd);
#endifresp = (resp_upiu_t *)utrd.resp_upiu;return size - resp->res_trans_cnt;
}

4.3 ufs_send_cmd

  1. get_utrd(utrd);
  2. ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);
  3. ufs_send_request(utrd->task_tag);
  4. ufs_check_resp(utrd, RESPONSE_UPIU, CMD_TIMEOUT_MS);
static void ufs_send_cmd(utp_utrd_t *utrd, uint8_t cmd_op, uint8_t lun, int lba, uintptr_t buf,size_t length)
{int result, i;for (i = 0; i < UFS_CMD_RETRIES; ++i) {get_utrd(utrd);result = ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);assert(result == 0);ufs_send_request(utrd->task_tag);result = ufs_check_resp(utrd, RESPONSE_UPIU, CMD_TIMEOUT_MS);if (result == 0 || result == -EIO) {break;}}assert(result == 0);(void)result;
}

4.4 get_utrd

  • get_utrd函数用于获取一个公共的utrd结构
  • hd->ucdba = utrd->upiu & UINT32_MAX; hd->ucdbau = (utrd->upiu >> 32) & UINT32_MAX;用于UTP传输请求列表基地址的配置。
    在这里插入图片描述
/* UTP Transfer Request Descriptor */
typedef struct utrd_header {uint32_t        reserved0 : 24;uint32_t        i : 1;          /* interrupt */uint32_t        dd : 2;         /* data direction */uint32_t        reserved1 : 1;uint32_t        ct : 4;         /* command type */                                                                                                                                                         uint32_t        reserved2;uint32_t        ocs : 8;        /* Overall Command Status */uint32_t        reserved3 : 24;uint32_t        reserved4;uint32_t        ucdba;          /* aligned to 128-byte */uint32_t        ucdbau;         /* Upper 32-bits */uint32_t        rul : 16;       /* Response UPIU Length */uint32_t        ruo : 16;       /* Response UPIU Offset */uint32_t        prdtl : 16;     /* PRDT Length */uint32_t        prdto : 16;     /* PRDT Offset */
} utrd_header_t;        /* 8 words with little endian */typedef struct utp_utrd {uintptr_t       header;         /* utrd_header_t */uintptr_t       upiu;uintptr_t       resp_upiu;                                                                                                                                                                                 uintptr_t       prdt;size_t          size_upiu;size_t          size_resp_upiu;size_t          prdt_length;int             task_tag;
} utp_utrd_t;static void get_utrd(utp_utrd_t *utrd)
{uintptr_t base;int result;utrd_header_t *hd;assert(utrd != NULL);result = is_slot_available();assert(result == 0);/* clear utrd */memset((void *)utrd, 0, sizeof(utp_utrd_t));base = ufs_params.desc_base;/* clear the descriptor */memset((void *)base, 0, UFS_DESC_SIZE);utrd->header = base;utrd->task_tag = 1; /* We always use the first slot *//* CDB address should be aligned with 128 bytes */utrd->upiu = ALIGN_CDB(utrd->header + sizeof(utrd_header_t));utrd->resp_upiu = ALIGN_8(utrd->upiu + sizeof(cmd_upiu_t));utrd->size_upiu = utrd->resp_upiu - utrd->upiu;utrd->size_resp_upiu = ALIGN_8(sizeof(resp_upiu_t));utrd->prdt = utrd->resp_upiu + utrd->size_resp_upiu;hd = (utrd_header_t *)utrd->header;hd->ucdba = utrd->upiu & UINT32_MAX;hd->ucdbau = (utrd->upiu >> 32) & UINT32_MAX;/* Both RUL and RUO is based on DWORD */hd->rul = utrd->size_resp_upiu >> 2;hd->ruo = utrd->size_upiu >> 2;(void)result;
}

4.5 ufs_prepare_cmd

4.5.1 COMMAND UPIU

The COMMAND UPIU contains the basic UPIU header plus additional information needed to specify a command. The Initiator device will generate this UPIU and send it to a Target device to request a SCSI command service to be performed by the Target.
COMMAND UPIU 包含基本 UPIU 标头以及指定命令所需的附加信息。启动程序设备将生成此 UPIU 并将其发送至目标设备,以请求目标设备执行 SCSI 命令服务。
在这里插入图片描述

4.5.2 READ (10) Command

The READ (10) command requests that the Device Server read from the medium the specified number of logical block(s) and transfer them to the Application Client.
READ (10) 命令要求设备服务器从介质读取指定数量的逻辑块,并将其传输到应用程序客户端。
The Command CDB shall be sent in a single COMMAND UPIU.
命令 CDB 应在单个 COMMAND UPIU 中发送。
The RDPROTECT field is set to zero for UFS.
对于 UFS,RDPROTECT 字段设置为零。
在这里插入图片描述

4.5.3RESPONSE UPIU

The RESPONSE UPIU contains the basic UPIU header plus additional information indicating the command and device level status resulting from the successful or failed execution of a command. The Target will generate this UPIU and send it to the Initiator device after it has completed the requested task.
RESPONSE UPIU 包含基本的 UPIU 标头和附加信息,表明命令和设备级状态,这些状态来自命令的成功或失败执行。目标设备将生成此 UPIU,并在完成请求任务后将其发送给启动设备。
Before terminating a command which requires Data-Out data transfer and before sending the RESPONSE UPIU, the Target device shall wait until it receives all DATA OUT UPIUs related to any outstanding READY TO TRANSFER UPIUs. Also, the Target device should stop sending READY TO TRANSFER UPIUs for the command which requires Data-Out data transfer and to be terminated.
在终止需要数据输出数据传输的命令和发送 RESPONSE UPIU 之前,目标设备应等待收到与任何未完成的 "准备传输 "UPIU 相关的所有 "数据输出 "UPIU。此外,目标设备应停止为需要数据输出数据传输和终止的命令发送 READY TO TRANSFER UPIU。
在这里插入图片描述

4.5.4 WRITE (10) Command

The WRITE (10) UFS command requests that the Device Server transfer the specified number of logical blocks(s) from the Application Client and write them to the medium.
WRITE (10) UFS 命令要求设备服务器从应用程序客户端传输指定数量的逻辑块并将其写入介质。
The Command CDB shall be sent in a single COMMAND UPIU.
命令 CDB 应在单个命令 UPIU 中发送。
The RDPROTECT field is set to zero for UFS.
对于 UFS,RDPROTECT 字段设置为零。
在这里插入图片描述

4.5.5 ufs_prepare_cmd

  • 按照ufs_send_cmd的cmd_op去组command upiu。
  • 对于ufs的读写操作,其cmd_op分别为CDBCMD_READ_10CDBCMD_WRITE_10
  • upiu->cdb[0] = op;
  • CDBCMD_READ_10对于读来说,其upiu以及command的组织形式
	case CDBCMD_READ_10:hd->dd = DD_OUT;upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;upiu->lun = lun;upiu->cdb[1] = RW_WITHOUT_CACHE;/* set logical block address */upiu->cdb[2] = (ulba >> 24) & 0xff;upiu->cdb[3] = (ulba >> 16) & 0xff;upiu->cdb[4] = (ulba >> 8) & 0xff;upiu->cdb[5] = ulba & 0xff;/* set transfer length */upiu->cdb[7] = (lba_cnt >> 8) & 0xff;upiu->cdb[8] = lba_cnt & 0xff;break;
  • CDBCMD_WRITE_10对于写来说,其upiu以及command的组织形式
	case CDBCMD_WRITE_10:hd->dd = DD_IN;upiu->flags = UPIU_FLAGS_W | UPIU_FLAGS_ATTR_S;upiu->lun = lun;upiu->cdb[1] = RW_WITHOUT_CACHE;/* set logical block address */upiu->cdb[2] = (ulba >> 24) & 0xff;upiu->cdb[3] = (ulba >> 16) & 0xff;upiu->cdb[4] = (ulba >> 8) & 0xff;upiu->cdb[5] = ulba & 0xff;/* set transfer length */upiu->cdb[7] = (lba_cnt >> 8) & 0xff;upiu->cdb[8] = lba_cnt & 0xff;break;

函数实现

/*- Prepare UTRD, Command UPIU, Response UPIU.*/
static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,int lba, uintptr_t buf, size_t length)
{utrd_header_t *hd;cmd_upiu_t *upiu;prdt_t *prdt;unsigned int ulba;unsigned int lba_cnt;uintptr_t desc_limit;uintptr_t prdt_end;hd = (utrd_header_t *)utrd->header;upiu = (cmd_upiu_t *)utrd->upiu;hd->i = 1;hd->ct = CT_UFS_STORAGE;hd->ocs = OCS_MASK;upiu->trans_type = CMD_UPIU;upiu->task_tag = utrd->task_tag;upiu->cdb[0] = op;ulba = (unsigned int)lba;lba_cnt = (unsigned int)(length >> UFS_BLOCK_SHIFT);switch (op) {case CDBCMD_TEST_UNIT_READY:break;case CDBCMD_READ_CAPACITY_10:hd->dd = DD_OUT;upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;upiu->lun = lun;break;case CDBCMD_READ_10:hd->dd = DD_OUT;upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;upiu->lun = lun;upiu->cdb[1] = RW_WITHOUT_CACHE;/* set logical block address */upiu->cdb[2] = (ulba >> 24) & 0xff;upiu->cdb[3] = (ulba >> 16) & 0xff;upiu->cdb[4] = (ulba >> 8) & 0xff;upiu->cdb[5] = ulba & 0xff;/* set transfer length */upiu->cdb[7] = (lba_cnt >> 8) & 0xff;upiu->cdb[8] = lba_cnt & 0xff;break;case CDBCMD_WRITE_10:hd->dd = DD_IN;upiu->flags = UPIU_FLAGS_W | UPIU_FLAGS_ATTR_S;upiu->lun = lun;upiu->cdb[1] = RW_WITHOUT_CACHE;/* set logical block address */upiu->cdb[2] = (ulba >> 24) & 0xff;upiu->cdb[3] = (ulba >> 16) & 0xff;upiu->cdb[4] = (ulba >> 8) & 0xff;upiu->cdb[5] = ulba & 0xff;/* set transfer length */upiu->cdb[7] = (lba_cnt >> 8) & 0xff;upiu->cdb[8] = lba_cnt & 0xff;break;default:assert(0);break;}if (hd->dd == DD_IN) {flush_dcache_range(buf, length);} else if (hd->dd == DD_OUT) {inv_dcache_range(buf, length);}utrd->prdt_length = 0;if (length) {upiu->exp_data_trans_len = htobe32(length);assert(lba_cnt <= UINT16_MAX);prdt = (prdt_t *)utrd->prdt;desc_limit = ufs_params.desc_base + ufs_params.desc_size;while (length > 0) {if ((uintptr_t)prdt + sizeof(prdt_t) > desc_limit) {ERROR("UFS: Exceeded descriptor limit. Image is too large\n");panic();}prdt->dba = (unsigned int)(buf & UINT32_MAX);prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);/* prdt->dbc counts from 0 */if (length > MAX_PRDT_SIZE) {prdt->dbc = MAX_PRDT_SIZE - 1;length = length - MAX_PRDT_SIZE;} else {prdt->dbc = length - 1;length = 0;}buf += MAX_PRDT_SIZE;prdt++;utrd->prdt_length++;}hd->prdtl = utrd->prdt_length;hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2;}prdt_end = utrd->prdt + utrd->prdt_length * sizeof(prdt_t);flush_dcache_range(utrd->header, prdt_end - utrd->header);return 0;
}

4.6 ufs_send_request

  • mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot); UFS HCI 向设备端发送一个doorbell,告诉设备端对应的slot去处理由host 发送给设备端的命令。
    UTP Task Management Request List DoorBell Register(UTMRLDBR): This field is bit significant. Each bit corresponds to a slot in the task management request List, where bit 0 corresponds to slot 0. A bit in this field is set by host software to indicate to the host controller that a task management request has been built in system memory for the associated task management request slot, and may be ready for execution. The host software indicates no change to request slots by setting the associated bits in this field to ‘0’. Bits in this field shall only be set to ‘1’ by host software when UTMRLRSR is set to ‘1’.
    UTP任务管理请求列表门铃寄存器(UTMRLDBR):该字段是位有效的。每个位对应任务管理请求列表中的一个槽,其中位 0 对应槽 0。该字段中的位由主机软件设置,以向主机控制器指示系统内存中已为该任务建立了一个任务管理请求。关联的任务管理请求槽,并且可以准备好执行。主机软件通过将该字段中的相关位设置为“0”来指示请求时隙没有变化。当 UTMRLRSR 设置为“1”时,该字段中的位只能由主机软件设置为“1”。
    When a task management request is completed (with success or error), the corresponding bit is cleared to ‘0’ by the host controller.
    当任务管理请求完成(成功或错误)时,相应位被主机控制器清除为“0”。
    The host controller always process task management request in-order according to the order submitted to the list. In case of multiple requests with single doorbell register ringing (batch mode), The dispatch order for these requests by host controller will base on their index in the List. A task management with lower index value will be executed before a task management request with higher index value.
    主机控制器总是按照提交到列表的顺序按顺序处理任务管理请求。如果单个门铃寄存器响铃有多个请求(批处理模式),主机控制器对这些请求的调度顺序将基于它们在列表中的索引。具有较低索引值的任务管理将在具有较高索引值的任务管理请求之前执行。
    This field is also cleared when UTMRLRSR is written from a ‘1’ to a ‘0’ by host software.
    当主机软件将 UTMRLRSR 从“1”写入“0”时,该字段也会被清除。
    在这里插入图片描述
static void ufs_send_request(int task_tag)
{unsigned int data;int slot;slot = task_tag - 1;/* clear all interrupts */mmio_write_32(ufs_params.reg_base + IS, ~0);mmio_write_32(ufs_params.reg_base + UTRLRSR, 1);assert(mmio_read_32(ufs_params.reg_base + UTRLRSR) == 1);data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) |UTRIACR_IATOVAL(0xFF);mmio_write_32(ufs_params.reg_base + UTRIACR, data);/* send request */mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
}

4.7 ufs_check_resp

  • data = mmio_read_32(ufs_params.reg_base + UTRLDBR);在ufs_check_resp函数中检查UTRLDBR状态,检查对应slot位的状态值。
static int ufs_check_resp(utp_utrd_t *utrd, int trans_type, unsigned int timeout_ms)
{utrd_header_t *hd;resp_upiu_t *resp;sense_data_t *sense;unsigned int data;int slot, result;hd = (utrd_header_t *)utrd->header;resp = (resp_upiu_t *)utrd->resp_upiu;result = ufs_wait_for_int_status(UFS_INT_UTRCS, timeout_ms, false);if (result != 0) {return result;}slot = utrd->task_tag - 1;data = mmio_read_32(ufs_params.reg_base + UTRLDBR);assert((data & (1 << slot)) == 0);/** Invalidate the header after DMA read operation has* completed to avoid cpu referring to the prefetched* data brought in before DMA completion.*/inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);assert(hd->ocs == OCS_SUCCESS);assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);sense = &resp->sd.sense;if (sense->resp_code == SENSE_DATA_VALID &&sense->sense_key == SENSE_KEY_UNIT_ATTENTION && sense->asc == 0x29 &&sense->ascq == 0) {WARN("Unit Attention Condition\n");return -EAGAIN;}(void)resp;(void)slot;(void)data;return 0;
}

相关文章:

ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks使用分析

ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks使用分析 1 ATF的下载链接2 ATF BL1/BL2 ufs_read_blocks/ufs_write_blocks处理流程2.1 ATF BL1/BL2 ufs_read_blocks2.2 ATF BL1/BL2 ufs_write_blocks 3 UFS System Model4 ufs_read_blocks/ufs_write_blocks详细分析4.1 ufs_re…...

Elasticsearch(十二)搜索---搜索匹配功能③--布尔查询及filter查询原理

一、前言 本节主要学习ES匹配查询中的布尔查询以及布尔查询中比较特殊的filter查询及其原理。 复合搜索&#xff0c;顾名思义是一种在一个搜索语句中包含一种或多种搜索子句的搜索。 布尔查询是常用的复合查询&#xff0c;它把多个子查询组合成一个布尔表达式&#xff0c;这些…...

解决Windows下的docker desktop无法启动问题

以管理员权限运行cmd 报错&#xff1a; docker: error during connect: Post http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.40/containers/create: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows,…...

LLM生成式 AI 项目生命周期Generative AI project lifecycle

在本课程的其余部分中&#xff0c;您将学习开发和部署LLM驱动应用所需的技巧。在这个视频中&#xff0c;您将了解一个能帮助您完成此工作的生成式AI项目生命周期。此框架列出了从构思到启动项目所需的任务。到课程结束时&#xff0c;您应该对您需要做的重要决策、可能遇到的困难…...

java高并发系列 - 第13天:JUC中的Condition对象

java高并发系列 - 第13天:JUC中的Condition对象 java高并发系列第13篇文章 本文内容 synchronized中实现线程等待和唤醒Condition简介及常用方法介绍及相关示例使用Condition实现生产者消费者使用Condition实现同步阻塞队列Object对象中的wait(),notify()方法,用于线程等待…...

【TTY子系统】printf与printk深入驱动解析

tty子系统解析 tty子系统是一个庞大且复杂&#xff0c;也是内核维护者所头大的子系统。 At a first glance, the TTY layer wouldn’t seem like it should be all that challenging. It is, after all, just a simple char device which is charged with transferring byte-o…...

无涯教程-PHP - 全局变量函数

全局变量 与局部变量相反,可以在程序的任何部分访问全局变量。通过将关键字 GLOBAL 放置在应被识别为全局变量的前面,可以很方便地实现这一目标。 <?php$somevar15;function addit() {GLOBAL $somevar;$somevar;print "Somevar is $somevar";}addit(); ?> …...

shell脚本之循环语句

循环语句 循环含义 将某代码段重复运行多次&#xff0c;通常有进入循环的条件和退出循环的条件 for循环语句 一般知道循环次数使用for循环 第一类 格式1&#xff1a; for名称 in 取值次数;do;done; 格式2&#xff1a; for 名称 in {取值列表} do done# 打印20次 for i i…...

派森 #P122. 峰值查找

描述 给定一个长度为n的列表nums&#xff0c;请你找到峰值并返回其索引。数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回任何一个所在位置即可。 &#xff08;1&#xff09;峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于&#xff1b; &…...

基础网络详解4--HTTP CookieSession 思考

一、cookie技术思考 一台多用户浏览器发起了三笔请求&#xff0c;将某款产品放入购物车中&#xff0c;A一次&#xff0c;选择了篮球&#xff1b;B两次&#xff0c;第一次选了足球&#xff0c;第二次选了钢笔。如何确认选择篮球、足球、钢笔的请求属于谁呢&#xff1f;如果不确认…...

14. 利用Canvas自制时钟组件

1. 说明 在自定义时钟组件时&#xff0c;使用到的基本控件主要是Canvas&#xff0c;在绘制相关元素时有两种方式&#xff1a;一种时在同一个canvas中绘制所有的部件元素&#xff0c;这样需要不断的对画笔和画布的属性进行保存和恢复&#xff0c;容易混乱&#xff1b;另一种就是…...

微信小程序使用云存储和Markdown开发页面

最近想在一个小程序里加入一个使用指南的页面&#xff0c;考虑到数据存储和减少页面的开发工作量&#xff0c;决定尝试在云存储里上传Markdown文件&#xff0c;微信小程序端负责解析和渲染。小程序端使用到一个库Towxml。 Towxml Towxml是一个可将HTML、Markdown转为微信小程…...

【C++】运算符重载 | 赋值运算符重载

Ⅰ. 运算符重载 引入 ❓什么叫运算符重载&#xff1f; 就是&#xff1a;运用函数&#xff0c;将现有的运算符重新定义&#xff0c;使其能满足各种自定义类型的运算。 回想一下&#xff0c;我们以前运算的对象是不是都是int、char这种内置类型&#xff1f; 那我们自定义的“…...

Python学习 -- 类对象从创建到常用函数

在Python编程中&#xff0c;类是一种强大的工具&#xff0c;用于创建具有共同属性和行为的对象。本篇博客将详细介绍Python中类和对象的创建&#xff0c;类的属性和方法&#xff0c;以及一些常用的类函数&#xff0c;通过丰富的代码例子来帮助读者深入理解。 一、类和对象的创…...

数组分割(2023省蓝桥杯)n种讨论 JAVA

目录 1、题目描述&#xff1a;2、前言&#xff1a;3、动态规划&#xff08;bug)&#xff1a;3、递归 剪枝&#xff08;超时&#xff09;&#xff1a;4、数学&#xff08;正解&#xff09;&#xff1a; 1、题目描述&#xff1a; 小蓝有一个长度为 N 的数组 A [A0, A1,…, AN−…...

很好的启用window10专业版系统自带的远程桌面

启用window10专业版系统自带的远程桌面 文章目录 启用window10专业版系统自带的远程桌面前言1.找到远程桌面的开关2. 找到“应用”项目3. 打开需要远程操作的电脑远程桌面功能 总结 前言 Windows操作系统作为应用最广泛的个人电脑操作系统&#xff0c;在我们身边几乎随处可见。…...

TCP定制协议,序列化和反序列化

目录 前言 1.理解协议 2.网络版本计算器 2.1设计思路 2.2接口设计 2.3代码实现&#xff1a; 2.4编译测试 总结 前言 在之前的文章中&#xff0c;我们说TCP是面向字节流的&#xff0c;但是可能对于面向字节流这个概念&#xff0c;其实并不理解的&#xff0c;今天我们要介…...

YOLOX在启智AI GPU/CPU平台部署笔记

文章目录 1. 概述2. 部署2.1 拉取YOLOX源码2.2 拉取模型文件yolox_s.pth2.3 安装依赖包2.4 安装yolox2.5 测试运行2.6 运行报错处理2.6.1 ImportError: libGL.so.1: cannot open shared object file: No such file or directory2.6.2 ImportError: libgthread-2.0.so.0: cannot…...

23种设计模式攻关

&#x1f44d;一、创建者模式 &#x1f516;1.1、单例模式 单例模式&#xff08;Singleton Pattern&#xff09;&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供全局访问点。 在某些情况下&#xff0c;我们需要确保一个类只能有一个实例&#xff0c;比如数据库连接…...

【jsthreeJS】入门three,并实现3D汽车展示厅,附带全码

首先放个最终效果图&#xff1a; 三维&#xff08;3D&#xff09;概念&#xff1a; 三维&#xff08;3D&#xff09;是一个描述物体在三个空间坐标轴上的位置和形态的概念。相比于二维&#xff08;2D&#xff09;只有长度和宽度的平面&#xff0c;三维增加了高度或深度这一维度…...

unity将结构体/列表与json字符串相互转化

编写Unity程序时&#xff0c;面对大量需要传输或者保存的数据时&#xff0c;为了避免编写重复的代码&#xff0c;故采用NewtonJson插件来将定义好的结构体以及列表等转为json字符串来进行保存和传输。 具体代码如下&#xff1a; using System; using System.IO; using Newtons…...

【Vue】vue2项目使用swiper轮播图2023年8月21日实战保姆级教程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、npm 下载swiper二、使用步骤1.引入库声明变量2.编写页面3.执行js 总结 前言 swiper轮播图官网 参考文章&#xff0c;最好先看完他的介绍&#xff0c;再看…...

【算法日志】贪心算法刷题:单调递增数列,贪心算法总结(day32)

代码随想录刷题60Day 目录 前言 单调递增数列 贪心算法总结 前言 今天是贪心算法刷题的最后一天&#xff0c;今天本来是打算刷两道题&#xff0c;其中的一道hard题做了好久都没有做出来(主要思路错了)。然后再总结一下。 单调递增数列 int monotoneIncreasingDigits(int n…...

MATLAB算法实战应用案例精讲-【深度学习】模型压缩

目录 模型压缩概述 1. 为什么需要模型压缩 2. 模型压缩的基本方法 Patient-KD 1. Patient-KD 简介...

Matlab使用

Matlab使用 界面介绍 新建脚本&#xff1a;实际上就是新建一个新建后缀为.m的文件 新建编辑器&#xff1a;ctrlN 打开&#xff1a;打开最近文件&#xff0c;以找到最近写过的文件 点击路径&#xff0c;切换当前文件夹 预设&#xff1a;定制习惯用的界面 常见简单指令 ;…...

BladeX多数据源配置

启用多租户数据库隔离&#xff0c;会默认关闭mybatis-plus多数据源插件的启动&#xff0c;从而使用自定义的数据源识别 若不需要租户数据库隔离只需要字段隔离&#xff0c;而又需要用到多数据源的情况&#xff0c;需要前往LauncherService单独配置 数据源切换失败 详情请看说明…...

go里面关于超时的设计

设想一下你在接收源源不断的数据&#xff0c;如果有700ms没有收到&#xff0c;则认为是一个超时&#xff0c;需要做出处理。 逻辑上可以设计一个grouting,里面放一个通道&#xff0c;每收到一条数据进行相应处理。通道中夹杂一个timer定时器的处理&#xff0c;若通道在700ms内…...

Qt下使用ModbusTcp通信协议进行PLC线圈/保持寄存器的读写(32位有符号数)

文章目录 前言一、引入Modbus模块二、Modbus设备的连接三、各寄存器数据的读取四、各寄存器数据的写入五、示例完整代码总结 前言 本文主要讲述了使用Qt的Modbus模块来进行ModbusTcp的通信&#xff0c;实现对PLC的线圈寄存器和保持寄存器的读写&#xff0c;基于TCP/IP的Modbus…...

ElasticSearch学习2

1、索引的操作 1、创建索引 对ES的操作其实就是发送一个restful请求&#xff0c;kibana中在DevTools中进行ES操作 创建索引时需要注意ES的版本&#xff0c;不同版本的ES创建索引的语句略有差别&#xff0c;会导致失败 如下创建一个名为people的索引&#xff0c;settings&…...

3D角色展示

先看效果&#xff1a; 再看代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>3D卡片悬停</title><style>font-face {font-family: "Exoct";src: url("htt…...

前端面试:【Angular】打造强大Web应用的全栈框架

嗨&#xff0c;亲爱的Angular探险家&#xff01;在前端开发的旅程中&#xff0c;有一个全栈框架&#xff0c;那就是Angular。Angular提供了模块化、组件化、依赖注入、路由和RxJS等特性&#xff0c;助力你构建强大、可扩展的Web应用。 1. 什么是Angular&#xff1f; Angular是…...

数据结构:栈和队列

文章目录 一、栈1.栈的概念及结构1.栈的概念及结构2.栈的实现 2.栈的顺序表实现1.栈的结构体和实现的功能函数2.栈的初始化&#xff0c;入栈和出栈操作3.栈的其他操作 3.栈的链表实现1.栈的结构体和实现的功能函数2.栈功能函数的实现 二、队列1.队列的概念及结构1.队列的概念及…...

SpringCloud Gateway服务网关的介绍与使用

目录 1、网关介绍2、SpringCloudGateway工作原理3、三大组件3.1 、Route&#xff08;路由&#xff09;3.2、断言 Predicate3.3、过滤器 filter 4、Gateway整合nacos的使用4.1 、引入依赖4.2、 编写基础类和启动类4.3、 编写基础配置和路由规则4.4 、测试结果 1、网关介绍 客户…...

深入解析:如何打造高效的直播视频美颜SDK

在当今数字化时代&#xff0c;视频直播已经成为人们交流、娱乐和信息传递的重要方式。然而&#xff0c;许多人在直播时都希望能够呈现出最佳的外观&#xff0c;这就需要高效的直播视频美颜技术。本文将深入解析如何打造高效的直播视频美颜SDK&#xff0c;以实现令人满意的视觉效…...

每日一博 - MPP(Massively Parallel Processing,大规模并行处理)架构

文章目录 概述优点缺点小结 概述 MPP&#xff08;Massively Parallel Processing&#xff0c;大规模并行处理&#xff09;架构是一种常见的数据库系统架构&#xff0c;主要用于提高数据处理性能。它通过将多个单机数据库节点组成一个集群&#xff0c;实现数据的并行处理。 在 …...

ssh框架原理及流程

1.hibernate工作原理&#xff1a; 读取并解析配置文件读取并解析映射信息&#xff0c;创建sessionFactory打开session创建事务transaction持久化操作提交事务关闭session关闭sessionFactory 为什么使用&#xff1a; 对JDBC访问数据库的代码做了封装&#xff0c;大大简化了数据…...

eslint 配置和用法

在一个使用Webpack的项目中配置ESLint&#xff0c;你可以按照以下步骤操作&#xff1a; 首先&#xff0c;你需要在你的项目中安装ESLint和对应的Webpack loader。你可以使用npm或者yarn来安装。在你的项目根目录下打开终端&#xff0c;然后运行以下命令&#xff1a; 使用npm&…...

字符设备驱动实例(PWM和RTC)

目录 五、PWM 六、RTC 五、PWM PWM(Pulse Width Modulation&#xff0c;脉宽调制器)&#xff0c;顾名思义就是一个输出脉冲宽度可以调整的硬件器件&#xff0c;其实它不仅脉冲宽度可调&#xff0c;频率也可以调整。它的核心部件是一个硬件定时器&#xff0c;其工作原理可以用…...

Ribbon 源码分析

Ribbon 源码分析 Ribbon Debug 分析 断点 LoadBalancerInterceptor LoadBalancerInterceptor 实现了 ClientHttpRequestInterceptor 接口&#xff0c;重写了其中的 intercept 方法&#xff0c;用来拦截请求&#xff1b; 获取原始的 uri 和 服务名&#xff0c;调用 LoadBalanc…...

【1-3章】Spark编程基础(Python版)

课程资源&#xff1a;&#xff08;林子雨&#xff09;Spark编程基础(Python版)_哔哩哔哩_bilibili 第1章 大数据技术概述&#xff08;8节&#xff09; 第三次信息化浪潮&#xff1a;以物联网、云计算、大数据为标志 &#xff08;一&#xff09;大数据 大数据时代到来的原因…...

宇宙原理:黑洞基础。

宇宙原理&#xff1a;黑洞基础TOC 黑洞的数理基础&#xff1a;一个由满数组成的数盘&#xff0c;经过自然演进&#xff0c;将会逐步稀疏化、最终会向纯数方案发展&#xff1b;纯数方案虽然只有{2}、无数&#xff08;虚拟&#xff09;、{0,1,2,3}&#xff08;虚拟&#xff09;、…...

分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测

分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测 目录 分类预测 | MATLAB实现SCNGO-CNN-LSTM-Attention数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.SCNGO-CNN-LSTM-Attention数据分类预测程序&#xff0c;改进算法&#xff0c;融合正余弦和…...

Android学习之路(7) Frament

Fragment 表示应用界面中可重复使用的一部分。fragment 定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。fragment 不能独立存在。它们必须由 activity 或其他 fragment 托管。fragment 的视图层次结构会成为宿主的视图层次结构的…...

metallb , istio ingress 部署httpbin使用例子

安装metaillb,参考&#xff1a;Kubernetes的负载均衡方案&#xff1a;MetalLB - 文章详情 wget https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-frr.yaml -O metallb.yaml kubectl apply -f metallb-frr.yaml 配置负载均衡ip池 apiVe…...

基于swing的销售管理系统java仓库库存信息jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于swing的销售管理系统 系统有1权限&#xff1a;管…...

FreeCAD傻瓜式教程之约束设定和构建实体、开孔、调整颜色等

本内容基于官方教程中的绘制简单的零件中的体会&#xff0c;在初次绘制的时候&#xff0c;总是无法完成&#xff0c;几经尝试才发现其关键点所在&#xff0c;以此文记录&#xff0c;用以被查资料&#xff0c;同时也希望能够帮到纯白新手快速熟悉该软件的绘图方法。 一、. 打开…...

代码随想录算法训练营day41 | 343. 整数拆分,96. 不同的二叉搜索树

目录 343. 整数拆分 96. 不同的二叉搜索树 343. 整数拆分 类型&#xff1a;动态规划 难度&#xff1a;medium 思路&#xff1a; dp[i]所用的拆分方法至少已经拆分了两次&#xff0c;比如dp[2]1&#xff0c;小于2&#xff0c;在大于2的数中&#xff0c;最后的2是不会拆的。 …...

飞天使-k8sv1.14二进制安装

文章目录 安装前准备安装前设置分发脚本 开始安装k8s集群cfssl 安装部署kubectl命令行工具创建admin证书和私钥创建kubeconfig文件部署ETCD集群部署Flannel网络kube-apiserver 高可用KeepLived 部署部署master节点部署高可用kube-controller-manager集群kube-controller-manage…...

TypeScript封装Axios

TypeScript封装Axios Axios的基本使用 因axios基础使用十分简单&#xff0c;可参考axios官方文档&#xff0c;这里不在介绍他基本用法&#xff0c;主要讲解拦截器。 拦截器主要分为两种&#xff0c;请求拦截器和响应拦截器。 请求拦截器&#xff1a;请求发送之前进行拦截&…...

指针(一)【C语言进阶版】

大家好&#xff0c;我是深鱼~ 【前言】&#xff1a; 指针的主题&#xff0c;在初阶指针章节已经接触过了&#xff0c;我们知道了指针的概念&#xff1a; 1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址的唯一标识一块内存空间&#xff08;指针变量&#xff09;&a…...