Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: 1 2 3 [Все]   Вниз
  Печать  
Автор Тема: Реализация буфера данных в USB-драйвере.  (Прочитано 116386 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Bulat
Участник

ru
Offline Offline

« : 17-06-2010 05:40 » 

Решаю всю ту же проблему, что была обозначена в конце темы https://forum.shelek.ru/index.php/topic,24622.0.html. А именно, мой USB-девайс при работе с драйвером, созданным в DS 3.2 пропускает данные на медленных машинах (PIV) и не пропускает данные на машине Core 2 Duo, при условии, если не запущены приложения, требующие значительных ресурсов (Opera). Отсюда сделал вывод, что пропуски могут проходить на уровне драйвера. Девайс работает следующим образом: подготовив данные для передачи по USB (заполнив FIFO UDP-модуля контроллера, отвечающего за работу с USB), ставит флаг готовности для передачи пакета данных размером 60 байт по USB. Далее ожидает, пока придет запрос от Хоста и уже после этого начинает передачу данных. Запросы формирует драйвер, который в свою очередь принимает их от приложения. Если я правильно понял, то в медленных или загруженных другими приложениями эти запросы могут задерживаться и в случае маленького буфера для запросов - теряться. Таким образом, какой смысл делать большой буфер для принимаемых драйвером от девайса данных, если при этом запросы на считывание этих данных приложением будут поступать с той же  частотой или реже?
Что вы посоветуете для решения подобной проблемы?
Заранее благодарен!
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 17-06-2010 08:09 » 

Цитата: Bulat
не пропускает данные на машине Core 2 Duo, при условии, если не запущены приложения, требующие значительных ресурсов (Opera). Отсюда сделал вывод, что пропуски могут проходить на уровне драйвера.

Не могу понять логическую цепь, которая приводит к такому выводу.

Цитата: Bulat
в медленных или загруженных другими приложениями эти запросы могут задерживаться и в случае маленького буфера для запросов - теряться

Теряться не могут. Что касается задержек, то если драйвер работает на уровне меньше DISPATCH_LEVEL, то поток, в контексте которого выполняется код драйвера, ничем не лучше и не хуже любых других потоков.
Записан
Bulat
Участник

ru
Offline Offline

« Ответ #2 : 17-06-2010 09:02 » 

Цитата
Не могу понять логическую цепь, которая приводит к такому выводу.
Потому что само приложение простое - в одном потоке считывает данные из драйвера, в другом записывает в статический массив. С одним и тем же драйвером проверял на двух девайсах, одинаковых по функциональности,но реализованных на разных контроллерах, ситуация одинаковая - оба пропускают на машинах типа  PIV и не пропускают на Core 2Duo. Отсюда, методом исключения сделал вывод, что во всем виноват драйвер Улыбаюсь
Цитата
Теряться не могут. Что касается задержек, то если драйвер работает на уровне меньше DISPATCH_LEVEL, то поток, в контексте которого выполняется код драйвера, ничем не лучше и не хуже любых других потоков.
А где приоритет работы драйвера устанавливается?
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 17-06-2010 11:45 » 

А что такое приоритет драйвера?

Есть серьезное подозрение, что "приоритет драйвера" тут вообще не при чем. Вот кривонаписанный драйвер или юзермодная часть, это запросто.
Записан
Bulat
Участник

ru
Offline Offline

« Ответ #4 : 18-06-2010 03:55 » 

1.Драйвер собиралв DS 3.2. Никаких своих изменений не вносил. Пошаговая сборка приведена в прикрепленном архиве.
2.В приложении я просто в отдельных потоках выполняю readfile и writefile в синхронном режиме:
Код:
UINT TransmitThread( LPVOID pParam )
{
    ...
    while(update == 0)
    {
        //считывание данных из статического массива в buf_w
        ...
        Success = WriteFile(PipeOut, &buf_w, 60, &nBytes, NULL);
        ...
     }
     return 0;   // thread completed successfully
     AfxEndThread(0, TRUE);
}
UINT ReceiveThread( LPVOID pParam )
{
    ....
    while(stop_r == 0)
    {
         ...
         RealRead = 0;
         ReadFile(PipeIn, &buf_r, 60, &RealRead, NULL);
         //запись данных в статический массива из buf_r
         ...
    }
    return 0;
    AfxEndThread(0, TRUE);
}

* скриншоты.zip (343.15 Кб - загружено 1056 раз.)
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 20-06-2010 09:46 » 

тут кстати не факт что драйвер виноват...
к сожалению не знаю как для USB реализована передача пакетов, но для 1394 было так.
1. устройство накапливает пакет, и тут же его выплевывает в шину и ждет подтверждения приема.
2. ПК автоматически принимает этот пакет в ISR (видимо), разбирает его, и ставит в очередь DPC драйверу. а так же генерит второй "системный" DPC, для отправки устройству пакета подтверждения приема.
3. драйвер обрабатывает DPC.
4. устройство получает подтверждение и только после этого!!! освобождает FIFO отправленного пакета, и может отправить следующий пакет(но тут возможны варианты, зависит от алгоритма железа)
5. в некоторых случаях в устройстве стоит FIFO на  несколько пакетов, чтобы повысить пропускную способность на малом отрезке времени. в противном случае -  нагрузка на fifo становится импульсной, что может привести к его переполнению.

для 1394 существовал второй режим, когда подтверждения приема должен был отправить пользовательский драйвер.
1. устройство накапливает пакет, и тут же его выплевывает в шину и ждет подтверждения приема.
2. ПК автоматически принимает этот пакет в ISR (видимо), разбирает его, и ставит в очередь DPC драйверу. но НЕ генерит второй "системный" DPC, для отправки устройству пакета подтверждения приема.
3. драйвер обрабатывает DPC, в котором он обязан отослать пакет подтверждения (или то что он сочтет нужным)
4. устройство получает подтверждение и только после этого!!! освобождает FIFO отправленного пакета.
второй способ позволил мне избавиться от удвоения количества DPC на один переданный пакет, и немного уменьшить импульсную нагрузку на аппаратное FIFO.
в обоих случаях - скорость может быть ограничена большим временем отклика на принятый пакет.
кроме того выяснилось, что кривой драйвер CD-ROM на некоторых ПК тормозит очередь DPC на единицы  мс.

в вашем случае, возможно, проблема именно в размере FIFO самого устройства.
на медленных и загруженных ПК, комп может обрабатывает очередь DPC с задержками. из за этого может падает скорость.

теперь неплохо бы подтвердить эту идею... я к сожалению, каким то макаром, отключил счетчики производителсьности на своей машине. так что попробуйте посмотреть у себя.
панель управления-> администрирование-> счетчики производительности:
добавьте отслеживание количества DPC и соотнесите со скоростью вашего потока. если я прав то количество вызовов  будет соответствовать скорости потока деленной на 60 байт.

PS это я по аналогии с 1394 предлагаю сделать, но я не уверен что реализация USB сделана именнно так(времени разобраться - у меня совсем нема)
если кто-то знает точнее  - опровергайте!
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #6 : 16-08-2010 11:26 » 

Здравствуйте) По производственным причинам пришлось отложить этот вопрос. Извиняюь, что спустя такое время, опять его поднимаю, но он все еще остается для меня открытым.
По вашей рекомендации посмотрел счетчики производительности. Прикрепляю 2 скриншота. На изображении "Core2.jpg" приведен график, который снят на машине Core2Duo c 1Гб ОЗУ. То есть на графике отображен тот момент времени, когда мой девайс активно передавал принимал данные от ПК по USB. На картинке же "PIV_1,8HGz.jpg" приведен  график, снятый соответственно на машине PIV с 256 Мб ОЗУ. Видно, что характеристика "% времени DPC" имеет периодические всплески на машине PIV, в отличие от Core2. Именно на машине PIV моя тестовая программа для ПК фиксирует пропуски данных, принимаемых от девайса (возможно и передаваемых на девайс тоже), а на Core2 пропусков нет. Девайс работает с интерфейсом Arinc, со скоростью приема и передачи данных 100 кбит/с. Размер одного слова 4 байта. Для передачи по USB девайс разбивает принятое по Аринку слово на байты и формирует пакеты по 60 байт, затем отправляет их на ПК.


* Core2 (141.99 Кб - загружено 3171 раз.)
* PIV_1,8HGz (114.48 Кб - загружено 3076 раз.)
« Последнее редактирование: 04-07-2011 13:28 от Ochkarik » Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 16-08-2010 12:47 » 

у вас на скриншотах самый важный параметр "поставлено в очередь DPC" зашкалил.
отмасштабируйте плс) он должен строго соответствовать скорости поступления ваших USB пакетов:100кбит/60 байт=208 DPC/сек. возможно в этом параметре будут различия... хотя, там DPC еще системные будут...
в любом случае любопытно взглянуть.

да, и введите контроль поступления прямо в драйвере - необходимо отловить кто виноват: драйвер или приложение.
« Последнее редактирование: 16-08-2010 12:51 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #8 : 17-08-2010 05:07 » 

Прикладываю отмаштабированные графики под сетчик "поставлено в очередь DPC/сек", а также график с системными DPC. И еще, мой девайс принимает из Аринк одновременно по 2-м каналам, каждый по 100 кбит/с, то есть реальный входной поток в по USB ПК составляет 200 кбит/с. Но всеравно  счетчик поставленных в очередь DPC слишком велик, причем на машине Core2 он больше. Напомню, что в процессе эксперимента на машине Core2 пропуски принимаемых от девайса данных не зафиксированы, а на PIV их 10-ки тысяч (за 1-2 мин наблюдений). При этом счетчики скорости записи и чтения данных  на моем тестовом приложении падают. Например, если скорость записи на мой девайс на машине core2 составляет ~14 кбайт/с, то на PIV около 12 кбайт/с, соответственно и скорость чтения из девайса 28 и 24 кбайт/с.
На графике, снятом на PIV наблюдаются значительные всплески в процессе работы (кроме тестового приложения и счетчика производительности ничего не запущено).
А как ввести контроль поступления прямо в драйвер?



* Core2_1.JPG (106.93 Кб - загружено 3233 раз.)
* PIV_1,8HGz_1.JPG (84.51 Кб - загружено 2890 раз.)
* Системный_Сore2.JPG (98.04 Кб - загружено 3163 раз.)
« Последнее редактирование: 04-07-2011 13:29 от Ochkarik » Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 17-08-2010 10:19 » 

ну что сказать.. явно на второй машине кто то много времени в DPC занимает. возможно чей то кривой драйвер...
хм... а попробуйте лишнее оборудование отключить в дереве устройств. CD-ром например... что там еще не нужного

контроль... ну точно так же как в приложении. у вас очередность пакетов как-то помечается?
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #10 : 17-08-2010 10:50 » 

так ведь драйвер одинаковый на обеих машинах.
Цитата
контроль... ну точно так же как в приложении.
Это вы имеете в виду выбрать Объект, при выборе счетчика? Там у меня в качестве объекта выбран "Процессор".
Цитата
у вас очередность пакетов как-то помечается?
Не совсем понял где они должны помечаться?)

У меня в девайсе при приеме данных от ПК используется две страницы FIFO буфера, то есть пока разбирается первый пакет в 60 байт, второй может приниматься по USB от ПК. А при передаче на ПК я пользуюсь одной страницей. То есть, заполняю FIFO, затем ставлю флаг на отправку и пока ПК не считает данные из FIFO моего девайса, я туда больше ничего записать не могу. Я рассчитываю на то, что скорость передачи данных по USB гораздо выше 100 кбит/с, поэтому ПК должен успеть считать все 60 байт и отправить подтверждение, пока девайс принимает по Аринку следующее 32-битное слово. Так как, 32-битное слово с 40 мкс паузой по каналу Аринк девайс принимает за 360 мкс. За эти 360 мкс по USB 2.0 можно переслать 4320 бит (12 Мбит/с), а реально нужно успеть отправить лишь 60 байт (480 бит).
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 17-08-2010 12:13 » 

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

и ваш расчет скоростей  не совсем  верен. оно конечно 12 мбит и все дела. но только все забывают при каких условиях эти 12 мбит? это поди использование 4кб пакетов, и фифо на несколько страниц на обоих концах. а то что комп программно каждый пакет обрабатывает - все молчат.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #12 : 18-08-2010 03:35 » 

меня смущает то, что на медленных машинах скорость записи на мой девайс ( PIV) около 12 кбайт/с, что на 2 кбайт/с ниже чем на Core2. То есть, "слабый" ПК посылает по USB с уже заниженной скоростью, поэтому я и смотрю в сторону драйвера...
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 19-08-2010 10:20 » 

тогда попробуйте смотреть в сторону связки драйвера с приложением... возможно в этом суть... а вообще скорости смешные)) независимо от машины.
и еще смотрите в сторону реализации буфера в железе. почитайте Агурова, сколько там таймауты между пакетами могут быть.
что еще можно посоветовать..... попробуйте перенести код приложения сразу в драйвер.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #14 : 26-08-2010 04:34 » 

Почему Driver studio не дает возможность использовать буферы данных для конечных точек при обработке запросов IRP_MJ_READ и IRP_MJ_WRITE и при попытке установки Bufferd method выдает сообщение о том, что только Direct method можно использовать с конечными точками (см. скриншот в прикрепленном файле)? Ведь мне как раз и необходимо буферизовать данные.

* DS.JPG (59.58 Кб - загружено 1133 раз.)
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 26-08-2010 11:47 » 

угу. тока это не совсем тот буфер)
это просто промежуточная операция копирования входных/выходных данных. с точки зрения быстродействия - ничего особо не изменится.
это НЕ FIFO!
размер буфера в точности равен размеру max(входных, выходных) данных IOCTL.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #16 : 09-09-2010 10:46 » 

   Я еще раз хотел бы расписать все положения моего вопроса и, таким образом, корректнее перейти к интересующим меня вопросам.
Мое USB-устройство низкоскоростное (100 кбит/с - скорость приема и передачи). В самом устройстве буферы маленькие и нет возможности реализовать больший буфер. Поэтому для синхронизации с высокоскоростным протоколом USB нужно сформировать буфер данных на прием и передачу в драйвере устройства (подобный тому, что есть в драйвере USB-устройства, имитирующего com-порт).
У меня имеется драйвер, сгенрированный DS 3.2, c Direct методом записи и чтения. 
   Считывание данных из устройства в конечную точку Pipe0 осуществляется следующим образом:
