Разработка классов-дескрипторов на c++/cli

Properties¶

Calling is a succinct way of building a data descriptor that
triggers function calls upon access to an attribute. Its signature is:

property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

The documentation shows a typical use to define a managed attribute :

class C(object):
    def getx(self): return self.__x
    def setx(self, value): self.__x = value
    def delx(self): del self.__x
    x = property(getx, setx, delx, "I'm the 'x' property.")

To see how is implemented in terms of the descriptor protocol,
here is a pure Python equivalent:

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None
            return self
        if self.fget is None
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

The builtin helps whenever a user interface has granted
attribute access and then subsequent changes require the intervention of a
method.

For instance, a spreadsheet class may grant access to a cell value through
. Subsequent improvements to the program require the cell
to be recalculated on every access; however, the programmer does not want to
affect existing client code accessing the attribute directly. The solution is
to wrap access to the value attribute in a property data descriptor:

1.2. Использование семантики стека

Шаблон Basic Dispose также реализуется компилятором, если в классе имеется член освобождаемого типа и он объявлен с использованием семантики стека. Это означает, что для объявления используется имя типа без крышки (»), а инициализация происходит в списке инициализации конструктора, а не с помощью . Семантика стека описана в .

Приведем пример:

Компилятор в этом случае делает следующее:

  1. Для класса реализует интерфейс .
  2. В обеспечивает вызов для .

Финализация определяется соответствующей функциональностью класса . Как и в предыдущем случае, наследование от можно указать явно, а самостоятельно определить нельзя. Естественно, класс может иметь еще другие члены, объявленные с использованием семантики стека, и для них также обеспечивается вызов их .

2. Управляемые шаблоны

И наконец, еще одна замечательная особенность C++/CLI позволяет максимально упростить создание классов-дескрипторов. Речь идет об управляемых шаблонах (managed templates). Это не обобщения (generics), а настоящие шаблоны, как в классическом C++, но шаблоны не родных, а управляемых классов. Инстанцирование таких шаблонов приводит к созданию управляемых классов, которые можно использовать в качестве базовых классов или членов других классов внутри сборки. Управляемые шаблоны описаны в .

Просмотр таблицы дескрипторов с помощью отладчика ядра.

В команде !handle отладчика ядра используются три аргумента: !handle <индекс дескриптора> <флаги> <идентификатор процесса>

Индекс дескриптора идентифицирует запись дескриптора в таблице дескрипторов. (Нуль означает «показать все дескрипторы».) Индекс первого дексритора имеет значение 4, второго — 8 и так далее. Например, после ввода команды !handle 4 будет показан первый дескриптор для текущего процесса.

Флаги можно указать в виде поразрядной маски, где разряд 0 означает «показать только информацию в записи дескриптора», разряд 1 означает «показать свободные (то есть неиспользуемые) дескрипторы, а разряд 2 означает «показать информацию об объекте, на который ссылается дескриптор». Следующая команда приводит к показу всех подробностей о таблице дескрипторов для процесса с идентификатором 0x62C:

lkd> !handle 0 7 62c

processor number 0, process 000000000000062c

Searching for Process with Cid == 62c

PROCESS fffffa80052a7060

SessionId: 1 Cid: 062c Peb: 7fffffdb000 ParentCid: 0558

DirBase: 7e401000 ObjectTable: fffff8a00381fc80 HandleCount: 111.

Image: windbg.exe

Handle table at fffff8a0038fa000 with 113 Entries in use

0000: free handle, Entry address fffff8a0038fa000, Next Entry 00000000fffffffe

0004: Object: fffff8a005022b70 GrantedAccess: 00000003 Entry: fffff8a0038fa010

Object: fffff8a005022b70 Type: (fffffa8002778f30) Directory

ObjectHeader: fffff8a005022b40fffff8a005022b40 (new version)

HandleCount: 25 PointerCount: 63

Directory Object: fffff8a000004980 Name: KnownDlls

0008: Object: fffffa8005226070 GrantedAccess: 00100020 Entry: fffff8a0038fa020

Object: fffffa8005226070 Type: (fffffa80027b3080) File

ObjectHeader: fffffa8005226040fffffa8005226040 (new version)

HandleCount: 1 PointerCount: 1

Directory Object: 00000000 Name: \Program Files\Debugging Tools for Windows (x64)

{HarddiskVolume2}

Первым флагом является бит блокировки, показывающий, что запись в настоящее время используется. Вторым флагом является указатель на возможность наследования, то есть он показывает, получат ли процессы, созданный данным процессом, копию этого дескриптора в свои таблицы дескрипторов. Как уже отмечалось, наследование дескрипторов может быть указано при создании дескриптора или после него с помощью функции SetHandleInformation.

Третий флаг показывает, должно ли закрытие объекта генерировать контрольное сообщение (флаг не показывается в Windows, диспетчер объектов использует его для внутренних нужд). Бит защиты от закрытия хранится в неиспользованной части маски доступа и показывает, разрешено ли вызывающей программе закрыть этот дескриптор (флаг может быть установлен с помощью системного вызова NtSetInformationObject).

Системным компонентам и драйверам устройств зачастую нужно открывать дескрипторы объектов, к которым не должны иметь доступ приложения пользовательского режима. Это делается путем создания дескрипторов в таблице дескрипторов ядра (внутренняя ссылка на которую осуществляется по имени ObpKernelHandleTable).

Дескрипторы в этой таблице доступны только из режима ядра и в контексте любого процесса. Это означает, что функция режима ядра может сослаться на дескриптор в контексте любого процесса, не оказывая отрицательного влияния на производительность системы. Диспетчер объектов распознает ссылки на дескрипторы из таблицы дескрипторов ядра, когда установлен старший бит дескриптора, то есть когда ссылки на дескрипторы из таблицы дескрипторов ядра имеют значение, больше чем 0x80000000.

Таблица дескрипторов ядра также служит в качестве таблицы дескрипторов для процесса System, и все дескрипторы, созданные процессом System (например, кодом, запущенным в системных потоках), автоматически помечаются как дескрипторы ядра, поскольку они размещаются в таблице дескрипторов ядра по определению.

Системные вызовы обработки файлов

В следующей таблице кратко описаны системные вызовы, связанные с обработкой файлов:

%eax Имя системного вызова %ebx %ecx %edx
2 sys_fork struct pt_regs
3 sys_read unsigned int char * size_t
4 sys_write unsigned int const char * size_t
5 sys_open const char * int int
6 sys_close unsigned int
8 sys_creat const char * int
19 sys_lseek unsigned int off_t unsigned int

Необходимые шаги для использования системных вызовов:

   Поместите номер системного вызова в регистр EAX.

   Сохраните аргументы системного вызова в регистрах EBX, ECX и т.д.

   Вызовите соответствующее прерывание ().

   Результат обычно возвращается в регистр EAX.

16.3. Индексные дескрипторы файлов

Каждому файлу на диске соответствует один и только
один индексный дескриптор файла, который идентифицируется своим
порядковым номером — индексом файла. Это означает, что
число файлов, которые могут быть созданы в файловой системе,
ограничено числом индексных дескрипторов, которое либо явно задается
при создании файловой системы, либо вычисляется исходя из физического
объема дискового раздела.

Строение индексного дескриптора файла приведено в
табл. 16.4.

Таблица
16.4.
Структура индексного дескриптора

Название поля

Тип

Описание

i_mode

USHORT

Тип
и права доступа к данному файлу

i_uid

USHORT

Идентификатор
владельца файла (Owner Uid)

i_size

ULONG

Размер
файла в байтах

i_atime

ULONG

Время
последнего обращения к файлу (Access time)

i_ctime

ULONG

Время
создания файла

i_mtime

ULONG

Время
последней модификации файла

i_dtime

ULONG

Время
удаления файла

i_gid

USHORT

Идентификатор
группы (GID)

i_links_count

USHORT

Счетчик
числа связей (Links count)

i_blocks

ULONG

Число
блоков, занимаемых файлом

i_flags

ULONG

Флаги
файла (File flags)

i_reserved1

ULONG

Зарезервировано
для ОС

i_block

ULONG

Указатели
на блоки, в которых записаны данные файла (это поле подробно
описано в разд. 16.4)

i_version

ULONG

Версия
файла (для NFS)

i_file_acl

ULONG

ACL
файла

i_dir_acl

ULONG

ACL
каталога

i_faddr

ULONG

Адрес
фрагмента (Fragment address)

i_frag

UCHAR

Номер
фрагмента (Fragment number)

