基于riscv64架构的Dayu800开发板的napi_demo开发介绍

itopen组织
1、提供OpenHarmony优雅实用的小工具
2、手把手适配riscv + qemu + linux的三方库移植
3、未来计划riscv + qemu + ohos的三方库移植 + 小程序开发
4、一切拥抱开源,拥抱国产化

一、环境准备工作

1.1 Ubuntu20.04环境配置

如果已经配置OpenHarmony的编译环境则不需要要配置

# root环境配置
git clone https://gitee.com/itopen/openharmony_env_init
cd openharmony_env_init
bash root_init.sh# 个人用户环境配置
git config --global user.name "yourname"
git config --global user.email "your-email-address"
git config --global core.editor vim
git config --global credential.helper store
git config --global http.sslverify false

1.2 下载、安装DevEco Studio

dayu800使用的是Openharmony-3.2-Release分支,所对应的API版本为9,DevEco Studio目前最新版的5.x支持的API版本为10、11、12,并不支持9,所以需要下载3.1.1Release版本

DevEco Studio 下载链接

下载完毕后安装,可以直接勾选修改“PATH”后重启,这样不用手动添加环境变量

1.3 初始化DevEco Studio环境

以管理员权限启动DevEco,然后create project,选择空项目即可,按照提示完成环境配置,之后根据UI提示等待环境配置完成。

有可能还需要配置SDK,在工具栏file>setting>SDK中配置。

二、下载、编译、烧录duyu800代码

2.1 下载duyu800代码

代码下载使用自动化下载工具下载,关于自动化下载工具使用参见itopen: 一键下载openharmony代码

# 下载dayu800代码,关于
git clone https://gitee.com/itopen/ohos_download.git
cd ohos_download
./ohos_download
# 选择1.1

2.2 编译dayu800代码

# 首次编译需要下载预处理文件
cd ~/Openharmony/dayu800-ohos
./build/prebuilts_download.sh# 全量编译代码,添加--gn-args full_mini_debug=false这次参数会编译比较快,否则中间会有一段停留30分钟的时间
./build.sh --product-name dayu800 --gn-args full_mini_debug=false --ccache

2.3 镜像烧录

关于dayu800的烧录参考itopen: dayu800开发板使用说明

三、NAPI Demo介绍

3.1 napi demo代码处理

itopen: napi_demo代码下载放置到dayu800-ohos代码的device/soc/thead/th1520/hardware目录下,然后在BUILD.gn中添加napi_demo模块

cd device/soc/thead/th1520/hardware
git clone https://gitee.com/itopen/napi_demo.git
vim BUILD.gn
# 添加napi_demo:napi_demo
group("hardware_group") {deps = ["bootanimation:bootanimation","isp8000:isp8000","camera:camera","hap:th1520_hap","napi_demo:napi_demo", # 第一个napi_demo表示napi_demo目录,第二个napi_demo表示napi_demo目录下BUILD.gn中的napi_demo模块]
}

3.2 查看接口功能

关于NAPI有哪些接口请查看OpenHarmony NAPI接口介绍和使用

NAPI提供了提供了一系列接口函数,需要声明包含如下2个头文件中

#include "napi/native_api.h"
#include "napi/native_node_api.h"

该头文件在//foundation/arkui/napi/interfaces/kits/napi和//foundation/arkui/napi/interfaces/inner_api/napi之中

3.3 代码简单介绍

代码结构如下

.
├── BUILD.gn
├── CMakeLists.txt
├── include
│   ├── i_serialport_client.h
│   ├── log
│   │   └── serialport_log_wrapper.h
│   ├── serial_callback_base.h
│   └── serialport_types.h
├── serial_async_callback.cpp
├── serial_async_callback.h
├── serial_helper.cpp
├── serial_opt.cpp
├── serial_opt.h
├── types
│   └── libserialhelper
│       ├── package.json
│       └── serialhelper.d.ts
├── x_napi_tool.cpp
└── x_napi_tool.h

下面以一段打开串口的代码为例进行说明。

void OpenSerial_execute(XNapiTool *pxt, void *data)
{OpenSerial_value_struct *vio = (OpenSerial_value_struct *)data;vio->out = OpenSerial(vio->in0.c_str());return;
}void OpenSerial_complete(XNapiTool *pxt, void *data)
{int32_t ret = -1;OpenSerial_value_struct *vio = (OpenSerial_value_struct *)data;napi_value result = nullptr;result = NUMBER_C_2_JS(pxt, Int32, vio->out);{napi_value args[XNapiTool::ARGV_CNT] = {result, nullptr};if(vio->out > 0)ret = 0;pxt->FinishAsync(ret, args);}delete vio;
}
napi_value OpenSerial_middle(napi_env env, napi_callback_info info)
{XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release();if (pxt->IsFailed()) {napi_value err = pxt->GetError();delete pxt;return err;}struct OpenSerial_value_struct *vio = new OpenSerial_value_struct();pxt->SwapJs2CUtf8(pxt->GetArgv(0), vio->in0);napi_value result = pxt->StartAsync(OpenSerial_execute, vio, OpenSerial_complete,pxt->GetArgc() == 2 ? pxt->GetArgv(1) : nullptr);if (pxt->IsFailed()) {result = pxt->GetError();}return result;
}
  • 这段C++函数用于在node.js环境中通过NAPI异步打开串口
  • 主要流程如下
    • JavaScript调用:从JavaScript代码中调用 openSerial函数。
    • 中间层函数:OpenSerial_middle函数被调用,准备参数并启动异步操作。
    • 后台线程执行:OpenSerial_execute函数在后台线程中执行,执行实际的串口打开操作。
    • 主线程回调:一旦后台操作完成,OpenSerial_complete函数在主线程中被调用,处理结果并回调到JavaScript。

3.4 创建类型声明文件

类型声明文件的命名方式为动态库名称.d.ts,参照以下编写

/** Copyright (C) 2021-2022 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import {AsyncCallback, Callback} from "basic";/*** Provides methods related to serialport services.** @since 7* @syscap SystemCapability.Miscservices.SerialportService*/
declare namespace serialHelper {
/*** Set serial port options.* @param dev Indicates the serial port dev.* @param speeds baud rate.* @param bits 7/8.* @param events 'O'/'E'/'N'* @param stops 1/2*/function setOptions(dev:string, speeds:number, bits:number, events:number, stops: number, callback: AsyncCallback<void>): void;function setOptions(dev:string, speeds:number, bits:number, events:number, stops: number): Promise<void>;/*** Open serial port.* @param dev Indicates the serial port dev.*/function openSerial(dev:string, callback: AsyncCallback<void>): void;function openSerial(dev:string): Promise<void>;/*** Close serial port.* @param dev Indicates the serial port dev.*/function closeSerial(dev:string, callback: AsyncCallback<void>): void;function closeSerial(dev:string): Promise<void>;/*** tcflush serial port.* @param dev Indicates the serial port dev.* @param selector 0 in 1 out 2 in&out.*/function clearBuffer(dev:string, selector:number, callback: AsyncCallback<void>): void;function clearBuffer(dev:string, selector:number): Promise<void>;/*** Send data to serial port.* @param dev Indicates the serial port dev.* @param data.*/function sendData(dev:string, data:Uint8Array, callback: AsyncCallback<void>): void;function sendData(dev:string, data:Uint8Array): Promise<void>;/*** read data from serial port.* @param dev Indicates the serial port dev.* @param timeout*/function recvData(dev:string, timeout:number, callback: AsyncCallback<Uint8Array>): void;function recvData(dev:string, timeout:number): Promise<Uint8Array>;/*** transmit Send and Read data* @param dev Indicates the serial port dev.* @param cmd Indicates the command.* @param timeout* @param callback Returns the Uint8Array*/function transmit(dev:string, cmd: Uint8Array, timeout: number, callback: AsyncCallback<Uint8Array>): void;function transmit(dev:string, cmd: Uint8Array, timeout: number): Promise<Uint8Array>;/*** on/off serial data* @param type Indicates the serial port dev.* @param callback serial data*/function on(type: '/dev/ttyXRUSB0', callback: Callback<Uint8Array>): void;function on(type: '/dev/ttyXRUSB1', callback: Callback<Uint8Array>): void;function on(type: '/dev/ttyXRUSB2', callback: Callback<Uint8Array>): void;function on(type: '/dev/ttyXRUSB3', callback: Callback<Uint8Array>): void;function off(type: '/dev/ttyXRUSB0'): void;function off(type: '/dev/ttyXRUSB1'): void;function off(type: '/dev/ttyXRUSB2'): void;function off(type: '/dev/ttyXRUSB3'): void;/*** Set GPIO Direction.** @param portNo Gpio number.* @param dirIn Is it an input port.* @permission None*/function setGPIODirection(portNo:number, dirIn:boolean, callback: AsyncCallback<void>): void;function setGPIODirection(portNo:number, dirIn:boolean): Promise<void>;/*** Set GPIO Value.** @param portNo Gpio number.* @param value Gpio value, 0 or 1.* @permission None*/function setGPIOValue(portNo:number, value:number, callback: AsyncCallback<void>): void;function setGPIOValue(portNo:number, value:number): Promise<void>;/*** Get GPIO Value.** @param portNo Gpio number.* @param callback Returns gpio value of portNo, 0 or 1.* @permission None*/function getGPIOValue(portNo:number, callback: AsyncCallback<number>): void;function getGPIOValue(portNo:number): Promise<number>;
}export default serialHelper;

3.5 BUILD.gn文件介绍

import("//build/ohos.gni")#ohos_shared_library()中的serialhelper决定了生成动态库的名称,增量编译阶段生成动态库libserialhelper.z.soohos_shared_library("serialhelper") {#编译需要的源文件sources = ["serial_opt.cpp",  "serial_helper.cpp","x_napi_tool.cpp",]include_dirs = [#根据增量编译阶段报错添加的头文件目录"//third_party/node/src","./include","//base/hiviewdfx/hilog/interfaces/native/kits/include",]remove_configs = [ "//build/config/compiler:no_rtti","//build/config/compiler:no_exceptions",]
#根据增量编译时clang编译器报警,添加的cflagcflags = [ "-mno-relax","-fpermissive","-Wno-writable-strings","-Wno-error=pointer-to-int-cast","-Wno-error=void-pointer-to-int-cast","-Wno-error=conversion","-Wno-error=implicit-function-declaration","-Wno-error",]ldflags = ["-lpthread","-ldl","-lrt",]#指定编译依赖hilog_ndkdeps = ["//base/hiviewdfx/hilog/frameworks/hilog_ndk:hilog_ndk",]#指定编译依赖libhilog.z.so动态库external_deps = [ "hilog_native:libhilog","napi:ace_napi",]defines = [ "MY_TEST_DEFINE" ]#组件名称是prebuilt_happart_name = "prebuilt_hap"#子系统名称是applicationssubsystem_name = "applications"
}ohos_executable("serialdebug") {sources = ["serial_opt.cpp",]include_dirs = ["//third_party/node/src","./include","//base/hiviewdfx/hilog/interfaces/native/kits/include",]remove_configs = [ "//build/config/compiler:no_rtti","//build/config/compiler:no_exceptions",] cflags = [ "-mno-relax","-fpermissive","-Wno-writable-strings","-Wno-error=pointer-to-int-cast","-Wno-error=void-pointer-to-int-cast","-Wno-error=conversion","-Wno-error=implicit-function-declaration","-Wno-error",]ldflags = ["-lpthread","-ldl","-lrt",]deps = ["//base/hiviewdfx/hilog/frameworks/hilog_ndk:hilog_ndk",]external_deps = [ "hilog_native:libhilog","napi:ace_napi",]defines = [ "MY_TEST_DEFINE" ]part_name = "prebuilt_hap"subsystem_name = "applications"
}group("napi_demo") {deps = [":serialhelper",":serialdebug",]
}

3.6 napi_demo编译

  • 为了节省时间,可以先通过指定target的指令先查看是否编写错误 ./build.sh --product-name dayu800 --ccache --build-target=serialhelperlib或者直接./build.sh --product-name dayu800 --ccache进行全量编译
  • 全量编译完成后,使用find -name 指令查找类似libserialhelper.z.so的文件,若找到则编译完成,将其发送到烧录了Openharmony3.2.2镜像的设备的/system/lib64/module目录中
./build.sh --product-name dayu800 --ccache --build-target=napi_demo# 编译的libserialhelper.z.so和serialdebug位于./out/dayu800/thead_products/thead_products/目录中

四、测试NAPI接口功能

4.1 编写测试ets

打开DevEco Studio并创建一个空项目

在entry/src/main/ets/pages/Index.ets中编写typescript程序。

// 示例代码
// @ts-ignore
import testNapi from '@ohos.serialhelper'@Entry
@Component
struct Index {@State message: string = 'Hello World'fd: number = -1devPath: string = '/dev/ttyS3'async openChuankouFn() {this.fd = await testNapi.openSerial(this.devPath);console.log('daihai openChuankouFn this.fd: ' + this.fd)}async serialSet() {let ret = await testNapi.setOptions(this.fd, 115200, 8, 0, 1);console.log('daihai serialSet ret: ' + ret)}async SerialSend() {const databuff = [0x61, 0xaa, 0x0a, 0x15, 0x00]; // send ABCDEconsole.log('daihai SerialSend databuff len: ' + databuff.length)let uint8Arr = new Uint8Array(databuff);let ret = await testNapi.sendData(this.fd, uint8Arr);console.log('daihai SerialSend ret: ' + ret)// if (msg[9] == this.dwMap[this.index]) {//   this.warnFlag[this.index] = '2'// }}async SerialRecv(timeout?: number) {let revTestInfo = await testNapi.recvData(this.fd, timeout, 16);console.log('daihai revTestInfo: ',JSON.stringify(revTestInfo))//let revTestInfo = testNapi.SerialRecv(this.fd, timeout, 6);// const message = revTestInfo?.recevedBuf?.toString()// console.log('daihai revTestInfo.revTestInfo.recevedLen: ',revTestInfo.recevedLen)// console.log('daihai revTestInfo.recevedBuf.toString(): ',revTestInfo.recevedBuf)// console.log('daihai revTestInfo.recevedBuf.toString(): ',revTestInfo.recevedBuf.toString())}openChuankouFnCb() {testNapi.openSerial(this.devPath, (err, ret) => {console.log('daihai openChuankouFn this.fd: ' + this.fd)})}serialSetCb() {testNapi.setOptions(this.fd, 115200, 8, 0, 1, (err, ret) => {console.log('daihai serialSet ret: ' + ret)})}SerialSendCb() {const databuff = [0x61, 0xaa, 0x0a, 0x15, 0x00]; // send ABCDEconsole.log('daihai SerialSend databuff len: ' + databuff.length)let uint8Arr = new Uint8Array(databuff);testNapi.sendData(this.fd, uint8Arr, (err, ret) => {console.log('daihai SerialSend ret: ' + ret)})// if (msg[9] == this.dwMap[this.index]) {//   this.warnFlag[this.index] = '2'// }}SerialRecvCb(timeout?: number) {testNapi.recvData(this.fd, timeout, 16, (err, revTestInfo) => {console.log('daihai revTestInfo: ',JSON.stringify(revTestInfo))})}build() {Row() {Column() {Button('open').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.openChuankouFn()})Button('open cb').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.openChuankouFnCb()}).margin({ top: 20 })Button('serialSet').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.serialSet()}).margin({ top: 20 })Button('serialSet cb').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.serialSetCb()}).margin({ top: 20 })Button('SerialSend').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.SerialSend()}).margin({ top: 20 })Button('SerialSend cb').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.SerialSendCb()}).margin({ top: 20 })Button('SerialRecv').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.SerialRecv(3000)}).margin({ top: 20 })Button('SerialRecv cb').fontSize(20).fontWeight(FontWeight.Bold).onClick(() => {this.SerialRecvCb(3000)}).margin({ top: 20 })}.width('100%')}.height('100%')}
}
  • 因为在编写接口时已经将d.ts文件加入so库中,所以需要加入// @ts-ignore防止编译失败

  • 编写完成后点击右上角头像进行登陆,然后选择file>Project Structure>Signing configs>Automatically generate signature进行自动签名

  • 连接开发板,点击右上角的debug按钮

  • 点击下方log按钮,在搜索栏内设置过滤白名单,点击设备上显示的open按钮,查看返回信息

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

目标检测 YOLOv5-7.0 详细调试自制数据集实战

目标检测 YOLOv5-7.0 详细调试&自制数据集实战 一、项目介绍及环境配置&#xff08;一&#xff09;项目解读&#xff08;二&#xff09;版本选择&#xff08;三&#xff09;环境配置 二、如何利用YOLOv5进行预测&#xff08;detect.py&#xff09;&#xff08;一&#xff0…

Windows 实用小工具:窗口钉子/文件管理 2024/7/27

一: wintop 窗口置顶工具 二:WinDirStat 这是一个免费的、开源的磁盘使用分析工具&#xff0c;适用于Windows系统。它会扫描你的硬盘&#xff0c;列出所有文件和文件夹的大小&#xff0c;并以图形化的方式展示&#xff0c;便于理解。 可以用来检测硬盘文件夹占用从而,酌情处…

【C#】获取DICOM图像像素的像素值

8位像素深度的像素值 public byte GetGreyValue(int x, int y) {x Math.Min(x, m_nWidth - 1);y Math.Min(y, m_nHeight - 1);unsafe{byte* greyValue (byte*)m_pDicomData.ToPointer() y * m_nWidth x;return *greyValue;} } 16位像素深度的像素值 public ushort GetG…

JAVA.抽象、接口、内部类

1.抽象 共性&#xff0c;父类定义抽象方法&#xff0c;子类必须重写&#xff0c;或者子类也是抽象类 示例代码 animal package animalabstract;//定义抽象类animal public abstract class animal {String name;int age;//定义抽象方法eat&#xff0c;子类必须重写public abs…

Java给定一些元素随机从中选择一个

文章目录 代码实现java.util.Random类实现随机取数(推荐)java.util.Collections实现(推荐)Java 8 Stream流实现(不推荐) 完整代码参考&#xff08;含测试数据&#xff09; 在Java中&#xff0c;要从给定的数据集合中随机选择一个元素&#xff0c;我们很容易想到可以使用 java.…

Redis快速入门(一)

一、初识Redis 1、认识NoSQL NoSql可以翻译做Not Only Sql(不仅仅是SQL),或者是No Sql(非Sql的)数据库。是相对于传统关系型数据库而言,有很大差异的一种特殊的数据库,因此也称之为非关系型数据库。   a)结构化与非结构化   传统关系型数据库是结构化数据,每一张…

