vazz 0 26 апреля, 2011 Опубликовано 26 апреля, 2011 · Жалоба Второй день воюю над автоматическим определением своего девайса программой под винду.. Пришел к выводу, что либо я либо лыжи.. Вобщем есть устройство, состоящее из 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? Может я неправильно понимаю логику их работы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firstvald 24 26 апреля, 2011 Опубликовано 26 апреля, 2011 · Жалоба Я думаю что часть таймаутов идут от тех что были в структуре COMMTIMEOUTS. Если найдете их подробное описание - то станет понятно что за что отвечает и тут. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lvbnhbq 0 26 апреля, 2011 Опубликовано 26 апреля, 2011 · Жалоба 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 27 апреля, 2011 Опубликовано 27 апреля, 2011 (изменено) · Жалоба 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.. не угадал? :-) не угадал походу) попробовал непосредственно перед чтением вставить установку таймаутов, не помогло.. Изменено 27 апреля, 2011 пользователем vazz Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Schulz_K 0 27 апреля, 2011 Опубликовано 27 апреля, 2011 · Жалоба Что такое 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-й пункт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 27 апреля, 2011 Опубликовано 27 апреля, 2011 · Жалоба короче заработало вот так: 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, то этот таймаут по приему из библиотеки не сработает вообще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Schulz_K 0 27 апреля, 2011 Опубликовано 27 апреля, 2011 (изменено) · Жалоба В стандартных примерах от 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 ? Изменено 27 апреля, 2011 пользователем Schulz_K Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mozart 0 21 сентября, 2011 Опубликовано 21 сентября, 2011 · Жалоба может запоздал. возникала такая же задача решил её потоками, при чём считывать серийный код микросхемы нет надобности. приведу только алгоритм работы моей программы. 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 строчек, не считая настроек также в созданном потоке происходит проверка принятых комманд и их обработка. имхо это будет лучше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mp41 0 31 января, 2012 Опубликовано 31 января, 2012 · Жалоба Как Вы думаете, могла ли FT232RL "подгореть" из-за того, что я на разъеме перепутал выводы из-за неправильной разводки (питание пошло на линии D+, D-). Сейчас устройство работает в BitBang-режиме, но при выдаче массива на выводы поток как бы рвется. И периодически теряется связь с микросхемой. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
svss 0 31 января, 2012 Опубликовано 31 января, 2012 · Жалоба Как Вы думаете, могла ли FT232RL "подгореть" из-за того, что я на разъеме перепутал выводы из-за неправильной разводки (питание пошло на линии D+, D-). Маловероятно. И кроме того, why not to use WM_DEVICECHANGE? (али у Вас не виндА?) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mp41 0 31 января, 2012 Опубликовано 31 января, 2012 · Жалоба Маловероятно. И кроме того, why not to use WM_DEVICECHANGE? (али у Вас не виндА?) Винда XP, программирую на Delphi. Is there any examples how to use that method? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
svss 0 31 января, 2012 Опубликовано 31 января, 2012 · Жалоба А, пардон, плохо читал, виндА. Тогда в качестве компенсации за моральный вред кусок кода, обрабатывающего горячее отключение-подключение 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 ); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mp41 0 31 января, 2012 Опубликовано 31 января, 2012 (изменено) · Жалоба svss, спасибо. Правда во время зависания устройство не отваливается (нет характерного звука), а зависание обнаруживается при попытке получить список доступных устройств или при попытке послать данные. Лечится передергиванием шнура (уже с характерными звуками). Изменено 31 января, 2012 пользователем МП41 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
svss 0 31 января, 2012 Опубликовано 31 января, 2012 · Жалоба svss, спасибо. Правда во время зависания устройство не отваливается (нет характерного звука), а зависание обнаруживается при попытке получить список доступных устройств или при попытке послать данные. Лечится передергиванием шнура (уже с характерными звуками). Бывало подобное. Мучился, даже на FTDIchip жалобы писАл. Отвечали: "освежи драйвер". Давно, правда, было - года два тому. Но помогало. Один раз FTDI даже написали upgrade драйвера по моей наводке-жалобе на синий экран. Впрочем, это - другая история. В Вашем случае проблема, возможно, в Вашей софтИне. Как гарантируется закрытие устройства при падении клиента? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mp41 0 31 января, 2012 Опубликовано 31 января, 2012 · Жалоба Только что проверил, у FTDI есть уже откомпилированная программа, которая слушает эти WM_DEVICECHANGE и выводит соответствующие сообщения. При зависании устройства ничего не произошло, а зависло оно после того, как было подключено на горячую 12В питание связанных с FT232R цепей. Отвисло только после выдергивания шнура USB. В Вашем случае проблема, возможно, в Вашей софтИне. Как гарантируется закрытие устройства при падении клиента? Да в софте там всё "стандартно" и просто до безобразия, открываю устройство по серийному номеру, и если открытие произошло успешно, то посылаю пачку байт в битбэнге и закрываю. Соответственно если открытия не произошло, то и закрывать по условию не будет. А если зависнет, то после передергивания шнура программа пишет что-то вроде "General I/O Error" и другие ошибки. Больше склоняюсь к кривой разводке, хотя тантал стоит, керамика разных размеров и т.д. И еще не понимаю почему, отсылаю пачку байт на порты из примерно 8кБ, а эта пачка на выходе при одних скоростях рвётся, а на других - нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться