Handling ISR generated by PCI Board

Hi,

I’m trying to use a PCI Board (ADLINK PCI8554 multifonction Counter / timer
Card)
under QNX 6.x. I translated a DOS library to use this card.

Most of the code in the library consist of some basic in/out (C instruction)
at baseaddress+xx
i put a ThreadCtl(_NTO_TCTL_IO,0) to permit in/out
There is also some call to intr_V86 to get Base Address, it work as good as
calls to pci
* function.

I try to generate an interruption every second.
which is made like that :
_8554_Write_Counter( cno , 11 , 3 ,8000); // write 8000 to counter 11
_8554_Write_Counter( cno , 12 , 3 ,1000); // write 1000 to counter 12
_8554_Set_INT_Control( cno , 1,0 ); // Enable Interrupt on
Output of counter 12

If I a remove the line _8554_Set_INT_Control( cno , 1,0 );
the program works well but no interruption
is catched else it freeze the OS (all i can do is resetting)

I don’t understand why it freeze QNX, the same
program work well under DOS.

My Board use IRQ11.
Which Interrupt must I Attach to: 11 or 0x73 ?

I tried on 0x73 but it does nothing (no freeze, no interruption)

I also tried to link the output of counter 12 to the ACK of my
parrallel port and try to catch interrupt 7 and it work well.

The support team at ATLINK does not support QNX so I’m
stuck

Can someone help me get out of this.

I can’t send the Board Specific code (Non disclosure agreement).

Any help will be appreciated !

Sorry for my poor English !

Here is my little program :
----- CUT HERE ----

#include <sys/neutrino.h>
#include <hw/inout.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/timeb.h>
#include <sys/siginfo.h>
#include <sys/neutrino.h>
#include “acl_pci.h”

#define CLR_IRQ1 0x20 /* For clear H/W IRQ1 /
#define CLR_IRQ2 0x21 /
For clear H/W IRQ2 */
#define PLX_INTCSR 0x4C


U16 cno,IRQ;
PCI_INFO info;

struct sigevent event;
int d=0;

const struct sigevent *handler(void *area, int id)
{
U8 b;
U16 plx_lcr_ba;

d++;

// CLEAR H/W Interrupt 1 on PCI8554
plx_lcr_ba = info.baseAddr[cno];
out8(plx_lcr_ba + CLR_IRQ1, 0x00 );
b = in8 ( plx_lcr_ba+ PLX_INTCSR );
out8( plx_lcr_ba+ PLX_INTCSR , b & 0x7F );

return(&event);
}

int main()
{
int id;
U16 bn=0;

event.sigev_notify = SIGEV_INTR;
ThreadCtl(_NTO_TCTL_IO,0);

_8554_Initial( &bn, &info );
_8554_Software_Reset( cno );

_8554_Write_Counter( cno , 11 , 3 ,8000);
_8554_Write_Counter( cno , 12 , 3 ,1000);
_8554_Set_INT_Control( cno , 1,0 );

id = InterruptAttach(11, &handler, NULL, 0, 0);

while (d<10) {
InterruptWait(NULL, NULL);
printf("%d\n",d);
}

InterruptDetach(id);

return 0;
}

Have you checked the status of the PIC to see if IRQ11 is masked?


Cheers,
Adam

QNX Software Systems Ltd.
[ amallory@qnx.com ]

With a PC, I always felt limited by the software available.
On Unix, I am limited only by my knowledge.
–Peter J. Schoenster <pschon@baste.magibox.net>
“Y.LEROUX” <y.leroux@nospam.actris.com> wrote in message
news:a33rsm$b35$1@inn.qnx.com

Hi,

I’m trying to use a PCI Board (ADLINK PCI8554 multifonction Counter /
timer
Card)
under QNX 6.x. I translated a DOS library to use this card.

Most of the code in the library consist of some basic in/out (C
instruction)
at baseaddress+xx
i put a ThreadCtl(_NTO_TCTL_IO,0) to permit in/out
There is also some call to intr_V86 to get Base Address, it work as good
as
calls to pci
* function.

I try to generate an interruption every second.
which is made like that :
_8554_Write_Counter( cno , 11 , 3 ,8000); // write 8000 to counter 11
_8554_Write_Counter( cno , 12 , 3 ,1000); // write 1000 to counter 12
_8554_Set_INT_Control( cno , 1,0 ); // Enable Interrupt on
Output of counter 12