【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件

目录 ​编辑 前言 系统调用 open 参数flags 参数mode write 追加方式 read close 文件描述符 打开多个文件并观察其文件描述符 C语言文件操作 理解一切皆文件 理解open操作 前言 各类语言的文件操作其实是对系统调用的封装 我们经常说&#xff0c;创建一个文件&a…

力扣第三十七题——解数独

内容介绍 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09; 数独…

每天一个数据分析题(四百四十四)- 数据仓库

企业数据仓库里面的数据一般是由业务数据经过ETL技术处理后来的&#xff0c;以下关于ETL的说法错误的是 A. ETL过程中的主要环节是数据抽取、数据转换和加工、数据流转 B. 增量数据抽取过程中&#xff0c;提取增量数据的方法有通过时间戳、建立触发器、全表比对、日志比对等 …

springboot整合pgsql

demo代码说明 springboot使用mybatis-plus整合pgsql 在springboot项目中使用pgsql&#xff0c;使用了mybatis-plus、druid 代码见 spring-demo: springboot 结合各种插件 demo 注意事项&#xff1a; 版本兼容 正常springboot使用&#xff0c;但是注意需要添加pgsql正确版…

CVE-2024-39700 (CVSS 9.9):JupyterLab 模板中存在严重漏洞

在广泛使用的 JupyterLab 扩展模板中发现了一个严重漏洞&#xff0c;编号为CVE-2024-39700 。此漏洞可能使攻击者能够在受影响的系统上远程执行代码&#xff0c;从而可能导致大范围入侵和数据泄露。 该漏洞源于在扩展创建过程中选择“测试”选项时自动生成“update-integratio…

