Перейти к содержанию
    

Второй день воюю над автоматическим определением своего девайса программой под винду.. Пришел к выводу, что либо я либо лыжи.. Вобщем есть устройство, состоящее из FT232R и МК. Программа под винду которую пишу в теневом режиме каждые 5 секунд проверяет подключен ли девайс к компу. Алгоритм определения именно моего устройства следующий: с помощью функций библиотеки ftd2xx.dll я определяю сколько FT устройств подключено, затем по их порядковым индексам получаю серийные номера всех этих устройств и начинаю поочереди их открывать с заданными параметрами обмена (скорость, стопы, четность, управление), при каждом открытии FT устройства я отправляю 2 байта 0x58, чтобы вывести МК моего устройства на рабочий режим, затем передергиваю вывод RTS ("1" -> "0" -> "1"), при этом передергивании МК отвечает 1 байтом 0x3E (МК переходит в режим настройки извне), затем снова отправляю 2 байта 0x58, чтобы вывести МК снова в рбочий режим. В итоге если после всех этих операций в приемном буфере остается принятый 0x3E, то я считаю что именно мое устройство подключено к компу и прерываю цикл проверки подключенных FT устройств и возвращаю в программу серийный номер FT устройства, определенного как мое устройство. Привожу ниже фрагмент кода функции, проделывающей эти операции с уже открытым FT устройством (после выполнения этой функции устройство закрывается в месте откуда эта функция была вызвана).

 

function getModemAnswer(FTHandle)
    --clear scanning flag
    RFMfound = false;
    --setting RX and TX timeouts, set latency timer
    result1 = modem:SetTimeouts(FTHandle,50,50);
    result2 = modem:SetLTimer(FTHandle,10);
    result3 = modem:SetRTS(FTHandle, false);
    if (result1 == 0 and result2 == 0 and result3 == 0) then
        --transmit 2 bytes (0x58,0x58) mean EXIT
        result1 = modem:WriteFrame(FTHandle,{88,88},2);
        if (result1 == 2) then
            Dialog.Message("Notice", FTLibraryVer, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1); -- delay 1
            --reset RX,TX buffers
            temptable3 = modem:FTReset(FTHandle,false,false,true,true);
            if (temptable3[3] == 0 and temptable3[4] == 0) then
                --enter RFM configure mode
                result1 = modem:SetRTS(FTHandle, true);
                result2 = modem:SetRTS(FTHandle, false);
                if (result1 == 0 and result2 == 0) then
                    --transmit 2 bytes (0x58,0x58) mean EXIT
                    result1 = modem:WriteFrame(FTHandle,{88,88},2);
                    if (result1 == 2) then
                        Dialog.Message("Notice", FTLibraryVer, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1); -- delay 2
                        --reading answer (0x3E), if possible
                        temptable3 = modem:ReadFrame(FTHandle,1);
                        temptable4 = temptable3[3];
                        if (temptable3[1] == 0 and temptable3[2] > 0 and temptable4[1] == 62) then
                            RFMfound = true;
                        end
                    end
                end
            end
        end
    end
    return RFMfound
end

 

строки помеченные как delay 1 и delay 2 добавлены вынуждено как раз по причине "меня или лыж". Эти две строки являются своеобразными точками останова временно пока не разберусь, только так мое устройство определяется программой (т.е. байт 0x3E выуживается успешно). Попытки заменить эти диалоговые окошки на пассивные задержки (т.е. пустые циклы) только затормаживают работу программы и при этом все равно не получается отловить нужный байт. Главные вопросы и непонятки на данный момент: НА КОЙ ЧЕРТ в библиотеке ftd2xx.dll нужна функция установки таймаутов по приему и передачи? К примеру, я увеличиваю задержку по приему до 5000мс, чтобы избавиться от строки delay 2, но это не спасает и после вызова функции FT_Read и отработки интервала 5000 мне возвращается значение кол-ва принятых байт = 0! Я думал этот таймаут как раз и нужен для того чтобы допустим вызвать FT_Read с кол-вом байт которые должны быть приняты например 256 и ждать свой 1 байтик все 5 секунд пока он появится, на практике так не получается. Таймаут для передачи тож непонятно как работает, но я пока с ним особо не игрался.. Также есть еще установка времени запаздывания FT_SetLatencyTimer (от 2 до 255мс), это чиво еще такое? С библиотекой работаю через написанный свой ActiveX враппер, поэтому поясню приведенный код:

 

