Linux---应用层获取usb设备描述信息通过endpoint地址数据通讯

在这里插入图片描述

文章目录

    • 🌈应用层获取USB设备信息总体思路
    • 🌈应用层代码实例
    • 🌈实例测试
    • 🌈应用层通过endpoint进行数据读写

🌈应用层获取USB设备信息总体思路

应用层可以打开USB设备的节点,读取包括USB设备的配置,端口,端点等信息。具体来说对于USB设备均存在对应的VID PID,其中VID指的是Vendor ID(厂商识别码),用于唯一标识USB设备的制造商。PID指的是Product ID(产品识别码),用于唯一标识USB设备的产品型号。通过VID和PID,可以确定一个具体的USB设备,因为每个设备的VID和PID是唯一的,可以帮助系统识别和与设备进行交互。


如果上位机正常识别USB设备,我们可以通过对应节点信息/sys/bus/usb/devices按照文件目录去搜索,如果目录中idVendor和idProduct与我们要搜索的一致,可以判定为我们需要找的设备节点。如下图1-4目录中的idVendor和idProduct与我们要找寻的一致:

root@Vostro:/sys/bus/usb/devices/1-4# ls -al
total 0
drwxr-xr-x 12 root root     0 Aug 31 20:55 .
drwxr-xr-x  8 root root     0 Aug 10 11:55 ..
drwxr-xr-x  6 root root     0 Aug 31 20:55 1-4:1.0
drwxr-xr-x  6 root root     0 Aug 31 20:55 1-4:1.1
drwxr-xr-x  7 root root     0 Aug 31 20:55 1-4:1.2
drwxr-xr-x  7 root root     0 Aug 31 20:55 1-4:1.3
drwxr-xr-x  7 root root     0 Aug 31 20:55 1-4:1.4
drwxr-xr-x  7 root root     0 Aug 31 20:55 1-4:1.5
drwxr-xr-x  7 root root     0 Aug 31 20:55 1-4:1.6
-rw-r--r--  1 root root  4096 Aug 31 20:55 authorized
-rw-r--r--  1 root root  4096 Aug 31 20:55 avoid_reset_quirk
-r--r--r--  1 root root  4096 Aug 31 20:55 bcdDevice
-rw-r--r--  1 root root  4096 Aug 31 20:55 bConfigurationValue
-r--r--r--  1 root root  4096 Aug 31 20:55 bDeviceClass
-r--r--r--  1 root root  4096 Aug 31 20:55 bDeviceProtocol
-r--r--r--  1 root root  4096 Aug 31 20:55 bDeviceSubClass
-r--r--r--  1 root root  4096 Aug 31 20:55 bmAttributes
-r--r--r--  1 root root  4096 Aug 31 20:55 bMaxPacketSize0
-r--r--r--  1 root root  4096 Aug 31 20:55 bMaxPower
-r--r--r--  1 root root  4096 Aug 31 20:55 bNumConfigurations
-r--r--r--  1 root root  4096 Aug 31 20:55 bNumInterfaces
-r--r--r--  1 root root  4096 Aug 31 20:55 busnum
-r--r--r--  1 root root  4096 Aug 31 20:55 configuration
-r--r--r--  1 root root 65553 Aug 31 20:55 descriptors
-r--r--r--  1 root root  4096 Aug 31 20:55 dev
-r--r--r--  1 root root  4096 Aug 31 20:55 devnum
-r--r--r--  1 root root  4096 Aug 31 20:55 devpath
lrwxrwxrwx  1 root root     0 Aug 31 20:55 driver -> ../../../../../bus/usb/drivers/usb
drwxr-xr-x  3 root root     0 Aug 31 20:55 ep_00
lrwxrwxrwx  1 root root     0 Aug 31 20:55 firmware_node -> ../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:4c/device:4d/device:51
-r--r--r--  1 root root  4096 Aug 31 20:55 idProduct
-r--r--r--  1 root root  4096 Aug 31 20:55 idVendor
-r--r--r--  1 root root  4096 Aug 31 20:55 ltm_capable
-r--r--r--  1 root root  4096 Aug 31 20:55 manufacturer
-r--r--r--  1 root root  4096 Aug 31 20:55 maxchild
drwxr-xr-x  2 root root     0 Aug 31 20:55 physical_location
lrwxrwxrwx  1 root root     0 Aug 31 20:55 port -> ../1-0:1.0/usb1-port4
drwxr-xr-x  2 root root     0 Aug 31 20:55 power
-r--r--r--  1 root root  4096 Aug 31 20:55 product
-r--r--r--  1 root root  4096 Aug 31 20:55 quirks
-r--r--r--  1 root root  4096 Aug 31 20:55 removable
--w-------  1 root root  4096 Aug 31 20:55 remove
-r--r--r--  1 root root  4096 Aug 31 20:55 rx_lanes
-r--r--r--  1 root root  4096 Aug 31 20:55 serial
-r--r--r--  1 root root  4096 Aug 31 20:55 speed
lrwxrwxrwx  1 root root     0 Aug 31 20:55 subsystem -> ../../../../../bus/usb
-r--r--r--  1 root root  4096 Aug 31 20:55 tx_lanes
-rw-r--r--  1 root root  4096 Aug 31 20:55 uevent
-r--r--r--  1 root root  4096 Aug 31 20:55 urbnum
-r--r--r--  1 root root  4096 Aug 31 20:55 version

