чтение из FTDI-устройства
От: cr lf  
Дата: 11.07.07 06:06
Оценка:
Hi all,
кто-нибудь программировал устройства на базе микросхем FTDI ?
У меня вот тут на столе самопальный девайс и надо написать program, который будет с ним работать.
Например, мне нужно отслеживать появление сигнала на одной из входных линий устройства.
В настоящее время этот сигнал я подаю ручным замыканием двух контактов на печатной плате (в будущем это будет делать фотоэлемент, мимо которого проскользнул некий объект/субъект).
Имеется dll-библиотека процедур для работы с устройством.
Я пытаюсь делать так
while <условие> do begin
  Read_USB_Device_Buffer(1);
  Signal := FT_In_Buffer[0] and $10 <> 0; // поступил сигнал
    if Signal then begin
     работа
    .............
    end;
end


Проблема в том, при замыкании контактов я имею не один сигнал (единичку в 4-м разряде), а целую кучу.
Причем, естественно, имеет место т.н. "дребезг" сигнала, т.е. эта куча единичек не непрерывная, хотя замыкание одно.
Пример:
00010000
00010000
00000000
00010000
00010000
00010000
00010000


Как сделать, чтобы программа воспринимала это как единый сигнал?
Может я вообще все делаю не так, как это обычно делается, — просто опыта подобного программирования у меня до сих пор не было.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 11.07.07 06:42
Оценка:
Здравствуйте, cr lf, Вы писали:

CL>кто-нибудь программировал устройства на базе микросхем FTDI ?

Я занимался, но сейчас перешли на Cypress (usb 2.0)

CL>У меня вот тут на столе самопальный девайс и надо написать program, который будет с ним работать.

CL>Например, мне нужно отслеживать появление сигнала на одной из входных линий устройства.
CL>В настоящее время этот сигнал я подаю ручным замыканием двух контактов на печатной плате (в будущем это будет делать фотоэлемент, мимо которого проскользнул некий объект/субъект).
Была и такая задача... Дребезг есть всегда (особенно если объект/субъект дырявый). Единственное, что я не очень силен в электронике, так что как смогу — помогу.
FTDI отвечает только за обмен данными по USB, а вся логика работы устройства должна быть реализована где-нибудь еще... У нас есть еще одна микросхема, для которой написана прошивка с логикой. Так вот там и учитывается дребезг. Можно конечно реализовать его и в своем софте, но это не логично.
Потом она отправляет через FTDI команду "затемнен датчик", а ты ее принимаешь софтом.
Логика дребезга следующая:
— Затемнение датчика
1) Получаешь первый сигнал о затемнении и значит датчик затемнился.
— Просветление датчика
1) Если в течение N миллисекунд небыло сигналов о затемнении, то просветлился.
Соответственно состояния надо запоминать и учитывать только их изменения.
Re[2]: чтение из FTDI-устройства
От: cr lf  
Дата: 11.07.07 07:29
Оценка:
CL>>кто-нибудь программировал устройства на базе микросхем FTDI ?
G>Я занимался, но сейчас перешли на Cypress (usb 2.0)
Что такое Cypress ?

CL>>У меня вот тут на столе самопальный девайс и надо написать program, который будет с ним работать.

CL>>Например, мне нужно отслеживать появление сигнала на одной из входных линий устройства.
CL>>В настоящее время этот сигнал я подаю ручным замыканием двух контактов на печатной плате (в будущем это будет делать фотоэлемент, мимо
CL>> которого проскользнул некий объект/субъект).
G>Была и такая задача... Дребезг есть всегда.
G>FTDI отвечает только за обмен данными по USB, а вся логика работы устройства должна быть реализована где-нибудь еще... У нас есть еще одна
G> микросхема, для которой написана прошивка с логикой. Так вот там и учитывается дребезг. Можно конечно реализовать его и в своем софте, но
G> это не логично.
Я тоже не силен в электронике, а тот мужик, который паял данное устройство, думаю, вряд ли обрадуется собирать логику для учета дребезга, потому как разработка малобюджетная.
Так что, видимо, придется реализовывать программно.
И если я правильно понял твою идею насчет измерения временных интервалов между единичками и нулями, то сделать это будет достаточно сложно, т.к. требуемая точность измерений составляет 1-2 мс.


Другой вопрос: является ли правильной сама организация программы чтения в виде цикла ?
Вот если бы можно было связать появление единички на входе с неким событием ...
Там в библиотеке есть какая-то FT_SetEventNotification, но я не совсем понял как ей пользоваться.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 11.07.07 08:12
Оценка:
Здравствуйте, cr lf, Вы писали:

CL>Что такое Cypress ?

Cypress — микросхема аля FTDI только для USB 2.0 и от другого производителя.

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

CL>Так что, видимо, придется реализовывать программно.
CL>И если я правильно понял твою идею насчет измерения временных интервалов между единичками и нулями, то сделать это будет достаточно сложно, т.к. требуемая точность измерений составляет 1-2 мс.

CL>Другой вопрос: является ли правильной сама организация программы чтения в виде цикла ?

