help with DUIM application 
Author Message
 help with DUIM application

What would be the correct way to use DUIM to create an application which
periodically (about 1 Hz) reads a sequence of data received via a serial
port and translates the data for display in a simple dialog window?

My first thoughts were:

1.  Have two threads.  One for the serial input task and one for the display
task.  Assuming that to be the design, what is the proper way in DUIM to
signal the display task that new data is available for translation and
display.  I know that DUIM has event queue processing, but I don't know how
it works.  Would it make sense to define a new subclass of <event>, say
<io-ready-event>,  and use it to signal from the serial input task to the
display task?  The display task would, of course, somehow have to have a
modified event loop that recognizes the new class <io-ready-event>.  The
event handling for the event in the display task would be to grab the data
from the input task and then translate and display it.

2.  The other idea I had was to simply call the serial input function at a
rate of approximately once per second.  Well, how do you accomplish timed
periodic events in DUIM?  Or is there some other event in the Win32 API that
I could use?

I'm not an expert on either DUIM or Win32, so pardon if the answer is
obvious to the DUIM/Win32 experts.

Thanks for any help.



Sun, 01 Dec 2002 03:00:00 GMT  
 help with DUIM application

Quote:

>What would be the correct way to use DUIM to create an application which
>periodically (about 1 Hz) reads a sequence of data received via a serial
>port and translates the data for display in a simple dialog window?

>My first thoughts were:

>1.  Have two threads.  One for the serial input task and one for the
display
>task.  Assuming that to be the design, what is the proper way in DUIM to
>signal the display task that new data is available for translation and
>display.  I know that DUIM has event queue processing, but I don't know how
>it works.  Would it make sense to define a new subclass of <event>, say
><io-ready-event>,  and use it to signal from the serial input task to the
>display task?  The display task would, of course, somehow have to have a
>modified event loop that recognizes the new class <io-ready-event>.  The
>event handling for the event in the display task would be to grab the data
>from the input task and then translate and display it.

>2.  The other idea I had was to simply call the serial input function at a
>rate of approximately once per second.  Well, how do you accomplish timed
>periodic events in DUIM?  Or is there some other event in the Win32 API
that
>I could use?

>I'm not an expert on either DUIM or Win32, so pardon if the answer is
>obvious to the DUIM/Win32 experts.

If I were doing it, I would use two threads.  Because of some
Windows idiosyncracies, you are best off using the initial thread
to manage your user interface, and start a different thread to
manage the serial input.  Use the threads library, and have the
first thread await some sort of signal from the serial input thread.

You could look at the Life example to see how a multi-threaded
DUIM app works.  The UI thread draws the display and handles
inout events, such as the user selecting something from a menu.
The "compute" thread (which corresponds to your serial input
thread) computes each new generation and notifies the UI thread
when a new generation is fully computed.



Sun, 01 Dec 2002 03:00:00 GMT  
 help with DUIM application


Quote:
> If I were doing it, I would use two threads.  Because of some
> Windows idiosyncracies, you are best off using the initial thread
> to manage your user interface, and start a different thread to
> manage the serial input.  Use the threads library, and have the
> first thread await some sort of signal from the serial input thread.

> You could look at the Life example to see how a multi-threaded
> DUIM app works.  The UI thread draws the display and handles
> inout events, such as the user selecting something from a menu.
> The "compute" thread (which corresponds to your serial input
> thread) computes each new generation and notifies the UI thread
> when a new generation is fully computed.

Thanks for the ideas Scott and Jason.  I looked at the Life example a
bit.  If I understand it correctly, the notifications going on in the
Life example are in the opposite direction of what I would want, and the
logic and display threads in the Life example are VERY tightly coupled.
I mean that the logic thread actually is involved in drawing and knows
about the slots in the main frame.  I'd rather avoid that.

It occurs to me that this is really just another example of one of the
most common design patterns:  the subject/observer or publish/subscribe
pattern.  The serial-io thread is a data producer, which I think of as a
subject.  The display thread is an observer.  So, following the design
pattern, I think the display thread (i.e. the main frame) would need a
Notify() method (in GOF terminology).  It would also register with the
serial-io thread at startup.  When the serial-io thread has new data, it
would call the Notify() method for the display thread.  What I like
about thinking about the problem in this way is that by following this
pattern I would have a more general solution to the problem.  For
example, it would be possible to have multiple objects and/or threads
register with the data producer.  The data producer could then call the
Notify() methods for all observers when it has new data.

Now how this fits into the suggestions given already...   Is the
call-in-frame method the equivalent of the Notify() method?  I'll have
to think about that some more.

Thanks again for the ideas.

Sent via Deja.com http://www.deja.com/
Before you buy.



Sun, 01 Dec 2002 03:00:00 GMT  
 help with DUIM application
On Tue, 13 Jun 2000 22:45:02 -0400 (EDT), "John Whittaker"

Quote:

> What would be the correct way to use DUIM to create an application which
> periodically (about 1 Hz) reads a sequence of data received via a serial
> port and translates the data for display in a simple dialog window?

> My first thoughts were:

> 1.  Have two threads.  One for the serial input task and one for the display
> task.  Assuming that to be the design, what is the proper way in DUIM to
> signal the display task that new data is available for translation and
> display.  I know that DUIM has event queue processing, but I don't know how
> it works.  Would it make sense to define a new subclass of <event>, say
> <io-ready-event>,  and use it to signal from the serial input task to the
> display task?  The display task would, of course, somehow have to have a
> modified event loop that recognizes the new class <io-ready-event>.  The
> event handling for the event in the display task would be to grab the data
> from the input task and then translate and display it.

As Scott says you basically do it this way. However, you don't need to create
any new event class or modify any event loop stuff. You just call either
call-in-frame or apply-in-frame (depending on your needs) and that will create
an event behind the scenes and run the given method on the UI thread for that
frame. Its trivial.

e.g. in its simplest form (untested):

begin
  let frame = make(<my-frame>);
  make(<thread>, function: curry(start-data-capture, frame));
  start-frame(frame); // NB uses up main thread
end;