在找到对应目录后,读取该目录下面的uevent节点,会获取到该USB设备对应的主设备号,次设备号,设备名称、设备类型等相关信息,如下图:

root@Vostro:/sys/bus/usb/devices/1-4# cat uevent 
MAJOR=189
MINOR=115
DEVNAME=bus/usb/001/116
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=2cb7/1/100
TYPE=0/0/0
BUSNUM=001
DEVNUM=116

这里我们需要获取的是DEVNAME=bus/usb/001/116这个信息,该信息表示在/dev设备目录下/dev/bus/usb/001/116为该USB设备的节点,我们后续读取USB设备信息以及数据读写操作都是通过这个节点进行的,如下图我们可以看到/dev/bus/usb/001/目录下有多个USB设备,其中116为我们需要的设备节点:

root@Vostro:/sys/bus/usb/devices/1-4# cd /dev/bus/usb/001/
root@Vostro:/dev/bus/usb/001# ls -al
total 0
drwxr-xr-x 2 root root      120 Sep  1 17:59 .
drwxr-xr-x 4 root root       80 Aug 10 11:55 ..
crw-rw-rw- 1 root root 189,   0 Aug 10 11:56 001
crw-rw-rw- 1 root root 189,   2 Aug 10 11:56 003
crw-rw-rw- 1 root root 189,   3 Aug 10 11:56 004
crw-rw-rw- 1 root root 189, 115 Aug 31 20:55 116

找到该节点后,通过应用层的open函数打开设备,通过read函数读取并解析设备的相关信息,即可获得USB设备的配置,端点,端口等信息。


🌈应用层代码实例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/ch9.h>#define BUF_SIZE 512
#define MAX_PATH_LEN 512
#define USB_DIR_BASE    "/sys/bus/usb/devices"typedef struct
{int idVendor;int idProduct;int InterfaceNum;int usbdev;char portname[BUF_SIZE];char syspath[BUF_SIZE];char busname[BUF_SIZE];int bulk_ep_in;int bulk_ep_out;int wMaxPacketSize;int usb_need_zero_package;int (* write)(const void *handle, void *pbuf, int size, int portnum);int (* read)(const void *handle, void *pbuf, int size, int portnum);
} s_usbdev_t;s_usbdev_t udev;int strStartsWith(const char *str, const char *match_str)
{for ( ; *str != '\0' && *match_str != '\0'; str++, match_str++) {if (*str != *match_str) {return 0;}}return *match_str == '\0';
}static int get_usbsys_val(const char *sys_filename, int base)
{char buff[64] = {0};int ret_val = -1;int fd = open(sys_filename, O_RDONLY);if (fd < 0) {return -1;}if (read(fd, buff, sizeof(buff)) <= 0) {printf("read:%s failed\n", sys_filename);}else {ret_val = strtoul(buff, NULL, base);}close(fd);return ret_val;
}static int get_busname_by_uevent(const char *uevent, char *busname)
{FILE *fp = NULL;char line[BUF_SIZE] = {0};int MAJOR = 0, MINOR = 0;char DEVTYPE[64] = {0}, PRODUCT[64] = {0};fp = fopen(uevent, "r");if (fp == NULL) {printf("fopen %s failed, errno:%d(%s)\n", uevent, errno, strerror(errno));return -1;}while (fgets(line, sizeof(line), fp)){if (line[strlen(line) - 1] == '\n' || line[strlen(line) - 1] == '\r') {line[strlen(line) - 1] = 0;}if (strStartsWith(line, "MAJOR=")){MAJOR = atoi(&line[strlen("MAJOR=")]);}else if (strStartsWith(line, "MINOR=")){MINOR = atoi(&line[strlen("MINOR=")]);}else if (strStartsWith(line, "DEVICE=")){strncpy(busname, &line[strlen("DEVICE=")], MAX_PATH_LEN);}else if (strStartsWith(line, "DEVNAME=")){strncpy(busname, &line[strlen("DEVNAME=")], MAX_PATH_LEN);}else if (strStartsWith(line, "DEVTYPE=")){strncpy(DEVTYPE, &line[strlen("DEVTYPE=")], sizeof(DEVTYPE));}else if (strStartsWith(line, "PRODUCT=")){strncpy(PRODUCT, &line[strlen("PRODUCT=")], sizeof(PRODUCT));}}fclose(fp);if (MAJOR != 189  || MINOR == 0 || busname[0] == 0|| DEVTYPE[0] == 0 || PRODUCT[0] == 0|| strStartsWith(DEVTYPE, "usb_device") == 0) {return -1;}return 0;
}int usb_dev_open(int usb_vid, int usb_pid)
{char devdesc[MAX_PATH_LEN*2] = {0};char devname[MAX_PATH_LEN+128] = {0};size_t desc_length = 0, len = 0;int bInterfaceNumber = 0;DIR *usbdir = NULL;struct dirent *dent = NULL;int idVendor = 0, idProduct = 0;int bNumInterfaces = 0, bConfigurationValue = 0;char sys_filename[MAX_PATH_LEN] = {0};usbdir = opendir("/sys/bus/usb/devices");if (usbdir == NULL) {return -1;}while ((dent = readdir(usbdir)) != NULL){if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {continue;}snprintf(sys_filename, sizeof(sys_filename), "%s/%s/idVendor", USB_DIR_BASE, dent->d_name);if ((idVendor = get_usbsys_val(sys_filename, 16)) <= 0) {continue;}snprintf(sys_filename, sizeof(sys_filename), "%s/%s/idProduct", USB_DIR_BASE, dent->d_name);if ((idProduct = get_usbsys_val(sys_filename, 16)) <= 0) {continue;}snprintf(sys_filename, sizeof(sys_filename), "%s/%s/bConfigurationValue", USB_DIR_BASE, dent->d_name);if ((bConfigurationValue = get_usbsys_val(sys_filename, 10)) <= 0) {continue;}snprintf(sys_filename, sizeof(sys_filename), "%s/%s/bNumInterfaces", USB_DIR_BASE, dent->d_name);if ((bNumInterfaces = get_usbsys_val(sys_filename, 10)) <= 0) {continue;}if((idVendor == usb_vid)&&(idProduct == usb_pid)){udev.idVendor = idVendor;udev.idProduct = idProduct;printf("----------------------------------\n");printf("idVendor: %04x\n", udev.idVendor);printf("idProduct: %04x\n", udev.idProduct);printf("bNumInterfaces: %d\n", bNumInterfaces);printf("bConfigurationValue: %d\n", bConfigurationValue);snprintf(sys_filename, sizeof(sys_filename), "%s/%s/uevent", USB_DIR_BASE, dent->d_name);get_busname_by_uevent(sys_filename, udev.busname);printf("busname: %s\n", udev.busname);printf("----------------------------------\n");break;}usleep(10000);}if (usbdir) {closedir(usbdir);usbdir = NULL;}snprintf(devname, sizeof(devname), "/dev/%s", udev.busname);if (access(devname, F_OK | R_OK| W_OK)) {printf("access %s failed, errno:%d(%s)\n", devname, errno, strerror(errno));return -1;}udev.usbdev = open(devname, O_RDWR | O_NOCTTY);if (udev.usbdev < 0) {printf("open %s failed, errno:%d(%s)\n", devname, errno, strerror(errno));return -1;}printf("[%s] OK.\n", devname);desc_length = read(udev.usbdev, devdesc, sizeof(devdesc));printf("desc_length is %zu,read length is %zu\r\n", sizeof(devdesc), desc_length);for (len=0; len<desc_length;){struct usb_descriptor_header *h = (struct usb_descriptor_header *)(devdesc + len);if (h->bLength == sizeof(struct usb_device_descriptor) && h->bDescriptorType == USB_DT_DEVICE){struct usb_device_descriptor *device = (struct usb_device_descriptor *)h;printf("P: idVendor: %04x idProduct:%04x\n", device->idVendor, device->idProduct);}else if (h->bLength == sizeof(struct usb_config_descriptor) && h->bDescriptorType == USB_DT_CONFIG){struct usb_config_descriptor *config = (struct usb_config_descriptor *)h;printf("C: bNumInterfaces: %d\n", config->bNumInterfaces);}else if (h->bLength == sizeof(struct usb_interface_descriptor) && h->bDescriptorType == USB_DT_INTERFACE){struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)h;printf("I: If#= %d Alt= %d #EPs= %d Cls=%02x Sub=%02x Prot=%02x\n",interface->bInterfaceNumber, interface->bAlternateSetting, interface->bNumEndpoints,interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bInterfaceProtocol);bInterfaceNumber = interface->bInterfaceNumber;}else if (h->bLength == USB_DT_ENDPOINT_SIZE && h->bDescriptorType == USB_DT_ENDPOINT){struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)h;if ( (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK){if (endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {udev.bulk_ep_in = endpoint->bEndpointAddress;printf("bulk_ep_in:0x%02X\n", udev.bulk_ep_in);} else {udev.bulk_ep_out = endpoint->bEndpointAddress;printf("bulk_ep_out:0x%02X\n", udev.bulk_ep_out);}udev.wMaxPacketSize = endpoint->wMaxPacketSize;printf("wMaxPacketSize:%d\n", endpoint->wMaxPacketSize);}}len += h->bLength;}return 0;
}int main(int argc, char * * argv)
{int vid_hex,pid_hex;if(argc !=3 ){printf("Usage: usb_read_device_info USB_VID USB_PID \r\n");return -1;}sscanf(argv[1], "%x", &vid_hex);sscanf(argv[2], "%x", &pid_hex);printf("USB VID %4x, PID is %4x\r\n", vid_hex, pid_hex);usb_dev_open(vid_hex,pid_hex);
}

🌈实例测试

插入一个VID PID为2cb7 0001的USB设备,运行上面的测试程序(编译过程省略),main函数入口参数传入VID 2CB7及 PID 0001运行如下:

book@Vostro:~/Joy/Test$ sudo ./USB_read_device_info 2cb7 0001
USB VID 2cb7, PID is    1
----------------------------------
idVendor: 2cb7
idProduct: 0001
bNumInterfaces: 7
bConfigurationValue: 1
busname: bus/usb/001/116
----------------------------------
[/dev/bus/usb/001/116] OK.
desc_length is 1024,read length is 221
P: idVendor: 2cb7 idProduct:0001
C: bNumInterfaces: 7
I: If#= 0 Alt= 0 #EPs= 1 Cls=02 Sub=06 Prot=00
I: If#= 1 Alt= 0 #EPs= 0 Cls=0a Sub=00 Prot=00
I: If#= 1 Alt= 1 #EPs= 2 Cls=0a Sub=00 Prot=00
bulk_ep_in:0x81
wMaxPacketSize:512
bulk_ep_out:0x01
wMaxPacketSize:512
I: If#= 2 Alt= 0 #EPs= 2 Cls=ff Sub=ff Prot=ff
bulk_ep_in:0x82
wMaxPacketSize:512
bulk_ep_out:0x02
wMaxPacketSize:512
I: If#= 3 Alt= 0 #EPs= 2 Cls=ff Sub=ff Prot=ff
bulk_ep_in:0x83
wMaxPacketSize:512
bulk_ep_out:0x03
wMaxPacketSize:512
I: If#= 4 Alt= 0 #EPs= 2 Cls=ff Sub=ff Prot=ff
bulk_ep_in:0x84
wMaxPacketSize:512
bulk_ep_out:0x04
wMaxPacketSize:512
I: If#= 5 Alt= 0 #EPs= 2 Cls=ff Sub=ff Prot=ff
bulk_ep_in:0x85
wMaxPacketSize:512
bulk_ep_out:0x05
wMaxPacketSize:512
I: If#= 6 Alt= 0 #EPs= 2 Cls=ff Sub=42 Prot=01
bulk_ep_in:0x86
wMaxPacketSize:512
bulk_ep_out:0x06
wMaxPacketSize:512

