鸿蒙开发(API 12 Beta6版)【通用属性协议】 网络篇

简介

通用属性协议是GATT(Generic Attribute)的缩写,它是一种用于在蓝牙低功耗设备之间传输数据的协议,定义了一套通用的属性和服务框架。通过GATT协议,蓝牙设备可以向其他设备提供服务,也可以从其他设备获取服务。

场景介绍

主要场景有:

  • 连接server端读取和写入信息。
  • server端操作services和通知客户端信息。

接口说明

具体接口说明如下表。

接口名功能描述
connect()client端发起连接远端蓝牙低功耗设备。
disconnect()client端断开与远端蓝牙低功耗设备的连接。
close()关闭客户端功能,注销client在协议栈的注册,调用该接口后GattClientDevice实例将不能再使用。
getDeviceName()client获取远端蓝牙低功耗设备名。
getServices()client端获取蓝牙低功耗设备的所有服务,即服务发现 。
readCharacteristicValue()client端读取蓝牙低功耗设备特定服务的特征值。
readDescriptorValue()client端读取蓝牙低功耗设备特定的特征包含的描述符。
writeCharacteristicValue()client端向低功耗蓝牙设备写入特定的特征值。
writeDescriptorValue()client端向低功耗蓝牙设备特定的描述符写入二进制数据。
getRssiValue()client获取远端蓝牙低功耗设备的信号强度 (Received Signal Strength Indication, RSSI),调用connect接口连接成功后才能使用。
setBLEMtuSize()client协商远端蓝牙低功耗设备的最大传输单元(Maximum Transmission Unit, MTU),调用connect接口连接成功后才能使用。
setCharacteristicChangeNotification()向服务端发送设置通知此特征值请求。
setCharacteristicChangeIndication()向服务端发送设置通知此特征值请求。
on(type: ‘BLECharacteristicChange’)订阅蓝牙低功耗设备的特征值变化事件。需要先调用setNotifyCharacteristicChanged接口才能接收server端的通知。
off(type: ‘BLECharacteristicChange’)取消订阅蓝牙低功耗设备的特征值变化事件。
on(type: ‘BLEConnectionStateChange’)client端订阅蓝牙低功耗设备的连接状态变化事件。
off(type: ‘BLEConnectionStateChange’)取消订阅蓝牙低功耗设备的连接状态变化事件。
on(type: ‘BLEMtuChange’)client端订阅MTU状态变化事件。
off(type: ‘BLEMtuChange’)client端取消订阅MTU状态变化事件。
addService()server端添加服务。
removeService()删除已添加的服务。
close()关闭服务端功能,去注销server在协议栈的注册,调用该接口后GattServer实例将不能再使用。
notifyCharacteristicChanged()server端特征值发生变化时,主动通知已连接的client设备。
sendResponse()server端回复client端的读写请求。
on(type: ‘characteristicRead’)server端订阅特征值读请求事件。
off(type: ‘characteristicRead’)server端取消订阅特征值读请求事件。
on(type: ‘characteristicWrite’)server端订阅特征值写请求事件。
off(type: ‘characteristicWrite’)server端取消订阅特征值写请求事件。
on(type: ‘descriptorRead’)server端订阅描述符读请求事件。
off(type: ‘descriptorRead’)server端取消订阅描述符读请求事件。
on(type: ‘descriptorWrite’)server端订阅描述符写请求事件。
off(type: ‘descriptorWrite’)server端取消订阅描述符写请求事件。
on(type: ‘connectionStateChange’)server端订阅BLE连接状态变化事件。
off(type: ‘connectionStateChange’)server端取消订阅BLE连接状态变化事件。
on(type: ‘BLEMtuChange’)server端订阅MTU状态变化事件。
off(type: ‘BLEMtuChange’)server端取消订阅MTU状态变化事件。

主要场景开发步骤

连接server端读取和写入信息

  1. import需要的ble模块。

  2. 创建gattClient实例对象。

  3. 连接gattServer。

  4. 读取gattServer的特征值和描述符。

  5. 向gattServer写入特征值和描述符。

  6. 断开连接,销毁gattClient实例。

  7. 示例代码:

import { ble } from '@kit.ConnectivityKit';
import { constant } from '@kit.ConnectivityKit';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';const TAG: string = 'GattClientManager';export class GattClientManager {device: string = undefined;gattClient: ble.GattClientDevice = undefined;connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902一般用于notification或者indicationmySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';found: boolean = false;// 构造BLEDescriptorprivate initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {let descriptor: ble.BLEDescriptor = {serviceUuid: this.myServiceUuid,characteristicUuid: this.myCharacteristicUuid,descriptorUuid: des,descriptorValue: value};return descriptor;}// 构造BLECharacteristicprivate initCharacteristic(): ble.BLECharacteristic {let descriptors: Array<ble.BLEDescriptor> = [];let descBuffer = new ArrayBuffer(2);let descValue = new Uint8Array(descBuffer);descValue[0] = 11;descValue[1] = 12;descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);let charBuffer = new ArrayBuffer(2);let charValue = new Uint8Array(charBuffer);charValue[0] = 1;charValue[1] = 2;let characteristic: ble.BLECharacteristic = {serviceUuid: this.myServiceUuid,characteristicUuid: this.myCharacteristicUuid,characteristicValue: charBuffer,descriptors: descriptors};return characteristic;}private logCharacteristic(char: ble.BLECharacteristic) {let message = 'logCharacteristic uuid:' + char.characteristicUuid + '\n';let value = new Uint8Array(char.characteristicValue);message += 'logCharacteristic value: ';for (let i = 0; i < char.characteristicValue.byteLength; i++) {message += value[i] + ' ';}console.info(TAG, message);}private logDescriptor(des: ble.BLEDescriptor) {let message = 'logDescriptor uuid:' + des.descriptorUuid + '\n';let value = new Uint8Array(des.descriptorValue);message += 'logDescriptor value: ';for (let i = 0; i < des.descriptorValue.byteLength; i++) {message += value[i] + ' ';}console.info(TAG, message);}private checkService(services: Array<ble.GattService>): boolean {for (let i = 0; i < services.length; i++) {if (services[i].serviceUuid != this.myServiceUuid) {continue;}for (let j = 0; j < services[i].characteristics.length; j++) {if (services[i].characteristics[j].characteristicUuid != this.myCharacteristicUuid) {continue;}for (let k = 0; k < services[i].characteristics[j].descriptors.length; k++) {if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.myFirstDescriptorUuid) {console.info(TAG, 'find expected service from server');return true;}}}}console.error(TAG, 'no expected service from server');return false;}// 1. 订阅连接状态变化事件public onGattClientStateChange() {if (!this.gattClient) {console.error(TAG, 'no gattClient');return;}try {this.gattClient.on('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {let state = '';switch (stateInfo.state) {case 0:state = 'DISCONNECTED';break;case 1:state = 'CONNECTING';break;case 2:state = 'CONNECTED';break;case 3:state = 'DISCONNECTING';break;default:state = 'undefined';break;}console.info(TAG, 'onGattClientStateChange: device=' + stateInfo.deviceId + ', state=' + state);if (stateInfo.deviceId == this.device) {this.connectState = stateInfo.state;}});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 2. client端主动连接时调用public startConnect(peerDevice: string) { // 对端设备一般通过ble scan获取到if (this.connectState != constant.ProfileConnectionState.STATE_DISCONNECTED) {console.error(TAG, 'startConnect failed');return;}console.info(TAG, 'startConnect ' + peerDevice);this.device = peerDevice;// 2.1 使用device构造gattClient,后续的交互都需要使用该实例this.gattClient = ble.createGattClientDevice(peerDevice);try {this.onGattClientStateChange(); // 2.2 订阅连接状态this.gattClient.connect(); // 2.3 发起连接} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 3. client端连接成功后,需要进行服务发现public discoverServices() {if (!this.gattClient) {console.info(TAG, 'no gattClient');return;}console.info(TAG, 'discoverServices');try {this.gattClient.getServices().then((result: Array<ble.GattService>) => {console.info(TAG, 'getServices success: ' + JSON.stringify(result));this.found = this.checkService(result); // 要确保server端的服务内容有业务所需要的服务});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 4. 在确保拿到了server端的服务结果后,读取server端特定服务的特征值时调用public readCharacteristicValue() {if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {console.error(TAG, 'no gattClient or not connected');return;}if (!this.found) { // 要确保server端有对应的characteristicconsole.error(TAG, 'no characteristic from server');return;}let characteristic = this.initCharacteristic();console.info(TAG, 'readCharacteristicValue');try {this.gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => {this.logCharacteristic(outData);})} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 5. 在确保拿到了server端的服务结果后,写入server端特定服务的特征值时调用public writeCharacteristicValue() {if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {console.error(TAG, 'no gattClient or not connected');return;}if (!this.found) { // 要确保server端有对应的characteristicconsole.error(TAG, 'no characteristic from server');return;}let characteristic = this.initCharacteristic();console.info(TAG, 'writeCharacteristicValue');try {this.gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => {if (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);return;}console.info(TAG, 'writeCharacteristicValue success');});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 6. 在确保拿到了server端的服务结果后,读取server端特定服务的描述符时调用public readDescriptorValue() {if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {console.error(TAG, 'no gattClient or not connected');return;}if (!this.found) { // 要确保server端有对应的descriptorconsole.error(TAG, 'no descriptor from server');return;}let descBuffer = new ArrayBuffer(0);let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);console.info(TAG, 'readDescriptorValue');try {this.gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => {this.logDescriptor(outData);});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 7. 在确保拿到了server端的服务结果后,写入server端特定服务的描述符时调用public writeDescriptorValue() {if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {console.error(TAG, 'no gattClient or not connected');return;}if (!this.found) { // 要确保server端有对应的descriptorconsole.error(TAG, 'no descriptor from server');return;}let descBuffer = new ArrayBuffer(2);let descValue = new Uint8Array(descBuffer);descValue[0] = 11;descValue[1] = 12;let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);console.info(TAG, 'writeDescriptorValue');try {this.gattClient.writeDescriptorValue(descriptor, (err) => {if (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);return;}console.info(TAG, 'writeDescriptorValue success');});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 8.client端主动断开时调用public stopConnect() {if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {console.error(TAG, 'no gattClient or not connected');return;}console.info(TAG, 'stopConnect ' + this.device);try {this.gattClient.disconnect(); // 8.1 断开连接this.gattClient.off('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {});this.gattClient.close() // 8.2 如果不再使用此gattClient,则需要close} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}
}let gattClientManager = new GattClientManager();
export default gattClientManager as GattClientManager;