CL>Вот если бы можно было связать появление единички на входе с неким событием ...
CL>Там в библиотеке есть какая-то FT_SetEventNotification, но я не совсем понял как ей пользоваться.

Если логику организовывать у себя в софте, тогда эт немного сложнее. Но думаю, что мужику все равно придется переделывать что-то. Потому что на сколько я понял, то сигнал уст-ва тебе приходит только когда замкнута цепь, иначе уст-во молчит. Если так, то ничего не получится либо как-то завернуто... Ты должен иметь возможность постоянно опрашивать состояние оптического датчика либо в крайнем случае, чтоб тебе постоянно приходили сигналы о его состоянии. Время можно не использовать, это у нас нужно было необходимо время, ты можешь заменить количеством отсчетов "0" в последовательности "100110101010101" (если N "0" подряд, то просветлился) ("0" или "1" — это твой пятый бит).

По поводу архитектуры программы, то тут вопрос не простой. Все зависит от того, как работает электроника, что еще тебе надо отслеживать на ней и какие задачи выполняет сам софт. Лучше конечно с устройствами работать в отдельных потоках, а при работе с портами использовать Overlap-структуры.
Твой цикл ничего не сможет отобразить на экране, если он выполняется в контексте основного потока и прога будет висеть. Либо пользоваться надо дубовым методом "Application.ProcessMessages;" но это на мой взгляд ацтойно использовать. Хотя можно еще на таймер повесить проверку, но это не лучший стиль (лучше так не делать).
Re[4]: чтение из FTDI-устройства
От: cr lf  
Дата: 11.07.07 09:07
Оценка:
Здравствуйте, grom555, Вы писали:

G>Здравствуйте, cr lf, Вы писали:


CL>>Что такое Cypress ?

G>Cypress — микросхема аля FTDI только для USB 2.0 и от другого производителя.
А FTDI не USB2.0 ?
Впрочем, мне без разницы.

CL>>Другой вопрос: является ли правильной сама организация программы чтения в виде цикла ?

CL>>Вот если бы можно было связать появление единички на входе с неким событием ...
CL>>Там в библиотеке есть какая-то FT_SetEventNotification, но я не совсем понял как ей пользоваться.

G>Если логику организовывать у себя в софте, тогда эт немного сложнее. Но думаю, что мужику все равно придется переделывать что-то. Потому что на сколько я понял, то сигнал уст-ва тебе приходит только когда замкнута цепь, иначе уст-во молчит.

А разве можно как-нибудь иначе ?

G>Ты должен иметь возможность постоянно опрашивать состояние оптического датчика либо в крайнем случае, чтоб тебе постоянно приходили сигналы

G> о его состоянии.
Так ведь это и делается
while <условие> do begin
  Read_USB_Device_Buffer(1);
  Signal := FT_In_Buffer[0] and $10 <> 0; // поступил сигнал
    if Signal then begin
     работа
    .............
    end;
end


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

Мне надо
1. записать в устройство 4 байта — 00000000,000000001,00000010,00000011,
2. дождаться прихода от него других 3-х байт — 00010000b,00001000,00000100.
3. засечь интервалы времени между этими сигналами.

G>Лучше конечно с устройствами работать в отдельных потоках, а при работе с портами использовать Overlap-структуры.

Что такое Overlap-структуры ?

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

Почему же не сможет ? — Если приложение консольное (это пока), то отображает, ну а потом при переходе на GUI я собирался засунуть его либо в отдельный поток, либо в TTimer.

G> Хотя можно еще на таймер повесить проверку, но это не лучший стиль (лучше так не делать).

Почему ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 11.07.07 09:50
Оценка:
Здравствуйте, cr lf, Вы писали:

CL>>>Что такое Cypress ?

G>>Cypress — микросхема аля FTDI только для USB 2.0 и от другого производителя.
CL>А FTDI не USB2.0 ?
CL>Впрочем, мне без разницы.
Наша была USB 1.1. Может они и сделали уже USB 2.0 — я не знаю.

CL>>>Другой вопрос: является ли правильной сама организация программы чтения в виде цикла ?

CL>>>Вот если бы можно было связать появление единички на входе с неким событием ...
CL>>>Там в библиотеке есть какая-то FT_SetEventNotification, но я не совсем понял как ей пользоваться.

G>>Если логику организовывать у себя в софте, тогда эт немного сложнее. Но думаю, что мужику все равно придется переделывать что-то. Потому что на сколько я понял, то сигнал уст-ва тебе приходит только когда замкнута цепь, иначе уст-во молчит.

CL>А разве можно как-нибудь иначе ?
Можно. Можно опрашивать устройство на предмет засветки датчика. Или постоянно принимать сигнал с этого датчика, характеризующий его засветку.

G>>Ты должен иметь возможность постоянно опрашивать состояние оптического датчика либо в крайнем случае, чтоб тебе постоянно приходили сигналы