If I a remove the line _8554_Set_INT_Control( cno , 1,0 );
the program works well but no interruption
is catched else it freeze the OS (all i can do is resetting)

I don’t understand why it freeze QNX, the same
program work well under DOS.

My Board use IRQ11.
Which Interrupt must I Attach to: 11 or 0x73 ?

I tried on 0x73 but it does nothing (no freeze, no interruption)

I also tried to link the output of counter 12 to the ACK of my
parrallel port and try to catch interrupt 7 and it work well.

The support team at ATLINK does not support QNX so I’m
stuck

Can someone help me get out of this.

I can’t send the Board Specific code (Non disclosure agreement).

Any help will be appreciated !

Sorry for my poor English !

Here is my little program :
----- CUT HERE ----

#include <sys/neutrino.h
#include <hw/inout.h
#include <stdio.h
#include <stdlib.h
#include <time.h
#include <signal.h
#include <errno.h
#include <unistd.h
#include <time.h
#include <sys/timeb.h
#include <sys/siginfo.h
#include <sys/neutrino.h
#include “acl_pci.h”

#define CLR_IRQ1 0x20 /* For clear H/W IRQ1 /
#define CLR_IRQ2 0x21 /
For clear H/W IRQ2 */
#define PLX_INTCSR 0x4C


U16 cno,IRQ;
PCI_INFO info;

struct sigevent event;
int d=0;

const struct sigevent *handler(void *area, int id)
{
U8 b;
U16 plx_lcr_ba;

d++;

// CLEAR H/W Interrupt 1 on PCI8554
plx_lcr_ba = info.baseAddr[cno];
out8(plx_lcr_ba + CLR_IRQ1, 0x00 );
b = in8 ( plx_lcr_ba+ PLX_INTCSR );
out8( plx_lcr_ba+ PLX_INTCSR , b & 0x7F );

return(&event);
}

int main()
{
int id;
U16 bn=0;

event.sigev_notify = SIGEV_INTR;
ThreadCtl(_NTO_TCTL_IO,0);

_8554_Initial( &bn, &info );
_8554_Software_Reset( cno );

_8554_Write_Counter( cno , 11 , 3 ,8000);
_8554_Write_Counter( cno , 12 , 3 ,1000);
_8554_Set_INT_Control( cno , 1,0 );

id = InterruptAttach(11, &handler, NULL, 0, 0);

while (d<10) {
InterruptWait(NULL, NULL);
printf("%d\n",d);
}

InterruptDetach(id);

return 0;
}

In article <a33rsm$b35$1@inn.qnx.com>, y.leroux@nospam.actris.com says…

Hi,

I’m trying to use a PCI Board (ADLINK PCI8554 multifonction Counter / timer
Card)
under QNX 6.x. I translated a DOS library to use this card.

Most of the code in the library consist of some basic in/out (C instruction)
at baseaddress+xx
i put a ThreadCtl(_NTO_TCTL_IO,0) to permit in/out
There is also some call to intr_V86 to get Base Address, it work as good as
calls to pci
* function.

I try to generate an interruption every second.
which is made like that :
_8554_Write_Counter( cno , 11 , 3 ,8000); // write 8000 to counter 11
_8554_Write_Counter( cno , 12 , 3 ,1000); // write 1000 to counter 12
_8554_Set_INT_Control( cno , 1,0 ); // Enable Interrupt on
Output of counter 12

If I a remove the line _8554_Set_INT_Control( cno , 1,0 );
the program works well but no interruption
is catched else it freeze the OS (all i can do is resetting)

I don’t understand why it freeze QNX, the same
program work well under DOS.

My Board use IRQ11.
Which Interrupt must I Attach to: 11 or 0x73 ?

I tried on 0x73 but it does nothing (no freeze, no interruption)

I also tried to link the output of counter 12 to the ACK of my
parrallel port and try to catch interrupt 7 and it work well.

The support team at ATLINK does not support QNX so I’m
stuck

Can someone help me get out of this.

I can’t send the Board Specific code (Non disclosure agreement).

Any help will be appreciated !

Sorry for my poor English !

Here is my little program :
----- CUT HERE ----