server端操作services和通知客户端信息

  1. import需要的ble模块。

  2. 创建gattServer实例对象。

  3. 添加services信息。

  4. 当向gattServer写入特征值通知gattClient。

  5. 移除services信息。

  6. 注销gattServer实例。

  7. 示例代码:

import { ble } from '@kit.ConnectivityKit';
import { constant } from '@kit.ConnectivityKit';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';const TAG: string = 'GattServerManager';export class GattServerManager {gattServer: ble.GattServer = undefined;connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902一般用于notification或者indicationmySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';// 构造BLEDescriptorprivate initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {let descriptor: ble.BLEDescriptor = {serviceUuid: this.myServiceUuid,characteristicUuid: this.myCharacteristicUuid,descriptorUuid: des,descriptorValue: value};return descriptor;}// 构造BLECharacteristicprivate initCharacteristic(): ble.BLECharacteristic {let descriptors: Array<ble.BLEDescriptor> = [];let descBuffer = new ArrayBuffer(2);let descValue = new Uint8Array(descBuffer);descValue[0] = 31;descValue[1] = 32;descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);let charBuffer = new ArrayBuffer(2);let charValue = new Uint8Array(charBuffer);charValue[0] = 21;charValue[1] = 22;let characteristic: ble.BLECharacteristic = {serviceUuid: this.myServiceUuid,characteristicUuid: this.myCharacteristicUuid,characteristicValue: charBuffer,descriptors: descriptors};return characteristic;}// 1. 订阅连接状态变化事件public onGattServerStateChange() {if (!this.gattServer) {console.error(TAG, 'no gattServer');return;}try {this.gattServer.on('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {let state = '';switch (stateInfo.state) {case 0:state = 'DISCONNECTED';break;case 1:state = 'CONNECTING';break;case 2:state = 'CONNECTED';break;case 3:state = 'DISCONNECTING';break;default:state = 'undefined';break;}console.info(TAG, 'onGattServerStateChange: device=' + stateInfo.deviceId + ', state=' + state);});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 2. server端注册服务时调用public registerServer() {let characteristics: Array<ble.BLECharacteristic> = [];let characteristic = this.initCharacteristic();characteristics.push(characteristic);let gattService: ble.GattService = {serviceUuid: this.myServiceUuid,isPrimary: true,characteristics: characteristics};console.info(TAG, 'registerServer ' + this.myServiceUuid);try {this.gattServer = ble.createGattServer(); // 2.1 构造gattServer,后续的交互都需要使用该实例this.onGattServerStateChange(); // 2.2 订阅连接状态this.gattServer.addService(gattService);} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 3. 订阅来自gattClient的读取特征值请求时调用public onCharacteristicRead() {if (!this.gattServer) {console.error(TAG, 'no gattServer');return;}console.info(TAG, 'onCharacteristicRead');try {this.gattServer.on('characteristicRead', (charReq: ble.CharacteristicReadRequest) => {let deviceId: string = charReq.deviceId;let transId: number = charReq.transId;let offset: number = charReq.offset;console.info(TAG, 'receive characteristicRead');let rspBuffer = new ArrayBuffer(2);let rspValue = new Uint8Array(rspBuffer);rspValue[0] = 21;rspValue[1] = 22;let serverResponse: ble.ServerResponse = {deviceId: deviceId,transId: transId,status: 0, // 0表示成功offset: offset,value: rspBuffer};try {this.gattServer.sendResponse(serverResponse);} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 4. 订阅来自gattClient的写入特征值请求时调用public onCharacteristicWrite() {if (!this.gattServer) {console.error(TAG, 'no gattServer');return;}console.info(TAG, 'onCharacteristicWrite');try {this.gattServer.on('characteristicWrite', (charReq: ble.CharacteristicWriteRequest) => {let deviceId: string = charReq.deviceId;let transId: number = charReq.transId;let offset: number = charReq.offset;console.info(TAG, 'receive characteristicWrite: needRsp=' + charReq.needRsp);if (!charReq.needRsp) {return;}let rspBuffer = new ArrayBuffer(0);let serverResponse: ble.ServerResponse = {deviceId: deviceId,transId: transId,status: 0, // 0表示成功offset: offset,value: rspBuffer};try {this.gattServer.sendResponse(serverResponse);} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 5. 订阅来自gattClient的读取描述符请求时调用public onDescriptorRead() {if (!this.gattServer) {console.error(TAG, 'no gattServer');return;}console.info(TAG, 'onDescriptorRead');try {this.gattServer.on('descriptorRead', (desReq: ble.DescriptorReadRequest) => {let deviceId: string = desReq.deviceId;let transId: number = desReq.transId;let offset: number = desReq.offset;console.info(TAG, 'receive descriptorRead');let rspBuffer = new ArrayBuffer(2);let rspValue = new Uint8Array(rspBuffer);rspValue[0] = 31;rspValue[1] = 32;let serverResponse: ble.ServerResponse = {deviceId: deviceId,transId: transId,status: 0, // 0表示成功offset: offset,value: rspBuffer};try {this.gattServer.sendResponse(serverResponse);} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 6. 订阅来自gattClient的写入描述符请求时调用public onDescriptorWrite() {if (!this.gattServer) {console.error(TAG, 'no gattServer');return;}console.info(TAG, 'onDescriptorWrite');try {this.gattServer.on('descriptorWrite', (desReq: ble.DescriptorWriteRequest) => {let deviceId: string = desReq.deviceId;let transId: number = desReq.transId;let offset: number = desReq.offset;console.info(TAG, 'receive descriptorWrite: needRsp=' + desReq.needRsp);if (!desReq.needRsp) {return;}let rspBuffer = new ArrayBuffer(0);let serverResponse: ble.ServerResponse = {deviceId: deviceId,transId: transId,status: 0, // 0表示成功offset: offset,value: rspBuffer};try {this.gattServer.sendResponse(serverResponse);} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}});} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 7. server端删除服务,不再使用时调用public unRegisterServer() {if (!this.gattServer) {console.error(TAG, 'no gattServer');return;}console.info(TAG, 'unRegisterServer ' + this.myServiceUuid);try {this.gattServer.removeService(this.myServiceUuid); // 7.1 删除服务this.gattServer.off('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => { // 7.2 取消订阅连接状态});this.gattServer.close() // 7.3 如果不再使用此gattServer,则需要close} catch (err) {console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}
}let gattServerManager = new GattServerManager();
export default gattServerManager as GattServerManager;

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 鸿蒙 (OpenHarmony)开发学习视频》
  • 鸿蒙生态应用开发V2.0白皮书》
  • 鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 鸿蒙开发基础》
  • 鸿蒙开发进阶》
  • 鸿蒙开发实战》