Код:
NTSTATUS A5M2Pipe0Io(
    IN  PA5M2_DEVICE_EXTENSION   DeviceExtension,
    IN  PIRP                                Irp,
    IN  PUSBD_PIPE_INFORMATION              PipeInformation
    )
{
    PA5M2_IO_CONTEXT ioContext;
    NTSTATUS                    status;
    PUCHAR                      virtualAddress;
    ULONG                       totalLength;
    ULONG                       transferLength;
    PMDL                        mdl;
    PURB                        urb;
    PIO_STACK_LOCATION          irpStack;

    A5M2DebugPrint(DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp);

    // we will use do{}while(FALSE); structure
    // for resources cleanup
    status = STATUS_SUCCESS;
    ioContext = NULL;
    mdl = NULL;

    do
    {
        Irp->IoStatus.Information = 0;

        // allocate io context to pass to completion routine
        ioContext = (PA5M2_IO_CONTEXT)ExAllocatePoolWithTag(
                                                    NonPagedPool,
                                                    sizeof(A5M2_IO_CONTEXT),
                                                    A5M2_POOL_TAG
                                                    );

        if (ioContext == NULL)
        {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        if (Irp->MdlAddress != NULL)
        {
            totalLength = MmGetMdlByteCount(Irp->MdlAddress);
        }
        else
        {
            totalLength = 0;
        }

        if (totalLength == 0)
        {
            status = STATUS_SUCCESS;
            break;
        }

        virtualAddress = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress);

        if (totalLength > USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE)
        {
            transferLength = USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
        }
        else
        {
            transferLength = totalLength;
        }

        mdl = IoAllocateMdl(virtualAddress, totalLength, FALSE, FALSE, NULL);
        if (mdl == NULL)
        {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        IoBuildPartialMdl(Irp->MdlAddress, mdl, virtualAddress, transferLength);

        urb = (PURB)ExAllocatePoolWithTag(
                        NonPagedPool,
                        sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                        A5M2_POOL_TAG
                        );

        if (urb == NULL)
        {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        UsbBuildInterruptOrBulkTransferRequest(
            urb,
            sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
            PipeInformation->PipeHandle,
            NULL,
            mdl,
            transferLength,
            USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
            NULL
            );
...

То есть, создается mdl и туда записываются данные принятые от устройства. Если мне вводить свой буфер, тогда функция UsbBuildInterruptOrBulkTransferRequest  будет выглядеть следующим образом:

Код:
            UsbBuildInterruptOrBulkTransferRequest(
            urb,
            sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
            PipeInformation->PipeHandle,
            MyBuffer,                                                              //буфер для хранения принятых данных                                                                             
            NULL,
            transferLength,
            USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
            NULL
            );
   Так вот, объем данных, который будет записан в MyBuffer будет равен transferLength, то есть равен объему данных, запрашиваемых приложением. Мне же необходимо, чтобы считывание данных из устройства проходило постоянно, независимо от прихода запросов от приложения и , чтобы эти данные накапливались в MyBuffer, а при приходе запроса от приложения часть данных определяемая  transferLength копировалась бы в созданную ранее mdl.
   Насколько я понимаю, функция A5M2Pipe0Io вызывается при каждом запросе на чтение, пришедшем  от приложения. Получается для моего случая нужно писать отдельную процедуру, которая многократно выполняет функцию UsbBuildInterruptOrBulkTransferRequest и производит запись в MyBuffer, а  A5M2Pipe0Io будет переписывать данные из MyBuffer в mdl, но без выполнения функции UsbBuildInterruptOrBulkTransferRequest?
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 09-09-2010 11:39 » 

да, все верно. направление ввода DIRECTION только не перепутайте) это может быть отдельная нитка в драйвере.

либо вы можете попробовать использовать формирование очереди на базе асинхронных запросов к драйверу.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #18 : 13-09-2010 10:03 » 

Начал реализовывать, описанное выше, в коде и столкнулся с рядом вопросов.
1.Где инициализировать и запускать процедуру, которая будет непрерывно считывать данные из девайса в буфер?
Я решил проинициализировать ее в заголовочном файле А5М2.h, в котором у меня проинициализированы все  точки входа в драйвер.
Код:
VOID A5M2RcvData(
     IN  PA5M2_DEVICE_EXTENSION   DeviceExtension,
     IN  PIRP                                Irp,
     IN  PUSBD_PIPE_INFORMATION              PipeInformation
Запускаю же в точке входа A5M2AddDevice
Код:
A5M2RcvData(
IoContext->DeviceExtension,
IoContext->Irp,
IoContext->PipeInformation
);
2. Где создать буфер, в котором будут накапливаться принятые от девайса данные?
Решил проинициализировать его также в заголовочном файле А5М2.h в структуре
Код:
_A5M2_DEVICE_EXTENSION { ...
PVOID MyBuffer[1000];}

3. Как осуществить непрерывный прием данных из девайса в буфер?
Функцию A5M2RcvData разместил в файле usb.c, там же, где и функция A5M2Pipe0Io.
Код:
//++++++++++++++++++Функция непрерывного приема данных из девайса++++++++++++
VOID A5M2RcvData(
     IN  PA5M2_DEVICE_EXTENSION   DeviceExtension,
     IN  PIRP                                Irp,
     IN  PUSBD_PIPE_INFORMATION              PipeInformation
    )
{
    PA5M2_IO_CONTEXT ioContext;
    ULONG                       transferLength;
    PURB                        urb;

transferLength = 60;

urb = (PURB)ExAllocatePoolWithTag(
                        NonPagedPool,
                        sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                        A5M2_POOL_TAG
                        );

if (urb == NULL)
              {
                 status = STATUS_INSUFFICIENT_RESOURCES;
                 break;
              }


                  UsbBuildInterruptOrBulkTransferRequest(
                  urb,
                  sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                  PipeInformation->PipeHandle,
                  &deviceExtension->MyBuffer,
                  NULL,
                  transferLength,
                  USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
                  NULL
                  );

    // save io parameters in our io context
                  ioContext->DeviceExtension = DeviceExtension;
                  ioContext->Urb = urb;

    return;
}
А как ее непрерывно вызывать? не в поток же ставить с циклом while(1)..

4. Как переписать данные из MyBuffer в mdl, который был создан в A5M2Pipe0Io? В предыдущем посте я приводил код A5M2Pipe0Io и там принятые от девайса данные писались в mdl с помощью функции UsbBuildInterruptOrBulkTransferRequest. А как переписывать в моем случае?

Заранее спасибо за ответы!
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 13-09-2010 11:33 » 

1. там где вам удобно) я не совсем понял при чем тут вообще h-файл?)
вы перед программированием сначала продумайте, как оно у вас в теории работать должно. по шагам. или в виде блок схемы. и только потом задавайте себе вопросы. если вы правильно будете формулировать вопрос - в нем будет содержаться процентов 80 необходимого вам ответа.

2.
_A5M2_DEVICE_EXTENSION { ...
PVOID    MyBuffer[1000];}
-это не инициализация а объявление переменной, чтоб вы знали.

3. вы так не шутите))) оно конечно while(1) в конечном счете будет, но вы сначала подймайте
еще раз посмотрите на алгоритм и код которым принимается ОДИН пакет. представьте его целиком в одной процедуре.
не забудьте про возможности асинхронного приема. и еще раз подумайте)

4. для копирования данных обычно используют memcpy() Ага

PS пардон за уклончивые ответы, но  намеки гораздо полезнее)

Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #20 : 16-09-2010 09:55 » 

1.
Цитата
3. вы так не шутите))) оно конечно while(1) в конечном счете будет, но вы сначала подймайте
еще раз посмотрите на алгоритм и код которым принимается ОДИН пакет. представьте его целиком в одной процедуре.
не забудьте про возможности асинхронного приема. и еще раз подумайте)

Приходит запрос от приложения IRP_MJ_READ, вызывается обработчик A5M2ReadDispatch, в котором пришедший IRP ставится в очередь. Затем с помощью функции A5M2ReadQueueStartIo достается из очереди этот запрос и помещается в функцию  A5M2Pipe0Io, которая в свою очередь считывает данные из конечной точки в mdl-буфер. И так все операции с драйвером происодят через процедуры, вызов которых инициируется IRP запрсами. А моя функция должна работать непрерывно. Инициализироваться она может при первом запросе IRP_MJ_READ, но потом ей же нужно непрерывно опрашивать конечную точку. В пользовательских приложениях такая задача обычно решается с помощью потока. А в моем случае поток нельзя использовать?

2.
Цитата
для копирования данных обычно используют memcpy()
Не совсем понятно как пользоваться этой функцией для mdl-буфера. memcpy(PMDL mdl, PVOID MyBuffer, length)? Простите за такие вопросы, просто первый раз с mdl-сталкиваюсь.

Цитата
PS пардон за уклончивые ответы, но  намеки гораздо полезнее)
Я понима Улыбаюсь Спасибо большое за помощь!
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #21 : 16-09-2010 10:34 » 

3. Как осуществить непрерывный прием данных из девайса в буфер?
Функцию A5M2RcvData разместил в файле usb.c, там же, где и функция A5M2Pipe0Io.
А как ее непрерывно вызывать? не в поток же ставить с циклом while(1)..

По-моему тут без вариантов:

1. Сделать пользовательский поток для приема поступающих данных.
2. В нем ожидать 2-х ивентов:
    - прекращение работы и выход из потока;
    - получение очередного пакета из устройства;
3. Принятые пакеты буферизировать, откуда основное приложение сможет их прочитать (не забыть про закрытые секции записи/считывания пакетов в/из буфера).

Тут требуется, чтобы драйвер устанавливал ивент по приему пакета, как это делает, к примеру, драйвер CyUSB.sys фирмы Cypress (я работаю с чипом CY7C68013A). А далее основное приложение может забирать принятые пакеты когда захочет.

P.S. Даже на дохлейшей enbedded-материнке с процессором класса P-III достигается скорость передачи по USB 2.0 порядка 35 МБайт/сек. Правда, при этом процессор забивается конкретно. На меньших скоростях проблем вовсе нет.
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 16-09-2010 20:19 » 

вариантов на самом деле гораздо больше. главное найти оптимальный.
1. постановка вопроса, что нужно реализовать: непрерывный опрос конечной точки.
что для этого нужно?
 как только завершится первый запрос - немедленно ставить второй.
ранее - это выполняло приложение: посылало запрос драйверу, тот ставил запрос в очередь, приходил пакет от устройства, запрос удовлетворялся, управление возвращалось драйверу(фактически драйвер ждал  WFSO WaiteForSingleObject), драйвер завершал запрос запрос приложения, приложение получало управление и все повторялось заново.
основные накладные расходы - на каждой итерации ожидание события.

как избежать: исключить из очереди эти два ожидания.
    как исключить - например осуществить очередь на уровне драйвера USB - ставить в очередь USB запросов - сразу несколько. и обеспечить непрерывное поддержание нескольких необработанных запросов.

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

собственно запросы от приложения в общем виде тоже могут быть асинхронны по такой же схеме.
теперь вопрос - а можно ли сразу поставить в очередь запросов USB сначала одного а затем второго пакета, не дожидаясь завершения первого?(честно говоря не пробовал, но не вижу причин, почему это невозможно)
 по пришествии первого (в этот момент драйвер USB ждет обработку второго запроса) сразу ставить в очередь еще один запрос или более, так чтобы в этой очереди всегда были ожидающие запросы?
реализовать это можно и отдельной ниткой в драйвере, а можно и на основе очереди асинхронных запросов от приложения.

PS создание потока в драйвере - PsCreateSystemThread().
еще посмотрите в сторону IoQueueWorkItem  - можно попробовать использовать их.
обязательно разберитесь, что такое DPC процедуры и зачем они нужны.
и самое важное - посмотрите как реализуются асинхронные процедуры в драйвере и как они работают. посмотрите как реализована синхронная процедура ожидания пакета от USB драйвера. нумега обычно генерит функцию синхронного вызова - посмотрите как она реализована. может быть это натолкнет вас на разные идеи)

 jur, как видите варианты все же есть) ну по крайней мере мне так кажется)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #23 : 17-09-2010 07:28 » 

Довольно интересная дискуссия, не так ли? :-)

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

Безусловно! Только я продолжаю думать, что оптимальный вариант (точнее, алгоритм) - один :-) Сейчас поясню, что я имею ввиду.

1. постановка вопроса, что нужно реализовать: непрерывный опрос конечной точки.
что для этого нужно?
 как-только завершится первый запрос - немедленно ставить второй.
ранее - это выполняло приложение: посылало запрос драйверу, тот ставил запрос в очередь, приходил пакет от устройства, запрос удовлетворялся, управление возвращалось драйверу(фактически драйвер ждал  WFSO WaiteForSingleObject), драйвер завершал запрос запрос приложения, приложение получало управление и все повторялось заново.
основные накладные расходы - на каждой итерации ожидание события.

Вот это оно и есть. Как ни крути, а без отдельного потока не обойтись. И вот почему.

Приложение выполняется, делает какую-то работу, наверное, обслуживает интерфейс пользователя, выполняет какую-то обработку данных, вывод результатов и т.п. Таким образом получается, что висеть и ждать очередного пакета, видимо, не стоит (ведь при этом все приложение остановится). Значит имеет смысл просто спрашивать у потока приема пакетов: "Эй, друг! Пакеты есть? Нет? Ну ладно, зайду в другой раз.". Если обработка завершилась, а новых пакетов еще нет, то можно и WFSO, или прицепиться к системному таймеру, или еще что-то, не нагружающее процессор.

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

собственно запросы от приложения в общем виде тоже могут быть асинхронны по такой же схеме.
теперь вопрос - а можно ли сразу поставить в очередь запросов USB сначала одного а затем второго пакета, не дожидаясь завершения первого?(честно говоря не пробовал, но не вижу причин, почему это невозможно)
 по пришествии первого (в этот момент драйвер USB ждет обработку второго запроса) сразу ставить в очередь еще один запрос или более, так чтобы в этой очереди всегда были ожидающие запросы?
реализовать это можно и отдельной ниткой в драйвере, а можно и на основе очереди асинхронных запросов от приложения.