可以看到通过解析read函数读取的相关信息,打印出了该USB设备的configuration、interface、endpoint等信息。

🌈应用层通过endpoint进行数据读写

使用USB的endpoint进行数据读写,需要了解每个endpoint的地址,并且endpoint为单向的,对于USB设备每interface下面可以有多个endpoint,这些endpoint可以是输入,也可以是输出,下面实例的设备节点USB_DEV_PATH 是由上面应用程序获取,通讯具体的endpoint地址也是由上面应用程序获取,这里直接写死对应数值以便测试:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>// USB设备节点路径,可通过上部分应用层实例代码获取某VID PID 对应的usb设备节点
#define USB_DEV_PATH "/dev/bus/usb/001/018"  int usbfs_bulk_write(int fd, char *data, size_t dataLen)
{int ret;struct usbdevfs_urb urb_write;struct usbdevfs_urb *urb = NULL;memset(&urb_write, 0, sizeof(urb_write));urb_write.type = USBDEVFS_URB_TYPE_BULK;urb_write.endpoint = 0x05;urb_write.status = -1;urb_write.buffer = (void *)data;urb_write.buffer_length = dataLen;urb_write.usercontext = &urb_write;printf("endpoint is %d, buffer_length is %d\r\n", urb_write.endpoint, urb_write.buffer_length);do {ret = ioctl(fd, USBDEVFS_SUBMITURB, &urb_write);} while ((ret < 0) && (errno == EINTR));if (ret != 0) {printf("USBDEVFS_SUBMITURB failed, ret: %d, errno:%d(%s)\n", ret, errno, strerror(errno));return -1;}do {urb = NULL;ret = ioctl(fd, USBDEVFS_REAPURB, &urb);} while ((ret < 0) && (errno == EINTR));if (ret == 0 && urb && urb->status == 0 && urb->actual_length) {return urb->actual_length;}return -1;
}int usbfs_bulk_read(int fd, char *data, size_t dataLen)
{int ret = -1;struct usbdevfs_bulktransfer bulk;bulk.ep = 0x85;bulk.len = dataLen;bulk.data = data;bulk.timeout = 3000;do {ret = ioctl(fd, USBDEVFS_BULK, &bulk);} while ((ret < 0) && (errno == EINTR));return ret;
}int main() 
{// 准备要写入的数据unsigned char data[] = {0x01,0xaa,0xaa,0xaa,0x01,0x55,0x73,0x01,0x14,0x00,0x00,0x00,0x06,0x67,0xbb,0xbb,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x44,0x09,0x7e};size_t dataLen = sizeof(data);int ret;int fd = open(USB_DEV_PATH, O_RDWR | O_NOCTTY);  // 打开USB设备文件描述符if (fd == -1) {perror("Failed to open USB device");return -1;}ret = usbfs_bulk_write(fd, data, dataLen);printf("usbfs_bulk_write ret is %d\r\n", ret);ret = usbfs_bulk_read(fd, data, dataLen);printf("usbfs_bulk_read ret is %d\r\n", ret);return 0;
}