define method start-data-capture (frame)
  while (#t)
    let data = blocking-read-for-device-data();
    call-in-frame(frame, update-my-frame, data);
  end;
end method;

define method update-my-frame (frame :: <my-frame>, data)
  // insert display changing code here
end method;

__Jason

_____________________________________________________________________
This message has been checked for all known viruses by Star Internet delivered
through the MessageLabs Virus Control Centre. For further information visit
http://www.star.net.uk/stats.asp



Sun, 01 Dec 2002 03:00:00 GMT  
 help with DUIM application

Quote:

> Now how this fits into the suggestions given already...   Is the
> call-in-frame method the equivalent of the Notify() method?  I'll have
> to think about that some more.

Loosely coupling the components like this is orthogonal to the issue of
combining the threading. It might be done as follows:

8<----------------------------------------------------------------------

begin
  let frame = make(<my-frame>);
  add!(*hooks*, method (data) call-in-frame(frame, update-my-frame, data) end);
  make(<thread>, function: start-data-capture);
  start-frame(frame); // NB uses up main thread
end;

define constant *hooks* = make(<stretchy-vector>);

define method start-data-capture ()
  while (#t)
    let data = blocking-read-for-device-data();
    do(method (hook) hook(data) end, *hooks*);
  end;
end method;

define method update-my-frame (frame :: <my-frame>, data)
  // insert display changing code here
  // (gets run on frame thread)
end method;

8<----------------------------------------------------------------------

Now anyone can add themselves to hooks to get told about new data.

The 'Pattern' literation generally assumes message-passing OO-style. Hence they
are forced to think in terms of protocols (eg Notify), which aren't necessary
in Dylan although you could define them if you wanted to:

8<----------------------------------------------------------------------

begin
  let frame = make(<my-frame>);
  add!(*observers*, frame);
  make(<thread>, function: start-data-capture);
  start-frame(frame); // NB uses up main thread
end;

define constant *observers* = make(<stretchy-vector>);

define method start-data-capture ()
  while (#t)
    let data = blocking-read-for-device-data();
    do(method (observer) notify(observer, data) end, *observers*);
  end;
end method;

define method notify (frame :: <my-frame>, data)
  method (data) call-in-frame(frame, update-my-frame, data) end);
end method;

define method update-my-frame (frame :: <my-frame>, data)
  // insert display changing code here
  // (gets run on frame thread)
end method;

8<----------------------------------------------------------------------

__Jason

_____________________________________________________________________
This message has been checked for all known viruses by Star Internet delivered
through the MessageLabs Virus Control Centre. For further information visit
http://www.star.net.uk/stats.asp



Sun, 01 Dec 2002 03:00:00 GMT  
 help with DUIM application

Quote:

> Now how this fits into the suggestions given already...  Is the
> call-in-frame method the equivalent of the Notify() method?  I'll
> have to think about that some more.

Have you looked at the channels library that ships with FD? The source
is in sources/lib/channels. It seems to do observer pattern style
stuff. Receivers tune into channels which can broadcast information to
all tuned in receivers. I haven't used it but it may do something of
what you want.

Chris.
--
http://www.double.co.nz/dylan



Mon, 02 Dec 2002 03:00:00 GMT  
 help with DUIM application

Having just spent about half a day during working hours and numerous other
at home hours working on my pet Dylan project--getting serial data from an
avionics product for testing the product--I have learned a number of things
about FD 2.0 and DUIM.  These are somewhat random thoughts, so be
forewarned.  You don't have to read this if you don't want to.

1.  I really think that FD 2.0 is a full-fledged, heavyweight tool now, and
Dylan is a very powerful and flexible language.  Previous releases of the
Harlequin version had a few too many rough spots.  FD 2.0 works well in
almost all areas (except perhaps documentation of DUIM.  Dustin Voss may
have similar opinions), and downright great in some areas.  I used nothing
but FD 2.0 to set up and read from the COM1 port via Win32 calls.  It was
painless to do in FD 2.0.  The hard part was learning how the Win32 calls
worked, and trying to learn DUIM.  Although it's not FD's job to help with
Win32, the profiler ended up helping me with the Win32 stuff (see below).
The compiler is fast.  Setting up projects is easy once you've learned the
library structure.  Linking is really lightning fast now that I use the
Microsoft linker.  Kudos to FunctionalObjects for supporting it.  I can make
dll's as easily as exe's, and I can incorporate a dll project in an
executable as a subproject.  It just works well, even intuitively.  Color
dispath optimization is COOL..

There are definitely some rough spots still remaining.  Sometimes the IDE
seems to get confused about rebuilding when I've got a project and its
subproject open.  The editor still has a few gotchas.  Perhaps some more
native look and feel tools for DUIM-- I don't know.  But these are minor,
and I'm sure that the next release will eliminate most of these annoyances
(I hope).

2.  I still have a long way to go in understanding DUIM.  Most of my at home
time was spent looking over DUIM doc and example code trying to figure out
how to get a <gadget> to update itself.  I was lost...for hours.  The
problem (for me) was that the <gadget> was buried inside a pane which was
buried inside a frame.  It may sound silly, but it's true.  I finally
figured out by looking at some other code that the pane surrounding the
gadget works when passed to update-gadget (see the code below).  I still
don't have the relationship between frames, panes, and sheets straight.  If
I understood that, building DUIM apps would probably be much easier.

define frame <thread-frame> (<dialog-frame>)
  pane stop-button (frame)
    make(<push-button>, label: "Stop",
         activate-callback: stop-app);
  pane quicktune-pane (frame)
    make(<text-field>, label: "QuickTune:",
                              width: 100, fixed-width?: #t,
                             activate-callback: not-yet-implemented);
  pane task-layout (frame)
      vertically ()
          frame.quicktune-pane;
          frame.stop-button;
      end;
  layout (frame) frame.task-layout;
  keyword title: = "KLN 94 QuickTune Info";
end frame <thread-frame>;

define variable display-thread-frame :: false-or( <thread-frame> ) = #f;

define method update-gui (data :: <byte-string> ) => ()

   local method update-quicktune( s :: <byte-string> )
      gadget-text-setter( s,  display-thread-frame.quicktune-pane );
      update-gadget( quicktune-pane( display-thread-frame ) );   // insert
display changing code here
   end method update-quicktune;

   call-in-frame( display-thread-frame, update-quicktune, as( <byte-string>
, data));
 end method;

define method main () => ()
  // Your program starts here...
  display-thread-frame :=  make( <thread-frame> );
  make(<thread>, function: curry(quicktune-thread, display-thread-frame));
  start-frame( display-thread-frame );
end method main;

<-------------------------- AND IN ANOTHER PROJECT, THE CODE FOR THE OTHER
THREAD -------------------->

define open generic update-gui( data :: <byte-string> ) => ();

define method quicktune-thread ( gui-frame :: <frame> ) => ()

 let  port = setup-94-serial-data();
 while (#t)
   let (result , num-read ) = get-94-serial-data(port);
   let quicktune-pattern = make( <byte-string> , size: 1 );
   quicktune-pattern[0] :=  'q';
   //quicktune-pattern[1] := as( <byte> , 'q' );
   if (num-read > 0 )
      let current-data = copy-sequence( buffer-94.buf1, start: 0, end:
num-read );
      let quicktune-found = subsequence-position( current-data ,
quicktune-pattern );
      if ( quicktune-found ~= #f )
         let quicktune = copy-sequence( current-data,
                                        start: quicktune-found, end:
quicktune-found + 7 );
         update-gui( as( <byte-string>, quicktune ));
      end if;
   end if;
   threads-sleep( 0.5 );
 end while;
end method quicktune-thread;

3.  The threads library is very rich.  It may have everything you'd ever
need for threads and/or synchronization.  But, even though the code shown
above works as two separate threads, I don't think it goes as far as I would
like to in decoupling the two threads.  I'm not exactly sure what the
sematics of call-in-frame is.  Do the calling thread and the called thread
(i.e., the frame thread) synchronize in this function somehow?    Suppose I
wanted the quicktune-thread to just dump its data, a buffer at a time, into
a queue.  Then signal (I don't know how) the GUI thread that it has done so.
How does a GUI thread running in a frame "catch" a signal?  I assume that
the main thread loop for a gui frame looks something like:

   while ( alive )
      event := get-next-event();
      process-event( event );
   end while;

The "event" would be some DUIM translation of Windows events (I'm guessing).
Granted that this is all based on my possibly flawed assumptions, but how
could you extend/modify the processing of a frame's thread to somehow check
for a signal from another thread?

4.  The profiler is slick.  Even though the high level code for my whole toy
(but useful) application is contained in just the few lines above, my
application was taking about 35% of a Pentium III, 500.   Pretty terrible,
huh.     Well, I had never even played with the FD profiler before, but I
fired it up, and it quickly showed me just what I was expecting--that I was
probably wasting a lot of time in a wait in the Windows ReadFile function.
The commented out code below and its replacement below make all the
difference in how much cpu the application takes.  With the BAD, BAD, BAD
code, it takes about 35% of the cpu.   With the good code, it takes the much
more reasonable 3%.   My point is that with the Profiler I quickly was able
to confirm my suspicions about the source of the bad performance.  With a
little experimentation, I fixed it.  (I still don't think I get why the
$MAXDWORD approach is bad though).  The Profiler is one of the necessary
tools of a heavyweight compiler.  FD has it and it works.

define method get-94-serial-data( port-handle ) => ( #rest results)

 /* BAD BAD BAD
   set-comm-timeouts( port-handle, read-interval: $MAXDWORD,
                       read-total-multiplier: as( <machine-word>, 0) ,
                       read-total-constant: as( <machine-word>, 0) );
*/
   set-comm-timeouts( port-handle, read-interval: as( <machine-word>, 3),
                       read-total-multiplier: as( <machine-word>, 0) ,
                       read-total-constant: as( <machine-word>, 0) );
   let temp-buf = make( <c-string>, size: 2 );
   let ( result , num-read ) = read-comm-data( port-handle, temp-buf ,
num-bytes: 1 );
   while ( num-read > 0 & (temp-buf[0] ~= '\<2>') )
      let (result, num-read ) = read-comm-data( port-handle, temp-buf,
num-bytes: 1 );
   end while;

   if ( num-read > 0)
     set-comm-timeouts( port-handle, read-interval: as( <machine-word>, 2),
                       read-total-multiplier: as( <machine-word>, 3) ,
                       read-total-constant: as( <machine-word>, 20)  );
     read-comm-data( port-handle, buffer-94.buf1, num-bytes: (115 + 34) );
   else
      PurgeComm( port-handle, $PURGE-RXABORT );
      values( #f, 0 );
   end if;
end method get-94-serial-data;



Tue, 03 Dec 2002 03:00:00 GMT  
 help with DUIM application
On Fri, 16 Jun 2000 01:00:01 -0400 (EDT), "John Whittaker"

Quote:

> define variable display-thread-frame :: false-or( <thread-frame> ) = #f;

Dylan programmers would conventionally name this variable with '*'s :

  define variable *display-thread-frame* :: false-or( <thread-frame> ) = #f;

I'm also trying to encourage a convention where false-or types are made
explicit by combining the conventions for types and predicates as follows:

  define constant <thread-frame>? = false-or( <thread-frame> );
  define variable *display-thread-frame* :: <thread-frame>? = #f;

.

Quote:
> 3.  The threads library is very rich.  It may have everything you'd ever
> need for threads and/or synchronization.  But, even though the code shown
> above works as two separate threads, I don't think it goes as far as I would
> like to in decoupling the two threads.

What did you think about the *hooks* or *observers* solution?  Chris also
pointed out the 'Channels' library which FD uses internally to decouple
components.

Quote:
>  I'm not exactly sure what the
> sematics of call-in-frame is.  Do the calling thread and the called thread
> (i.e., the frame thread) synchronize in this function somehow?

Yes. I don't have Dylan's DUIM sources installed on my work machine following a
disk crash and a machine upgrade, but I think call-in-frame creates a
<function-event> which is pushed onto the event queue for the frame. The frame
thread then encounters this event just like the other 'real' windows ones.

Quote:
>    Suppose I
> wanted the quicktune-thread to just dump its data, a buffer at a time, into
> a queue.  Then signal (I don't know how) the GUI thread that it has done so.
> How does a GUI thread running in a frame "catch" a signal?  I assume that
> the main thread loop for a gui frame looks something like:

>    while ( alive )
>       event := get-next-event();
>       process-event( event );
>    end while;

> The "event" would be some DUIM translation of Windows events (I'm guessing).
> Granted that this is all based on my possibly flawed assumptions, but how
> could you extend/modify the processing of a frame's thread to somehow check
> for a signal from another thread?

Your assumptions are roughly correct I think, and call-in-frame (or
apply-in-frame ) is already doing what you want.

__Jason

_____________________________________________________________________
This message has been checked for all known viruses by Star Internet delivered
through the MessageLabs Virus Control Centre. For further information visit
http://www.star.net.uk/stats.asp



Tue, 03 Dec 2002 03:00:00 GMT  
 help with DUIM application

Quote:

>Subject: Re: FD 2.0 is quite a tool! --long post

> I'm also trying to encourage a convention where false-or types are made
> explicit by combining the conventions for types and predicates as follows:

>   define constant <thread-frame>? = false-or( <thread-frame> );
>   define variable *display-thread-frame* :: <thread-frame>? = #f;

This is cool. Should that be <thread-frame?>    ? The <> emphasize
classness, which should probably have higher precedence than precendence.
Also, people are used to typing the <> outside everything else, so this may
lead to more mis-types. Just thinking out loud. :-)

- Rob.



Tue, 03 Dec 2002 03:00:00 GMT  
 help with DUIM application

Quote:


> >Subject: Re: FD 2.0 is quite a tool! --long post

> > I'm also trying to encourage a convention where false-or types are made
> > explicit by combining the conventions for types and predicates as follows:

> >   define constant <thread-frame>? = false-or( <thread-frame> );
> >   define variable *display-thread-frame* :: <thread-frame>? = #f;

> This is cool. Should that be <thread-frame?>    ? The <> emphasize
> classness, which should probably have higher precedence than precendence.
> Also, people are used to typing the <> outside everything else, so this may
> lead to more mis-types. Just thinking out loud. :-)

Well, I considered that alternative when I dreamt up the convention, but I
prefer <thread-frame>? because I think of the type as modifier on
<thread-frame> (like false-or() itself), and so mangling the ? inside the <>
didn't feel right to me.

__Jason

_____________________________________________________________________
This message has been checked for all known viruses by Star Internet delivered
through the MessageLabs Virus Control Centre. For further information visit
http://www.star.net.uk/stats.asp



Tue, 03 Dec 2002 03:00:00 GMT  
 help with DUIM application
I guess I like the idea of <thread-frame>?, but we're not heading down a
slippery slope toward Hungarian names are we?  (Just kidding.)

Quote:
>-----Original Message-----

>Sent: Friday, June 16, 2000 4:48 AM
>To: Rob Myers

>Subject: Re: FD 2.0 is quite a tool! --long post

>Well, I considered that alternative when I dreamt up the convention, but I
>prefer <thread-frame>? because I think of the type as modifier on
><thread-frame> (like false-or() itself), and so mangling the ? inside the
<>
>didn't feel right to me.

>__Jason



Tue, 03 Dec 2002 03:00:00 GMT  
 
 [ 12 post ] 

 Relevant Pages 

1. Help: Standalone application does not run (Error #-10007), but development application does

2. HELP! Interfacing prolog application with MS-WINDOWS application

3. problem with DUIM at higher resolutions

4. DUIM focus question

5. A duim menu question

6. updating an icon label in DUIM

7. updating an icon label in DUIM

8. DUIM font question

9. DUIM question

10. DUIM clipboard

11. <tree-node> in DUIM

12. Browser gadget sugguestions for a DUIM app

 

 
Powered by phpBB® Forum Software