Совершенно верно. Именно так я и поступаю. У меня по USB поступают пакеты размером 512 байт. Период их поступления варьируется от 40 до 350 микросекунд. Т.к. скорость поступления пакетов достаточно высока (имею ввиду Win XP, которая отнюдь не ОС РВ), я обращаюсь к драйверу с запросом сразу нескольких пакетов в пачке. Эмпирическим путем я установил, что загрузка процессора разко падает, когда число пакетов в пачке возрастает от 1 до 8. Дальнейшее падение загрузки заметно замедляется, поэтому я остановился на 8 пакетах. И еще важный момент: в потоке приема я запускаю сразу несколько запросов к драйверу (круговая очередь на 4 запроса). Пока принимаю одну порцию - драйвер USB нижнего уровня получает следующую.

jur, как видите варианты все же есть) ну по крайней мере мне так кажется)

:-)

P.S. Да, забыл сказать. При таком алгоритме действий, какой я применяю, с драйвером вообще ничего делать не надо :-) Я использую драйвер CyUSB.sys как есть, без модификаций (каковые я и не смог бы сделать, ввиду отсутствия исходных текстов драйвера, т.к. фирма Cypress их не предоставляет).

« Последнее редактирование: 17-09-2010 07:37 от jur » Записан

MPEG-4 - в массы!
Bulat
Участник

ru
Offline Offline

« Ответ #24 : 17-09-2010 08:54 » 

Цитата
я обращаюсь к драйверу с запросом сразу нескольких пакетов в пачке

Цитата
P.S. Да, забыл сказать. При таком алгоритме действий, какой я применяю, с драйвером вообще ничего делать не надо Улыбаюсь Я использую драйвер CyUSB.sys как есть, без модификаций (каковые я и не смог бы сделать, ввиду отсутствия исходных текстов драйвера, т.к. фирма Cypress их не предоставляет).

 Получается сразу несколько запросов из приложения делаете, посредством ф-ии readfile? Или вы имеете в виду запрос от драйвера верхнего уровня (которым занимаюсь я) к драйверу нижнего уровня?
А ваш драйвер CyUSB.sys можно будет попробовать с моим чипом at91sam7s? Например, родной атмелевский драйвер даже с многопоточным приложением работать не может, сразу экран смерти появляется.
 
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #25 : 17-09-2010 10:18 » 

jur, это я просто прозрачно так намекал, что можно нитку получения данных реализовать в драйвере, а можно вынести ее в приложение) - уже два варианта как минимум.
мне, например, удобнее было бы все в драйвере делать - так как я свои силы знаю, и сколько времени у меня уйдет на это - тоже.
кому то, покажется проще запускать такую нить в приложении, и не тратить много времени на изучение драйверов...
собственно именно на это я и намекал все время)

PS а по сути ток вечерком смогу ответить, ежели чего... работа, блин, ждет)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #26 : 17-09-2010 12:29 » 

Цитата
P.S. Да, забыл сказать. При таком алгоритме действий, какой я применяю, с драйвером вообще ничего делать не надо :-) Я использую драйвер CyUSB.sys как есть, без модификаций (каковые я и не смог бы сделать, ввиду отсутствия исходных текстов драйвера, т.к. фирма Cypress их не предоставляет).

 Получается сразу несколько запросов из приложения делаете, посредством ф-ии readfile? Или вы имеете в виду запрос от драйвера верхнего уровня (которым занимаюсь я) к драйверу нижнего уровня?

С этим драйвером можно работать, как с любым другим, но удобнее использовать его CyAPI. По этому вопросу у нас было довольно большое обсуждение в ветке "CY7C680013A Киньте ссылкой на софт и лит-ру" на форуме ELECTRONIX.ru. Идея реализации приема в пользовательской программе почерпнута из примера Streamer из Cypress'овской USB DevStudio (распространяется бесплатно). Вкратце суть в том, что очередь заданий запускается вот таким образом (QUEUE_SIZE - размер очереди, у меня 4):

  // Queue-up the first batch of transfer requests
  for (int i = 0; i < QUEUE_SIZE; i++)
    contexts = pUsDataInEndpt->BeginDataXfer(buffers, len, &inOvLap);


А вообще этот драйвер (точнее, его API) позволяет осуществлять передачу данных двумя способами: синхронно и асинхронно. Синхронный способ проще (всего один вызов), но намного медленнее асинхронного. Им хорошо пользоваться для каких-нибудь редких, однократных передач, например, передача команд по ендпойнте управления.

Асинхронный метод использует 3 функции:

BeginDataXfer, WaitForXfer и FinishDataXfer. Первая стартует запрос к драйверу. Вторая ожидает выполнения трансакции. Третья завершает трансакцию. Вот их я и использую для быстрой передачи пакетов. (В том обсуждении можно посмотреть скриншоты примера Streamer со значениями скорости передачи, пост #45 и другие.)

А ваш драйвер CyUSB.sys можно будет попробовать с моим чипом at91sam7s? Например, родной атмелевский драйвер даже с многопоточным приложением работать не может, сразу экран смерти появляется.

Ну вообще-то это не мой драйвер, иначе я мог бы зело гордиться собой :-) А с другими микросхемами я не пробовал. Подозреваю, что будет работать без проблем, т.к. из устройства USB драйвер считывает только дескрипторы. А в них можно написать, что угодно.

А BSOD'а я с этим драйвером не видел. Точнее, в ходе начальных экспериментов, когда я еще и железо насиловал, BSOD пару раз видел. Но это было давно и возникало из-за аппаратно-программных заморочек.

jur, это я просто прозрачно так намекал, что можно нитку получения данных реализовать в драйвере, а можно вынести ее в приложение)

Тогда понятно, а я сразу не допёр :-)
Записан

MPEG-4 - в массы!
Bulat
Участник

ru
Offline Offline

« Ответ #27 : 21-09-2010 05:39 » 

jur, это я просто прозрачно так намекал, что можно нитку получения данных реализовать в драйвере, а можно вынести ее в приложение) - уже два варианта как минимум.
1.То есть, это два равноценных решения? По скорости работы буфер в драйвере не будет быстрее аналогичного буфера в приложении?
2. Вопрос непросредственно по реализации такой очереди в потоке чтения и записи приложения.
Изначально потоки записи и чтения в моем приложении работали в синхронном режиме:
Код:
//Поток записи
UINT TransmitThread( LPVOID pParam )
{
   update = 0;
   //непрерывная запись, пока не установится флаг update
   while(update == 0)
   {
      //заполняем буфер размером 60 байт для записи
      ...
      Success = WriteFile(PipeOut, &buf_w, 60, &nBytes, NULL);
      WR_spd += nBytes;
      nBytes=0;
    }
    return 0;   // thread completed successfully
    AfxEndThread(0, TRUE);
}

//Поток чтения
UINT ReceiveThread( LPVOID pParam )
{
   stop_r = 0;
   //
   while(stop_r == 0)
   {
      RealRead = 0;
      ReadFile(PipeIn, &buf_r, 60, &RealRead, NULL);
      RD_spd += RealRead;
      RealRead=0;
      //Разбираем принятый буфер
      ...
    }
}
Если делать прием и передачу в асинхр режиме и если writefile или readfile возвращают 0, то необходимо WaitForSingleObject какой то таймаут, что уже ведет к задержке выполнения потока. Но я пока пытаюсь реализовать простой асинхронный режим без буферизации.
Привожу пример потоков чтения и записи в асинхр режиме:
Код:
//Поток записи
UINT TransmitThread( LPVOID pParam )
{
   update = 0;
   //непрерывная запись, пока не установится флаг update
   while(update == 0)
   {
      //заполняем буфер размером 60 байт для записи
      ...
      Success = WriteFile(PipeOut, &buf_w, 60, &nBytes, &gOverLapped_Write);
      if(!Success)
      {
DWORD flag = WaitForSingleObject(hEvent_Write,200);
if(flag==WAIT_OBJECT_0) GetOverlappedResult(PipeOut,&gOverLapped_Write,&nBytes,TRUE);
if(flag==WAIT_TIMEOUT) Sleep(1);
      }
      WR_spd += nBytes;
      nBytes=0;
    }
    return 0;   // thread completed successfully
    AfxEndThread(0, TRUE);
}

//Поток чтения
UINT ReceiveThread( LPVOID pParam )
{
   stop_r = 0;
   //
   while(stop_r == 0)
   {
      RealRead = 0;
      if(!Success)
      {
      Success = ReadFile(PipeIn, &buf_r, 60, &RealRead, &gOverLapped_Read);
        DWORD flag = WaitForSingleObject(hEvent_Read,200);
if(flag==WAIT_OBJECT_0) GetOverlappedResult(PipeIn,&gOverLapped_Read,&RealRead,TRUE);
if(flag==WAIT_TIMEOUT) Sleep(1);
      }   
      RD_spd += RealRead;
      RealRead=0;
      //Разбираем принятый буфер
      ...
    }
}
В таком исполнении асинхр. ввод/вывод ничем от синхронного не отличается. Приложение также пропускает данные, в случае запуска сторонних приложении или запуска на старой машине.
Если делать очередь из запросов readfile и writefile, то всеравно при каждом выполнении readfile и writefile нужно дожидаться их исполнения, а потом уже выполнять новые функции readfile и writefile. Или я что-то неправильно понимаю? Здесь была моя ладья...
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #28 : 21-09-2010 07:33 » 

1.То есть, это два равноценных решения? По скорости работы буфер в драйвере не будет быстрее аналогичного буфера в приложении?

По-моему - один черт :-) IMHO, тут весь вопрос не в скорости, а в приоритете процесса. А скорость приема данных - 30-40 и более МБ/сек даже на слабой машине.

2. Вопрос непросредственно по реализации такой очереди в потоке чтения и записи приложения.
Изначально потоки записи и чтения в моем приложении работали в синхронном режиме:

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

Если делать прием и передачу в асинхр режиме и если writefile или readfile возвращают 0, то необходимо WaitForSingleObject какой то таймаут, что уже ведет к задержке выполнения потока. Но я пока пытаюсь реализовать простой асинхронный режим без буферизации.

IMHO, WaitForSingleObject не очень подходит. Дело в том, что в случае непрогнозируемой скорости поступления данных становится не понятно, каким же выбрать таймаут? Я делаю вот так:

Код:
Завожу массив евентов:

  HANDLE   hEventArray[QUEUE_SIZE+1];

Первым, наиболее приоритетным, ставлю ивент закрытия потока, который выставляет главная программа по завершению работы (или смене режима).

Далее в вечном цикле ожидаю события:

    nEvent = WaitForMultipleObjects(QUEUE_SIZE+1, hEventArray, FALSE, INFINITE);
    if(nEvent == 0) { // Shutdown event
      sprintf_s(s,"%s: Shutdown event\r\n",module);
      ::OutputDebugString(s);
      break;
    }
    else if(nEvent > 0 && nEvent <= QUEUE_SIZE) { // US-data event
      // тут производится прием данных из драйвера
      recv_index = nEvent-1;
      result = false;
      rLen   = len;  // Reset this each time through because
                     // FinishDataXfer may modify it
      // Wait for the xfer to complete.
      if (!pUsDataInEndpt->WaitForXfer(&inOvLap[recv_index], ENDPT_TIMEOUT)) {
        pUsDataInEndpt->Abort();
        // Wait for the stalled command to complete
        WaitForSingleObject(inOvLap[recv_index].hEvent,INFINITE);
      }
      // Must always call FinishDataXfer to release memory of contexts[i]
      result = pUsDataInEndpt->FinishDataXfer(buffers[recv_index], rLen, &inOvLap[recv_index], contexts[recv_index]);
      ResetEvent(inOvLap[recv_index].hEvent);
      // Prepare read data
      ...
      // Re-submit this request to keep the queue full
      contexts[recv_index] = pUsDataInEndpt->BeginDataXfer(buffers[recv_index], len, &inOvLap[recv_index]);
    }
    else {
      sprintf_s(s,"%s: unknown event 0x%08X\r\n",module,nEvent);
      ::OutputDebugString(s);
    }

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

В таком исполнении асинхр. ввод/вывод ничем от синхронного не отличается. Приложение также пропускает данные, в случае запуска сторонних приложении или запуска на старой машине.

Пропуск данных в обычной Винде - вполне закономерная вещь. Она ведь не ОС РВ. Но минимизировать этот эффект можно. Как я сказал, сделать поток чтения высокоприоритетным, запрашивать данные у драйвера посредством очереди запросов, постоянно поддерживая ее наполненной, и запрашивать у драйвера не по одному пакету, а сразу порцию из 8-16-32 пакетов. В моем приборе пропуск пакетов иногда происходит, но достаточно редко, только если параллельно запустить какую-нить процессорожрущую программу. К примеру, в момент запуска Интернет Эксплорера может пропасть несколько пакетов. А так прием происходит надежно, без сбоев.

Если делать очередь из запросов readfile и writefile, то всеравно при каждом выполнении readfile и writefile нужно дожидаться их исполнения, а потом уже выполнять новые функции readfile и writefile. Или я что-то неправильно понимаю? :-/

Тут дело в том, чтобы запустить не один readfile/writefile, а сразу целую кучу. Тогда потоку некогда будет расслабляться :-)

Ну а если в процессе приема данных обязательно нужно еще и выполнять какую-то другую работу, особенно связанную с регулярным запуском ресурсоемких программ, то это тяжелый случай... Тогда нужно, IMHO, спускаться на более низкий уровень, поближе в системному драйверу USB, который максимально приближен к аппаратным прерываниям, и который работает с высоким приоритетом и первым получает пакеты. Этого я еще не умею :-)
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #29 : 21-09-2010 07:46 » 

jur, тогда уж и REALTIME_PRIORITY_CLASS процессу имеет смысл назначить...
а вообще я в приоритеты "не верю") по моему ИМХО, для правильно распланированной программы - никакие приоритеты не нужны)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #30 : 21-09-2010 13:22 » 

jur, тогда уж и REALTIME_PRIORITY_CLASS процессу имеет смысл назначить...

Ну... Весь процесс целиком может и не быть столь критичным. У меня, к примеру, именно так. Потоки, работающие после получения данных, могут прерываться без проблем. Главное - получить эти данные вовремя (в моей системе со стороны "железа" стоит буфер только на два пакета).