上述代码实际测试结果如下:

root:/home/Joy/Test# ./usb_bulk_write_read
endpoint is 5, buffer_length is 35
usbfs_bulk_write ret is 35
usbfs_bulk_read ret is 10

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

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

相关文章

deepspeed训练报错torch.distributed.elastic.multiprocessing.errors.ChildFailedError

测试场景&#xff1a;使用deepspeed框架训练gpt模型 问题&#xff1a; 报错torch.distributed.elastic.multiprocessing.errors.ChildFailedError 具体见截图&#xff1a;

UMA 2 - Unity Multipurpose Avatar☀️六.Advanced Occlusion高级遮挡功能解决皮肤服饰穿模

文章目录 🟥 本节功能效果展示🟧 基础项目配置🟨 本节项目配置🟩 配置MeshHideAsset1️⃣ 创建MeshHideAsset2️⃣ 配置SlotDataAsset3️⃣ 配置遮挡信息🟦 将 MeshHideAsset 配置到 Recipe🟥 本节功能效果展示 未遮挡前的穿模问题: 遮挡后效果:

厂商征集 | 2023年中国RPA市场洞察研究报告正式启动

RPA中国基于在科技行业的资源积累&#xff0c;以及对各领域「技术领导者」、「技术应用者」、「产品服务商」的深度调研&#xff0c;2023年&#xff0c;我们重点推出MI报告 ( Market Insight )、CI Vendor报告&#xff08;Comprehensive Influence Vendor&#xff09;两个系列。…

【Jmeter】什么是BeanShell?

一、什么是BeanShell&#xff1f; BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器&#xff0c;JMeter性能测试工具也充分接纳了BeanShell解释器&#xff0c;封装成了可配置的BeanShell前置和后置处理器&#xff0c;分别是 BeanShell Pre…

NoSQL之Redis配置与优化(一)

关系数据库与非关系型数据库 &#xff1a; ●关系型数据库&#xff1a; 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记录。 SQL 语句&#xff08;标准数据查询语言&#xff09;就是一种基于…

FP7122 具有平均模式恒定电流控制的LED驱动器芯片

FP7122 具有平均模式恒定电流控制的LED驱动器芯片 一般说明 FP7122是在恒定关闭时间模式下工作的平均电流模式控制LED驱动器IC。FP7122不产生峰值到平均的误差&#xff0c;因此大大提高了LED电流的精度、线路和负载调节&#xff0c;而不需要任何回路补偿或高侧电流传感。输出的…

VB:二分法查找

VB&#xff1a;二分法查找 二分查找算法 Private Sub Command1_Click()Dim i%, m%, n%Dim x(1 To 10) As SingleFor i 1 To 10x(i) Val(InputBox("请输入"))Next iCall bubbleSort(x)For i LBound(x) To UBound(x) LBound(x)和UBound(x)是用于获取数组x的下界和上…

运营技巧|如何在不同的平台上高效批量管理账户?

在当今全球化时代&#xff0c;中国出海企业和B2B外贸企业越来越重视海外社媒营销&#xff0c;这已成为企业抢占市场份额的关键。并且&#xff0c;为了获取到更多流量&#xff0c;跨境人们还会开通Facebook、Twitter、Google、TikTok、Instagram等平台账号&#xff0c;搭建自己的…

教你制作作业查询系统

嗨&#xff0c;各位老师们&#xff0c;今天我要给你们介绍一个超级方便的工具——易查分&#xff01;你知道吗&#xff0c;利用易查分&#xff0c;我们可以轻松制作一个便捷高效的作业查询系统哦&#xff01; 是不是想有个自己的分班or成绩查询页面&#xff1f;博主给老师们争取…

提醒一个xampp启动mysql创建函数存在的坑

一直以来本地搭建的项目为了方便我都是使用xampp作为mysql的管理工具&#xff0c;比较简洁可视化比较好。但是最近程序的一个报错暴露了他与mysql之间的一些问题。 使用自增序列nextval函数时&#xff0c;突然抛出来一句&#xff1a; select nextval( SEQ_REGISTER_ID) > …