在这里插入图片描述

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿
1


http://www.ppmy.cn/news/1524225.html

相关文章

目标检测-YOLOv6

YOLOv6 YOLOv6 是 YOLO 系列的一个新版本&#xff0c;相比 YOLOv5 进行了大量的优化与改进。YOLOv6 的设计目标是在提高模型检测精度的同时&#xff0c;进一步优化速度和效率&#xff0c;特别是在推理速度和部署便捷性方面。它采用了更先进的网络架构和优化技巧&#xff0c;在…

TriangleIcon 鸿蒙ArkTS自定义View 实现带颜色的上下箭头

TriangleIcon 鸿蒙ArkTS自定义View 实现带颜色的上下箭头 最近将公司项目中VUE实现的的一个数据看板模块进行了纯血鸿蒙的实现&#xff0c;里面有个效果就是 数据指标上升 一个绿色箭头朝上&#xff0c;数据指标下降一个红色箭头向下 具体的效果可以查看上图&#xff0c; 其中V…

【办公类】大组工会学习(文心一言+Python批量)

背景需求&#xff1a; 每学期要写一份工会的大组政治学习读后感&#xff08;9月-1月&#xff0c;共5次&#xff09; 学习内容 9月、10月、11月、12月、1月的学习内容文字稿 在班级里&#xff0c;我擅长电脑工作&#xff0c;所以这种写的工作都包了。 中2班三位老师一共写3篇&…