а вообще я в приоритеты "не верю") по моему ИМХО, для правильно распланированной программы - никакие приоритеты не нужны)

Не, они реально работают. Опять же, сошлюсь на свой опыт. Как приоритет считывателя сделаю обычным - тут же пакеты пропадают :-)
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #31 : 21-09-2010 14:43 » 

общий приоритет складывается из приоритета процесса и нити. там такая двухступенчатая шкала) посмотрите на msdn.
а насчет работает... по моему тут больше вопрос размера буфера)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #32 : 21-09-2010 16:12 » 

общий приоритет складывается из приоритета процесса и нити. там такая двухступенчатая шкала) посмотрите на msdn.

У меня сложилось впечатление, что Билли наш Гейц - хитрейший мужик! :-) Что и как он позаимствовал из Юникса по вопросу планирования процессов - никто не знает. Поэтому, IMHO, MSDN нужно читать между строк :-)

а насчет работает... по моему тут больше вопрос размера буфера)

У меня буфер (на приемной стороне) стандартный, 256 пакетов (по 512 байт каждый). Пакеты представляют собой ультразвуковые лучи (УЗИ), отображаемые на экране. Понятно, что очень важно, чтобы никакие лучи не пропадали. Практика показала, что при нормальном приоритете лучи пропадают, а при повышенном - нет. Вот я и сделал такой вывод :-)
Записан

MPEG-4 - в массы!
PredatorAlpha
Помогающий

us
Offline Offline

« Ответ #33 : 21-09-2010 19:34 » 

Просмотрел тему, может несколько поверхностно, но складывается впечатление непродуманности архитектур.
В одном случае совершенно неприемлемо, что в зависимости от нагрузки устройство не успевает обрабатывать DPC на однопроцессорной машине. Архитектура должна быть построена так, что бы драйвер гарантировано получал всё без пропусков на однопроцессорной, пусть даже и на все запущенное пользовательского уровня и не останется процессора. Тогда можно гарантировать, что на двухпроцессорном будет всё отлично работать. А когда всё тормозит если что-то большое запустили на двухпроцессорном - это абздец. Мало ли что можно запустить...
Я конечно понимаю, что от программиста мало зависит, когда система даст управление DPC, но если уже период вызова DPC критично важен, значит нужно искать другие методы. Использовать ISR, например. Неверняка там предусмотрен callback для драйверов конечных устройств из ISR контроллера после получения порции данных. Если нет - значит его нужно организовать самому, любым образом. В конце концов, скопировать 60 (даже и 512) байт можно и из ISR (и пусть весь мир подождёт!).
Во втором случае, совершенно неприемлимо, что на пользовательский процесс (вызов readfile) что-то завязано.  readfile не должен нести никакой функциональной части, кроме доставки данных в пользовательский процесс. Я конечно понимаю, что используется готовое, и оно не сильно предназначено для "скоростных" устройств, но чувство неправильности такого подхода остаётся...
« Последнее редактирование: 21-09-2010 21:07 от PredatorAlpha » Записан
jur
Помогающий

lt
Offline Offline

« Ответ #34 : 22-09-2010 18:49 » 

Я конечно понимаю, что от программиста мало зависит, когда система даст управление DPC, но если уже период вызова DPC критично важен, значит нужно искать другие методы. Использовать ISR, например. Неверняка там предусмотрен callback для драйверов конечных устройств из ISR контроллера после получения порции данных. Если нет - значит его нужно организовать самому, любым образом. В конце концов, скопировать 60 (даже и 512) байт можно и из ISR (и пусть весь мир подождёт!).

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

Только я этого делать еще не научился :-) Поэтому привел пример своего решения на уровне пользовательской программы, которое в общем-то позволяет решить задачу. Однако мне уже начинает мешать отсутствие умения делать прием данных прямо в драйвере (у меня уже скопилось порядка 4-5 разных видов пакетов, которые правильнее было бы раскладывать в отдельные буфера). А вот приступить к созданию собственного драйвера как-то пока боязно :-)
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #35 : 22-09-2010 20:04 » 

jur, длину буфера лучше выражать не количеством пакетов, а скоростью потока.
Размера буферизации(будь то кольцевой буфер, или очередь) должно хватать МИНИМУМ на 200-500мс заполнения с вашей максимальной скоростью потока.
и это действительно МИНИМУМ! вообще говоря, лучше, когда его длины хватает на несколько секунд, по возможности.
максимум - на время запуска "тяжелых" приложений - десятки секунд (но это не всегда реализуемо).

PS откуда такой счет "минумума"(грубо):  размер кванта в винде, помножить на  пять-семь гипотетических процессов(если они все внезапно захотят выжрать весь свой полный квант), + запас в два раза;)

PPS PredatorAlpha, полностью согласен)
« Последнее редактирование: 22-09-2010 20:06 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #36 : 23-09-2010 05:51 » 

IMHO, WaitForSingleObject не очень подходит. Дело в том, что в случае непрогнозируемой скорости поступления данных становится не понятно, каким же выбрать таймаут? Я делаю вот так:
Не совсем понятно как создется массив ивентов. У меня всего два ивента - чтение и запись. Как создать очередь из ивентов чтения, например, не понятно, то есть как различать ивенты чтения между собой. Так я создаю ивенты:
Код:
hEvent_Write = CreateEvent(
NULL,    // default security attribute
TRUE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

// set up overlapped structure fields
gOverLapped_Write.Offset     = 0;
gOverLapped_Write.OffsetHigh = 0;
gOverLapped_Write.hEvent     = hEvent_Write;

hEvent_Read = CreateEvent(
NULL,    // default security attribute
TRUE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

// set up overlapped structure fields
gOverLapped_Read.Offset     = 0;
gOverLapped_Read.OffsetHigh = 0;
gOverLapped_Read.hEvent     = hEvent_Read;
То есть у меня всего один ивент чтения hEvent_Read и один ивент записи hEvent_Write. А как тогда заполнить массив ивентов для потока чтения hEventArray_read[QUEUE_SIZE+1] и записи hEventArray_erite[QUEUE_SIZE+1]. Или я неправильно понял?
Цитата
Первым, наиболее приоритетным, ставлю ивент закрытия потока

Мне нет необходимости заводить ивент закрытия потока, так как я его закрываю по флагу и пока этот флаг сброшен поток в бесконечном цикле принимает данные.
И потом ивент чтения возникает же после того, как будет выполнена ф-ия readfile, тогда если WaitForMultipleObjects с атрибутом INFINITE выполнять перед выполнением ф-ии readfile, то разве он дождется события?
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #37 : 23-09-2010 08:42 » 

Цитата
Не совсем понятно как создется массив ивентов.
а в цикле события создать - это так сложно догадаться? и массив хендлов заполнить? Жжешь
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #38 : 25-09-2010 11:31 » 

а в цикле события создать - это так сложно догадаться? и массив хендлов заполнить? Жжешь
Создать, то я создал, только WaitForMultipleObjects  возвращает все время 0-й ивент.
Код:
//Первые ивенты в массивах устанавливаются при создании потоков записи и чтения соответственно
hEvent_Write[0] = CreateEvent(
NULL,    // default security attribute
TRUE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object
hEvent_Read[0] = CreateEvent(
NULL,    // default security attribute
TRUE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

for(int i=0; i<queuesize; i++)
{

hEvent_Write[i+1] = CreateEvent(
NULL,    // default security attribute
TRUE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object



// set up overlapped structure fields
gOverLapped_Write[i].Offset     = 0;
gOverLapped_Write[i].OffsetHigh = 0;
gOverLapped_Write[i].hEvent     = hEvent_Write[i+1];

hEvent_Read[i+1] = CreateEvent(
NULL,    // default security attribute
TRUE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object



// set up overlapped structure fields
gOverLapped_Read[i].Offset     = 0;
gOverLapped_Read[i].OffsetHigh = 0;
gOverLapped_Read[i].hEvent     = hEvent_Read[i+1];
}

Поток записи:
Код:
UINT TransmitThread( LPVOID pParam )
{

unsigned char buf_w[60];
DWORD recv_index;

BOOL sete = SetEvent(hEvent_Write[0]);  //Создание первого ивента при открытии потока

update = 0;
while(update == 0)
{
DWORD nEvent = WaitForMultipleObjects(queuesize+1, hEvent_Write, FALSE, INFINITE);
if(nEvent > 0 && nEvent <= queuesize)
{
recv_index = nEvent-1;
Success = WriteFile(PipeOut, &buf_w[recv_index], 60, &nBytes, &gOverLapped_Write[recv_index]);
WaitForSingleObject(hEvent_Write[recv_index],INFINITE);
GetOverlappedResult(PipeOut,&gOverLapped_Write[recv_index],&nBytes, FALSE);
}
                                          WR_spd += nBytes;
nBytes=0;

}//while(update == 0)

              return 0;   // thread completed successfully
AfxEndThread(0, TRUE);
}
Так вот, nEvent  у меня всегда 0, аналогично и в потоке чтения..
Записан
resource
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #39 : 26-09-2010 00:51 » 

Код прямо "черные сказки белой зимы". Мозг разорван на части. Вопрос (риторический): это работает?
И еще очень хотелось бы глянуть на код, который сигналит ивенты.
« Последнее редактирование: 26-09-2010 12:45 от resource » Записан
jur
Помогающий

lt
Offline Offline

« Ответ #40 : 26-09-2010 07:47 » 

Так вот, nEvent  у меня всегда 0, аналогично и в потоке чтения..

Складывается впечатление, что многочисленные ивенты созданы как-то несистемно... И еще важный вопрос: созданные ивенты типа "manual-reset event". А кто их сбрасывает?! Вот и долбится первый ивент до посинения :-)

Мой алгоритм действий при старте потока такой.

1. В hEventArray[0] заношу ивент выхода их потока. Этот ивент с автосбросом.
2. В hEventArray[1..N] заношу ивенты получения очередной порции данных. ВНИМАНИЕ! Эти ивенты я сделал с ручным сбросом потому, что мне нужно их ожидать. Дело в том, что CyAPI тоже пользуется этим ивентом и, если ивент с автосбросом, то мой поток этого события не увидит (он автосбросится внутри CyAPI).

Поэтому я полагаю, что во-первых, нужно все-таки завести ивент прекращения записи/считывания (выхода из потока). Во-вторых, внимательно просмотреть всю цепочку работы с ивентами: произошло событие, получил порцию данных, сбросил ивент, запустил следующую порцию I/O. У меня это уже немало лет нормально работает.
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #41 : 26-09-2010 10:40 » 

у вас первый эвент в массиве - hEvent_Write[0].  с ручным сбросом.
и вы его сами перед циклом устанавливаете в сигнальное состояние(хотя он при рождении уже в нем):
Код:
BOOL sete = SetEvent(hEvent_Write[0]); 
и нигде больше не сбрасываете... что ж вы хотите? логично предположить что он всегда будет проверятся первым))) и всегда будет возвращен 0.

не понял зачем вот это ожидание нужно было сразу после записи?:
Код:
WaitForSingleObject(hEvent_Write[recv_index],INFINITE);
GetOverlappedResult(PipeOut,&gOverLapped_Write[recv_index],&nBytes, FALSE);

честно говоря совершенно непонятно что в коде происходит... с бухты барахты какие то эвенты ожидаются... - откуда они вообще приходят? да еще и с ручным сбросом... первый раз такое вижу)
если они с ручным сбросом - они ж там постоянно будут стоять!
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #42 : 28-09-2010 10:17 » 

В соответствии с вышесказанным исправил свой код.
Передача:
Код:
UINT TransmitThread( LPVOID pParam )
{

unsigned char buf_w[60];
DWORD recv_index;

hEvent_Write[0] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

for(int i=0; i<queuesize; i++)
{

hEvent_Write[i+1] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

// set up overlapped structure fields
gOverLapped_Write[i].Offset     = 0;
gOverLapped_Write[i].OffsetHigh = 0;
gOverLapped_Write[i].hEvent     = hEvent_Write[i+1];
}

nBytes=0;
update = 0;
while(update == 0)
{
//Заполняется буфер buf_w

DWORD nEvent = WaitForMultipleObjects(queuesize+1, hEvent_Write, FALSE, INFINITE);
if(nEvent > 0 && nEvent <= queuesize)
{
recv_index = nEvent-1;
Success = WriteFile(PipeOut, &buf_w, 60, &nBytes, &gOverLapped_Write[recv_index]);
GetOverlappedResult(PipeOut,&gOverLapped_Write[recv_index],&nBytes, FALSE);

if(nBytes) {WR_spd += nBytes; nBytes=0;}
}//if(nEvent > 0 && nEvent <= queuesize)
//}//while(recv_index!=queuesize)

}//while(update == 0)

    return 0;   // thread completed successfully
AfxEndThread(0, TRUE);

}

Прием:
Код:
UINT ReceiveThread( LPVOID pParam )
{

unsigned char buf_r[queuesize][60];
DWORD recv_index=0;

hEvent_Read[0] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

for(int i=0; i<queuesize; i++)
{
hEvent_Read[i+1] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object



// set up overlapped structure fields
gOverLapped_Read[i].Offset     = 0;
gOverLapped_Read[i].OffsetHigh = 0;
gOverLapped_Read[i].hEvent     = hEvent_Read[i+1];
}

stop_r = 0;
RealRead = 0;
while(stop_r == 0)
{
nEvent = WaitForMultipleObjects(queuesize+1, hEvent_Read, FALSE, INFINITE);
if(nEvent > 0 && nEvent <= queuesize)
{
recv_index = nEvent-1;
Success = ReadFile(PipeIn, &buf_r, 60, &RealRead, &gOverLapped_Read[recv_index]);
GetOverlappedResult(PipeIn,&gOverLapped_Read[recv_index],&RealRead, FALSE);

                                if(RealRead) {RD_spd += RealRead; RealRead=0;}
                         }
                          ...
                         //Разбор принятого буфера
          }
         return 0;
AfxEndThread(0, TRUE);
}

В таком виде данные принимаются и передаются.
Но при этом для записи и чтения используется одномерный буфер, который умещает только один пакет. Если буферизовать пакеты, то соответственно нужно вводить двумерный буфер. Например, буфер для чтения: unsigned char buf_r[queuesize][60].
Тогда, операция чтения будет выглядеть следующим образом:
Код:
        while(stop_r == 0)
{
while(recv_index!=queuesize)
{
nEvent = WaitForMultipleObjects(queuesize+1, hEvent_Read, FALSE, INFINITE);
if(nEvent > 0 && nEvent <= queuesize)
{
recv_index = nEvent-1;
Success = ReadFile(PipeIn, &buf_r[recv_index], 60, &RealRead, &gOverLapped_Read[recv_index]);
GetOverlappedResult(PipeIn,&gOverLapped_Read[recv_index],&RealRead, FALSE);
                        }
                 }
         } 
Но в таком виде в буфер buf_r ничего не записывается? При этом ивенты поступают..
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #43 : 28-09-2010 13:00 » 

сделайте пояснения в каждой строчке кода,  иначе мне совершенно не ясно, что вы пытались сделать) по-моему вам и самому это не совсем ясно Ага