G>> о его состоянии.
CL>Так ведь это и делается
CL>
CL>while <условие> do begin
CL>  Read_USB_Device_Buffer(1);
CL>  Signal := FT_In_Buffer[0] and $10 <> 0; // поступил сигнал
CL>    if Signal then begin
CL>     работа
CL>    .............
CL>    end;
CL>end
CL>

Вот это не совсем так. Тут ты читаешь только данные, пришедшие в USB, а опрашивать — это значит ты отправляешь некую команду в свое устройство и получаешь ответ от него с состоянием датчиков или чего угодно.

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

CL>Мне надо
CL>1. записать в устройство 4 байта — 00000000,000000001,00000010,00000011,
CL>2. дождаться прихода от него других 3-х байт — 00010000b,00001000,00000100.
CL>3. засечь интервалы времени между этими сигналами.
Я обычно пишу свой класс для работы с устройствами, в котором есть поток, отвечающий за прием/передачу данных. В классе есть методы для отправки команд и события по их приходу с устройства. Поток должен иметь синхронизацию! Я использую критические секции и TEvent.
Больше сказать сложно, т.к. не понятно назначение этих байт... Как часто нужно их получать...
Каждое конкретное устройство (из-за своей логики и назначения) требует своего подхода и решений. Нет универсальных решений... Есть только рекомендации.

G>>Лучше конечно с устройствами работать в отдельных потоках, а при работе с портами использовать Overlap-структуры.

CL>Что такое Overlap-структуры ?
Это просто другой способ общения через порты. Почитай... Есть доки. Даже в справке Delphi описано. Основной смысл в том, что ты НЕ ИСПОЛЬЗУЕШЬ просто ReadFile/WriteFile и не ждешь данных, а можешь повесить на прием евент и ждать его WaitForSingleObject (тогда будешь точно знать когда пришли данные и прога не останавливает работу).

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

CL>Почему же не сможет ? — Если приложение консольное (это пока), то отображает, ну а потом при переходе на GUI я собирался засунуть его либо в отдельный поток, либо в TTimer.
Если консольное — то конечно.

G>> Хотя можно еще на таймер повесить проверку, но это не лучший стиль (лучше так не делать).

CL>Почему ?
Потому, что это плохой стиль. Все равно что GOTO использовать. Таймером можно только часы сделать на форме... Ну или мигание какое-нибудь...
Re[6]: чтение из FTDI-устройства
От: cr lf  
Дата: 11.07.07 12:09
Оценка:
CL>>Так ведь это и делается
CL>>
CL>>while <условие> do begin
CL>>  Read_USB_Device_Buffer(1);
CL>>  Signal := FT_In_Buffer[0] and $10 <> 0; // поступил сигнал
CL>>    if Signal then begin
CL>>     работа
CL>>    .............
CL>>    end;
CL>>end
CL>>