揭秘蛇形机器人的主动SLAM算法和障碍物避让策略

更多优质内容&#xff0c;请关注公众号&#xff1a;智驾机器人技术前线 1.论文信息 论文标题&#xff1a;An active SLAM with multi-sensor fusion for snake robots based on deep reinforcement learning 作者&#xff1a;Xin Liu, Shuhuan Wen, Yaohua Hu, Fei Han, Hong…

ARM基础---编程模型---ARM汇编

一、编程模型 1.1.数据和指令集 1.数据 ARM 采用的是32位架构。 ARM 约定:Byte &#xff1a; 8 bits Halfword &#xff1a; 16 bits (2 byte)Word : 32 bits (4 byte)Doubleword 64-bits&#xff08;8byte&#xff09;&#xff08;Cortex-A处理器&#xff09; 2.指令 ARM…

Docker 镜像配置

在 Docker 的使用过程中&#xff0c;拉取镜像是一个常见的操作&#xff0c;但在国内由于网络问题&#xff0c;直接从 Docker Hub 拉取镜像可能会比较慢。为了解决这个问题&#xff0c;我们可以配置 Docker 使用国内镜像源&#xff0c;从而加速镜像的拉取过程。本文将介绍如何配…

若依Ruoyi之智能售货机运营管理系统(新增运营运维工单管理)

idea抽取独立方法快捷键&#xff1a;ctrlaltm TaskDto.java package com.dkd.manage.service.impl;import java.time.Duration; import java.util.List; import java.util.stream.Collectors;import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUti…

数据结构(2)单向链表排序和双向链表操作