SetTimeouts(FTHandle,50,50) - эт я устанавливаю таймауты для RX и TX

SetLTimer(FTHandle,10) - эт равносильно FT_SetLatencyTimer

SetRTS(FTHandle, false), SetRTS(FTHandle, true) - сброс/установка сигнала RTS

WriteFrame(FTHandle,{88,88},2) - посылка массива из двух элементов

FTReset(FTHandle,false,false,true,true) - универсальная функция сброса, сброс: порта, устройства, RX буффера, TX буффера (в данном случае 2 последних сбрасываю)

ReadFrame(FTHandle,1) - функция чтения из буффера, возвращает массив, 1й элемент - код ошибки (если были), 2й - кол-во принятых байт, 3й - содержит массив, собственно полученные данные

 

Я конечно догадываюсь, что мой выход из ситуации - это работать по таймерам внутри своей программы под винду, НО. ЗАЧЕМ ВСЕ ЭТИ ТАЙМАУТЫ предоставляемые библиотекой ftd2xx.dll? Может я неправильно понимаю логику их работы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я думаю что часть таймаутов идут от тех что были в структуре COMMTIMEOUTS. Если найдете их подробное описание - то станет понятно что за что отвечает и тут.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

When a read timeout value has been specified in a previous call to FT_SetTimeouts, FT_Read returns when the timer expires or dwBytesToRead have been read, whichever occurs first. If the timeout occurred, FT_Read reads available data into the buffer and returns FT_OK.

 

Когда значение таймаута чтения определено предыдущим вызовом функции FT_SetTimeouts, FT_Read возвращает когда таймер истечёт, или количество байт (dwBytesToRead) будет прочитано, что произойдёт первым. Если время истекло, FT_Read считывает доступные данные в буфер и возвращает FT_OK.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

FT_Read returns when the timer expires or dwBytesToRead have been read, whichever occurs first. If the timeout occurred, FT_Read reads available data into the buffer and returns FT_OK.

 

я про это понимать)) я не понимать следующее: приведенный комментарий в programmers guide означает, что вызов функции FT_SetTimeouts запускает таймер (приема/передачи) или его предустанавливает, а запуск таймера происходит при вызове функции FT_Read? какая логика? Я сейчас склонен подумать, что все таки первое, т.е. я должен вызывать функцию FT_SetTimeouts непосредственно перед вызовом функции FT_Read.. не угадал? :-)

 

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

Изменено пользователем vazz

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что такое FT_SetTimeouts я и сам не могу понять. А вот касательно FT_SetLatencyTimer есть в документе AN232B-04 (DataLatencyFlow) такое:

When transferring data from an FTDI USB-Serial or USB-FIFO IC device to the PC, the device will

send the data given one of the following conditions:

1. The buffer is full (64 bytes made up of 2 status bytes and 62 user bytes).

2. One of the RS232 status lines has changed (USB-Serial chips only). A change of level (high

or low) on CTS# / DSR# / DCD# or RI# will cause it to pass back the current buffer even

though it may be empty or have less than 64 bytes in it.

3. An event character had been enabled and was detected in the incoming data stream.

4. A timer integral to the chip has timed out. There is a timer (latency timer) in the FT232R,

FT245R, FT2232C, FT232BM and FT245BM chips that measures the time since data was last

sent to the PC. The default value of the timer is set to 16 milliseconds. Every time data is

sent back to the PC the timer is reset. If it times-out then the chip will send back the 2 status

bytes and any data that is held in the buffer.

 