G>Вот это не совсем так. Тут ты читаешь только данные, пришедшие в USB, а опрашивать — это значит ты отправляешь некую команду в свое
G> устройство и получаешь ответ от него с состоянием датчиков или чего угодно.
Наверное я тупой, но я не вижу разницы в твоих словах и в моем коде ;(
Я читаю данные из USB, которые и описывают состояние датчика.
Датчик является тем самым устройством, которое замыкает/размыкает цепь, подающую сигнал на вход микросхемы FTDI, а она в свою очередь переправляет его в USB.

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

CL>>Мне надо
CL>>1. записать в устройство 4 байта — 00000000,000000001,00000010,00000011,
CL>>2. дождаться прихода от него других 3-х байт — 00010000b,00001000,00000100.
CL>>3. засечь интервалы времени между этими сигналами.
G>Я обычно пишу свой класс для работы с устройствами, в котором есть поток, отвечающий за прием/передачу данных. В классе есть методы для
G> отправки команд и события по их приходу с устройства. Поток должен иметь синхронизацию! Я использую критические секции и TEvent.
G>Больше сказать сложно, т.к. не понятно назначение этих байт... Как часто нужно их получать...
Непонятно насчет синхронизации ... ;(
Мне там синхронизировать особенно нечего.
Записываемые байты пишутся с интервалом в 1 сек.
После чего следует ожидать 00010000b,00001000b,00000100b именно в этой последовательности.
Хотя 00010000b может прийти и раньше, чем будут отправлены в устройство первые 4 байта.
Короче суть задачи:
стоит автомобиль на старте, перед ним светофор.
Зажигается
— красный сигнал (00000000b)
— красный сигнал (00000001b)
— красный сигнал (00000010b)
— зеленый сигнал (00000011b)
Старт — срабатывает фотоэлемент — получаем 00010000b, начинаем отсчет времени.
Где-то посередине дистанции другой фотоэлемент, проехав через который, получаем 00001000b.
И в конце дистанции третий фотоэлемент, который даст нам 00000100b
Вот собственно и все.
Разве что, если у водителя дрогнут нервы, он может стартовать раньше зеленого сигнала и тогда мы получим сигнал от первого фотоэлемента раньше, чем запишем 00000011b

G>>>Лучше конечно с устройствами работать в отдельных потоках, а при работе с портами использовать Overlap-структуры.

CL>>Что такое Overlap-структуры ?
G>Это просто другой способ общения через порты. Почитай... Есть доки. Даже в справке Delphi описано. Основной смысл в том, что ты НЕ
G> ИСПОЛЬЗУЕШЬ просто ReadFile/WriteFile и не ждешь данных, а можешь повесить на прием евент и ждать его WaitForSingleObject (тогда будешь
G> точно знать когда пришли данные и прога не останавливает работу).
Вот я и говорю, что есть там какая-то FT_SetEventNotification

FT_STATUS FT_SetEventNotification (FT_HANDLE ftHandle, DWORD dwEventMask, PVOID pvArg)
Sets conditions for event notification.

Parameters
ftHandle - Handle of the device.
dwEventMask - Conditions that cause the event to be set.
pvArg - Interpreted as the handle of an event.


но воспользоваться ей у меня так и не получилось, хотя там и пример есть.
Вот ты говоришь, что прога не останавливает работу...
Как же не останавливает ?! — WaitForSingleObject в данном случае вешает программу навечно:
hEvent := CreateEvent(0,false,false,'');
FT_SetEventNotification(h,FT_EVENT_RXCHAR,@hEvent);
WaitForSingleObject(hEvent,Infinite);
FT_GetStatus(h,@RxBytes,@TxBytes,@EventDWord);
if RxBytes > 0 then begin
  FT_Read(h,@Buf,1,@Count);
  WriteLn('buf = ',IntToBin(buf));
end;



G>>> Хотя можно еще на таймер повесить проверку, но это не лучший стиль (лучше так не делать).

CL>>Почему ?
G>Потому, что это плохой стиль. Все равно что GOTO использовать.
Остается TThread ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 11.07.07 12:59
Оценка:
Здравствуйте, cr lf, Вы писали:

CL>Наверное я тупой, но я не вижу разницы в твоих словах и в моем коде ;(

CL>Я читаю данные из USB, которые и описывают состояние датчика.
CL>Датчик является тем самым устройством, которое замыкает/размыкает цепь, подающую сигнал на вход микросхемы FTDI, а она в свою очередь переправляет его в USB.
Тогда вопрос: в какой момент начинать считывать инфу? Сейчас? Через минуту? Через 10 минут? Ведь для функции чтения есть TimeOut.
Прочитав все, могу спросить: Что будет, если машины совсем не поедут?

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

CL>>>Мне надо
CL>>>1. записать в устройство 4 байта — 00000000,000000001,00000010,00000011,
CL>>>2. дождаться прихода от него других 3-х байт — 00010000b,00001000,00000100.
CL>>>3. засечь интервалы времени между этими сигналами.
G>>Я обычно пишу свой класс для работы с устройствами, в котором есть поток, отвечающий за прием/передачу данных. В классе есть методы для
G>> отправки команд и события по их приходу с устройства. Поток должен иметь синхронизацию! Я использую критические секции и TEvent.
G>>Больше сказать сложно, т.к. не понятно назначение этих байт... Как часто нужно их получать...
CL>Непонятно насчет синхронизации ... ;(
CL>Мне там синхронизировать особенно нечего.
Когда работаешь с потоками, то синхронизация обязательна почти всегда. Особенно в случае, когда твой поток работает постоянно, а ты только подсовываешь ему различные данные для обработки или в качестве параметров. Или в случае, если поток выводит что-нить на экран.

CL>Записываемые байты пишутся с интервалом в 1 сек.

CL>После чего следует ожидать 00010000b,00001000b,00000100b именно в этой последовательности.
CL>Хотя 00010000b может прийти и раньше, чем будут отправлены в устройство первые 4 байта.
CL>Короче суть задачи:
CL>стоит автомобиль на старте, перед ним светофор.
CL>Зажигается
CL>- красный сигнал (00000000b)
CL>- красный сигнал (00000001b)
CL>- красный сигнал (00000010b)
CL>- зеленый сигнал (00000011b)
CL>Старт — срабатывает фотоэлемент — получаем 00010000b, начинаем отсчет времени.
CL>Где-то посередине дистанции другой фотоэлемент, проехав через который, получаем 00001000b.
CL>И в конце дистанции третий фотоэлемент, который даст нам 00000100b
CL>Вот собственно и все.
CL>Разве что, если у водителя дрогнут нервы, он может стартовать раньше зеленого сигнала и тогда мы получим сигнал от первого фотоэлемента раньше, чем запишем 00000011b
Вот теперь стало гораздо понятней!
Можно уже придумать архитектуру софта.
Например реализовать так:
I) Создать класс для работы с USB устройством
Методы (необходимые): -подключить устройство
-отключить устройство
-послать байт
События: -сработал фотоэлемент номер N
В этом классе должен быть поток по приему/передаче данных. В теле потока пишешь процедуру:
while not Terminated do
begin
1) Если есть данные для отправки, то отправить
2) Читать из порта с таймаутом ~100ms (таймаут должен быть небольшой <1sec)
3) Если принято сообщение от датчика, то вызов обработчика события с номером датчика (обработчик не должен быть длительным, т.к. здесь происходит затык в ходе выполнения потока)
end;
При вызове метода "-подключить устройство" нужно законектиться с USB устройством и запустить поток.
При вызове метода "-отключить устройство" нужно вызвать у потока Terminate, подождать WaitFor и отконектить девайс.
При вызове метода "-послать байт" нужно вызвать у потока метод посылки байта в девайс. (вот тут и нужна синхронизация критическими секциями, т.к. два разных потока попытаются обратиться к одним данным). В методе потока по посылке просто устанавливаи переменную в нужное значение <>0, а в теле потока делай ее =0 после отправки;

