# Command queue structure help?

**URL:** <https://www.ruby-forum.com/t/command-queue-structure-help/110316>\
**Category:** Ruby\
**Created:** [July 25, 2007, 8:55am UTC](https://www.ruby-forum.com/t/command-queue-structure-help/110316 "2007-07-25T08:55:48Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![mouse\_059](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e95f7d/32.png) [@mouse\_059](https://www.ruby-forum.com/u/mouse_059)\
**Post date:** [July 25, 2007, 8:55am UTC](https://www.ruby-forum.com/t/command-queue-structure-help/110316/1 "2007-07-25T08:55:48Z")

</div>

Greetings. I have been studying Ruby, have the pickaxe and Ruby Way  
(Fulton). Studying for a long time as I am a diehard C/assembly  
programmer and it is very hard to get out of the data-driven mindset.  
I believe to have finally found my killer application for Ruby (not  
rails, or the web.) I am however unfamiliar with OOP-isms and am  
trying to come to grips with them. Any assistance or direction anyone  
could help me with, I appreciate!

PS: The first time I coded this, it worked without a hitch. A real  
testament to Ruby.

The application: Picture a grid of NTSC monitors controlled by Apple  
II computers. Each Apple II has a serial card in it, hooked up to a  
portmaster, connected to a LAN and showing up on the local system (the  
Console) as virtual ttys a la /dev/ttyr1, etc. The Apples are running  
custom assembly routines, triggered by a write to the serial port from  
the Console to the tty port. (I figured Ruby wouldn’t be able to  
handle this kind of IO. Dead wrong, me!) The routines make the Apple  
monitor do different things - I can Fill the screen with a letter,  
Draw a horizontal or vertical line, Display a compressed image stored  
on the machine, etc. For synchronization, when the Apple is done, it  
sends a ACK bit to the serial port.

Here is what I have now, that works:  
#name #port #y value #x value  
MATRIX1 =[  
[“iip1”, “/dev/ttyr2”, 0, 0],  
[“iip2”, “/dev/ttyr3”, 0, 1],  
[“iic”, “/dev/ttyr1”, 0, 2] ]

MATRIX2 = [[“iie”, “/dev/ttyr5”] ]

MATRIXES = [MATRIX1, MATRIX2]

class Matrixes is a simple array (@store = []) and holds each  
DisplayMatrix. Each DisplayMatrix has its own group of computers and  
may have different properties - for example the first three machines  
are black and white, and in a row, so they make up a x,y display (40 \*  
3) by (24 \* 1). The second matrix has one machine in it and is  
color. A visualization can receive any number of these matrixes.

class Matrixes  
def initialize  
@store = []  
end

```
    def <<(data)
            @store << data
    end

    def each
            @store.each{ |mx| yield mx }
    end

    def flush_and_wait
            threads = []
            @store.each{ |mx| threads <<

```

Thread.new{ mx.flush\_and\_wait } }  
threads.each{ |t| t.join }  
end  
end

class DisplayMatrix holds an array of machines and has routines to  
flush an entire matrix, and wait for all machines to be finished. It  
also knows things about its structure (for example it knows the  
maximum horizontal and vertical resolution of the “virtual” text  
screen).

class DisplayMatrix  
def initialize(machines)  
@machines = machines  
end

```
    def flush_and_wait
            threads = []
            @machines.each{ |m| threads <<

```

Thread.new{ m.flush\_and\_wait } }  
threads.each{ |t| t.join }  
end

class Machine is one machine, and does all the communication with the  
serial port and keeps the object in a current state. It receives  
command requests and stores them on a queue.

class Machine  
def initialize(name, port, y, x)  
@name = name  
@y, @x = y, x  
@dev = open\_and\_init(port) # calls open, also uses  
Termios library

```
            @q = []
            @q.extend(MonitorMixin)
    end

    def enqueue(data)
            @q.synchronize{ @q << data }
    end

    def flush_and_wait
            @q.synchronize do
                    @q.each{ |q| @dev.syswrite(q) }
                    @q.clear

                    readyfd = select([@dev], nil, nil)
                    raise "select on our fd didn't yield it?" if

```

not  
readyfd.flatten.include? @dev  
@dev.sysread(100) #read & toss acknowlegement,  
right now simply a  
SPACE  
end  
end

Here is how I have a visualization currently. You will see I can make  
a visualization with custom parameters - in this case how many times  
to loop it. Other variables I can think of are how long to flash it,  
which character to flash it with, etc. So I must “create” a new  
FlashVis object based on custom parameters and how I want to run it.

Queueing the letter F, and then an ascii SPACE, makes that Apple II  
have a white on black screen.  
Queueing the letter F, and then hex A0, blanks the Apple II screen (it  
is an apple II normal space).

When I do a flush on the entire visualization matrix I wait for all  
Apples to be done. This creates O(n) threads as you can see, but  
seems to have negligable performance impact.

# BlinkVis simply blinks the Apple II screens

class BlinkVis  
def initialize(count)  
@count = count  
end

```
    def run(mxs)
            return Thread.new do
                    @count.times do
                            mxs.each{ |mx| mx.queue_to_all("F ") }
                            mxs.flush_and_wait

                            mxs.each{ |mx| mx.queue_to_all("F

```

\xa0") }  
mxs.flush\_and\_wait  
end  
end  
end  
end

And then the main program where you can see all the objects created  
cleanly:  
begin  
mxs = Matrixes.new

```
    MATRIXES.each do |matrix_def|
            ms = []
            matrix_def.each{ |name, port, y, x| ms <<

```

Machine.new(name, port, y, x) }  
mxs \<\< DisplayMatrix.new(ms)  
end

```
    vis = BlinkVis.new(3)
    while true do
            thr = vis.run(mxs)
            thr.join
    end

```

end

\***(end of program code)**

A few things are apparent about this and I must say - FIrst of all  
this code does exactly what my C code does with about 10x less the  
amount of lines due to ruby’s excellent hierarchical error passing and  
excellent array support, as you can imagine eliminating each “if fcntl  
\< 0 then error… if tcgetattr \< 0 then error… if select \< 0 then  
error… if read \< 0 then error…” took a crap load of code away.  
Secondly the code is extremely easy to parse.

Now that it does what my server coded in C does, I would like to  
know: What is the best way to abstract away the “intention” or  
“notion” of the command from the “actual” command I need to  
send to the Apple? (eg,

machine.enqueue( FLASH, A2\_SPACE | A2\_INVERSE ) instead of  
machine.enqueue(“F\xa0”)  
machine.enqueue( FLASH, A2\_SPACE | A2\_NORMAL ) instead of  
machine.enqueue("F ")

EG: The 6502 code also prints vertical lines “V” and horizontal lines  
“H” with three parameters: x from 0 to 39, y from 0 to 23, and  
length. It prints a compressed text screen block “E” with parameters  
which char to use for the light bits, which char for the dark bits,  
and the block. It will make a kaleidoscope in lo-res graphics by  
passing “K”. I can picture many more modes I will program in 6502 -  
for example, printing text in varying sizes and fonts on the hi-res  
screen,  
etc.

machine.enqueue( KALEIDOSCOPE, optional starting\_color )  
machine.enqueue( HLINE, starty, startx, length, optional color )  
machine.enqueue( TEXT, “The quick brown fox”, FONT\_BLA, 16 )

So with all these different commands, and parameters, what is the best  
way to “enqueue” one of these commands to the machine for sending/  
updating? And I would like to be able to handle different kinds of  
Machine in the future - it could be an Apple II, or it could be a dumb  
terminal, or possibly a NES system with custom cartridge & serial  
connection. In each case the output to the machine would be  
different. The way I have done it so far seems to imply I can do what  
I am asking here. (And a big pain in the butt in C, which is why I  
stopped and did this!!) Ruby example code would be helpful!

PS: If any of you are II fans and would like to use this I will be  
puting a webpage together with the assembly and all necessary  
materials. II Infinitum!

-m