Тут особенно интересен 4-й пункт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

короче заработало вот так:

 

function getModemAnswer(FTHandle)
    --clear scanning flag
    RFMfound = false;
    --setting RX and TX timeouts, set latency timer
    result1 = modem:SetTimeouts(FTHandle,500,0);
    result2 = modem:SetLTimer(FTHandle,2);
    result3 = modem:SetRTS(FTHandle, false);
    if (result1 == 0 and result2 == 0 and result3 == 0) then
        --transmit 2 bytes (0x58,0x58) mean EXIT
        result1 = modem:WriteFrame(FTHandle,{88,88},2);
        if (result1 == 2) then
            passDelay(50000); --delay 1
            --reset RX,TX buffers
            temptable3 = modem:FTReset(FTHandle,false,false,true,true);
            if (temptable3[3] == 0 and temptable3[4] == 0) then
                --enter RFM configure mode
                result1 = modem:SetRTS(FTHandle, true);
                result2 = modem:SetRTS(FTHandle, false);
                if (result1 == 0 and result2 == 0) then
                    --transmit 2 bytes (0x58,0x58) mean EXIT
                    result1 = modem:WriteFrame(FTHandle,{88,88},2);
                    if (result1 == 2) then
                        passDelay(50000); --delay 2
                        --reading answer (0x3E), if possible
                        temptable3 = modem:ReadFrame(FTHandle,1);
                        temptable4 = temptable3[3];
                        if (temptable3[1] == 0 and temptable3[2] > 0 and temptable4[1] == 62) then
                            RFMfound = true;
                        end
                    end
                end
            end
        end
    end
    return RFMfound
end
--passive delay function
function passDelay(pDelay)
    for passcount = 0, pDelay do
        -- empty cycle
    end
end

 

но это не оч хороший способ.. все таки хотелось бы от просвященных людей услышать вразумительное объяснение как работают эти таймауты FT_SetTimeouts, если честно как я понял таймаут по приему начинает отсчет когда возникает условие что принимается байт, т.е. этот таймаут просто не сработает если например задат его равным 5 секундам в момент когда фактически устройству FT ничего не передается из вне, грубо говоря таймаут начнет отрабатывать когда принят хотяб 1 байт, а если ничо не принято то и таймаут не запускается при вызове функции FT_Read. Из этого можно сделать вывод - таймауты эти эффективны только тогда, когда ты гарантированно знаешь что данные уже принимаются. А если ты оправил посылку устройству и ждешь ответа например миллисекунд так через 10-20, то этот таймаут по приему из библиотеки не сработает вообще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В стандартных примерах от FTDI они используют поллинг по фукнции FT_GetQueueStatus - она показывает сколько байт принято и находится в буфере чипа.

Вот из примеров на Delphi:

Repeat

Application.ProcessMessages;

PortStatus := Get_USB_Device_QueueStatus;

If PortStatus <> FT_OK then // Device no longer present ...

Begin

CloseFile(SaveFile);

Timer1.Enabled := True;

StatusBar1.Panels[0].Text := '';

Exit;

End;

Until FT_Q_Bytes > 0;

 

Кстати, тут может быть важно то, что они используют постоянно запуск функции Application.ProcessMessages для отработки системой всех накопленных запросов. Хотя, может, это особенность именно Delphi.

 

Кстати, попутный вопрос, чтобы не начинать новую тему - кто-нибудь использовал BaudRate 3 MBaud или 2 MBaud ? Интересно, почему в стандартном примере BaudRate константы прописаны только до 921600 ?

Изменено пользователем Schulz_K

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

может запоздал.

возникала такая же задача решил её потоками, при чём считывать серийный код микросхемы нет надобности.

приведу только алгоритм работы моей программы.

1. определяем количество устройство на основе FT232xx FT_CreateDeviceInfoList(&amount_dev), count_dev = 0;

1.5 открываем устройство count_dev, если устройства обнаружены

2. устанавливаем параметры микросхемы

3. посылаем байты в устройство