Решение не самое красивое, но подойдет. Лучше конечно пользоваться WaitForSingleObject.

G>>>>Лучше конечно с устройствами работать в отдельных потоках, а при работе с портами использовать Overlap-структуры.

CL>>>Что такое Overlap-структуры ?
G>>Это просто другой способ общения через порты. Почитай... Есть доки. Даже в справке Delphi описано. Основной смысл в том, что ты НЕ
G>> ИСПОЛЬЗУЕШЬ просто ReadFile/WriteFile и не ждешь данных, а можешь повесить на прием евент и ждать его WaitForSingleObject (тогда будешь
G>> точно знать когда пришли данные и прога не останавливает работу).
CL>Вот я и говорю, что есть там какая-то FT_SetEventNotification

CL>
CL>FT_STATUS FT_SetEventNotification (FT_HANDLE ftHandle, DWORD dwEventMask, PVOID pvArg)
CL>Sets conditions for event notification.
Она и нужна для Overlap.

CL>Parameters
CL>ftHandle - Handle of the device.
CL>dwEventMask - Conditions that cause the event to be set.
CL>pvArg - Interpreted as the handle of an event.
CL>


CL>но воспользоваться ей у меня так и не получилось, хотя там и пример есть.

CL>Вот ты говоришь, что прога не останавливает работу...
CL>Как же не останавливает ?! — WaitForSingleObject в данном случае вешает программу навечно:
CL>
CL>hEvent := CreateEvent(0,false,false,'');
CL>FT_SetEventNotification(h,FT_EVENT_RXCHAR,@hEvent);
CL>WaitForSingleObject(hEvent,Infinite);
CL>FT_GetStatus(h,@RxBytes,@TxBytes,@EventDWord);
CL>if RxBytes > 0 then begin
CL>  FT_Read(h,@Buf,1,@Count);
CL>  WriteLn('buf = ',IntToBin(buf));
CL>end;
CL>

Навечно она останавливается из-за вызова WaitForSingleObject с параметром Infinite. Лучше всего вызывать WaitForSingleObject из какого-нить потока, ответственного за прием данных. (к моему примеру выше это не относится, хотя его можно переписать с использованием WaitForSingleObject)


G>>>> Хотя можно еще на таймер повесить проверку, но это не лучший стиль (лучше так не делать).

CL>>>Почему ?
G>>Потому, что это плохой стиль. Все равно что GOTO использовать.
CL>Остается TThread ?
Да. Таймером не привыкай пользоваться в таких задачах.

На будущее по поводу Overlap. Винда рекомендует пользоваться именно этим для работы с портами. Говорят, что стабильнее работает.
Re[8]: чтение из FTDI-устройства
От: cr lf  
Дата: 11.07.07 15:02
Оценка:
CL>>Я читаю данные из USB, которые и описывают состояние датчика.
CL>>Датчик является тем самым устройством, которое замыкает/размыкает цепь, подающую сигнал на вход микросхемы FTDI, а она в свою очередь
CL>> переправляет его в USB.
G>Тогда вопрос: в какой момент начинать считывать инфу? Сейчас? Через минуту? Через 10 минут?
Считывать сразу же, как только начинаем запись.

G>Ведь для функции чтения есть TimeOut.