#include <sys/neutrino.h
#include <hw/inout.h
#include <stdio.h
#include <stdlib.h
#include <time.h
#include <signal.h
#include <errno.h
#include <unistd.h
#include <time.h
#include <sys/timeb.h
#include <sys/siginfo.h
#include <sys/neutrino.h
#include “acl_pci.h”

#define CLR_IRQ1 0x20 /* For clear H/W IRQ1 /
#define CLR_IRQ2 0x21 /
For clear H/W IRQ2 */
#define PLX_INTCSR 0x4C


U16 cno,IRQ;
PCI_INFO info;

struct sigevent event;
int d=0;

const struct sigevent *handler(void *area, int id)
{
U8 b;
U16 plx_lcr_ba;

d++;

// CLEAR H/W Interrupt 1 on PCI8554
plx_lcr_ba = info.baseAddr[cno];
out8(plx_lcr_ba + CLR_IRQ1, 0x00 );
b = in8 ( plx_lcr_ba+ PLX_INTCSR );
out8( plx_lcr_ba+ PLX_INTCSR , b & 0x7F );

return(&event);
}

int main()
{
int id;
U16 bn=0;

event.sigev_notify = SIGEV_INTR;
ThreadCtl(_NTO_TCTL_IO,0);

_8554_Initial( &bn, &info );
_8554_Software_Reset( cno );

_8554_Write_Counter( cno , 11 , 3 ,8000);
_8554_Write_Counter( cno , 12 , 3 ,1000);
_8554_Set_INT_Control( cno , 1,0 );

id = InterruptAttach(11, &handler, NULL, 0, 0);

while (d<10) {
InterruptWait(NULL, NULL);
printf("%d\n",d);
}

InterruptDetach(id);

return 0;
}
\

I would do a little more reading on ISR’s under QNX6.
They are not signal handlers!!
Look at some examples… in the on-line help - starting with
InterruptAttach()
(I suspect your parameter list is causing some problems, as are your lack
of other features required by ISRs…)


Stephen Munnings
Software Developer
Corman Technologies Inc.

I would do a little more reading on ISR’s under QNX6.
They are not signal handlers!!
Look at some examples… in the on-line help - starting with
InterruptAttach()
(I suspect your parameter list is causing some problems, as are your lack
of other features required by ISRs…)

OOps! My face is RED
Your code is not a signal handler (maybe I should be the one doing some
more reading!!)
I have written these! Honestly! It is just my memory that is faulty!
I guess I was mixing QNX4 and QNX6 styles in my mind.

I notice you are not clearing IRQ2 - is that the IRQ that is triggered,
by any chance??


Stephen Munnings
Software Developer
Corman Technologies Inc.

Adam Mallory <amallory@qnx.com> wrote in article <a36bdn$k1i$1@nntp.qnx.com>…

Have you checked the status of the PIC to see if IRQ11 is masked?

Adam, have I need to enable/unmask IRQ11 in QNX? Am I right that
InterruptAttach(11, &handler, NULL, 0, 0);
will not do it?

“Y.LEROUX” <> y.leroux@nospam.actris.com> > wrote in message
news:a33rsm$b35$> 1@inn.qnx.com> …
Hi,

I’m trying to use a PCI Board (ADLINK PCI8554 multifonction Counter /
timer
Card)
under QNX 6.x. I translated a DOS library to use this card.

Y.LEROUX, Unfortunately I have only DOS experience. In order to use IRQ11 in DOS you have:

  1. in main
    a) set up vector for your handler (I prefer to speak ISR)
    I think InterruptAttach() did it :wink:)
    b) unmask IRQ11 line
    byte=inp(0xa1);
    outp(0xa1, byte&0xf7);

Adam, should I do unmask IRQ11 in QNXRTP?

  1. in ISR
    a) send nonspecific End Of Interrupt in port 0x20
    b) send EOI in port 0xa0
    I guess
    outp(0x20, 0x20);
    outp(0xa0, 0x20);
    is the duty of OS when all ISRs finished. OS should see it’s second controller’s ISR and do step
    b), IMHO. And, of course, definitely it should do the step a). All other stuff is card-depending,
    and you have to do it before of steps a0 and b).

I’m not sure if it is useful for you, Y.LEROX. But who knows :wink:
Cheers,
Eduard.

“Y.LEROUX” wrote:

Hi,


[ clip …]
const struct sigevent *handler(void *area, int id)
{
U8 b;
U16 plx_lcr_ba;

d++;

→ check if there is an other device using IRQ11!

→ in general, you have to check whether the interrupt is really
raised up by your board.
→ interrupt sharing is common with PCI !


// CLEAR H/W Interrupt 1 on PCI8554
plx_lcr_ba = info.baseAddr[cno];
^^^^^^^^^^

→ Is this really an IO address or is it a memory address??

out8(plx_lcr_ba + CLR_IRQ1, 0x00 );
b = in8 ( plx_lcr_ba+ PLX_INTCSR );
out8( plx_lcr_ba+ PLX_INTCSR , b & 0x7F );

→ it is not common that a PCI board is handled by IO ports.
→ check if you have to map the controller area into your address
space …


return(&event);
}

int main()
{
int id;
U16 bn=0;

event.sigev_notify = SIGEV_INTR;
ThreadCtl(_NTO_TCTL_IO,0);

_8554_Initial( &bn, &info );
_8554_Software_Reset( cno );

_8554_Write_Counter( cno , 11 , 3 ,8000);
_8554_Write_Counter( cno , 12 , 3 ,1000);
_8554_Set_INT_Control( cno , 1,0 );

id = InterruptAttach(11, &handler, NULL, 0, 0);

while (d<10) {
InterruptWait(NULL, NULL);

→ I’m missing the InterrupUnmask call

Regards

Armin Steinhoff

http://www.steinhoff-automation.de


printf("%d\n",d);
}

InterruptDetach(id);

return 0;
}

Y.LEROUX <y.leroux@nospam.actris.com> wrote in article <a33rsm$b35$1@inn.qnx.com>…

My Board use IRQ11.

Also I’m puzzled a bit what have you done in order to use IRQ11? I maybe wrong, PCI bus is quite
new stuff for me :wink:
AFAIK, PCI bus uses INT #A, INT #B, INT #C and INT #D. Some of these lines should be translated to
physical interrupt line, for example IRQ11. Could anybody explain me how to do it?

Thanks.
Eduard.

ed1k wrote:

Y.LEROUX <> y.leroux@nospam.actris.com> > wrote in article <a33rsm$b35$> 1@inn.qnx.com> >…
snip

My Board use IRQ11.


Also I’m puzzled a bit what have you done in order to use IRQ11? I maybe wrong, PCI bus is quite
new stuff for me > :wink:
AFAIK, PCI bus uses INT #A, INT #B, INT #C and INT #D. Some of these lines should be translated to
physical interrupt line, for example IRQ11. Could anybody explain me how to do it?

This assignment of INT #A(BCD) to the IRQs is done by the PC bios.

Armin


Thanks.
Eduard.

Hi Eduard…

ed1k wrote:

Y.LEROUX <> y.leroux@nospam.actris.com> > wrote in article <a33rsm$b35$> 1@inn.qnx.com> >…
snip
My Board use IRQ11.

Also I’m puzzled a bit what have you done in order to use IRQ11? I maybe wrong, PCI bus is quite
new stuff for me > :wink:
AFAIK, PCI bus uses INT #A, INT #B, INT #C and INT #D. Some of these lines should be translated to
physical interrupt line, for example IRQ11. Could anybody explain me how to do it?

It is my understanding that these are hard-wired lines, and the BIOS
will assign an IRQ to them. I am not aware that you have a choice on
which IRQ the line gets connected to, whence you MUST always check which
IRQ the board is connected to by looking in the PCI register space.

Also, if you do a pci -v | more, do you see your board via vendor and
device ID? If so, then you may be able to use the pci_* set of
functions. Down bellow you’ll find a portion of how I get this
information from a cPCI board. Notice that I use mmap_device_memory()
to map the pci register base to local memory, and from then on you just
read/set information at will, including the IRQ and family.

Finally, the book “PCI System Architecture” is a good source.

Regards…

Miguel.

P.S. I use the VMIC 7755 cPCI cpu board.

Thanks.
Eduard.