一单向链表的插入排序 void insertion_sort_link(link_t* plink) { // 如果链表头为空&#xff0c;直接返回 if(NULL plink->phead) { return; } // 初始化指针&#xff0c;p指向当前已排序部分的最后一个节点 node_t* p plink->phead; // ptemp指向待插入的…

什么是单片机?为什么要学习单片机?

实现目标 1、熟悉单片机定义、特点、应用场景、发展历史等&#xff1b; 2、理解为什么要学习单片机&#xff1f;怎样学习单片机&#xff1f; 一、单片机是什么&#xff1f; 1、定义 单片机是集成在一块&#xff08;单&#xff09;芯片上的微型计算机。平时我们把 MCU&#x…

【ES备份和还原索引数据】

文章目录 备份&#xff08;Snapshot&#xff09;还原&#xff08;Restore&#xff09;注意事项示例 在 Elasticsearch 中&#xff0c;备份和还原索引数据通常通过快照&#xff08;Snapshot&#xff09;和恢复&#xff08;Restore&#xff09;机制来实现。以下是详细的操作步骤&…

最受欢迎的10款电脑监控软件大揭秘,员工电脑监控软件真心推荐

随着科技的迅猛发展&#xff0c;越来越多的企业和个人开始关注电脑监控软件的使用。这类软件能够帮助企业管理者更好地了解员工的工作状况&#xff0c;提升工作效率&#xff0c;并确保公司数据安全&#xff1b;个人用户也可以利用这些软件监控电脑活动&#xff0c;保护家人尤其…

php返回数据量较大怎么办

当 PHP 返回数据量较大时&#xff0c;可能会导致内存溢出、超时、网络传输慢等问题。以下是一些常见的优化方案&#xff0c;帮助有效处理大数据量返回&#xff0c;确保系统的性能和稳定性&#xff1a; 1. 分页加载数据 问题描述&#xff1a;一次性返回大量数据&#xff08;例…

Spring Boot3.x 启动自动执行sql脚本

1 引言 某些项目在首次启动时&#xff0c;需要先手动创建数据库表&#xff0c;然后再手动写入初始数据才能正常使用。为了省去这个手动操作过程&#xff0c;我们可以使用Spring Boot启动时执行sql脚本的配置&#xff0c;全自动完成这个过程。 2 配置 具体配置如下&#xff1…

使用 `readResolve` 防止序列化破坏单例模式

单例模式是一种设计模式&#xff0c;其目的是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。在 Java 中&#xff0c;我们常常通过私有化构造方法和提供静态访问方法来实现单例。然而&#xff0c;尽管这些手段可以有效防止类的实例化&#xff0c;反射和序列化依然能…

基于YOLOv8的风力涡轮机表面损坏检测系统

基于YOLOv8的风力涡轮机表面损坏检测系统 (价格85) 包含 [损坏] 1个类 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系统可以根据数据训练出的yolov8的权重文件&#xff0c;运用在其他检测系统上&#x…

【变化检测】基于STANet建筑物(LEVIR-CD)变化检测实战及ONNX推理

主要内容如下&#xff1a; 1、LEVIR-CD数据集介绍及下载 2、运行环境安装 3、STANet模型训练与预测 4、Onnx运行及可视化 运行环境&#xff1a;Python3.8&#xff0c;torch1.12.0cu113 likyoo变化检测源码&#xff1a;https://github.com/likyoo/open-cd 使用情况&#xff1a…

Android调整第三方库PickerView宽高--回忆录

一、效果 // 时间选择implementation com.contrarywind:Android-PickerView:4.1.9 多年前&#xff0c;使用到事件选择器&#xff0c;但是PickerView默认宽度使满屏的&#xff0c;不太符合业务需求&#xff0c;当时为此花了许多时间&#xff0c;最终找到了解决方案&#xff0c;…

为控制器的方法添加必要参数

前言&#xff1a;做这个系统时&#xff0c;要求每次调用接口时要传操作人、操作人电脑ip、菜单id&#xff0c;然后计入log。本来前端读取到然后加入请求头&#xff0c;后端写入log即可。但是老大要求后端也要把控必传参数&#xff0c;避免前端忘记。所以就写了这个。IOperation…

Git创建本地仓库

一、创建本地空仓库 1、创建项目文件夹 创建一个全新的文件夹&#xff0c;在文件夹中右键&#xff0c;就会显示出来以下两项&#xff1a; 2、初始化仓库 点击第二个&#xff0c;就会在此目录进入 git 的命令行&#xff0c;然后在命令行中输入以下指令&#xff0c; git init…

使用切换 JDK 的方式优化部署微服务占用内存过高的问题

使用切换 JDK 的方式优化部署微服务占用内存过高的问题 一、前言二、下载 J9 虚拟机的JDK三、切换 JDK1、上传到服务器2、解压3、修改 JDK 路径4、解决 JDK 没有切换成功的问题 一、前言 前段时间在服务器部署了微服务项目&#xff0c;但即使限制了每个服务的堆&#xff0c;内…