а перед этим прочитайте разделSynchronous and Asynchronous I/O (не картинки посмотреть, а именно прочитать до конца) а если поищите - найдете аналог описания и на русском, их полно должно быть в сети.

а так же прочитайте наконец описания функций, которые вы используете (ReadFile и GetOverlappedResult), но теперь уже ЦЕЛИКОМ. и не забывайте про возвращаемые значения. не понимаю, почему их все тотально игнорировать любят?!
пока все ваши ошибки из за невнимательности и нежелания подробно прочесть о используемых вами функциях.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #44 : 28-09-2010 19:43 » 

Bulat

Я не очень понял насчет записи, поэтому порассуждаю насчет чтения. На мой взгляд, в цикле "for(int i=0; i<queuesize; i++)" следует не просто назначать ивенты, а непосредственно запускать запросы считывания. IMHO, тут логическая ошибка: ивенты создаются, но ничего не организовывается. Повторю еще раз требуемый алгоритм.

Во-первых, создаем ивент для выхода из потока. (Да, да, я не устану об этом талдычить :-) И вот почему. Мы запустили кучу считываний. Ожидаем их завершения. А если данные перестанут поступать? Что делать, как выйти из потока? Вот тут-то и пригодится самый приоритетный, первый ивент. В основной программе мы его установим, дескать, пора линять, а в потоке это увидим. Тогда все красиво завершим и нормально выйдем.)

Во-вторых, запускаем сразу несколько считываний. Согласно размера очереди.

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

Замечание по поводу размера запроса. Как я уже упоминал, практика показала, что эффективнее запускать считывание не одного пакета, а сразу целой пачки. Соответственно, никаких многомерных массивов не нужно, а просто заводим массив считывания размером <размер пакета>*N, где N - какое-то приемлемое число, например, 8-16-32 и т.п.

Когда драйвер выполнит запрос, мы получим в своем буфере <размер пакета>*N байт принятых данных. Далее можем распоряжаться ими, как требуется.

Не знаю, как более понятно объяснить... Не сомневаюсь, что изучение, компиляция и запуск примера Streamer, обсуждение которого я упоминал, может полностью развеять неясности в вопросе работы с USB-драйвером.

« Последнее редактирование: 28-09-2010 20:12 от jur » Записан

MPEG-4 - в массы!
Bulat
Участник

ru
Offline Offline

« Ответ #45 : 30-09-2010 09:23 » 

Ochkarik
Привожу код с комментариями, а способ обработки возвращаемых значений функции readfile из msdn
Код:
UINT ReceiveThread( LPVOID pParam )
{

unsigned char buf_r[60];
DWORD recv_index=0;
//Создаю ивент, по которому буду выходить из потока
hEvent_Read[0] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object
        //Создаю ивенты чтения
for(int i=0; i<queuesize; i++)
{
hEvent_Read[i+1] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object



// set up overlapped structure fields
gOverLapped_Read[i].Offset     = 0;
gOverLapped_Read[i].OffsetHigh = 0;
gOverLapped_Read[i].hEvent     = hEvent_Read[i+1];
}

stop_r = 0;
RealRead = 0;
        //Запускаю бесконечный цикл
while(stop_r == 0)
{
                        //Ожидаю ивенты
                        nEvent = WaitForMultipleObjects(queuesize+1, hEvent_Read, FALSE, INFINITE);

                        //Ивент остановки потока
                        if(nEvent==0) {return 0; AfxEndThread(0, TRUE);}

                        //Ивент чтения
if(nEvent > 0 && nEvent <= queuesize)
{
recv_index = nEvent-1;
                                //Отсылаю запрос на считывание пакета в 60 байт
Success = ReadFile(PipeIn, &buf_r, 60, &RealRead, &gOverLapped_Read[recv_index]);
                           if (!Success)
   {
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of the file
// during the call to ReadFile
 
                       // code to handle that
}
 
case ERROR_IO_PENDING:
{
// asynchronous i/o is still in progress
 
                        // do something else for a while
//GoDoSomethingElse() ;
 
// check on the results of the asynchronous read
Success = GetOverlappedResult(PipeIn,&gOverLapped_Read[recv_index],&RealRead, FALSE);
 
// if there was a problem ...
if (!Success)
{
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of
// the file during asynchronous
// operation
}
 
// deal with other error cases
}   //end switch (dwError = GetLastError())
}
} // end case
 
// deal with other error cases, such as the default
 
} // end switch (dwError = GetLastError())
            } // end if (!Success)

                         }//if(nEvent > 0 && nEvent <= queuesize)
                          ...
                         //Разбор принятого буфера
          }
         
}

Записан
Bulat
Участник

ru
Offline Offline

« Ответ #46 : 30-09-2010 09:24 » 

jur
Я следовал алгоритму, который вы привели на первой страничке данной темы (Ответ #28), там операция считывания из драйвера в буфер выполнялась после WaitForMultipleObjects. Если смотреть на код приема данных, который я привел в последнем посте, то я там так и сделал.  Во время отладки значение nEvent, которое возвращает WaitForMultipleObjects меняется в каждом цикле от 0 до queuesize и readfile благополучно считывает все данные. Но в вашем последнем посте вы говорите о том, что надо сначало запустить серию запросов чтения данных и ссылаетесь на пример streamer. Но ведь и в вашем коде и в примере streamer используются функции библиотеки CyAPI, работа которых, насколько я понимаю, отличается от WinAPI функций. То есть, если я в цикле запущу сразу несколько функций readfile, не дожидаясь их выполнения, то я потеряю данные.
Код:
                for(int i=0; i<queuesize; i++)
{
Success = ReadFile(PipeIn, &buf_r[i], 60, &RealRead, &gOverLapped_Read[i]);
if (!Success)
{
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of the file
// during the call to ReadFile
 
                       // code to handle that
}
 
case ERROR_IO_PENDING:
{
// asynchronous i/o is still in progress
 
                        // do something else for a while
//GoDoSomethingElse() ;
 
// check on the results of the asynchronous read
Success = GetOverlappedResult(PipeIn,&gOverLapped_Read[i],&RealRead, FALSE);
 
// if there was a problem ...
if (!Success)
{
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of
// the file during asynchronous
// operation
}
 
// deal with other error cases
}   //end switch (dwError = GetLastError())
}
} // end case
 
// deal with other error cases, such as the default
 
} // end switch (dwError = GetLastError())
} // end if
}
Тут я применяю readfile, как сказано в msdn. Если я после этого цикла буду ожидать ивенты с помощью WaitForMultipleObjects, то я часть ивентов потеряю, так как они придут еще во время выполнения цикла с readfile и я их просто пропущу.
Вот я и не могу понять как можно создать очередь запросов из readfile, если прежде чем отправить следующий запрос readfile, надо обработать результат выполнения предыдущего запроса.
Цитата
Как я уже упоминал, практика показала, что эффективнее запускать считывание не одного пакета, а сразу целой пачки. Соответственно, никаких многомерных массивов не нужно,...
Дело в том, что мой девайс посылает Хосту пакеты по 60 байт и если я в readfile, ставлю считать, например 600 байт, то естественно функция ничего не возвращает. И вот тут опять возникает вопрос, касающийся очереди запросов. В приведенном выше коде используется буфер buf_r, который объявлен следующим образом unsigned char buf_r[60]. Когда мы ReadFile(PipeIn, &buf_r, 60, &RealRead, &gOverLapped_Read), то 60 байт записываются в buf_r, но тогда при каждой итерации i этот буфер будет перезаписываться и данные потеряются, если мы их оттуда не считаем до выполнения следующей итерации. Если записывать  ReadFile(PipeIn, &buf_r, 60,..., тогда не совсем понятно к чему относится индекс i, ведь  buf_r одномерный, а тут он получается вроде как двумерный buf_r[queuesize][60]?
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #47 : 30-09-2010 14:01 » 

мельком глянул, сорри, работа горит, поэтому кратко.

итак, на примере одного запроса:

1. СНАЧАЛА отправить запрос чтения с конкретным event-ом в overlapped. сразу после этого - НА САМОМ ДЕЛЕ - состояние буфера неизвестно! данные могут быть прочитаны а может быть и нет! поэтому:
2. проверить возвращенное значение,
    а) если оно success - запрос обработан - данные в выходном буфере readfile, и вы их должны сохранить для дальнейшего использования у себя.
    б) если вернулся пендинг -  то запрос ПОКА НЕ ОБРАБОТАН! БУФЕР после вызова readfile - ЕЩЕ ПУСТ! в этом случае вы должны ждать event из оверлапеда(то есть ждать завершение обработки операции чтения).  ТОЛЬКО после этого вы можете проверять статус операции readfile (при помощи GetOverlappedResult) - а выполнилась ли операция на самом деле? и только после этого вы можете использовать от массив который вы задавали в качестве входного для той операции readfile.

а у вас что то наоборот получилось: сначала вы ждете событие(кто его будет ставить если запроса еще не было?) потом отправляете запрос чтения для этого же эвента. а используете массив - вообще в непонятный момент, в котором его состояние по большому счету не определено.

кстати еще вопрос - а драйвер вообще асинхронные запросы держит? шо то я забыл как нумега их делает по умолчанию.

и наконец главное... код из msdn скопипастить у вас получилось... но вы хотя бы комментарии в этом коде прочли?)
PS
case ERROR_IO_PENDING:
...
            // asynchronous i/o is still in progress

                           // do something else for a while
            //GoDoSomethingElse() ;
 
            // check on the resultsof the asynchronous read
            Success = GetOverlappedResult(PipeIn,&gOverLapped_Read,&RealRead, FALSE);
             // if there was a problem ...
            if (!Success)
            {
               // deal with the error code
« Последнее редактирование: 30-09-2010 14:23 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #48 : 03-10-2010 11:41 » 

Я следовал алгоритму, который вы привели на первой страничке данной темы (Ответ #28), там операция считывания из драйвера в буфер выполнялась после WaitForMultipleObjects.

Совершенно верно. Предлагаю сначала рассмотреть ситуацию, когда очереди нет, т.е. делается всего один запрос чтения. Посмотрим, что происходит.

1. Запускаем операцию чтения. Драйвер начал свою работу.
2. Ожидаем завершения операции с помощью WaitForMultipleObjects.
3. Просыпаемся по ивенту, что говорит нам о поступлении запрошенных данных.
4. Получаем данные (копируем их в свой буфер).
5. Запускаем следующую операцию чтения.
6. Переходим к пункту 2.

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

Это будет нормально работать без малейших проблем. Однако в ситуации, когда время довольно критично (мой случай), будет непозволительной роскошью позволить драйверу расслабляться :-) (Бери больше, кидай дальше. Пока летит - отдыхай!) Поэтому думаем дальше.

Но в вашем последнем посте вы говорите о том, что надо сначало запустить серию запросов чтения данных и ссылаетесь на пример streamer.

Именно так. Проанализировав приведенный выше алгоритм, мы заметим, что пока мы просыпаемся и работаем с данными, драйвер нагло сычкует! Чтобы этого не допустить как раз и нужна очередь. В пункте 1 мы запускаем сразу несколько запросов. Далее в пункте 2 первый из них будет выполнен, мы просыпаемся и получаем данные. Но в это время драйвер продолжает работу и считывает следующие порции данных! Таким образом мы можем полностью загрузить систему, не допуская непроизводительных простоев процессора.

Но ведь и в вашем коде и в примере streamer используются функции библиотеки CyAPI, работа которых, насколько я понимаю, отличается от WinAPI функций.

Это совсем не так. Если программа работает под Виндой, то ничего кроме WinAPI она использовать не может :-) (Экзотику на уровне драйверов ядра мы не рассматриваем.) По сути CyAPI - это просто удобная оболочка для все тех же родимых обращений к драйверу.

То есть, если я в цикле запущу сразу несколько функций readfile, не дожидаясь их выполнения, то я потеряю данные.

Это еще почему?! Каждый запущенный запрос выполнится и никакой потери данных не будет. Просто нужно, как весьма резонно заметил коллега Ochkarik, весьма корректно и правильно выполнить требования asynchronous i/o.

Кстати, я именно потому и пользуюсь CyAPI, чтобы не ковыряться со всеми этими ERROR_IO_PENDING да GetOverlappedResult :-)

И еще одно замечание. Для начала - хрен с ним, с запросом пачки пакетов. Можно запросить всего один (на 60 байт). Весьма возможно, что и с одним пакетом производительности системы уже хватит. Тут главное - вдумчивая организация очереди запросов и внимательное прочтение ответа #47 коллеги Ochkarik. (Я в этих вопросах не силен, без CyAPI с драйвером USB серьезно работать еще не умею.)
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #49 : 03-10-2010 11:55 » 

PS глянул какой-то старый код для usb драйвера на ftdi который я нумегой делал - STATUS_PENDING оно поддерживало... причем, чуть ли не по умолчанию:
        IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
        status = STATUS_PENDING;
так что... разбирайтесь с асинхронными запросами и будет вам наверное счастье) это ж банальный API) тут (как впрочем и везде) надо просто внимательно читать документацию не пропуская ни строчки)

jur, да на самом деле все точно так же. что CyAPI что просто API... ничего там сверх естественного придумать нельзя) даже особо ничего скрыть не получится... ну чуть побольше if-ов с проверками, но по мне лучше сразу разбираться с первоисточником, чем с чужими "фичами", которые ни в коем случае не "баги")))
« Последнее редактирование: 03-10-2010 11:59 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #50 : 03-10-2010 17:42 » 