i_fsize

UCHAR

Размер
фрагмента (Fragment size)

i_pad1

USHORT

Заполнение

i_reserved2

ULONG

Зарезервировано

Поле типа и прав доступа к файлу представляет
собой двухбайтовое слово, каждый бит которого служит флагом,
индицирующим отношение файла к определенному типу или установку
одного конкретного права на файл.

Таблица
16.5.
Структура поля, задающего тип и права доступа

Идентификатор

Значение

Назначение флага (поля)

S_IFMT

F000

Маска
для типа файла

S_IFSOCK

A000

Доменное
гнездо (socket)

S_IFLNK

C000

Символическая
ссылка

S_IFREG

8000

Обычный
(regular) файл

S_IFBLK

6000

Блок-ориентированное
устройство

S_IFDIR

4000

Каталог

S_IFCHR

2000

Байт-ориентированное
(символьное) устройство

S_IFIFO

1000

Именованный
канал (fifo)

S_ISUID

0800

SUID —
бит смены владельца

S_ISGID

0400

SGID —
бит смены группы

S_ISVTX

0200

Бит
сохранения задачи (sticky bit)

S_IRWXU

01C0

Маска
прав владельца файла

S_IRUSR

0100

Право
на чтение

S_IWUSR

0080

Право
на запись

S_IXUSR

0040

Право
на выполнение

S_IRWXG

0038

Маска
прав группы

S_IRGRP

0020

Право
на чтение

S_IWGRP

0010

Право
на запись

S_IXGRP

0008

Право
на выполнение

S_IRWXO

0007

Маска
прав остальных пользователей

S_IROTH

0004

Право
на чтение

S_IWOTH

0002

Право
на запись

S_IXOTH

0001

Право
на выполнение

Среди индексных дескрипторов имеется несколько
дескрипторов, которые зарезервированы для специальных целей и играют
особую роль в файловой системе (табл. 16.6).

Таблица
16.6.
Особые индексные дескрипторы

Идентификатор

Значение

Описание

EXT2_BAD_INO

1

Индексный
дескриптор, в котором перечислены адреса дефектных блоков на диске
(Bad blocks inode)

EXT2_ROOT_INO

2

Индексный
дескриптор корневого каталога файловой системы (Root inode)

EXT2_ACL_IDX_INO

3

ACL
inode

EXT2_ACL_DATA_INO

4

ACL
inode

EXT2_BOOT_LOADER_INO

5

Индексный
дескриптор загрузчика (Boot loader inode)

EXT2_UNDEL_DIR_INO

6

Инлексный
дескриптор каталога для удаленных файлов (Undelete directory
inode)

EXT2_FIRST_INO

11

Первый
незарезервированный индексный дескриптор

Самый важный дескриптор в этом списке —
дескриптор корневого каталога. Этот дескриптор указывает на корневой
каталог, который, подобно всем каталогам, представляет собой
связанный список, состоящий из записей переменной длины. Каждая
запись имеет следующую структуру (табл. 16.7):

Таблица
16.7.
Структура дескриптора, описывающего корневой каталог

Название поля

Тип

Описание

Inode

ULONG

Номер
индексного дескриптора (индекс) файла

Rec_len

USHORT

Длина
этой записи

Name_len

USHORT

Длина
имени файла

Name

CHAR

Имя
файла

Использование
записей переменной длины позволяет использовать длинные имена файлов
без пустой траты дискового пространства. Отдельная запись в каталоге
не может пересекать границу блока (т. е. должна быть расположена
целиком внутри одного блока). Поэтому, если очередная запись не
помещается целиком в данном блоке, она переносится в следующий блок,
а предыдущая запись продолжается таким образом, чтобы она заполнила
блок до конца.

Следующий раздел

Stdin, stdout, and stderr

On a Unix-like operating system, the first three file descriptors, by default, are STDIN (standard input), STDOUT (standard output), and STDERR (standard error).

Name File descriptor Description Abbreviation
Standard input The default data stream for input, for example in a command pipeline. In the terminal, this defaults to keyboard input from the user. stdin
Standard output 1 The default data stream for output, for example when a command prints text. In the terminal, this defaults to the user’s screen. stdout
Standard error 2 The default data stream for output that relates to an error occurring. In the terminal, this defaults to the user’s screen. stderr

