Форум: "WinAPI";
Текущий архив: 2003.03.17;
Скачать: [xml.tar.bz2];
ВнизСовмещение DOS и Widows Найти похожие ветки
← →
Shuric (2002-11-26 22:46) [0]Я уже испрашивал совета (речь идет о снятии данных с АЦП) на тему выполнения процедуры без ее прерывания (допустим прерыванием Windows), но параллейно вопросу у меня возникло несколько дуратских идей... Не мог бы кто-нибудь высказать свое мнение (по пунктам) о реализации следующей идеи.
1. Раз программа под DOS работает совершенно (имеется в виду что под Windows), будет ли она работать так же и в свернутом режиме.
2. Если да, то можно ли реализовать следующий подход:
Для снятия данных использовать DOS программу, как-то обмениваться данными с Windows родительской программой (которая по идее должна отображать принятые данные)
3. И если да, то как совместно использовать память (допустим, Windows программа проверяет некие адреса на изменение данных... Понимаю, что есть разница под выделении памяти и разрядности :), но все же)
4. И если да, то как читать "память"
← →
Cobalt (2002-11-26 23:11) [1]1)Если не ошибаюсь, то свернутые окна (программы, не имеющие в данный момент фокуса ввода) имеют приоритет ниже, чем "текущая" (Рихтер), так что... Тестируй свою (Дос-)программу.
2)Для начала - Дос-программы не умеют общаться с Вин-программами. Они о них даже не подозревают, ибо выполняются в совсем другой ОС.
А вот Вин-проги вполне могут обращаться к запущенным ими Дос-прогам, напр. читая их поток вывода (stdOut)
3) Только в одном направлении, или через файл, проверяя его на время последнего изменения.
4) отпал сам собой.
← →
Shuric (2002-11-27 00:05) [2]Cobalt
Во первых как изменить статус приоритета выполнения DOS программы
Во вторых, DOS программе и не нужно общаться, ей все то надо предоставить адресс и клепать данные туда (пусть будет массив плюс допустим пару байт прочел не прочел Windows программой)... Пусть DOS программа сохранит адрес ну в файл... Опрос Windows программой адреса по таймеру... (как сделать?)
Формировать файл с данными программой DOS, допустим каждые 20 ms невозможно по этому только память...
← →
SottNick (2002-11-27 07:39) [3]а у меня другие вопросы
1. Как это читать данные с АЦП? Ведь не к процессору же компа он подключен. Данные читаются с какого-то порта?
2. Если протокол обмена известен или есть исходник DOS-проги, то от нее лучше отказаться за бесполезностью...
3. Отображение результатов обмена в любом случае прерывает сам обмен, хоть тресни. А менее 20мс - для отображения результатов - интересная задачка...
4. Решение: ЕГО НЕТ. :o) Делаешь, как все белые люди, приложение для отображения инфы, в нем поток для сбора данных с высоким приоритетом. Или, вряд ли тебя это спасет, приложение - аналог досовской проги без событий, сообщений, окон и других прелестей жизни с абсолютным приоритетом.
← →
msts (2002-11-27 11:57) [4]дешево и сердито:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
const
WM_DATAPACKET = WM_USER+1000;
DATA_PACKET_SIZE = 19; {-1}
DP_BUFFER_SIZE = 99; {-1}
type
TData = packed record
a : integer;
b : integer;
c : integer;
end;
TDataPacket = array[0..DATA_PACKET_SIZE] of TData;
PDataPacket = ^TDataPacket;
TDataBuffer = array[0..DP_BUFFER_SIZE] of PDataPacket;
TReceiveDataThread = class(TThread)
private
FOwner : THandle;
FSuspending : boolean;
protected
procedure Execute; override;
procedure SendDataPacket(Data : PDataPacket);
function ReceiveDataPacket(Data : PDataPacket) : PDataPacket;
function CreateDataPacket : PDataPacket;
public
constructor Create(Owner : THandle; CreateSuspended: Boolean);
procedure Suspending;
procedure Resumes;
end;
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Timer1: TTimer;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
Buffer : TBitmap;
DataBuffer : TDataBuffer;
DataBufferPos : integer;
Thread : TReceiveDataThread;
procedure WMDataPacket(var Message: TMessage); message WM_DATAPACKET;
procedure PaintBuffer(Canvas : TCanvas);
public
end;
var
Form1: TForm1;
implementation
uses Types;
{$R *.dfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
Buffer := TBitmap.Create;
with Buffer do begin
PixelFormat := pf8bit;
Height := PaintBox1.Height;
Width := PaintBox1.Width;
Canvas.Brush.Color:=clBlack;
Canvas.FillRect(Canvas.ClipRect);
end;
Timer1.Enabled := false;
Timer1.Interval := 10;
FillChar(DataBuffer, SizeOf(DataBuffer), 0);
DataBufferPos := 0;
Thread := TReceiveDataThread.Create(Self.Handle,True);
// Thread.Priority := tpHigher;
// Thread.Priority := tpHighest; -- не рекомендую
// так как все построено на сообщениях то -
// Thread их посылает быстрее чем форма успевает выбрать из очереди
// в результате увеличивается объем занимаемой памяти (очень быстро)
// и последующий крах
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
if Buffer.Canvas.LockCount=0 then
PaintBox1.Canvas.Draw(0,0,Buffer);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if Buffer.Canvas.LockCount=0 then begin
Buffer.Canvas.Lock;
PaintBox1.Tag := PaintBox1.Tag +1;
with Buffer do begin
Canvas.Brush.Color:=clBlack;
Canvas.FillRect(Canvas.ClipRect);
Canvas.Font.Color := clWhite;
Canvas.TextOut(10,10, IntToStr(PaintBox1.Tag));
Canvas.Pen.Color:=clBlue;
PaintBuffer(Canvas);
end;
PaintBox1.Canvas.Draw(0,0,Buffer);
Buffer.Canvas.Unlock;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Timer1.Enabled := not Timer1.Enabled;
if Timer1.Enabled then Thread.Resumes else Thread.Suspending;
end;
procedure TForm1.WMDataPacket(var Message: TMessage);
var
t : PDataPacket;
begin
t := DataBuffer[DataBufferPos];
DataBuffer[DataBufferPos]:=PDataPacket(Message.WParam);
if t<>nil then FreeMem(t);
if DataBufferPos+1>DP_BUFFER_SIZE then DataBufferPos:=0 else DataBufferPos := DataBufferPos +1;
end;
← →
msts (2002-11-27 11:58) [5]
procedure TForm1.PaintBuffer(Canvas: TCanvas);
var
t,i,x,x_ : integer;
function PaintDataPacket(Data : PDataPacket) : boolean;
var
j : integer;
begin
for j:=0 to DATA_PACKET_SIZE do begin
Canvas.MoveTo(x,Data^[j].a);
Canvas.LineTo(x,Data^[j].b);
Dec(x);
end;
result := (x_ > x);
end;
begin
x := Canvas.ClipRect.Right;
x_ := Canvas.ClipRect.Left;
t := DataBufferPos;
for i:=0 to DP_BUFFER_SIZE do begin
if t=0 then t:=DP_BUFFER_SIZE else t:=t-1;
if DataBuffer[t]<>nil then
if PaintDataPacket(DataBuffer[t]) then break;
end;
end;
{ TReceiveDataThread }
constructor TReceiveDataThread.Create(Owner : THandle; CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FOwner := Owner;
FSuspending := false;
end;
function TReceiveDataThread.CreateDataPacket: PDataPacket;
begin
GetMem(result,SizeOf(TDataPacket))
end;
procedure TReceiveDataThread.Execute;
begin
while true do SendDataPacket(ReceiveDataPacket(CreateDataPacket));
end;
function TReceiveDataThread.ReceiveDataPacket(Data: PDataPacket): PDataPacket;
var
i : integer;
begin
for i:=0 to DATA_PACKET_SIZE do begin
Data^[i].a:=random(40)+10;
Data^[i].b:=random(40)+10;
Data^[i].c:=0;
end;
result := Data;
end;
procedure TReceiveDataThread.Resumes;
begin
FSuspending := false;
Resume;
end;
procedure TReceiveDataThread.SendDataPacket(Data: PDataPacket);
begin
PostMessage(FOwner,WM_DATAPACKET,Integer(Data),0);
if FSuspending then Suspend else Sleep(0); //--- тут уж как надо
end;
procedure TReceiveDataThread.Suspending;
begin
FSuspending := true;
end;
end.
← →
msts (2002-11-27 12:02) [6]Соответсвенно можно сделать по другому -
завести фиксированный буфер 1000 элементов писать туда из потока
(т.е. без распределения памяти под новые данные - накрывая уже существующие) но тогда форма может не получить некоторые данные - будут накрыты новыми раньше чем она ими воспользуется
← →
Shuric (2002-11-27 15:32) [7]SottNick ©
DOS программа написана на Си, имеет два include файла, которые поставлялись с АЦП и в общем, занимаются:
1. Запрещение прерывания
2. Опрос порта
3. Разрешение прерывания
По этому, когда прога циклически этим занимается все очень даже быстро. А под винды - изменяешь напругу на входе, а изменения на экране могут быть мгновенными а могут быть и через 10 с
По многочисленным пожеланиям :) фирма учудила и под Windows, причем под Delphi не работало, а под Си нормалек. Пример представлял собой форму с таймером, то есть здесь опрос через их лабуду, да еще и по таймеру :( А по поводу перерисовки - элементарно, только используя не стандартный TBitmap.
← →
Shuric (2002-11-27 15:55) [8]msts
Спасибочки, буду разбираться...
← →
Cobalt (2002-11-27 22:10) [9]2 Shuric (27.11.02 00:05)
И смех, и грех...
Поясню - Вин-проги не умеют читать из адресного пространства Дос-прог. Но есть такая вещь, как чтение из потока вывода (stdOut) порожденной Дос(или др. консольной)-проги.
Так что просто выводи все данные "на экран", а Вин-клиент будет их читать и отображать "у себя"
Есть еще один вопрос - при выполнении Дос-проги из Виндов, "скорость реакции"(Дос-проги) - не падает?
И второй вопрос - целесообразность применения Вин-проги? Только для красоты?
← →
SottNick (2002-11-28 06:58) [10]> Shuric
ЗНАЧИТ
4. Делаешь, как все белые люди, приложение для отображения инфы, в нем поток для сбора данных с высоким приоритетом.
msts тебе почти всё неообходимое дал (и даже перестарался)
данные с порта считывай через драйвер, если он есть, а если нет, на асме накропай (под NT не заработает). Сишные исходники легко переделать.
И разберись с буфером. Нужен ли он тебе динамический такой? Если АЦП работает какими-то сессиями, то создай статический буфер, чтобы размера хватало на одну сессию. Создай переменную-флажок. В потоке считывания перед очередным сохранением данных проверяй, успевает ли комп данные забирать. Если не успевает, сообщай об этом миру (юзеру).
А DOS-прогу выкинь.
← →
Shuric (2002-11-28 15:21) [11]Cobalt ©
По поводу "не умеют читать из адресного пространства Дос-прог".
Если знать адресное пространство DOS программы, ну, в конечном счете адресок массива с считанными данными, то можно было бы попробовать API CopyMemory :)
"скорость реакции" лучше чем у Windows проги...
А по поводу целесообразности - снятие и отображение енто десятая часть программного комплекса и DOS здесь не катит.
← →
Shuric (2002-11-28 16:02) [12]SottNick ©
Ты не понял. Пример с исходниками на СИ работает, пример с исходниками на Delphi не работает и исходники на СИ не переделать. Поэтому пришлось пример на СИ упростить и сделать из него DLL :)
Прием данных в примере происходит примерно так
int ready = 0;
m_pADC->Get(ADC_GET_READY, &ready);
if (ready)
{
int data;
m_pADC->Get(ADC_GET_DATA, &data);
и т.д.
и не забывай по таймеру. А что делается в Get() никто кроме разработчиков не знает. Поэтому, если допустим АЦП, имеет свой таймер возможно рассогласования таймеров (не помню, как в науке называется, если представить таймеры как два дискретных процесса)
← →
SottNick (2002-11-29 07:55) [13]>>Ты не понял. Пример с исходниками на СИ работает,
>>пример с исходниками на Delphi не работает и исходники
>>на СИ не переделать.
>>Поэтому пришлось пример на СИ упростить и
>>сделать из него DLL :)
а по моему всё просто, как в армии
Вот тебе функция Get. Меряй.
function Get(port:word):word; pascal; assembler;
cli
nop
nop
nop
mov dx,port
in ax,dx
nop
nop
sti
end;
все nop можно попробовать выкинуть
проверяй на практике
только использование немного по другому
ready:=Get(ADC_GET_READY);
if (ready and 1)<>0
then
data:=Get(ADC_GET_DATA);
и еще
чтобы АЦП без посредника работало с компом, это надо поискать
скорее всего какой-то контроллер ловит прерывания
от тебя и договаривается с ацп сам
и никакие рассогласования с таймером возникнуть не могут (не должны)
в любом случае твой код (который работает) не держит между чтениями равное время, т.к. работает в многозадачной среде
← →
SottNick (2002-11-29 08:00) [14]слово пропало
повторяю
function Get(port:word):word; pascal; assembler;
asm
cli
nop
nop
nop
mov dx,port
in ax,dx
nop
nop
sti
end;
← →
Shuric (2002-11-29 15:29) [15]SottNick ©
Где-то читал и еще больше мне говорили, что конструкция "запретить - разрешить" прерывания удобоварима только для 16-ти разрядной среды, а для 32 это бывает смерти подобно...
← →
Victor_Cr (2002-11-30 00:02) [16]Мда... последний намек на меня... Не смерти подобно, а просто нереально. И запомни под виндой нет Доса, а есть всего лишь его эмуляция, т.е. программа выполняеться в винде, но под прикрытием того что она выполняется в Досе. Я думаю посе этого много вопросов отпадут.
← →
Shuric (2002-11-30 23:49) [17]Думаю пора эту тему закрывать, ввиду невозможности использовать DOS прогму как "дойную корову", хотя если вдруг кто-нибудь предложит примерчик на обмен с консольным приложением (а то, закончив аспирантуру и сдав экзамен по английскому - ни чего не понимаю в описании страшных функций группы :)) буду просто прыгать на "одной ноге" и кстати если консольное 16 то может быть там забацить прерывания...
← →
alnitak (2003-01-03 21:47) [18]По вопросу обмена Win9x c DOS-программой ,если есть ее исходники, прошу к alnitak@yandex.ru.
Можно использовать и досовское прерывание таймера (перестроенное
вплоть до 1 мс). Однако период прерывания будет немного размыт
(по сравнению с DOS). Учитывая последнее обстоятельство используйте мультимедийный таймер (WinAPI). Результат почти тот же, но наворотов меньше и прямо из DELPHI. Тем более, что и любые порты можно читать и писать из ассемблерных вставок.
с уважением alnitak
← →
OlegZ (2003-01-25 14:58) [19]Могу предложить следующее. DOS программа резидентна. До входа в Win она загружается, формирует в памяти буфер для обмена с Win - программой, адрес этого буфера пишет в специальный файл. Потом, когда Вы уже под Win, она по прерываниям опрашивает АЦП и заполняет данными буфер. Win - программа при запуске читает из файла адрес буфера, а затем по Delphi - таймеру забирает данные. Никакой потери нет, если буфер достаточного объема. Есть особенность: область памяти, где сидит DOS - программа и буфер должна быть защищена от вторжения Windows и приложений.
Я такую схему реализовал на Borland Pascal и Delphi3 для работы в W95/98 с АЦП под шину ISA. Все четко, данные идут непрерывно в фоновом режиме.
Если кого интересует, пишите zapisnyh@mtu-net.ru Могу дать исходные тексты.
← →
Shuric (2003-01-25 16:26) [20]Э э э... Спасибо, спасибо всем. Не могу подобрать слова, облечающию мою тупость, но это все в прошлом году осталось ;) Только повернутый программер может решать задачу о сложении 2 + 2 на трех страницах (из орешника). Беда была решена заменой таймера в Win на цикл, плюс в нем, для реализации обработки инфы от АЦП - CreateEvent...
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2003.03.17;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.008 c