Кстати, я не совсем понимаю что это такое ;(
И чем Time Out отличается от Latency.

G>Прочитав все, могу спросить: Что будет, если машины совсем не поедут?

Да ничего не будет — загорится зеленый и устройство будет ждать получения сигнала от фотоэлемента стоящего на старте.

CL>>WaitForSingleObject в данном случае вешает программу навечно:

CL>>
CL>>hEvent := CreateEvent(0,false,false,'');
CL>>FT_SetEventNotification(h,FT_EVENT_RXCHAR,@hEvent);
CL>>WaitForSingleObject(hEvent,Infinite);
CL>>FT_GetStatus(h,@RxBytes,@TxBytes,@EventDWord);
CL>>if RxBytes > 0 then begin
CL>>  FT_Read(h,@Buf,1,@Count);
CL>>  WriteLn('buf = ',IntToBin(buf));
CL>>end;
CL>>

G>Навечно она останавливается из-за вызова WaitForSingleObject с параметром Infinite.
Если я указываю определенный интервал, WaitForSingleObject заканчивается с результатом WAIT_TIMEOUT, хотя сигнал был и, стало быть, hEvent должен быть Signalled
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: чтение из FTDI-устройства
От: cr lf  
Дата: 11.07.07 16:01
Оценка:
G>Можно уже придумать архитектуру софта.
G>Например реализовать так:
G>I) Создать класс для работы с USB устройством
G> Методы (необходимые): -подключить устройство
G> -отключить устройство
G> -послать байт
G> События: -сработал фотоэлемент номер N
G>В этом классе должен быть поток по приему/передаче данных. В теле потока пишешь процедуру:
G>while not Terminated do
G>begin
G> 1) Если есть данные для отправки, то отправить
G> 2) Читать из порта с таймаутом ~100ms (таймаут должен быть небольшой <1sec)
G> 3) Если принято сообщение от датчика, то вызов обработчика события с номером датчика (обработчик не должен быть длительным, т.к. здесь происходит затык в ходе выполнения потока)
G>end;
G> При вызове метода "-подключить устройство" нужно законектиться с USB устройством и запустить поток.
G> При вызове метода "-отключить устройство" нужно вызвать у потока Terminate, подождать WaitFor и отконектить девайс.
G> При вызове метода "-послать байт" нужно вызвать у потока метод посылки байта в девайс. (вот тут и нужна синхронизация критическими
G> секциями, т.к. два разных потока попытаются обратиться к одним данным). В методе потока по посылке просто устанавливаи переменную в
G> нужное значение <>0, а в теле потока делай ее =0 после отправки;

Короче вот все, что понял.
type
  TUSBThread = class(TThread)
  private
    FOnSignal: TNotifyEvent;
  protected
    constructor Create(CreateSuspended: Boolean);
    procedure Execute; override;
    destructor Destroy; override;
  published
    property OnSignal: TNotifyEvent read FOnSignal write FOnSignal;
  end;

implementation

uses D2XXUnit;

constructor TUSBThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  Open_USB_Device;
  Set_USB_Device_LatencyTimer(2);
  Set_USB_Device_BitMode($e3,1);
end;

destructor TUSBThread.Destroy;
begin
  Set_USB_Device_BitMode($e3,0);
  Close_USB_Device;
  inherited;
end;

procedure TUSBThread.Execute;
begin
  while not Terminated do begin
    Read_USB_Device_Buffer(1);
    if FT_In_Buffer[0] and $10 <> 0 then
      if Assigned(OnSignal) then OnSignal(Self);
  end;
end;


Основной модуль
procedure TForm1.FormCreate(Sender: TObject);
begin
  UsbThread := TUsbThread.Create(True);
  UsbThread.OnSignal := Signal;
  UsbThread.Resume;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UsbThread.Free;
end;

procedure TForm1.Signal(Sender: TObject);
var
  i: Integer;
begin
//  реакция на сигнал
end;


Запускаем и получаем полную лажу ;(

Пока здесь никакой записи и вовсе нет.
Зачем делать запись в этом же классе ?
Зачем что-то синхронизировать, ведь они обращаются к разным данным ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 12.07.07 06:12
Оценка:
Здравствуйте, cr lf, Вы писали:

G>>Можно уже придумать архитектуру софта.

G>>Например реализовать так:
G>>I) Создать класс для работы с USB устройством
G>> Методы (необходимые): -подключить устройство
G>> -отключить устройство
G>> -послать байт
G>> События: -сработал фотоэлемент номер N
G>>В этом классе должен быть поток по приему/передаче данных. В теле потока пишешь процедуру:
G>>while not Terminated do
G>>begin
G>> 1) Если есть данные для отправки, то отправить
G>> 2) Читать из порта с таймаутом ~100ms (таймаут должен быть небольшой <1sec)
G>> 3) Если принято сообщение от датчика, то вызов обработчика события с номером датчика (обработчик не должен быть длительным, т.к. здесь происходит затык в ходе выполнения потока)
G>>end;
G>> При вызове метода "-подключить устройство" нужно законектиться с USB устройством и запустить поток.
G>> При вызове метода "-отключить устройство" нужно вызвать у потока Terminate, подождать WaitFor и отконектить девайс.
G>> При вызове метода "-послать байт" нужно вызвать у потока метод посылки байта в девайс. (вот тут и нужна синхронизация критическими
G>> секциями, т.к. два разных потока попытаются обратиться к одним данным). В методе потока по посылке просто устанавливаи переменную в
G>> нужное значение <>0, а в теле потока делай ее =0 после отправки;

CL>Короче вот все, что понял.

CL>
CL>type
CL>  TUSBThread = class(TThread)
CL>  private
CL>    FOnSignal: TNotifyEvent;
CL>  protected
CL>    constructor Create(CreateSuspended: Boolean);
CL>    procedure Execute; override;
CL>    destructor Destroy; override;
CL>  published
CL>    property OnSignal: TNotifyEvent read FOnSignal write FOnSignal;
CL>  end;

CL>implementation

CL>uses D2XXUnit;

CL>constructor TUSBThread.Create(CreateSuspended: Boolean);
CL>begin
CL>  inherited Create(CreateSuspended);
CL>  Open_USB_Device;
CL>  Set_USB_Device_LatencyTimer(2);
// Не помню, что такое LatencyTimer... Используй FT_SetTimeouts
CL>  Set_USB_Device_BitMode($e3,1);
CL>end;

CL>destructor TUSBThread.Destroy;
CL>begin
CL>  Set_USB_Device_BitMode($e3,0);
CL>  Close_USB_Device;
CL>  inherited;
CL>end;

CL>procedure TUSBThread.Execute;
CL>begin
CL>  while not Terminated do begin
CL>    Read_USB_Device_Buffer(1);
// Если Read_USB_Device_Buffer завершилось по таймауту, то не нужно дальше обрабатывать данные. Вставь IF.
CL>    if FT_In_Buffer[0] and $10 <> 0 then
CL>      if Assigned(OnSignal) then OnSignal(Self);
// Здесь правильно, только можно в параметрах OnSignal передавать номер фотоэлемента.
// Если соберешься выводить что-нить на экран в GUI, то придется пользовать Synchronize(OnSignal) (почитай как)
// И добавь сюда какой-нибудь флаг для того чтоб 2 раза не обрабатывать один датчик.
// Типа:
// if not flag1 then
// begin
//   if Assigned(OnSignal) then OnSignal(Self);
//   flag1 := true;
// end;
CL>  end;
CL>end;
CL>


CL>Основной модуль

CL>
CL>procedure TForm1.FormCreate(Sender: TObject);
CL>begin
CL>  UsbThread := TUsbThread.Create(True);
CL>  UsbThread.OnSignal := Signal;
CL>  UsbThread.Resume;
CL>end;

CL>procedure TForm1.FormDestroy(Sender: TObject);
CL>begin
// ДОБАВЬ:
// UsbThread.Terminate;
// UsbThread.WaitFor;     
CL>  UsbThread.Free;
CL>end;

CL>procedure TForm1.Signal(Sender: TObject);
CL>var
CL>  i: Integer;
CL>begin
CL>//  реакция на сигнал
CL>end;
CL>


CL>Запускаем и получаем полную лажу ;(

Посмотри сейчас, и расскажи, что получается...

CL>Пока здесь никакой записи и вовсе нет.

Записи нет и можешь не вставлять ее в поток. Можешь вставить в основной модуль линейно.
CL>Зачем делать запись в этом же классе ?
Затем, что если вставить в основной модуль, то прогу не вырубишь (подвиснет) в течение 4 секунд, пока будешь отправлять.
CL>Зачем что-то синхронизировать, ведь они обращаются к разным данным ?
Нет отправки — нет синхронизации.
Re[9]: чтение из FTDI-устройства
От: grom555 Беларусь  
Дата: 12.07.07 06:21
Оценка:
Здравствуйте, cr lf, Вы писали:

CL>>>Я читаю данные из USB, которые и описывают состояние датчика.

CL>>>Датчик является тем самым устройством, которое замыкает/размыкает цепь, подающую сигнал на вход микросхемы FTDI, а она в свою очередь
CL>>> переправляет его в USB.
G>>Тогда вопрос: в какой момент начинать считывать инфу? Сейчас? Через минуту? Через 10 минут?
CL>Считывать сразу же, как только начинаем запись.

G>>Ведь для функции чтения есть TimeOut.

CL>Кстати, я не совсем понимаю что это такое ;(
Это время, в течение которого функция будет ждать прихода данных в порт.
CL>И чем Time Out отличается от Latency.
Я тоже не знаю что такое Latency(лучше не пользуй). Нужно читать справку по API для FTDI.

G>>Прочитав все, могу спросить: Что будет, если машины совсем не поедут?

CL>Да ничего не будет — загорится зеленый и устройство будет ждать получения сигнала от фотоэлемента стоящего на старте.
Да. И их проги выйти поможет только диспетчер задач.

CL>>>WaitForSingleObject в данном случае вешает программу навечно:

CL>>>
CL>>>hEvent := CreateEvent(0,false,false,'');
CL>>>FT_SetEventNotification(h,FT_EVENT_RXCHAR,@hEvent);
CL>>>WaitForSingleObject(hEvent,Infinite);
CL>>>FT_GetStatus(h,@RxBytes,@TxBytes,@EventDWord);
CL>>>if RxBytes > 0 then begin
CL>>>  FT_Read(h,@Buf,1,@Count);
CL>>>  WriteLn('buf = ',IntToBin(buf));
CL>>>end;
CL>>>

G>>Навечно она останавливается из-за вызова WaitForSingleObject с параметром Infinite.
CL>Если я указываю определенный интервал, WaitForSingleObject заканчивается с результатом WAIT_TIMEOUT, хотя сигнал был и, стало быть, hEvent должен быть Signalled
Значит так и есть. Поставь интервал 1000мс или 10000мс. Или проверь второй параметр, может не того ждешь. Нет доков по FTDI... протерял где-то... не нахожу..
Re[10]: чтение из FTDI-устройства
От: cr lf  
Дата: 12.07.07 13:53
Оценка:
G>>>Ведь для функции чтения есть TimeOut.
CL>>Кстати, я не совсем понимаю что это такое ;(
G>Это время, в течение которого функция будет ждать прихода данных в порт.
CL>>И чем Time Out отличается от Latency.
G>Я тоже не знаю что такое Latency(лучше не пользуй). Нужно читать справку по API для FTDI.

In the FT8U232AM and FT8U245AM devices, the receive buffer timeout that is used to flush
remaining data from the receive buffer was fixed at 16 ms. In all other FTDI devices, this timeout
is programmable and can be set at 1 ms intervals between 2ms and 255 ms. This allows the
device to be better optimized for protocols requiring faster response times from short data packets.

Насколько я понял, latency — это интервал, в течение которого сохраняются непрочитанные данные в буфере устройства, прежде чем они потеряются.
Поправь, если я не прав.

G>>>Прочитав все, могу спросить: Что будет, если машины совсем не поедут?

CL>>Да ничего не будет — загорится зеленый и устройство будет ждать получения сигнала от фотоэлемента стоящего на старте.
G>Да. И их проги выйти поможет только диспетчер задач.
Почему ?
Во-первых, можно предусмотреть аварийный выход из цикла чтения даже в том варианте, который я постил, хотя это и нехорошо.
А во-вторых, это ведь только самый первый вариант, лишь бы заработало.
В окончательном варианте это, конечно, будет выполняться в отдельном потоке.

CL>>>>WaitForSingleObject в данном случае вешает программу навечно:

CL>>>>
CL>>>>hEvent := CreateEvent(0,false,false,'');
CL>>>>FT_SetEventNotification(h,FT_EVENT_RXCHAR,@hEvent);
CL>>>>WaitForSingleObject(hEvent,Infinite);
CL>>>>FT_GetStatus(h,@RxBytes,@TxBytes,@EventDWord);
CL>>>>if RxBytes > 0 then begin
CL>>>>  FT_Read(h,@Buf,1,@Count);
CL>>>>  WriteLn('buf = ',IntToBin(buf));
CL>>>>end;
CL>>>>

G>>>Навечно она останавливается из-за вызова WaitForSingleObject с параметром Infinite.
CL>>Если я указываю определенный интервал, WaitForSingleObject заканчивается с результатом WAIT_TIMEOUT, хотя сигнал был и, стало быть,
CL>> hEvent должен быть Signalled
G>Значит так и есть. Поставь интервал 1000мс или 10000мс. Или проверь второй параметр, может не того ждешь. Нет доков по FTDI... протерял
G> где-то... не нахожу..
Все проверил, все сделал как надо, сигнал есть, а выход по TimeOut ;(
Документацию могу прислать, если интересно.

Здесь отрывок:

FT_STATUS FT_SetEventNotification (FT_HANDLE ftHandle, DWORD dwEventMask, PVOID pvArg)
Sets conditions for event notification.

Parameters
ftHandle — Handle of the device.
dwEventMask — Conditions that cause the event to be set.
pvArg — Interpreted as the handle of an event.

Return Value
FT_OK if successful, otherwise the return value is an FT error code.

Remarks
An application can use this function to setup conditions which allow a thread to block until one of
the conditions is met. Typically, an application will create an event, call this function, then block on
the event. When the conditions are met, the event is set, and the application thread unblocked.
dwEventMask is a bit-map that describes the events the application is interested in. pvArg is
interpreted as the handle of an event which has been created by the application. If one of the
event conditions is met, the event is set.
If FT_EVENT_RXCHAR is set in dwEventMask, the event will be set when a character has been
received by the device. If FT_EVENT_MODEM_STATUS is set in dwEventMask, the event will be
set when a change in the modem signals has been detected by the device.

This example shows how to wait for a character to be received or a change in modem status.
First, create the event and call FT_SetEventNotification.

FT_HANDLE ftHandle; // handle of an open device
FT_STATUS ftStatus;
HANDLE hEvent;
DWORD EventMask;
hEvent = CreateEvent(NULL,false,false,"");
EventMask = FT_EVENT_RXCHAR | FT_EVENT_MODEM_STATUS;
ftStatus = FT_SetEventNotification(ftHandle,EventMask,hEvent);



Sometime later, block the application thread by waiting on the event, then when the event has
occurred, determine the condition that caused the event, and process it accordingly.

WaitForSingleObject(hEvent,INFINITE);

DWORD EventDWord;
DWORD RxBytes;
DWORD TxBytes;

FT_GetStatus(ftHandle,&RxBytes,&TxBytes,&EventDWord);
if (EventDWord & FT_EVENT_MODEM_STATUS) {
  // modem status event detected, so get current modem status
  FT_GetModemStatus(ftHandle,&Status);
  if (Status & 0x00000010) {
    // CTS is high
  }
  else {
    // CTS is low
  }
  if (Status & 0x00000020) {
    // DSR is high
  }
  else {
    // DSR is low
  }
}
if (RxBytes > 0) {
// call FT_Read() to get received data from device
}

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.