jur, да на самом деле все точно так же. что CyAPI что просто API... ничего там сверх естественного придумать нельзя) даже особо ничего скрыть не получится... ну чуть побольше if-ов с проверками, но по мне лучше сразу разбираться с первоисточником, чем с чужими "фичами", которые ни в коем случае не "баги")))

Полностью согласен. Тока я пока напрямую с драйверами работать не умею :-)

А с этой, не к ночи будь помянутой, FTDI я тоже работал. Еще перед Сайпресом. Переписывался с ними, доказывал, что то, что они называют фичей, - суть элементарный баг :-) (Они это потом в кремнии исправили. Уже запамятовал, о чем там речь, но что-то с их левым подходом, что импульс считывания нормальный, инверсный, а записи - нет. Там по падающему фронту положительного импульса, кажись. В общем, не помню уже.) Особо удручил меня их глюкодром под названием "Драйвер для COM-порта", который по-продвинутее.  После целой вереницы BSOD-ов я перешел на Сайпрес, чему рад по сей день :-)

Правда, надо отдать должное, с микросхемой FTDI (я работал с FT245AM, потом с FT245BM) организовать простейшее взаимодействие своего железа по USB максимально просто.
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #51 : 03-10-2010 17:59 » 

jur, так у нас ее и начали тыкать куда непопадя, из за этой простоты.
говорят они новую версию на полной скорости освоили.
кстати, напрямую -  это всего лишь банальный ReadFile/WriteFile ну или DeviceIoControl, что суть то же самое но с большими возможностями.
а "продвинутый" я делал. вроде проблем ни одной не было. там правда особо ничего не требовалось
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #52 : 07-10-2010 09:48 » 

Реализовал прием следующим образом:
Код:
UINT ReceiveThread( LPVOID pParam )
{
unsigned char buf_r[queuesize][60];
unsigned char buffer_r[queuesize][60];
DWORD nEvent;

        //Заполняю массив ивентов
for(int i=0; i<queuesize; i++)
{
hEvent_Read[i] = CreateEvent(
NULL,    // default security attribute
FALSE,    // manual-reset event
TRUE,    // initial state = signaled
NULL);   // unnamed event object

// set up overlapped structure fields
gOverLapped_Read[i].Offset     = 0;
gOverLapped_Read[i].OffsetHigh = 0;
gOverLapped_Read[i].hEvent     = hEvent_Read[i];
}


stop_r = 0;
RealRead = 0;
        //Запуск оснновного цикла приема данных
while(stop_r == 0)
{
DWORD dwError;

int queue_rem = queuesize; //Остаток очереди
                //Создаем очередь запросов на чтение
for(int i=0; i<queuesize; i++)
{
Success = ReadFile(PipeIn, &buf_r[i], 60, &RealRead, &gOverLapped_Read[i]);
if (Success) { for(int j=0; j<60; j++) {buffer_r[i][j] = buf_r[i][j];} CloseHandle(hEvent_Read[i]); queue_rem--;} //Данные приняты

}
//Разбираем остаток очереди запросов, которые не были обработаны сразу после выполнения readfile
for(int i=0; i<queue_rem; i++)
{
nEvent = WaitForMultipleObjects(queuesize, hEvent_Read, FALSE, INFINITE);
if(nEvent == WAIT_FAILED);
if(nEvent <= queuesize)
{
recv_index = nEvent;
Success = GetOverlappedResult(PipeIn,&gOverLapped_Read[i],&RealRead, FALSE);
if (!Success)
{
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of
// the file during asynchronous
// operation
}
 
// deal with other error cases
}   //end switch (dwError = GetLastError())
}//if (!Success)
else for(int j=0; j<60; j++) buffer_r[i][j] = buf_r[i][j]; //Данные приняты
if(RealRead) {RD_spd += RealRead; RealRead=0;}
}
}

                for(int i=0; i<queuesize; i++)
{
                     // разбираем buffer_r[i][j]
                }
               

}//while(stop_r == 0)

return 0;
AfxEndThread(0, TRUE);
}


Но это особо не помогло. Более того, при увеличении queuesize в 2-3 раза кол-во пропусков растет.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #53 : 07-10-2010 10:28 » 

CreateEvent( ......, TRUE, ...)    // initial state = signaled  
  - почему?Не понял?

if (Success) { for(int j=0; j<60; j++) {buffer_r[j] = buf_r[j];} CloseHandle(hEvent_Read); queue_rem--;} //Данные приняты
  - логически не верно. если один из запросов вернет TRUE (навряд ли, но мало ли) то вы удалите один хендел из массива (в произвольном месте), а после цикла передадите полный массив хендлов событий на WFSO. и будет ошибка.

if(nEvent == WAIT_FAILED); - классное выражение) особенно точка с запятой после if-a) и работает?

WFSO с INFINITE ожиданием - это не красиво. и никакой while(stop_r == 0) вам не поможет.

nEvent = WaitForMultipleObjects(...)
Success = GetOverlappedResult(PipeIn,&gOverLapped_Read,&RealRead, FALSE);
- вообще говоря тоже ошибка... позже -  вторая такая же. хотя в этом случае может и сработать. как повезет... пишите внимательнее.

ключевой вопрос - ка вы судите о наличии пропусков?
« Последнее редактирование: 07-10-2010 12:35 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Bulat
Участник

ru
Offline Offline

« Ответ #54 : 09-10-2010 08:55 » 

ключевой вопрос - ка вы судите о наличии пропусков?
Создаю огромный массив типа char, размером 5000000 и записываю туда принятые в потоке чтения пакеты. По останову потока начинаю разбирать этот массив. Некий девайс шлет моему девайсу по Arinc429-каналу поток данных от 1 до 256, я эти данные регистрирую и после останова анализирую на нарушение последовательности от 1 до 256, то есть 1,2,..256,1,2,..256,..

    Мне удалось серьезно снизить количество пропусков при приеме за счет того, что из потока чтения я убрал разбор принятых пакетов, а лишь записываю эти пакеты в мой огромный буфер.
Код:

unsigned char buffer_r[5000000][60];

UINT ReceiveThread( LPVOID pParam )
{

unsigned char buf_r[queuesize][60];
DWORD dwError;

for(int i=0; i<queuesize; i++)
{
hEvent_Read[i] = CreateEvent(
NULL,    // default security attribute
FALSE,    // auto-reset event
FALSE,    // initial state = nonsignaled
NULL);   // unnamed event object
// set up overlapped structure fields
gOverLapped_Read[i].Offset     = 0;
gOverLapped_Read[i].OffsetHigh = 0;
gOverLapped_Read[i].hEvent     = hEvent_Read[i];
}

stop_r = 0;
RealRead = 0;

while(stop_r == 0)
{
for(int i=0; i<queuesize; i++)
{
Success = ReadFile(PipeIn, &buf_r[i], 60, &RealRead, &gOverLapped_Read[i]);
}

for(int i=0; i<queuesize; i++)
{
nEvent = WaitForMultipleObjects(queuesize, hEvent_Read, FALSE, 100);
if(nEvent <= queuesize)
{
recv_index = nEvent;
Success = GetOverlappedResult(PipeIn,&gOverLapped_Read[i],&RealRead, FALSE);
if (!Success)
{
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of
// the file during asynchronous
// operation
}
 
// deal with other error cases
}   //end switch (dwError = GetLastError())
}//if (!Success)
                        else {
                    for(int j=0; j<RealRead; j++) buffer_r[i_rcv][j] = buf_r[i][j]; //Переписываю принятый пакет в буфер.
                    i_rcv++;
                        } //Данные приняты
                        if(RealRead) {RD_spd += RealRead; RealRead=0;}
}
}

}//while(stop_r == 0)

return 0;
AfxEndThread(0, TRUE);
}
Так вот, если я определю размер очереди queuesize равным 1, то есть очереди не будет, то количество пропусков такое же, как и при размере очереди 15, а если значительно увеличивать размер очереди (queuesize=50), то кол-во пропусков увеличивается.
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #55 : 09-10-2010 09:59 » 

Цитата
"Так вот, если я определю размер очереди queuesize равным 1, то есть очереди не будет, то количество пропусков такое же, как и при размере очереди 15, а если значительно увеличивать размер очереди (queuesize=50), то кол-во пропусков увеличивается."
- это говорит что у вас до сих пор алгоритм неверно построен. вы разделили его на два цикла в первом только отсылаете запросы, во втором ждете полного опустошения очереди запросов.
при правильно построенном алгоритме - очередь не должна полностью опустошаться.

ЗЫ кроме того... для копирования памяти обычно пользуются memcpy(). так быстрее

PPS вы должны отправлять новый запрос ReadFile, как только придет подтверждение чтения хотя бы одного из очереди... не дожидаясь пока придут все.
« Последнее редактирование: 09-10-2010 10:06 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #56 : 10-10-2010 12:36 » 

Так вот, если я определю размер очереди queuesize равным 1, то есть очереди не будет, то количество пропусков такое же, как и при размере очереди 15, а если значительно увеличивать размер очереди (queuesize=50), то кол-во пропусков увеличивается.

Уфф... Опять все неправильно... Я ведь несколько раз говорил, что запускать все запросы нужно до входа в цикл! Поэтому вот этот код:

Код:
for(int i=0; i<queuesize; i++)
{
    Success = ReadFile(PipeIn, &buf_r[i], 60, &RealRead, &gOverLapped_Read[i]);           
}

нужно поставить не внутрь цикла "while(stop_r == 0)", а перед ним. А в цикле просыпаться по ивенту одного единственного - очередного - выполненного считывания, т.е. очередной принятой порции данных. Получить эту порцию данных и снова запустить только вот это одно только что выполненное чтение! Т.о. в очереди всегда будет несколько ожидающих запросов, что и позволит принимать данные и быстро, и без потерь.

А то, что сделано у вас - это какое-то нагромождение непонятного кода, который работает без всякой очереди с разделением времени. Естественно, что queuesize равная 1 будет работать точно так же неправильно, как и queuesize = 15.

Чтобы очередь нормально работала (т.е. чтобы она вообще была) нужно просто реализовать алгоритм, который я подробно разжевал в посте #48.
Записан

MPEG-4 - в массы!
Bulat
Участник

ru
Offline Offline

« Ответ #57 : 14-10-2010 05:05 » 

Вроде получилось) Во всяком случае заметно влияние размера очереди queuesize. Правда больше 60 запросов не получается очередь сделать, не работает. Если приложение работает в режиме реального времени и отключен вывод по таймеру  принимаемого потока данных, то на медленных машинах пропусков нет, но дело в том, что я очередь сделал для приема, а для передачи еще не делал очереди. Насколько я понимаю, для передачи примерно такой же алгоритм, так что надеюсь, что решу эту проблему.
Код:
UINT ReceiveThread( LPVOID pParam )
{
unsigned char buf_r[queuesize][60];

for(int i=0; i<queuesize; i++)
{
hEvent_Read[i] = CreateEvent(
NULL,    // default security attribute
FALSE,    // auto-reset event
FALSE,    // initial state = nonsignaled
NULL);   // unnamed event object



// set up overlapped structure fields
gOverLapped_Read[i].Offset     = 0;
gOverLapped_Read[i].OffsetHigh = 0;
gOverLapped_Read[i].hEvent     = hEvent_Read[i];
}

stop_r = 0;
RealRead = 0;

for(int i=0; i<queuesize; i++) ReadFile(PipeIn, &buf_r[i], 60, &RealRead, &gOverLapped_Read[i]);

while(stop_r == 0)
{

nEvent = WaitForMultipleObjects(queuesize, hEvent_Read, FALSE, 100);
if(nEvent <= queuesize)
{
recv_index = nEvent;
Success = GetOverlappedResult(PipeIn,&gOverLapped_Read[recv_index],&RealRead, FALSE);
if (!Success)
{
// deal with the error code
switch (dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of
// the file during asynchronous
// operation

// deal with other error cases
}   //end switch (dwError = GetLastError())
}//if (!Success)
else {
memcpy(buffer_r[i_rcv],buf_r[recv_index],60);
i_rcv++;

if(RealRead) {RD_spd += RealRead; RealRead=0;}
ReadFile(PipeIn, &buf_r[recv_index], 60, &RealRead, &gOverLapped_Read[recv_index]);
} //Данные приняты
}

}//while(stop_r == 0)

return 0;
AfxEndThread(0, TRUE);
}

Спасибо большое за помощь!
Записан
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #58 : 14-10-2010 11:56 » 

похоже на правду)

PS кстати очень рекомендую всегда делать проверку ВСЕХ возможных возвращаемых значений на предмет ошибки.
это хороший стиль программирования, и всегда облегчает поиск багов)
а по нештатным возвращаемым значениям делать хотя бы MessageBox() или  assert().
это дает гарантию отлова таких ситуаций на момент поступления, а не по факту того: что непонятно где, непонятно что -  заработало криво.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #59 : 14-10-2010 20:30 » 

Вроде получилось)
...
Спасибо большое за помощь!

Ничуть не сомневался, что получится Улыбаюсь Успехов!
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #60 : 05-07-2011 13:05 » 

вот такой нюанс:
написал драйвер для USB 2.0 на Cypress-е FX2 (он же CY7C68013).
написал прошивку для самого CY7C68013 (там 51 процессор стоит).
добился обещанной производительности (порядка 40Мбайт/сек) - потоковый ввод!

логика работы всего этого безобразия.
в контроллере выделяю выходное (EP-3, IN) FIFO на 1кб*3. на всякий случай ставлю интервал опроса EP 1-2мс (реально ничем не отличаются от нуля). пакеты по 1кб.
при старте контроллера заполняю ВСЕ фифо 3мя пакетами по 1кб. далее по выталкиванию одного пакета (по прерыванию). заталкиваю еще 1кб (очень быстро, только заголовок меняю).
таким образом ФИФО контроллера всегда забито как минимум двумя готовыми к отправке пакетами.

теперь драйвер:
создал кольцевую очередь IRP-URB. (размер очереди может быть от 1 до 1024). чтобы всегда были необработанные IRP-URB запросы.
каждый запрос IRP-URB может содержать от 1кбайта до 256кбайт.
по обработке каждого IRP, зарегистрирована CompleteRoutine, которая по получению завершения IRP,  заново ставит ЭТОТ ЖЕ запрос IRP-URB в очередь: то есть фактически только IoCallDriver делает. и больше ничего. реально - ничего (interlockedIncrement наверное не в счет). к полученным данным больше никто не обращается.

ну вроде все ожило, начал бороться за производительность (в плане минимальной загрузки ЦП при максимальном потоке. и вот тут начались чудеса.
1. оказалось что 128 IRP в очереди - это не есть гуд. поток льется, но даже мышь по экрану не перемещается. оставил порядка 4-8 запросов.
2. дальше начал подбирать соотношение размера одного URB и количества IRP в очереди.
 вроде имеет смысл ставить размер запроса от 16 до 128кбайт, - это меняет частоту прерываний и частоту DPC.

а теперь то, что я понять не могу (графики загрузки ЦП - время ISR и время DPC при неизменной частоте ISR/DPC):
проц CoreDuo E8600 3.3ГГЦ. 4Г памяти. Windows XP-SP3.
контролер USB вроде intel.

вот эти хитрые всплески (только на DPC) примерно каждые секунд 30. и только при включенном вводе данных по USB.
вопрос: что это может быть? и как с этим бороться)

* USB_URB-256k_IRP-4.JPG (117.5 Кб - загружено 2375 раз.)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #61 : 15-09-2011 17:50 » 

вот такой нюанс:
написал драйвер для USB 2.0 на Cypress-е FX2 (он же CY7C68013).
...

Уважаемый коллега!

Весьма злободневная и интересная для меня тема! К моему огромному сожалению, я ничего не могу сказать по существу. Но мне хотелось бы обратиться к тебе с большой просьбой. Пожалуйста, поделись своим опытом!

Поясню. Я уже давненько работаю с этой микросхемой. До сих пор пользовался драйвером CyUSB.sys фирмы-изготовителя Cypress. Однако, также давно у меня возникали проблемы, связанные с необходимостью организации препарирования принимаемых сырых данных в самом драйвере. Дело в том, что мой прибор (ультразвуковой сканер) принимает данные разного рода по двум USB-каналам. Я каким-то левым образом организую их селекцию в триде приема (по-моему я об этом упоминал). Это не совсем хорошо.

Вот как выглядит комплект принимаемых данных из каналов приема:

1. Данные ультразвуковых лучей, представляющих собой УЗ-картинку.
2. Ультразвуковые данные конкретного места УЗ-картинки, формирующие "ленту самописца".
3. Ультразвуковые данные блока цветного допплера.
4. Данные блока обычного допплера.

Вся эта каша поступает по двум пайпам канала USB. Мне пришлось организовать два трида для их приема и сортировки "по принадлежности".

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

Большую часть этих проблем можно было бы устранить в случае применения своего драйвера. Ведь драйвер работает максимально близко к "железу" и обладает хорошей скоростью реакции на внешние события (приход очередной порции данных по USB).

Поэтому меня весьма заинтересовал факт, что ты написал драйвер для этой микросхемы. (Часом не на основе EzUSB?) Поделись, пожалуйста, исходниками и помощью в компиляции! Конечно, если это позволено твоей производственной политикой.

Спасибо!
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #62 : 15-09-2011 19:20 » 

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

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


чтоб я представлял, что хотелось бы:
а почему в один пайп все каналы смультиплексировать нельзя?
в каком виде данные на сайпрес приходят?  через какой интерфейс.
примерно опиши как хотелось бы, а я подумаю чего сделать можно.
да, и что за данные - потоковые, или по запросу?

PS обидно что 3-тий USB у сайпреса в течении месяца выйдет... сэмплы и демоборды уже были доступны с лета.

PPS я еще пока полностью не пробовал наступать на грабли QoS... в плане прерываемости по USB потока "из", потоком команд "в" и задержек передачи.

Добавлено через 3 дня, 23 часа и 37 секунд:
Ткнулся я в это дело... Пока отложил... Для начала поштудирую литературу. Я потом еще обращусь, хорошо?
PS обращайтесь, не вопрос)

PPS остальное перенес в c/c++)
« Последнее редактирование: 19-09-2011 18:25 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #63 : 19-09-2011 18:46 » 

чтоб я представлял, что хотелось бы:
а почему в один пайп все каналы смультиплексировать нельзя?
в каком виде данные на сайпрес приходят?  через какой интерфейс.
примерно опиши как хотелось бы, а я подумаю чего сделать можно.
да, и что за данные - потоковые, или по запросу?
У меня там такая каша... :-) Как это всегда бывает, началось с малого, а потом и это нужно добавить, и то...

Суть вот в чем:

Железо позволяет мне иметь два пайпа на ввод УЗ-данных.

1. Первый пайп принимает данные ультразвуковых лучей. Размер луча 512 байт, первый байт - флаговый (номер луча). Номера 0...254 - лучи картинки, 255 - спец-луч ленты самописца.

2. Второй пайп принимает данные блоков цветного и импульсного (обычного) допплеров. Цветной допплер генерирует лучи размером 4 кбайт, а импульсный - 512 байт. При этом, цветные лучи принимаются в виде восьми USB-пакетов.

Теперь, что со всем этим нужно делать.

1. Ультразвуковые лучи складываются в буфер кадра (согласно своего номера). Лучи самописца - в свой кольцевой буфер.

2. Лучи цветного допплера складываются в свой буфер кадра (тоже по номеру луча). А лучи обычного допплера - в свой кольцевой буфер.

Вся эта бодяга переваривается в DLL-ке с двумя высокоприоритетными тридами.

Для повышения надежности работы прием лучей и их предварительную сортировку я хотел бы делать в драйвере. Сложности тут никакой нет, но важна быстрая реакция на приходящие из USB пакеты. Иначе возникают дефекты картинки (если какие-то лучи выпадают).

Процесс УЗ-сканирования циклический, практически так же, как в обычном телике: набрали лучи на полный кадр - отобразили его на экране. Скорость поступления УЗ-лучей довольно высока: от 40 до 350 мксек. Допплеровские лучи идут в несколько раз медленнее, но неприятно то, что они все перемежаются друг с другом... Потому и каша получается :-)

P.S. Спасибо за перенос!
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #64 : 19-09-2011 19:06 » 

эээ... пока не вижу ничего такого...
там вроде был пример CyStream или как-то так... и вроде на нем сами сайпровцы демонстрируют потоковую скорость в 40мб? или я путаю?
либо вы забыли упомянуть, что то важное)
или как раз сложность каши - то есть синхронизации двух потоков? а родной драйвер сырой пакет не умеет отдавать? там вроде штамп времени был.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #65 : 19-09-2011 19:29 » 

Не, с 40МБ все ОК :-) Тут немного другое.

Если принимать из USB по 1 пакету, то проблем не будет. Но! Катастрофически падает быстродействие. Я опытным путем выяснил, что начиная с 8 пакетов за раз (т.е. к драйверу я обращаюсь за порцией в 8 пакетов), скорость приема становится приемлемой при сносной загрузке процессора. (В приборе стоит довольно слабенькая материнка.)

Однако, лучи самописца (т.н. М-лучи) и лучи обычного допплера нужно принимать очень быстро, сразу по их приходу. В результате получается, что в потоке обычных лучей в произвольные моменты времени вклиниваются М-лучи, которые я замечу только после того, как вся порция из 8-и пакетов (лучей) придет ко мне из драйвера. Это вызывает подергивание ленты самописца, что довольно неприятно.

Поэтому мне хочется убить одним выстрелом сразу двух зайцев вместо одного :-) Принимать по 1 пакету, но прямо в драйвере, т.е. быстро и без потери скорости работы. А приложению отдавать уже готовый кадр или одинаковые порции М-лучей.

P.S. У нас уже немало лет все более-менее работает. Но недавно возникла необходимость добавить еще и два допплеровских сигнала. Это тоже работает, но как-то на грани...
« Последнее редактирование: 19-09-2011 19:33 от jur » Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #66 : 19-09-2011 19:40 » 

ну кстати с приемом по одному пакету даже в драйвере не факт что быстродействие будет сильно лучше.
цифр не помню, но я ж тоже не зря размер URB запроса увеличивал до 16к и более. если меньше ставить - число ISR/DPC пропорционально расти начинает.
там в драйвере такая же ботва - ставишь требуемый размер и ждешь...
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #67 : 19-09-2011 20:03 » 

Не, погоди. Дело-то в том, что где-то там, в USBD.sys, из железа поступают именно отдельные пакеты. Они по одному следуют куда-то наверх, там заносятся в заданный буфер (те же 16К, к примеру) и по накоплении оного отдаются приложению.

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

Мне думается, что потери времени и производительности таятся в канале драйвер<->приложение, а не внутри драйвера. Ведь драйвер там, внизу все равно работает с каждым отдельным USB-пакетом индивидуально (т.е. запихивает его в буфер).
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #68 : 19-09-2011 20:26 » 

так вот в том и беда... что как только я ставил одиночные пакеты - что то мне не нравилось.... что конкретно - уже не вспомню. кажется число прерываний росло на порядок и число отложенных прерываний. соответственно ресурс ЦП жрался сильно. правда я при этом максимум потока из железа пересылал.
когда они по одному следуют - прерываний идет один к одному - сколько пакетов столько прерываний и отложенных прерываний.
а когда запросы групповые - видимо там в железке оно как-то компонуется при вычитке из аппаратного буфера. и прерываний меньше. других объяснений я не нашел...
в драйвере - доступа напрямую к железке и прерываниям - нет. там механизм точно таких же запросов через usbd.sys - строишь очередь запросов, и указываешь длинну каждого. можно и один пакет длины поставить - но тогда эти грабли в производительности.
может быть тебе поможет то что из разных пайпов можно разной длины запросы делать, но тоже не факт.

PS комп вообще не любит когда частота прерываний большая... при 40кГц у меня помню лет семь назад четвертый пень(или целерон?) загибался наглухо) сейчас наверное 20кГц прерываний - процентов 20% у 3ГГц проца жрет. если не ошибаюсь (на 1394 шине)
« Последнее редактирование: 19-09-2011 20:38 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #69 : 19-09-2011 21:09 » 

Весьма странно... Может быть я ошибаюсь, но работа с железом USB должна производиться по-пакетно. Иными словами, каждый пакет должен вызывать прерывание. (Как бы это посмотреть?) По этому прерыванию вызывается процедура обслуживания данного прерывания. Как пишут в книгах, реакция на аппаратное прерывание должна быть максимально быстрой и короткой, т.е. забрал пакет и тут же сбросил железный флаг прерывания. Потом, наверное, вызывается процедура обработки отложенного прерывания, которая забирает принятый пакет, кладет его в заданный буфер, сигнализирует пользователю, когда буфер заполнится и т.п.

Вот я и подумал, что если подцепиться к этому самому USBD.sys, то можно направлять поступающие пакеты не в общий сборник, а в разные процедуры отложенных прерываний. А т.к. драйвера, при вдумчивой организации дела, общаются между собой без переключения контекста, то и скорость должна быть хорошей, и загрузка процессора (сверх того, что и так есть) не должна сильно возрасти. Не так?
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #70 : 23-09-2011 14:51 » 

пардон. забыл ответить)
1. работа с железом не попакетно. прерывание генерить на каждый пакет можно, но на полной скорости - машина помрет) поэтому прерывание  генерится на порцию пакетов по запросу. видимо. это программно настраивается для каждого запроса.
2. к USBD тут не прицепишся таким образом. у него есть интерфейс - к нему все и цепляется. но сверх его возможностей - ничего не придумаешь. получать пакеты по одному можно, но... если поток не на полной скорости и ресурс ЦП можно тратить в угоду задержки доставки пакета.
насчет того что драйвера общаются.... это отдельная тема для разговора) в данном случае не это главное.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #71 : 27-09-2011 18:25 » 

Пребываю в полнейшем непонимании... Неужели там, внизу, железо программируется на получение нескольких пакетов?... Ведь это более чем сложно! Могут ведь приходить отбросы пакетов, требующие повторного считывания. Как это будет переваривать железо? Ведь ему придется отслеживать число нормально принятых пакетов, повторно считывать плохие, опять-же, хорошие пакеты куда-то складывать... И только по завершению приема всей пачки вырабатывать прерывание. А ведь перед этим USBD еще должен зарезервировать соответствующий буфер для переменного числа пакетов (соответственно, переменного размера)... А если буфер большой? Как железо с этим разберется? Вот запросит пользователь 1МБ данных - как железо организует прием 2000 пакетов перед тем, как выработать прерывание?...

Да... Нескоро я все это пойму :-)
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #72 : 27-09-2011 20:07 » 

там не совсем так...
передача все равно происходит по одному пакету. как только ПК примет один пакет - он формирует подтверждение приема для  устройства(для builk пакетов). и кстати инициатором передачи всегда является комп. даже если данные идут от устройства.
в контроллере ПК(хост) есть небольшой буфер(я совсем подробно не изучал). думаю, что что буфер не очень большой, думаю - порядка десятков-сотен кб.
а вот он уже выгребается по прерыванию программно. тонкости программирования хоста - я опять не же не изучал.
меня интересовало лишь накладные расходы на обработку этого прерывания и вообще получения данных. но факт в том, что при формировании программного запроса к USBD, указывается объем данных которые пользователь желает получить. и скорее всего реализация программно-аппаратная.
да, можно указать в качестве объема получаемых данных - один пакет, и делать очередь запросов. но при этом при общем потоке порядка 40мбайт/с значительно растут накладные расходы на обработку прерывания(ISR) и обработку отложенного прерывания(DPC). вплоть до 40-50% ресурсов ПК(а может и более, уже не помню)
поэтому я стал увеличивать длину одного запроса до тех пор, пока производительность не упала до некой "минимальной" величины. при этом длина запроса примерно составляла указанную ранее величину.

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

если интересно почитайте перевод статьи "USB in a NutShell" на русский
там относительно коротенько и по русски о работе шины с аппаратной точки зрения. в общих чертах, для ознакомления. или Агурова, но там "воды" много)

PS я уже несколько подзабыл свои опыты... начал сомневаться насчет того, по какому закону число прерываний от длины запроса зависит)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #73 : 29-09-2011 16:24 » 