高性能数据JS网格 Bryntum Grid 5.5.2 Crack

高性能数据网格 Bryntum Grid 是一个高性能的网络表格组件。它是用纯 JavaScript 构建的&#xff0c;并且可以轻松地与所有主要 JS 框架集成。 功能丰富 Bryntum Grid 具有您期望从专业网格组件获得的所有功能&#xff0c;包括&#xff1a; 很好的表现;很好的绩效 没有人喜欢缓…

演讲实录:大模型时代,我们需要什么样的AI算力系统?

当前&#xff0c;“百模大战”带来了算力需求的爆发&#xff0c;AI芯片产业也迎来巨大机遇&#xff0c;“创新架构开源生态”正在激发多元AI算力产品百花齐放。面对新的产业机会&#xff0c;AI算力产业链亟需通过上下游协作共同把握机遇。 近日&#xff0c;浪潮信息AI&HPC…

异步FIFO设计的仿真与综合技术(1)

概述 本文主体翻译自C. E. Cummings and S. Design, “Simulation and Synthesis Techniques for Asynchronous FIFO Design 一文&#xff0c;添加了笔者的个人理解与注释&#xff0c;文中蓝色部分为笔者注或意译。 摘要&#xff08;ABSTRACT&#xff09; FIFO通常被用于将数据…

万物目标识别——Detic使用图像级别的监督信号来进行目标检测模型推理(C++/Python)

一、目标识别 1.1 传统目标识别算法 传统目标检测通常将分类&#xff08;确定物体属于哪个类别&#xff09;和定位&#xff08;确定物体的位置&#xff0c;通常使用边界框bbox表示&#xff09;任务耦合在一起。这要求训练数据集中包含每个物体的类别标签以及其对应的bbox位置…

【开发】视频监控平台EasyCVR分组批量绑定/取消通道功能的后端代码设计逻辑介绍

视频监控平台/视频存储/视频分析平台EasyCVR基于云边端一体化管理&#xff0c;可支持视频实时监控、云端录像、云存储、磁盘阵列存储、回放与检索、智能告警、平台级联等功能。安防监控平台在线下场景中应用广泛&#xff0c;包括智慧工地、智慧工厂、智慧校园、智慧社区等等。 …

【Flink实战】玩转Flink里面核心的Sink Operator实战

&#x1f680; 作者 &#xff1a;“大数据小禅” &#x1f680; 文章简介 &#xff1a;玩转Flink里面核心的Sink Operator实战 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 目录导航 Flink Sink Operator简介Flink 核心知识 Sink Operator速览Fl…

便捷高效的查询系统

今天我要来给大家种草一个超级好用的教学工具——易查分&#xff01;使用易查分&#xff0c;老师们可以轻松制作一个方便快捷的成绩查询系统&#xff0c;让查询成绩变得简单又高效。下面就让我来为大家详细介绍一下使用教程吧&#xff01; 是不是想有个自己的分班or成绩查询页面…

Eclipse官网下载历史版本

进入官网 https://www.eclipse.org/ 进入下载页面 选择下载包 同一版本&#xff0c;又有不同类型 Eclipse IDE for Enterprise Java and Web Developers Eclipse IDE for Java Developers 任何Java开发人员必备的工具&#xff0c;包括Java IDE、Git客户端、XML编辑器、Mave…

Unity实现用WASD控制一个物体前后左右移动-小白课程01

1 根据业务逻辑搭建场景 02 根据业务写代码 using System.Collections; using System.Collections.Generic; using UnityEngine;//实现让被挂在的物体往前移动 //按下W键往前移动&#xff0c;按下S键往后移动 public class RoleMove : MonoBehaviour { public float myspe…

新手询问想要成功学好嵌入式开发有什么建议吗?

今日话题&#xff0c;想要成功学好嵌入式开发有什么建议吗&#xff1f;想要学好的话选择一门合适的编程语言是关键。虽然嵌入式开发支持多种语言&#xff0c;但C和C仍然是最常用的。如果你是初学者&#xff0c;从学习C语言开始是一个不错的选择。它相对容易学习&#xff0c;而且…