Operations on file descriptors

The following lists typical operations on file descriptors on modern Unix-like systems. Most of these functions are declared in the header, but some are in the header instead.

Creating file descriptors

  • open()
  • creat()
  • socket()
  • accept()
  • socketpair()
  • pipe()
  • epoll_create() (Linux)
  • signalfd() (Linux)
  • eventfd() (Linux)
  • timerfd_create() (Linux)
  • memfd_create() (Linux)
  • userfaultfd() (Linux)
  • fanotify_init() (Linux)
  • inotify_init() (Linux)
  • clone() (with flag CLONE_PIDFD, Linux)
  • pidfd_open() (Linux)
  • open_by_handle_at() (Linux)

Operations on a single file descriptor

  • read(), write()
  • readv(), writev()
  • pread(), pwrite()
  • recv(), send()
  • recvfrom(), sendto()
  • recvmsg(), sendmsg() (also used for sending FDs to other processes over a Unix domain socket)
  • recvmmsg(), sendmmsg()
  • lseek(), llseek()
  • fstat()
  • fstatvfs()
  • fchmod()
  • fchown()
  • ftruncate()
  • fsync()
  • fdatasync()
  • fdopendir()
  • fgetxattr(), fsetxattr() (Linux)
  • flistxatrr(), fremovexattr() (Linux)
  • statx (Linux)
  • setns (Linux)
  • vmsplice() (Linux)
  • pidfd_send_signal() (Linux)
  • waitid() (with P_PIDFD ID type, Linux)
  • fdopen() (stdio function:converts file descriptor to FILE*)
  • dprintf() (stdio function: prints to file descriptor)

Operations on multiple file descriptors

  • select(), pselect()
  • poll(), ppoll()
  • epoll_wait(), epoll_pwait() (Linux, takes a single epoll filedescriptor to wait on many other file descriptors)
  • epoll_ctl() (for Linux)
  • kqueue() (for BSD-based systems).
  • sendfile()
  • splice(), tee() (for Linux)
  • copy_file_range() (for Linux)

Operations on the file descriptor table

The fcntl() function is used to perform various operations on a file descriptor, depending on the command argument passed to it. There are commands to get and set attributes associated with a file descriptor, including F_GETFD, F_SETFD, F_GETFL and F_SETFL.

  • close()
  • closefrom() (BSD and Solaris only; deletes all file descriptors greater than or equal to specified number)
  • dup() (duplicates an existing file descriptor guaranteeing to be the lowest number available file descriptor)
  • dup2(), dup3() (Close fd1 if necessary, and make file descriptor fd1 point to the open file of fd2)
  • fcntl (F_DUPFD)

Operations that modify process state

  • fchdir() (sets the process’s current working directory based on a directory file descriptor)
  • mmap() (maps ranges of a file into the process’s address space)

Sockets

  • connect()
  • bind()
  • listen()
  • accept() (creates a new file descriptor for an incoming connection)
  • getsockname()
  • getpeername()
  • getsockopt()
  • setsockopt()
  • shutdown() (shuts down one or both halves of a full duplex connection)

Miscellaneous

ioctl() (a large collection of miscellaneous operations on a single file descriptor, often associated with a device)

Просмотр открытых дескрипторов.

Запустите Process Explorer и убедитесь, что нижняя панель включена и настроена на показ открытых дескрипторов. (View (Вид) — Lower Pane View (Просмотр нижней панели) — Handles (Дескрипторы)). После этого откройте окно командной строки и просмотрите таблицу дескрипторов для нового процесса Cmd.exe. Вы должны увидеть дескриптор открытого файла для текущего каталога. Например, предположим, что текущим является каталог C:\Users\Administrator, тогда Process Explorer покажет следующее.

Теперь поставьте Process Explorer на паузу, нажав клавишу Пробел или щелкнув на пунктах View (Вид) — Update Speed (Изменить скорость) — Pause (Пауза).

Затем измените текущий каталог с помощью команды cd и нажмите клавишу F5, чтобы обновить отображаемую информацию. Вы увидите в Process Explorer, что дескриптор предыдущего текущего каталога закрыт и открыт новый дескриптор для нового текущего каталога. Предыдущий дескриптор выделен красным цветом, а новый дескриптор выделен зеленым цветом.