3. настраиваем событие CreateEvent (в мануале для программеров есть как и что)

4. запускаем поток на чтение данных

5. если данные не прочитаны, закрываем устройство и count_dev++;

6. переходим к 1.5, пока count_dev < amount_dev

 

пишу на С эта функция заняла место в 15 строчек, не считая настроек

 

также в созданном потоке происходит проверка принятых комманд и их обработка.

имхо это будет лучше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как Вы думаете, могла ли FT232RL "подгореть" из-за того, что я на разъеме перепутал выводы из-за неправильной разводки (питание пошло на линии D+, D-). Сейчас устройство работает в BitBang-режиме, но при выдаче массива на выводы поток как бы рвется. И периодически теряется связь с микросхемой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как Вы думаете, могла ли FT232RL "подгореть" из-за того, что я на разъеме перепутал выводы из-за неправильной разводки (питание пошло на линии D+, D-).

Маловероятно.

 

И кроме того, why not to use WM_DEVICECHANGE?

(али у Вас не виндА?)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Маловероятно.

И кроме того, why not to use WM_DEVICECHANGE?

(али у Вас не виндА?)

Винда XP, программирую на Delphi. Is there any examples how to use that method?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А, пардон, плохо читал, виндА.

Тогда в качестве компенсации за моральный вред кусок кода, обрабатывающего горячее отключение-подключение USB устройства без "периодического опроса" (Windows Forms):

 [SecurityPermission(SecurityAction::Demand, Flags=SecurityPermissionFlag::UnmanagedCode)]
        virtual void WndProc( Message% m ) override
        {
            // Listen for operating system messages.
            switch ( m.Msg )
            {
                case WM_DEVICECHANGE:
                    // The WParam value identifies what is occurring.
                    if ( DBT_DEVNODES_CHANGED == (int)m.WParam ){
                        // .. and close any last open FTDI device. 
                        if (this->FTDI_device_list->RebuidFTDIportsList()){
                            // Any GUI controls are reset after the FTDI device is found working.
                            EnableControls(FTDI_device_list->ftStatus);     // using registry restored values, init GUI controls
                                                                                                // open the FTDI device there too.       
                        }
                    }
                break;
            }
            Form::WndProc( m );
        }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

svss, спасибо. Правда во время зависания устройство не отваливается (нет характерного звука), а зависание обнаруживается при попытке получить список доступных устройств или при попытке послать данные. Лечится передергиванием шнура (уже с характерными звуками).
Изменено пользователем МП41

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Бывало подобное. Мучился, даже на FTDIchip жалобы писАл. Отвечали: "освежи драйвер".

Давно, правда, было - года два тому. Но помогало. Один раз FTDI даже написали upgrade драйвера по моей наводке-жалобе на синий экран.

Впрочем, это - другая история.

 

В Вашем случае проблема, возможно, в Вашей софтИне.

Как гарантируется закрытие устройства при падении клиента?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что проверил, у FTDI есть уже откомпилированная программа, которая слушает эти WM_DEVICECHANGE и выводит соответствующие сообщения. При зависании устройства ничего не произошло, а зависло оно после того, как было подключено на горячую 12В питание связанных с FT232R цепей. Отвисло только после выдергивания шнура USB.

 

В Вашем случае проблема, возможно, в Вашей софтИне.

Как гарантируется закрытие устройства при падении клиента?

Да в софте там всё "стандартно" и просто до безобразия, открываю устройство по серийному номеру, и если открытие произошло успешно, то посылаю пачку байт в битбэнге и закрываю. Соответственно если открытия не произошло, то и закрывать по условию не будет. А если зависнет, то после передергивания шнура программа пишет что-то вроде "General I/O Error" и другие ошибки. Больше склоняюсь к кривой разводке, хотя тантал стоит, керамика разных размеров и т.д.

 

И еще не понимаю почему, отсылаю пачку байт на порты из примерно 8кБ, а эта пачка на выходе при одних скоростях рвётся, а на других - нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...