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

news2024/11/15 18:05:59

在这里插入图片描述

文章目录

    • 🌈应用层获取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.coloradmin.cn/o/985612.html

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

相关文章

核心实验12合集_vlan高级配置:基于子网划分vlan超级vlan相同vlan 端口隔离 _ENSP

项目场景一&#xff1a; 核心实验12合集-1_vlan高级配置_ENSP 基于子网划分vlan &#xff11; 当检测ip在192.168.10.0/24时候&#xff0c;PC接入交换机时&#xff0c;将其划为vlan10&#xff0c; 且可以和vlan 10 的服务器通信。 2 当检测ip在192.168.20.0/24时候&#xff0c;…

配电室数字电力智慧平台

配电室数字电力智慧平台依托电易云-智慧电力物联网&#xff0c;采用先进的人工智能、物联网、大数据技术&#xff0c;对配电室进行全面监控和管理&#xff0c;实现电力运行的自动化和智能化&#xff0c;有效降低运维成本&#xff0c;提高电力运行安全和可靠性。 该平台可以实时…

CTFHUB ICS(2)

1.modbus 还是通过strings输出文件 发现这次只找到了flag的字符666c61677b就是flag的16进制 通过strings和grep配合输出为10个数量的数据 strings 6.pcap | grep -E "^.{10}$" grep 搜索文本的工具 -E 使用扩展正则表达式 ^ 表示行的开始 . 匹配任意单…

内网渗透之凭据收集的各种方式

凭据收集是什么&#xff1f; 凭据收集是获取用户和系统凭据访问权限的术语。 这是一种查找或窃取存储的凭据的技术&#xff0c;包括网络嗅探&#xff0c;攻击者可以在网络嗅探中捕获传输的凭据。 凭证可以有多种不同的形式&#xff0c;例如&#xff1a; 帐户详细信息&#xf…

用上这个建筑管理技巧,我才知道有多省事!

在过去的几十年里&#xff0c;建筑和施工行业取得了巨大的进步。然而&#xff0c;这个行业也一直在不断面临挑战&#xff0c;如高成本、时间压力、安全隐患和资源浪费。 随着科技的飞速发展&#xff0c;我们进入了一个新的时代&#xff0c;一个改变着建筑和施工方式的时代 - 智…

TSINGSEE青犀视频AI分析/边缘计算/AI算法·安全帽检测功能——多场景高效运用

安全帽检测算法主要是对人员安全和事故预防的需要。在许多工业领域和施工现场&#xff0c;佩戴安全帽是一种重要的安全措施&#xff0c;可以减少头部受伤的风险。然而&#xff0c;由于工地人员数量众多且繁忙&#xff0c;人工监控难以有效覆盖所有区域&#xff0c;因此旭帆科技…

vue-别名路径联想提示的配置

在根路径下&#xff0c;新建 jsconfig.json 文件&#xff0c;即可 在输入 自动联想到src目录。 代码如下&#xff1a; // 别名路径联想提示&#xff1a;输入自动联想 {"compilerOptions":{"baseUrl":"./","paths": {"/*":[…

算法训练day43|动态规划 part05:0-1背包 (LeetCode 1049. 最后一块石头的重量 II、494. 目标和、474.一和零)

文章目录 1049. 最后一块石头的重量 II思路分析代码实现 494. 目标和思路分析动规方法代码实现总结思考 474.一和零思路分析代码实现思考总结 var code "57a5e730-4e5e-43ad-b567-720d69f0371a"1049. 最后一块石头的重量 II 题目链接&#x1f525;&#x1f525; 有…

泽众TestOne自动化测试平台,挡板测试(Mock测试)上线了!!

什么是挡板测试&#xff08;Mock测试&#xff09;&#xff1f; 主要应对与某些不容易构造或者不容易获取的对象以及暂时没有开发完成的对象&#xff0c;设计一个虚拟的对象&#xff0c;配置测试需求的业务数据&#xff0c;完成测试业务。 TestOne是泽众软件自主研发的一体化测…

静态函数(static)-> static 与 const