Большое спасибо, коллега, за помощь и ссылку! Попытаюсь дальше поковырять что там и как...

Однако... (Здоровенная ложка, даже скорее половник, дегтя в вожделенную бочку щедрой рукой влила Микрософт, будь она неладна...) Все более серьезно встает вопрос о подписи драйвера CyUSB.sys (да и моего - тоже, если когда-нить его разработаю). Статью про подписание драйверов читал, но еще не до конца понял, как это делается. Там упоминается тестовое окружение. А будет ли таким образом подписанный драйвер работать в любом окружении? IMHO, вся эта идиотская затея Микрософта не стоит и выеденного яйца! Все равно, злоумышленник обойдет эту херню как два пальца, а честные разработчики страдают... Я понимаю, лозунг: "Бабло побеждает зло!" висит у Гейца в Красном Углу. Но нельзя же быть настолько...

Ох, сладко мечтаю о том, что бы я сотворил с Гейцем и Балмером с помощью серпа!! :-)

P.S. Мощной струей вливаюсь в обсуждение Windows Embedded CE :-) Пока использую поиск и формулирую вопросы, стараясь выделить самый главный из них :-) Тебя, коллега, Win CE 6.0 часом не привлекает? (Возможно привлекает? Ведь это напрямую относится к разделу "Встраиваемые системы".)
« Последнее редактирование: 29-09-2011 16:32 от jur » Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #74 : 29-09-2011 19:50 » 

на майкрософт вы зря ругаетесь) сам не подписывал, но насколько слышал - это не так страшно, как кажется)
и потом... у вас всегда есть альтернатива в качестве линукса)))))
про подписание были вопросы на этом форуме. по-моему у людей все получалось...

тестовое окружение, если я правильно вас понял - имеется в виду некий режим в который можно принудительно  перевести ОС? при этом она не проверяет подписи. но это просто для удобства отладки при частой смене бинарника. это никоим образом не рабочий режим.

СЕ6.0 - нет, не входит в круг задач... быть может когда нибудь войдет что нибудь RealTime на каком нибудь DSP... но CE - вряд ли. ну еще Windows XP  Embeded может быть.. да и то вряд ли)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #75 : 29-09-2011 20:57 » 

на майкрософт вы зря ругаетесь) сам не подписывал, но насколько слышал - это не так страшно, как кажется)

Дык... Как же их не ругать, если они такую черню сочинили?! А что не страшно... Интернет ломится от стонов. Большинство смиряются и башляют. Однако, мне - как советскому человеку - совесть не позволяет раскошеливаться просто из-за того, что какой-то хрен с горы придумал очередное разводилово :-)

и потом... у вас всегда есть альтернатива в качестве линукса)))))

Увы, нету... Я в этом Линуксе ну совершенно не копенгаген... Как это, чтобы не было диска C:\ ?... :-)

про подписание были вопросы на этом форуме. по-моему у людей все получалось...

Искал я... Кстати, именно из вашего поста я почерпнул полезнейшую ссылку про подписание драйверов :-) Однако про опыт применения данной методики ничего не нашел...

тестовое окружение, если я правильно вас понял - имеется в виду некий режим в который можно принудительно  перевести ОС? при этом она не проверяет подписи. но это просто для удобства отладки при частой смене бинарника. это никоим образом не рабочий режим.

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

P.S. А Windows XP Embeded, зараза, дорогущая... С несколькими баксами Win CE не сравнить. Это при том, что 90% всей присутствующей в XP фигни нам в приборе даром не надо...
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #76 : 29-09-2011 21:23 » 

в 32битной семерке мой драйвер работает без подписи.
 мои шаловливые ручки пока не добрались до 64 битной платформы) так что пока ничего не могу сказать)
и народ что то не отписывал - что у них в итоге получилось...
« Последнее редактирование: 29-09-2011 21:25 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #77 : 30-09-2011 16:07 » 

в 32битной семерке мой драйвер работает без подписи.

Когда я пробовал свою систему на Win 7 до SP1, то у меня тоже все нормально заработало. Просто поставил драйвер CyUSB.sys  и порядок. А недавно мне снова понадобилось попробовать - и облом... Драйвер уже не устанавливается. (Я работаю исключительно с 32-битными системами.) Во гады мелкомягкие! :-)

и народ что то не отписывал - что у них в итоге получилось...

Во, во... Это даже как-то странно... Ведь наверняка эти проблемы возникают у множества коллег! Так какого ... они молчат?...
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #78 : 01-10-2011 00:59 » 

ну... подозреваю что мелкомягкие тут не при чем)
и вообще. я люблю микрософт)  у них изумительная документация - только сейчас это начал это ценить) или я просто научился ей пользоваться))))
а что не описывали... скорее всего все получалось. либо проблема не стояла так остро...
я больше надеюсь не первый вариант)
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #79 : 01-10-2011 15:55 » 

ну... подозреваю что мелкомягкие тут не при чем)

Здрасьте! А какая же тогда вражина ввела в новую Винду эту зловредную и совершенно бессмысленную процедуру запрета загрузки драйверов?! :-) (Понимаю... Проклятые марсиане... Угадал? :-)

и вообще. я люблю микрософт)  у них изумительная документация - только сейчас это начал это ценить) или я просто научился ей пользоваться))))

Я тоже не линуксоид :-) Хотя и неоднократно пытался проникнуться этой идеологией. Но у меня не получилось. Не люблю бардака и не умею вылавливать жемчужины полезной информации в широкой реке всякого хлама... Жаль, конечно, но я такой...

А научи, пожалуйста, и меня пользоваться их документацией?
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #80 : 01-10-2011 21:55 » 

Здрасьте! А какая же тогда вражина ввела в новую Винду эту зловредную и совершенно бессмысленную процедуру запрета загрузки драйверов?! Улыбаюсь (Понимаю... Проклятые марсиане... Угадал? Улыбаюсь

А научи, пожалуйста, и меня пользоваться их документацией?

во первых - только в x64.
а во вторых - не нахожу никакого запрета) кто мешает подписать?
а в третьих - должен быть какой то порядок...
хотя если говорить о будущем.... требования подписи - приведет к вытеснении с рынка мелких компаний. но у меня ощущение, что это повсеместно происходит.

а пользоваться документацией - очень просто) сначала роем интернет, потом внимательно читаем каждую букву их документации раза по три. так же читаем все, по  ссылкам данным на странице описания функции. и только потом внимательно пишем код, проверяем все статусы и делаем полную обработку всех возможных и невозможных ошибок, включая абсурдные. а потом не запуская полученное, заново перечитываем всю документацию)
для меня хорошо написанная функция - это та, которая в случае ошибки возвращает все ею сделанное в исходное состояние) и возвращаемый статус которой дает исчерпывающее объяснение ошибки. у меня это занимает до 70-80 процентов написанного кода)
хотя есть у них только один нюанс - все функции описываются изумительно а вот построение тех или иных подсистем и логика их взаимодействия - плохо. приходится разбирать по их примерам, которые зачастую сильно перегружены посторонней информацией.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #81 : 16-02-2013 03:30 » 

Кстати в процессе моих ковыряний с CY7C68013 на своем драйвере удалось достичь устойчивой потоковой скорости 48 Мбайт/с. ввод через 16-битный Ep2 4*1кБ от FPGA.
49 МБайт/с - уже не успевает, но может еще на других машинах проверю)

делал через непрерывную очередь запросов URB, после завершения каждого - заново ставлю запрос в очередь. запросы не менее 8кБ. количество запросов 8 и более. на конкретных цифрах пока не остановился. еще буду экспериментировать.
« Последнее редактирование: 16-02-2013 03:37 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #82 : 22-11-2014 12:40 » 

Приветствую!

Давненько мы не брали в руки шашек! :-)

Долго и упорно я сопротивлялся. Да и Cypress мне в этои помогала, выпустив подписанные драйвера под современные операционки (я про Винду). Но все хорошее когда-нибудь кончается...

По причине не реал-таймовости Винды назревает необходимость написать-таки свой драйвер. Я подумал о драйвере типа User mode driver.

Хотел спросить:

1. User mode driver позволит добиться приближения к реальному времени? Т.е. сможет ли он сразу получить управление, когда прийдет пакет из шины USB?

2. Если написать такой драйвер над стандартным драйвером ядра (от той же Cypress), нужно ли его тоже подписывать?

Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #83 : 22-11-2014 19:00 » 

1.
к сожалению не знаю архитектуру usermode-usb да и понятия "реалтайм" и "сразу" - весьма размыты)))
2. подпись вроде нужна.
Цитата
The driver code signing policy starting with Windows Vista and later versions of Windows requires that the following types of drivers have digital signatures:
For 64-bit versions of Windows, all kernel mode software, including, but not limited to, kernel-mode device drivers.
For 64-bit versions of Windows, user mode drivers, such as printer drivers.
Drivers that stream protected content.
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #84 : 26-11-2014 17:04 » 

1.к сожалению не знаю архитектуру usermode-usb да и понятия "реалтайм" и "сразу" - весьма размыты)))

"Давай поговорим об этом" (С) :-) (Ниже.)

2. подпись вроде нужна.

Я задал вопрос на форуме Кварта Технологии. Они, вроде как, круты в области embedded. Пока сказали, что "Для 32-битной операционной системы драйверы подписывать не обязательно. Будет просто предупреждение при установке драйвера." Жду дальнейших ответов. (см. P.S.)

Так вот, о драйвере. Я сначала обрисую ситуацию, как я ее понимаю.

1. Имеется системный драйвер шины USB. Он работает напрямую с железом (наверное через драйвера более низкого уровня).
2. Каждый пришедший пакет USB вызывает аппаратное прерывание (возможно я не прав). Этот пакет передается драйверу более высокого уровня, если таковой имеется.
3. Этот драйвер может что-то сделать с поступившим пакетом. Например, запомнить в буфере и выдать ивент процедуре позднейшей обработки (типа своей DPC).
4. Эта DPC запустится и выполнит с пришедшим пакетом нужные действия. Именно это меня и интересует. В этой процедуре я могу положить пришедший пакет в нужный буфер, проверить номер пакета, выдать ивент приложению, что, мол, нужная группа пакетов пришла и т.п.

Я предполагаю, что возможно в моем драйвере выполнить пункты 3 и 4. Функции п.3 получат управление немедленно (конечно, с учетом других функций этого же и более высокого приоритета). Именно этот момент я и подразумеваю под "реальным временем". Т.е. я надеюсь, что моя функция п.3 "сразу" получит управление. Конечно, я не могу надолго занимать процессор, поэтому она немедленно скопирует пакет в свой локальный буфер и запустит процедуру из п.4. Та дождется исполнения и дальше поступит с пакетом так, как ей указано.

Уважаемый коллега, пожалуйста, поправьте меня, если я что-то не так понимаю. Ведь, попросту говоря, эти самые драйверные функции, ранжированные по приоритетам, и составляют реалтаймовую часть Винды. Я не прав?

P.S. Меня, как разработчика приборов, интересует именно embedded ОС. Если в обычной десктопной операционке политика с подписью более строга, то это не будет меня смущать применительно к моему прибору. Который базируется и будет базироваться именно на встроенном варианте операционки.

« Последнее редактирование: 26-11-2014 17:11 от jur » Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #85 : 27-11-2014 10:27 » 

2. не каждый. по крайней мере у меня на поток 48Мб - было 2700 прерываний/сек сто при максимальном размере пакета в 1кб по шине - не сходится. так что там тоже какое то фифо стоит в контроллере ПК
3. ваш драйвер аппаратные прерывания USB не получит - в любом случае это будут лишь отголоски DPC. но это будет довольно шустро и кажется даже на DISPATCH_LEVEL. точно не знаю но думаю что CompletionRoutine от IOCTL_INTERNAL_USB_SUBMIT_URB  скорее всего и вызывается из DPC.

теперь поправляю) у винды нет и никогда не было реалтаймовской части! у нее практически везде - очереди и приоритеты. и при этом она не обещает и не гарантирует что очередь дойдет и завершится за заданное число тактов.
и даже DPC все равно выполняются по очереди.


Добавлено через 1 минуту и 32 секунды:
embedded ОС - ничего не могу сказать. 32 бита да - без подписи.
сертификат для подписи стоит что то порядка 100-200$/год.
« Последнее редактирование: 27-11-2014 10:29 от Ochkarik » Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
jur
Помогающий

lt
Offline Offline

« Ответ #86 : 01-12-2014 19:33 » 


Сегодня наконец-то получил ответ от спеца из Кварта Технологии. Вариант POSReady новой линейки операционок от Микрософт есть. Называется Windows Embedded 8.1 Industry. Это неплохо.

Про реалтаймовость все-равно не понимаю... Ведь если системные драйвера реагируют на аппаратные прерывания, причем достаточно быстро, так это и можно считать очень близким приближением к реалтаймовости. Нет? Конечно, не как в CE с ее 5 микросекундами, но все-же. Например, надстройка RTX позволяет оперировать временем реакции на прерывание порядка 5-10 микросекунд.

Но я думаю, что параметров RTX мне не нужно. Возможно DPC на уровне DISPATCH_LEVEL меня вполне устроит.

(У меня сейчас в голове каша неимоверная! :-))

Буду думать дальше...

P.S. Тут давеча (в прошлом году вроде) Cypress выложила исходники своего драйвера и CyAPI. Молодцы ребята! Они пишут, что нужна версия Windows Driver Kit Version 7.1.0 (BASEDIR=C:\WINDDK\7600.16385.0). Я ее скачал, но еще не попробовал. Пока раскачиваюсь...
Записан

MPEG-4 - в массы!
Ochkarik
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #87 : 01-12-2014 21:03 » 

RTX системный таймер позволяет перепрограммировать,  на нескольких порядков вниз.
я просто призываю осторожно обращаться со словом "реалтайм") драйвера "реагируют" и "достаточно быстро" это не линейка и не весы) и может различаться в зависимости от чужих железок и дрйверов.
  надо смотреть и набирать статистику на конкретном железе.
кашу - лечить соломоном-руссиновичем на ночь, последовательно, все, два раза)
PS драйвер? пропустил... ща посмотрим)) спасибо!
Записан

RTFM уже хоть раз наконец!  RTFM :[ ну или хотя бы STFW...
Страниц: 1 2 3 [Все]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines