/*

***********************************************************************
***
***  CDTV CDXL Example #1 - Simple but Useful
***
***     Written by Carl Sassenrath, Jan 1991
***
***     In this simple example 12 megabytes of random CDROM data are
***     transferred into two "ping-pong" buffers.  This is done by
***     creating a circular transfer list (tail connects back to head).
***     At the end of each transfer, a callback function is executed to
***     increment a counter.
***
***     Once you understand this example, it should take little time
***     to enhance it to deliver graphics, sound, text, etc. as your
***     application requires.
***
***     Read the CDXL developer notes for more information.
***
***     Compiled and Tested under SAS/C 5.10a (Lattice)
***     Compiler options: -b0  (32 bit addressing)
***
* Copyright (c) 1991 Commodore Business Machines, Inc.
* The source code examples included are used on the Welcome Disc.  These
* examples are provided for information purposes only, on an "as is" basis.
* No warranties of any nature, express or implied, are made.  Any use
* of these examples is at your own risk with no liability or responsability
* of any kind being assumed by Commodore, its suppliers and developers,
* or their employees.
*
* Subject to these limitations, executables based upon these examples
* may be developed and used in software for the Commodore CDTV.   All
* other rights are reserved.
*
***********************************************************************/


#include <exec/types.h>
#include <exec/io.h>
#include "cdtv.h"

extern  struct  IOStdReq *CreateStdIO();
extern  struct  MsgPort  *CreatePort();

#define FRAMES  1000
#define READLEN 6
#define BLKSIZE 2048
#define BUFSIZE (READLEN*BLKSIZE)
#define MUST(expr)  if (!(expr)) Quit(AssertFail);

int     Count = 0;
char    Buf[BUFSIZE*2];
char    AssertFail[] = "Assertion failed (MUST)";
struct  IOStdReq *IOReq = NULL;
struct  MsgPort  *IOPort = NULL;
struct  MinList XLList;
struct  CDXL XLNodes[2];

/***********************************************************************
***
***  Quit -- exit program and clean-up.  Return an error in needed.
***
***********************************************************************/
void Quit(s)
        char *s;        /* error message */
{
        if (IOReq && IOReq->io_Device) CloseDevice(IOReq);
        if (IOReq)      DeleteStdIO(IOReq);
        if (IOPort)     DeletePort(IOPort);
        if (s) {printf("\nERROR: %s\n",s); exit(40);}
        else exit(0);
}

/***********************************************************************
***
***  Init -- initialize program and structures
***
***********************************************************************/
void Init()
{
        MUST(IOPort = CreatePort(0,0));
        MUST(IOReq = CreateStdIO(IOPort));
        if (OpenDevice("cdtv.device",0,IOReq,0))
                Quit("CDTV Device will not open");

}

/***********************************************************************
***
***  SendIOR -- asynchronously execute a device command
***
***********************************************************************/
void SendIOR(req,cmd,off,len,data)

        struct IOStdReq *req;
        int cmd;
        long off;
        long len;
        APTR data;
{
        req->io_Command = cmd;
        req->io_Offset = off;
        req->io_Length = len;
        req->io_Data   = data;
        SendIO(req);
}


/***********************************************************************
***
***  XLCall -- XL Callback function (runs as an interrupt)
***
***********************************************************************/
void __interrupt XLCall()
{
        Count++;
}


/***********************************************************************
***
***  Main
***
***********************************************************************/
main(argc,argv)
        int argc;
        char *argv[];
{
        int i;

        printf("XL Example\n");

        Init();

        /* Create the Transfer List: */
        XLList.mlh_Head = (struct MinNode *)&XLList.mlh_Tail;
        XLList.mlh_Tail = NULL;
        XLList.mlh_TailPred = (struct MinNode *)&XLList.mlh_Head;
        for (i = 0; i < 2; i++)
        {
                XLNodes[i].Buffer = &Buf[i*BUFSIZE];
                XLNodes[i].Length = BUFSIZE;
                XLNodes[i].DoneFunc = XLCall;
                AddTail(&XLList,&XLNodes[i]);
        }

        /* Make it a circular list: */
        XLList.mlh_Head->mln_Pred = XLList.mlh_TailPred;
        XLList.mlh_TailPred->mln_Succ = XLList.mlh_Head;

        /* Start the transfer: */
        SendIOR(IOReq,CD_READXL,100,READLEN*FRAMES,XLList.mlh_Head);

        printf("Transferring data...\r");
        while (!CheckIO(IOReq)) printf("%8ld Bytes\n",Count*BUFSIZE);
        WaitIO(IOReq);

        Quit(0);
}