VIM基础配置

1. CTAGS配置 下载 上传虚拟机&#xff0c;解压&#xff0c;进入目录 tar -xzvf ctags-5.8.tar.gz cd ctags-5.8/编译 ./configure sudo make sudo make install查看是否安装成功 ctags --version打印如下 2. 使用Vundle 下载 git clone https://github.com/VundleVim/Vund…

Linux并发程序设计(3):守护进程

目录 前言 一、介绍 1.1 概念 1.2 特点 1.3 举例 二、系统编程 2.1 setsid函数 2.2 getpid函数 2.3 getsid函数 2.4 getpgid函数 2.5 chdir函数 三、代码例程 3.1 使子进程在后台运行 3.2 使子进程脱离原终端 3.3 更换目录&#xff0c;并设定权限&#xff08;非…

React--Redux

Redux 是一个用于 JavaScript 应用的状态管理库&#xff0c;特别是在 React 应用中非常流行。下面我将详细介绍一个使用 Redux 的简单案例&#xff0c;包括设置 Redux 环境、创建 store、定义 actions 和 reducers&#xff0c;以及如何连接 React 组件。 步骤 1: 安装依赖 首…

基于STM32通过云平台实现智慧大棚【手机远程查看温湿度】【报警】

文章目录 一、成果演示二、所用到的模块三、实现的功能四、接线说明五、WIFI模块配置步骤5.1云平台介绍5.2云平台使用5.3使用USB转TTL测试联通云平台 六、STM32代码编写七、手机上查看数据6.1下载软件&#xff08;仅限安卓手机&#xff09;6.2操作 一、成果演示 STM32通过物联网…

String、StringBuffer和StringBuilder

一、String类 1. String类的理解 2. String类结构 1. String类实现了Serializable接口,说明String对象可以串行化,即可以在网络上传输 2. String类实现了Comparable接口,说明String对象可以比较 String底层是一个字符数组,这个数组里存的是字符串的内容 例如:…

005 仿muduo实现高性能服务器组件_通信连接管理

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;仿muduo &#x1f4d2;代码仓库&#xff1a; 项目代码 &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言Channel模块设计原因整体设计代码如下 Connection模块设计原…

Florence2:Advancing a unified representation for a variety of vision tasks

Florence-2模型:开启统一视觉基础模型的新篇章_florence -2-CSDN博客文章浏览阅读1.1k次,点赞108次,收藏109次。Florence-2是由微软Azure AI团队开发的一款多功能、统一的视觉模型。它通过统一的提示处理不同的视觉任务,表现出色且优于许多大型模型。Florence-2的设计理念是…

用Postman Flows打造你的专属API:外部公开,轻松上手!

引言 Postman Flows 是一个使用 GUI 进行无代码 API 调用流程创建的服务。这篇文章我尝试使用 Flows 来构建将 Momento Topic 中的数据保存到 TiDB 的保存 API&#xff0c;因此想分享一些使用过程中的技巧等。 实现内容 将从 Momento Topics 配发的 JSON 数据保存到 TiDB 中。…

3086. 拾起 K 个 1 需要的最少行动次数

3086. 拾起 K 个 1 需要的最少行动次数 题目链接&#xff1a;3086. 拾起 K 个 1 需要的最少行动次数 代码如下&#xff1a; //参考链接:https://leetcode.cn/problems/minimum-moves-to-pick-k-ones/solutions/2692009/zhong-wei-shu-tan-xin-by-endlesscheng-h972 class Sol…