Свойство выделения разным цветом, имеющееся в Process Explorer, делает заметнее изменения в таблице дескрипторов. Например, если процесс допускает утечку дескрипторов, просмотр таблицы дескрипторов с помощью Process Explorer может быстро показать, какой дескриптор или какие дескрипторы были открыты, но не были закрыты. (Обычно виден длинный список дескрипторов для одного и того же объекта.) Эта информация поможет программисту обнаружить утечку дескрипторов.

Монитор ресурсов также показывает открытые (именованные) дескрипторы для процессов, выбранных путем установки флажков напротив их имен. Вот как выглядят дескрипторы открытого окна командной строки.

Таблицу открытых дескрипторов можно также вывести, используя средство командной строки Handle из серии программных продуктов Sysinternals.

Посмотрите, к примеру, на следующий, частично показанный вывод, полученный с помощью средства Handle при изучении дескрипторов файловых объектов, находящихся в таблице дескрипторов для процесса Cmd.exe до и после изменения каталога. По умолчанию Handle отфильтровывает нефайловые дескрипторы, пока не будет использован ключ –a, который приводит к выводу всех дескрипторов в процессе, аналогично Process Explorer.

C:\>handle -p cmd.exe

Handle v3.46

Copyright (C) 1997-2011 Mark Russinovich

Sysinternals — www.sysinternals.com

———————————————————————-

cmd.exe pid: 5124 Alex-Laptop\Alex Ionescu

3C: File (R-D) C:\Windows\System32\en-US\KernelBase.dll.mui

44: File (RW-) C:\

C:\>cd windows

C:\Windows>handle -p cmd.exe

Handle v3.46

Copyright (C) 1997-2011 Mark Russinovich

Sysinternals — www.sysinternals.com

———————————————————————-

cmd.exe pid: 5124 Alex-Laptop\Alex Ionescu

3C: File (R-D) C:\Windows\System32\en-US\KernelBase.dll.mui

40: File (RW-) C:\Windows

Дескриптор объекта является индексом в таблице дескрипторов, относящейся к конкретному процессу. Этот индекс указывается исполнительным блоком процесса (EPROCESS). Первый индекс дескриптора имеет значение 4, второй — 8 и т. д. Таблица дескрипторов процесса содержит указатели на все объекты, которые процесс открыл для своей работы.

Таблицы дескрипторов реализованы по древовидной схеме, подобной той, которую реализует блок управления памятью x86 для перевода виртуальных адресов в физические, которая дает максимальное значение, превышающее 16 000 000 дескрипторов на процесс.

При создании процесса выделяется только таблица дескрипторов самого низкого уровня, другие уровни создаются по мере необходимости. Таблица дескрипторов нижнего уровня состоит из такого количества записей, которое может поместиться на странице минус одна запись, которая используется для контроля дескрипторов.

Например, для систем x86 страница составляет 4096 байт и поделена на записи таблицы дескрипторов размером 8 байт, которых получается 512 минус 1, то есть всего 511 записей в таблице дескрипторов самого низкого уровня. Таблица дескрипторов среднего уровня содержит полную страницу указателей на таблицы нижнего уровня, поэтому количество таблиц дескрипторов нижнего уровня зависит от размера страницы и размера указателя для платформы. Схема таблицы дескрипторов в системе Windows показана на следующем рисунке.

Usage

const isDescriptor = require('is-descriptor');

isDescriptor({ value: 'foo' })
//=> true
isDescriptor({ get: function() {}, set: function() {} })
//=> true
isDescriptor({ get: 'foo', set: function() {} })
//=> false

You may also check for a descriptor by passing an object as the first argument and property name () as the second argument.

const obj = {};
obj.foo = null;

Object.defineProperty(obj, 'bar', { value: 'xyz' });
Reflect.defineProperty(obj, 'baz', { value: 'xyz' });

isDescriptor(obj, 'foo'); //=> true
isDescriptor(obj, 'bar'); //=> true
isDescriptor(obj, 'baz'); //=> true

CDC + MSC Composite Device

А теперь со всей этой фигней мы попробуем взлететь (С) анекдототсюда

  • У нас будет всего одна конфигурация, а в ней 3 интерфейса
  • Один интерфейс реализует MSC
  • CDC реализуется двумя интерфейсами.
    • Первый для управления. У него одна однонаправленная конечная точка для управления интерфейсом
    • Второй интерфейс CDC для данных. У него двунаправленная конечная точка — для передачи и приема
  • Еще одна конечная точка нужна для управления устройство в целом (реализуется ядром USB библиотеки)

