//*********************************************************************
//
//              General part of Scanner device
//
//                  version 2000.05.29
//
//*********************************************************************

#include <exec/types.h>
#include <exec/io.h>
#include <exec/errors.h>
#include <exec/devices.h>
#include <instrument.h>
#include <proto/exec.h>

#include <DriverIo.h>
#include <scanner.h>
#include <scanner_protos.h>

#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

struct ScannerIO
{
  struct InstrumentIO   IOScan;
  struct ScannerOptions option;
};

static BYTE SetUp(struct MsgPort *port,char *devName,int devUnit,struct ScannerOptions* option);
static void CleanUp(void);
static void MainLoop(struct Unit *Unit);

static void Start(struct InstrumentIO *io);
static void Stop(struct InstrumentIO *io);
static void Set(struct InstrumentIO *io);
static void Read(struct InstrumentIO *io);
static void LoadOption(struct InstrumentIO *io);

///////////////////////////////////////////
//
// Here starts and ends the process
//
//////////////////////////////////////////
void UnitMain(struct Unit *Unit,char* devName,int devUnit)
{
  struct ScannerIO* ior;

  // Get opening message (IO with io_Command = FCMD_OPEN)
  WaitPort(&Unit->unit_MsgPort);
  ior = (struct ScannerIO *)GetMsg(&Unit->unit_MsgPort);

  if( ior->IOScan.io_Message.mn_Length != sizeof(struct ScannerIO) )
  {
    Unit->unit_OpenCnt = 0;
    ior->IOScan.io_Error = SCAN_OPNERR_FATAL;
    ReplyMsg((struct Message *)ior);
  }
  
  ior->IOScan.io_Unit = &Unit;
  ior->IOScan.io_Error = SetUp(&Unit->unit_MsgPort,devName,devUnit,&ior->option);
  if( ior->IOScan.io_Error == SCAN_STATUS_OK )
  {
    Unit->unit_OpenCnt = 1;
    ReplyMsg((struct Message *)ior);

    MainLoop(Unit);

    CleanUp();
  }
  else
  {
    Unit->unit_OpenCnt = 0;
    ReplyMsg((struct Message *)ior);
  }
}

static BYTE SetUp(struct MsgPort *port,char *devName,int devUnit,struct ScannerOptions* option)
{
  BYTE status = 0;
 
  if( openDriverIo(devName,devUnit,port) )
  {
    openScanner(option,&status);
    if( status )
      closeDriverIo();
  }
  else
    status = SCAN_OPNERR_DEVICE;
  
  return status;
}

static void CleanUp()
{
  closeScanner();
  closeDriverIo();
}

////////////////////////////////////////////////
//
//  Event procedures
//
///////////////////////////////////////////////

static void MainLoop(struct Unit *Unit)
{
  struct InstrumentIO* io;

  while( TRUE )
  {
    while( io = (struct InstrumentIO*)waitForIOReq() )
    {
      switch(io->io_Command) 
      {
        case FCMD_OPEN:
          // IOScan->io_Unit = &Unit;
          // UnitMain->unit_OpenCnt++;
          io->io_Error = IOERR_UNITBUSY;
          break;
        case FCMD_CLOSE:
          Unit->unit_OpenCnt--;
          if( Unit->unit_OpenCnt == 0 )
          {
            CleanUp();
            ReplyMsg((struct Message*)io);
            return;
          }
          break;
        case SCANCMD_READOPTION:
          LoadOption(io);
          break;
        case SCANCMD_CONTROL:
          Set(io);
          break;
        case CMD_STOP:
          Stop(io);
          break;
        case CMD_START:
          Start(io);
          break;
        case CMD_READ:
          Read(io);
          break;
        default:
          io->io_Error = IOERR_NOCMD;
          break;
      }
      ReplyMsg((struct Message*)io);
    }
  }
}
///////////////////////////////////////////
//
// Utility procedures
//
///////////////////////////////////////////

static void Start(struct InstrumentIO *io)
{
  startScanning((struct ScanInformation*)io->io_Data,&io->io_Error);
}

static void Stop(struct InstrumentIO *io)
{
  stopScanning();
  io->io_Error = 0;
}

static void Set(struct InstrumentIO *io)
{
  controlOption((struct OptionValue*)io->io_Data,&io->io_Error);
}

static void LoadOption(struct InstrumentIO *io)
{
  readOption(&((struct ScannerIO*)io)->option,&io->io_Error);
}

static void Read(struct InstrumentIO *io)
{
  io->io_Actual = io->io_Length;
  readScanLine((struct ScanLine*)io->io_Data,&io->io_Error);
}


BOOL QuickIO(struct InstrumentIO *io)
{
  switch( io->io_Command ) 
  {
    case FCMD_OPEN:
    case FCMD_CLOSE:
    case SCANCMD_CONTROL:
    case SCANCMD_READOPTION:
    case CMD_STOP:
    case CMD_START:
    case CMD_READ:
      io->io_Flags &= ~IOF_QUICK;
      return FALSE;
      break;
    default:
      io->io_Error = IOERR_NOCMD;
      return TRUE;
      break;
  }
}