////////////////////////////////////////////////////////////////////////
template
int vmic::init_vmic7755( void )
{


////////////////////////////////////////////////////////////////////////
// PCI portion

////////////////////////////////////////////////////////////////////////
//… attach a handle to the PCI device
if( pci_handle = pci_attach( 0 ) < 0 )
{
perror( “Error attaching to the PCI server” );
return ( EXIT_FAILURE );
}


//… Locate the embedded PCI functions resources
memset( &vmic7755info, 0, sizeof( vmic7755info ) );
vmic7755info.VendorId = 0x114A;
vmic7755info.DeviceId = 0x6504;
//… get the information
bridgeHandle = pci_attach_device( NULL, PCI_SEARCH_VENDEV |
PCI_SHARE, 0, &vmic7755info );
//… did we do this right?
if( NULL == bridgeHandle )
{
perror( “pci_attach_device” );
return ( -1 );
}

printf( “Bridge device found\n”
" Vendor Id = 0x%x\n"
" Device Id = 0x%x\n"
" Subsystem Id = 0x%x\n"
" Subsystem Vendor Id = 0x%x\n"
" Bus Number = 0x%x\n"
" Device Function Number = 0x%x\n"
" Revision = 0x%x\n"
" Class = 0x%x\n"
" IRQ = 0x%x\n"
" PciBaseAddress[0] = 0x%llx\n"
" PciBaseAddress[1] = 0x%llx\n"
" CpuBaseAddress[0] = 0x%llx\n"
" CpuBaseAddress[1] = 0x%llx\n"
" BaseAddressSize[0] = %d \n"
" BaseAddressSize[1] = %d \n"
" CpuIoTranslation = 0x%llx\n"
" CpuMemTranslation = 0x%llx\n"
" CpuBmstrTranslation = 0x%llx\n"
" RomSize = 0x%x\n",
vmic7755info.VendorId, vmic7755info.DeviceId,
vmic7755info.SubsystemId,
vmic7755info.SubsystemVendorId,
vmic7755info.BusNumber, vmic7755info.DevFunc,
vmic7755info.Revision, vmic7755info.Class,
vmic7755info.Irq,
vmic7755info.PciBaseAddress[0],
vmic7755info.PciBaseAddress[1],
vmic7755info.CpuBaseAddress[0],
vmic7755info.CpuBaseAddress[1],
vmic7755info.BaseAddressSize[0],
vmic7755info.BaseAddressSize[1],
vmic7755info.CpuIoTranslation,
vmic7755info.CpuMemTranslation,
vmic7755info.CpuBmstrTranslation, vmic7755info.RomSize );

if( PCI_IS_MEM( vmic7755info.CpuBaseAddress[0] ) )
{ printf("\n vmic7755info.CpuBaseAddress[0] = 0x%llx is a memory
address\n", vmic7755info.CpuBaseAddress[0]);
}
if( PCI_IS_MEM( vmic7755info.CpuBaseAddress[1] ) )
{ printf("\n vmic7755info.CpuBaseAddress[1] = 0x%llx is a memory
address\n", vmic7755info.CpuBaseAddress[1]);
}

if( PCI_IS_IO( vmic7755info.CpuBaseAddress[0] ) )
{ printf("\n vmic7755info.CpuBaseAddress[0] = 0x%llx is a IO
address\n", vmic7755info.CpuBaseAddress[0]);
}
if( PCI_IS_IO( vmic7755info.CpuBaseAddress[1] ) )
{ printf("\n vmic7755info.CpuBaseAddress[1] = 0x%llx is a IO
address\n", vmic7755info.CpuBaseAddress[1]);
}




//… Get the base address of the CSR’s
if( pci_read_config( bridgeHandle,
0x10,
1,
sizeof( BaseAddr_ram ),
&BaseAddr_ram ) != PCI_SUCCESS )
{
perror( “pci_read_config” );
return ( -1 );
}
if( pci_read_config( bridgeHandle,
0x14,
1,
sizeof( BaseAddr_timer ),
&BaseAddr_timer ) != PCI_SUCCESS )
{
perror( “pci_read_config” );
return ( -1 );
}

////////////////////////////////////////////////////////////////////////
// END PCI portion

////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////
// Memory and Register mapping

////////////////////////////////////////////////////////////////////////
//… this is the register base memory
regBase = (volatile uint8_t *) mmap_device_memory( NULL,
vmic7755info.BaseAddressSize[1],
PROT_READ|PROT_WRITE|PROT_NOCACHE,
0,
vmic7755info.CpuBaseAddress[1]);
if( regBase == MAP_FAILED )
{ perror( “mmap_device_memory” );
//return ( -1 );
exit( EXIT_FAILURE );
}
//… this is the pointer to a map of the reg base…
vmicRegB = (vmic_timer_t *) regBase;

//… this is the presistant ram memory (will survive shutdown)
ramBase = (volatile uint8_t *) mmap_device_memory( NULL,
vmic7755info.BaseAddressSize[0],
PROT_READ|PROT_WRITE|PROT_NOCACHE,
0,
vmic7755info.CpuBaseAddress[0]);
if( regBase == MAP_FAILED )
{ perror( “mmap_device_memory” );
//return ( -1 );
exit( EXIT_FAILURE );
}

////////////////////////////////////////////////////////////////////////
// END Memory and Register mapping

////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////
// Hardware set up

////////////////////////////////////////////////////////////////////////
//… clear any intterrupt
//regBase[0x30] = 0; //… value written does not matter
vmicRegB->t1ic = 0;

////////////////////////////////////////////////////////////////////////
// END hardware set up

////////////////////////////////////////////////////////////////////////

//… success…
return ( 1 );

}
////////////////////////////////////////////////////////////////////////

\


my opinions are mine, only mine, solely mine, and they are not related
in any possible way to the institution(s) in which I study and work.

Miguel Simon
Research Engineer
School of Aerospace and Mechanical Engineering
University of Oklahoma
http://www.amerobotics.ou.edu/
http://www.saic.com

Hi Miguel,

Miguel Simon <simon@ou.edu> wrote in article <3C5887A4.E03C511C@ou.edu>…
<…>

Finally, the book “PCI System Architecture” is a good source.

Have you any info on that book, ISBN, author, etc.? I’d like to read this book. Thank you for
extensive answer.

Best regards,
Keys were pressed by Eduard.

Hi Eduard…

PCI System Architecture, 4th ed. Tom Shanley and Don Anderson,
MindShare, Inc.
ISBN: 0-201-30974-2

I just went to Barnes and Noble and got a copy. Amazon.com should have
it as well.

Regards…

Miguel.

P.S. the book should help a lot, and it is a must-have. However, I’ve
found that the book lacks some information that I have needed such as
non-trasparent PCI-to-PCI bridges and address translation across
pci-bridges.

ed1k wrote:

Hi Miguel,

Miguel Simon <> simon@ou.edu> > wrote in article <> 3C5887A4.E03C511C@ou.edu> >…

Finally, the book “PCI System Architecture” is a good source.


Have you any info on that book, ISBN, author, etc.? I’d like to read this book. Thank you for
extensive answer.

Best regards,
Keys were pressed by Eduard.

my opinions are mine, only mine, solely mine, and they are not related
in any possible way to the institution(s) in which I study and work.

Miguel Simon
Research Engineer
School of Aerospace and Mechanical Engineering
University of Oklahoma
http://www.amerobotics.ou.edu/
http://www.saic.com

I had the second edition. It was a very technical book. However I did
glean everything that I needed to program for PCI devices.


Bill Caroselli – 1(626) 824-7983
Q-TPS Consulting
QTPS@EarthLink.net


“Miguel Simon” <simon@ou.edu> wrote in message
news:3C5976D4.C128CA9F@ou.edu

Hi Eduard…

PCI System Architecture, 4th ed. Tom Shanley and Don Anderson,
MindShare, Inc.
ISBN: 0-201-30974-2

I just went to Barnes and Noble and got a copy. Amazon.com should have
it as well.

Regards…

Miguel.

P.S. the book should help a lot, and it is a must-have. However, I’ve
found that the book lacks some information that I have needed such as
non-trasparent PCI-to-PCI bridges and address translation across
pci-bridges.

ed1k wrote:

Hi Miguel,

Miguel Simon <> simon@ou.edu> > wrote in article
3C5887A4.E03C511C@ou.edu> >…

Finally, the book “PCI System Architecture” is a good source.


Have you any info on that book, ISBN, author, etc.? I’d like to read
this book. Thank you for
extensive answer.

Best regards,
Keys were pressed by Eduard.

my opinions are mine, only mine, solely mine, and they are not related
in any possible way to the institution(s) in which I study and work.

Miguel Simon
Research Engineer
School of Aerospace and Mechanical Engineering
University of Oklahoma
http://www.amerobotics.ou.edu/
http://www.saic.com