一.静态函数 静态函数&#xff08;Static Function&#xff09;是指在C中使用static关键字声明的函数。它们与普通成员函数和全局函数不同&#xff0c;具有以下特点&#xff1a; 作用域限制&#xff1a;静态函数在类的作用域内&#xff0c;但它们不依赖于类的实例&#xff0c;…

GIF动态表情如何制作?教你一招超简单的gif制作方法

动态gif表情包是如何制作的&#xff1f;gif格式动图作为网络上流行的一种图片格式&#xff0c;可以将多张静态图片变成一张gif动图&#xff0c;能够以生动有趣的方式传递信息。而且制作这种gif动图的方法也非常的简单&#xff0c;只需要使用gif在线制作&#xff08;https://www…

不就是G2O嘛

从零开始一起学习SLAM | 理解图优化&#xff0c;一步步带你看懂g2o代码 SLAM的后端一般分为两种处理方法&#xff0c;一种是以扩展卡尔曼滤波&#xff08;EKF&#xff09;为代表的滤波方法&#xff0c;一种是以图优化为代表的非线性优化方法。不过&#xff0c;目前SLAM研究的主…

Oracle数据库开发者工具

和开发者相关的数据库特性&#xff0c;功能与工具列举如下&#xff0c;但不限于以下。因为Oracle数据库中的许多功能其实都间接的和开发者发生关系&#xff0c;如Oracle高级安全选件中的透明数据加密&#xff0c;数据编辑。Oracle Spatial and Graph&#xff08;地理空间与图&a…

ansible搭建

一&#xff0c;ansible是一种由Python开发的自动化运维工具&#xff0c;集合了众多运维工具&#xff08;puppet、cfengine、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令等功能 二&#xff0c;特点 * 部署简单 * **默认…

数据结构入门-13-图

文章目录 一、图的概述1.1 图论的作用1.2 图的分类1.2.1 无向图1.2.2 有向图1.2.3 无权图1.2.4 有劝图 1.3 图的基本概念 二、树的基本表示2.1 邻接矩阵2.1.1 邻接矩阵 表示图2.1.2 邻接矩阵的复杂度 2.2 邻接表2.2.1 邻接表的复杂度2.2.2 邻接表By哈希表 三、图的深度优先遍历…

LLM文章阅读:Baichuan 2 干货

如有转载&#xff0c;请注明出处。欢迎关注微信公众号&#xff1a;低调奋进。打算开始写LLM系列文章&#xff0c;主要从数据、训练框架、对齐等方面进行LLM整理。 Baichuan 2: Open Large-scale Language Models 原始文章链接 https://cdn.baichuan-ai.com/paper/Baichuan2-…

Element Plus table formatter函数返回html内容

查看 Element Plus table formatter 支持返回 类型为string 和 VNode对象&#xff1b; 若依全局直接用h函数&#xff0c;无需引用 下面普通基本用法&#xff1a;在Element Plus中&#xff0c;你可以使用自定义的formatter函数来返回VNode对象&#xff0c;从而实现更灵活的自定…

FasterNet(PConv)paper笔记(CVPR2023)

论文&#xff1a;Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks 先熟悉两个概念&#xff1a;FLOPS和FLOPs&#xff08;s一个大写一个小写&#xff09; FLOPS: FLoating point Operations Per Second的缩写&#xff0c;即每秒浮点运算次数&#xff0c;或…

Pytorch实现鸟类品种分类识别(含训练代码和鸟类数据集)

Pytorch实现鸟类品种分类识别(含训练代码和鸟类数据集) 目录 Pytorch实现鸟类品种分类识别(含训练代码和鸟类数据集) 1. 前言 2. 鸟类数据集 &#xff08;1&#xff09;Bird-Dataset26 &#xff08;2&#xff09;自定义数据集 3. 鸟类分类识别模型训练 &#xff08;1&a…

核心实验13合集_vlan mapping 和QinQ_ENSP

项目场景一&#xff1a; 核心实验13合集-1_vlan高级配置_ENSP vlan mapping vlan转换 将用户端发来的vlan30-31的标签全部转换成vlan100向上发送 相关知识点&#xff1a; 定义: VLAN Mapping通过修改报文携带的VLAN Tag来实现不同VLAN的相互映 射。 目的: 在某些场景中&#xf…