Красивая картинка, которая описывает пример описания композитного устройства. Взято из спецификации IADспецификации этого дескриптора

Любую архитектурную проблему можно решить введением дополнительного абстрактного слоя… (С) еще один анекдот

отсюдаТутfrondersвыделятьКартинка из Reference Manual микроконтроллеров серии STM32F103бубном fronders

Descriptor Example¶

The following code creates a class whose objects are data descriptors which
print a message for each get or set. Overriding is
alternate approach that could do this for every attribute. However, this
descriptor is useful for monitoring just a few chosen attributes:

class RevealAccess(object):
    """A data descriptor that sets and returns values
       normally and prints a message logging their access.
    """

    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print('Retrieving', self.name)
        return self.val

    def __set__(self, obj, val):
        print('Updating', self.name)
        self.val = val

>>> class MyClass(object):
...     x = RevealAccess(10, 'var "x"')
...     y = 5
...
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20
>>> m.y
5

Descriptor Protocol¶

That is all there is to it. Define any of these methods and an object is
considered a descriptor and can override default behavior upon being looked up
as an attribute.

If an object defines or , it is considered
a data descriptor. Descriptors that only define are called
non-data descriptors (they are typically used for methods but other uses are
possible).

Data and non-data descriptors differ in how overrides are calculated with
respect to entries in an instance’s dictionary. If an instance’s dictionary
has an entry with the same name as a data descriptor, the data descriptor
takes precedence. If an instance’s dictionary has an entry with the same
name as a non-data descriptor, the dictionary entry takes precedence.

Definition and Introduction¶

In general, a descriptor is an object attribute with “binding behavior”, one
whose attribute access has been overridden by methods in the descriptor
protocol. Those methods are , , and
. If any of those methods are defined for an object, it is
said to be a descriptor.

The default behavior for attribute access is to get, set, or delete the
attribute from an object’s dictionary. For instance, has a lookup chain
starting with , then , and
continuing through the base classes of excluding metaclasses. If the
looked-up value is an object defining one of the descriptor methods, then Python
may override the default behavior and invoke the descriptor method instead.
Where this occurs in the precedence chain depends on which descriptor methods
were defined.

Немного теории

Usb in a nutshellпереводUSB Made Simpleспецификации для конкретных классов USB устройств

  • Дескриптор устройства (Device Descriptor) — описывает устройство в целом, его название, производитель, серийный номер. Строковые данные описываются отдельными строковыми дескрипторами (String Descriptor)
  • Дескриптор конфигурации (Configuration Descriptor) — устройство может иметь одну или несколько конфигураций. Каждая конфигурация определяет скорость общения с устройством, набор интерфейсов и параметры питания. Так, например, ноутбук, который работает от батареи, может попросить устройство (выбрать конфигурацию) использовать более низкую скорость обмена и переключиться на собственный источник питания (вместо ноутбучной батареи). Разумеется это работает только если устройство предоставляет такую конфигурацию.
  • Дескриптор интерфейса (Interface descriptor) — описывает интерфейс общения с устройством. Интерфейсов может быть несколько. Например разные функции (MSC, CDC, HID) будут реализовывать свои интерфейсы. Некоторые функции (например CDC или DFU) реализуют сразу несколько интерфейсов для своей работы. В нашем случае композитного устройства нам потребуется реализовать сразу несколько интерфейсов от разных функций и заставить их ужиться друг с другом.
  • Дескриптор конечной точки (Endpoint descriptor) — описывает канал связи в рамках конкретного интерфейса, задает размер пакета, описывает параметры прерываний. Используя конечные точки мы будем получать и принимать данные.
  • Есть еще куча разных дескрипторов, которые описывают отдельные аспекты конкретных интерфейсов

Ошибка номер 1400

Данная проблема часто встречается в семействе операционных систем Windows. При её появлении вместе с ней может быть и краткое описание — недопустимый дескриптор окна. А может встречаться и такая формулировка — «Error_invalid_window_handle» или 0х578.

Как бороться и что значит неверный дескриптор? В зависимости от контекста объекта, нужно принимать разные меры.

В любом случае стоит сразу же пройтись по стандартным мерам, принимаемым ко всем проблемам с системой:

  • перезагрузка компьютера;
  • запуск и сканирование ошибки с помощью утилиты проверки целостности системных файлов;
  • проверить компьютер на вирусы.

Если базовые шаги не помогли, то, возможно, стоит удалить и снова установить приложение, которое вызывает сбой.

Ещё один надёжный способ быстро восстановить работоспособность системы — сделать её откат с помощью стандартных инструментов. После использования «Восстановления системы», она вернётся к последней действующей резервной копии, при условии что она была ранее создана.

HTML

В языке разметки гипертекста, который применяется для создания статичных веб-страниц, дескрипторы — это не что иное, как тэги. В этой среде они выполняют роль меток, благодаря которым текст, размещённый между ними, отображается определенным способом. Таким образом и формируется дизайн и расположение элементов на странице.

Как правило, специфика языка определяет наличие открывающего дескриптора и закрывающего. Все, что между ними, подвержено изменению.

Дескриптор может иметь атрибуты, то есть определённые свойства. Их синтаксис выглядит так: имя атрибута = его значение.

Подчиняясь общей логике, дескрипторы в HTML представляют собой идентификационные метки объектов. С их помощью можно управлять внешним видом, взаимодействовать со страницей и присваивать ей особые значения.

CDC — виртуальный COM порт

переехал на STM32 CubeCube для контроллеров серии STM32F1графического конфигуратора CubeMXusb in a nutshellна русском

bDeviceClass, bDeviceSubClass и bDeviceProtocol — описывают хосту что же это у нас за устройство такое, что оно умеет и какие драйвера нужно грузить. В данном случае тут сказано, что устройство у нас реализует Communication Device Class, а значит хосту нужно сделать виртуальный COM порт и связать его с этим устройством.
PID (Product ID) и VID (Vendor ID) — по этим полям хост различает разные устройства, подключенные к системе. Устройства при этом реализовывать одинаковый класс

Говорят для устройств продаваемых на рынке очень важно иметь уникальные VID/PID, но я не узнавал кто и где выдает эти ID-шники. Для домашнего устройства в единственном экземпляре достаточно значений по умолчанию.

  • wTotalLength — размер всего пакета дескрипторов для этой конфигурации — чтобы хост знал где заканчивается эта конфигурация и начинается следующая. Нам его нужно будет поправить, когда мы будем делать композитное устройство. Напомню, что все интерфейсы для этой конфигурации должны располагаться сплошным блоком, а значение wTotalLength определяет длину этого блока.
  • bNumInterfaces: класс Communication Device реализуется с помощью двух интерфейсов. Один для управления, другой для собственно пересылаемых данных.
  • bmAttributes и MaxPower указывает, что наше устройство имеет собственный источник питания, но при этом хочет потреблять до 100 мА от USB порта. С этими параметрами явно придется поиграться в будущем.
  • Class Driver (в случае CDC это файлы usbd_cdc и usbd_cdc_if): реализуют логику конкретного класса устройств — CDC для виртуального COM порта, MSC для устройств хранения данных, HID для клавиатур/мышек и всяких специфических устройств с пользовательским интерфейсом.
  • USB Core (usbd_core.c, usbd_ctlreq.c, usbd_ioreq.c): реализует общую логику работы всех классов USB устройств, умеет отдавать хосту запрашиваемые дескрипторы, обрабатывает запросы от хоста и настраивает USB устройство в целом. Также перенаправляет потоки данных из уровня драйвера класса в нижележащие уровни и наоборот.
  • USB HW Driver (usbd_conf.c): Вышележащие слои платформенно независимые и работают одинаковым образом для нескольких серий микроконтроллеров. В коде нет низкоуровневых вызовов функций конкретного микроконтроллера. Файл usbd_conf.c реализует прослойку между USB Core и HAL — библиотеке низкоуровневых драйверов для выбранного микроконтроллера. В основном тут живут простые врапперы, которые перенаправляют вызовы сверху вниз и коллбеки снизу вверх.
  • HAL (stm32f1xx_hal_pcd.c, stm32f1xx_ll_usb.c): занимаются общением с железом микроконтроллера, оперирует регистрами и отвечает на прерывания.

тут Virtual COM Port драйвер от STM

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector