当前位置: 首页 > 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;三维增加了高度或深度这一维度…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…...