/* Incredibly Basic Terminal Program (C) 1995 Hydra/Tension

   DumpCON Part of the development for HBBS!

   read input from serial port and/or console window and dumps input as decimal
   numbers..

*/


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

#include <exec/exec.h>
#include <intuition/intuition.h>
#include <devices/console.h>
#include <devices/serial.h>
#include <dos/dos.h>
#include <libraries/reqtools.h>

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/intuition_protos.h>
#include <clib/console_protos.h>
#include <clib/dos_protos.h>
#include <clib/reqtools_protos.h>

#define ClrSignal(s)  SetSignal(0,s)

extern struct GfxBase *GfxBase;
extern struct IntuitionBase *IntuitionBase;
struct ReqToolsBase *ReqToolsBase;
struct Window *Win=NULL;
struct Screen *Scr=NULL;

struct IOStdReq *ConRead;
struct IOStdReq *ConWrite;
struct MsgPort *ConRPort;
struct MsgPort *ConWPort;

struct IOExtSer *SerRead;
struct IOExtSer *SerWrite;
struct MsgPort *SerPort;
//struct MsgPort *SerReadPort;

long __stack = 40000;

  char ConBuffer[2048];
  char SerBuffer[2048];
  char SerialInChar;
  ULONG SerBufLen;

BOOL SerFlag=FALSE;
BOOL ConFlag=FALSE;

void CloseLibs( void )
{
if (NULL != GfxBase )
  CloseLibrary( ( struct Library * )GfxBase );
if (NULL != IntuitionBase )
  CloseLibrary( ( struct Library * )IntuitionBase );
  if (ReqToolsBase)
    CloseLibrary ((struct Library *)ReqToolsBase);
  exit (0);
}

int OpenLibs( void )
{
  if (ReqToolsBase = (struct ReqToolsBase *) OpenLibrary (REQTOOLSNAME, REQTOOLSVERSION))
    if ( NULL != (GfxBase = (struct GfxBase * )OpenLibrary((UBYTE *)"graphics.library" , 37)))
      if ( NULL != (IntuitionBase = (struct IntuitionBase * )OpenLibrary((UBYTE *)"intuition.library" , 37)))
    return( 0L );
  CloseLibs();
return( 1L );
}

BYTE OpenConsole(struct IOStdReq *writereq, struct IOStdReq *readreq, struct Window *window)
{
  BYTE error;

  // point to window..

  writereq->io_Data = (APTR) window;
  writereq->io_Length = sizeof(struct Window);

  // open device..

  error = OpenDevice("console.device", 0, (struct IORequest*)writereq, 0);

  // duplicate data..

  readreq->io_Device = writereq->io_Device; /* clone required parts */
  readreq->io_Unit   = writereq->io_Unit;

  return(error);
}

void cancelcon( void )
{
  if (ConFlag)
  {
    AbortIO((struct IORequest *)ConRead);
    WaitIO((struct IORequest *)ConRead);
    ConFlag=FALSE;
  }
}

void readcon( void )
{
  if (!ConFlag)
  {
    ConRead->io_Command  = CMD_READ;
    ConRead->io_Data     = (APTR)ConBuffer;
    ConRead->io_Length   = 1;
    ClrSignal(1L << ConRPort->mp_SigBit);
    SendIO((struct IORequest*)ConRead);
    ConFlag=TRUE;
  }
}

void ConWriteData(UBYTE *data,ULONG length)
{
  cancelcon();
  ConWrite->io_Command  = CMD_WRITE;
  ConWrite->io_Data     = data;
  ConWrite->io_Length   = length;

  DoIO((struct IORequest *)ConWrite);
  readcon();
}

void cancelser( void )
{
  if (SerFlag)
  {
    AbortIO((struct IORequest *)SerRead);
    WaitIO((struct IORequest *)SerRead);
    SerFlag=FALSE;
  }
}

void readser( void )
{

  if (!SerFlag)
  {
    SerRead->IOSer.io_Command  = CMD_READ;
    SerRead->IOSer.io_Data     = &SerialInChar;
    SerRead->IOSer.io_Length   = 1;
    ClrSignal(1L << SerPort->mp_SigBit);
    SendIO((struct IORequest*)SerRead);
    SerFlag=TRUE;
  }
}

void SerWriteData(UBYTE *data,ULONG length)
{
  cancelser();
  SerWrite->IOSer.io_Command  = CMD_WRITE;
  SerWrite->IOSer.io_Data     = data;
  SerWrite->IOSer.io_Length   = length;

  DoIO((struct IORequest *)SerWrite);
}

void DumpData(UBYTE *data,ULONG length)
{
  int loop;
  for (loop=0; loop < length ; loop++ )
  {
    printf("%d ",data[loop]);
  }
  fflush(stdout);
}

void HandleIt( void )
{
  struct IntuiMessage *IMsg;
  BOOL done=FALSE;
  ULONG SerSigs,ConSigs,WinSigs,ReturnedSigs;


  while (!done)
  {
    if (!SerFlag) readser();
    if (!ConFlag) readcon();

    ConSigs=ConFlag ? 1L << ConRPort->mp_SigBit : 0;
    SerSigs=SerFlag ? 1L << SerPort->mp_SigBit : 0;
    WinSigs=1L << Win->UserPort->mp_SigBit;

    // the sigbreak bit can ONLY be activated if another program sends a break
    // to this program, something like artm or taske might be usefull! :-)
    // you can't type ctrl-c cos the console.device gets there first!


    // put the task to sleep until we get some input!

    ReturnedSigs=Wait(SerSigs | ConSigs | WinSigs | SIGBREAKF_CTRL_C);

    // check to see what input happened

    if (ReturnedSigs & SIGBREAKF_CTRL_C) done=TRUE;

    // something happened to the window..
    if (ReturnedSigs & WinSigs)
    {
      while (IMsg=(struct IntuiMessage *)GetMsg(Win->UserPort))
      {
        switch (IMsg->Class)
        {
          case IDCMP_CLOSEWINDOW:
            done=rtEZRequest("Quit ?","Yes|No",NULL,NULL,NULL);
            break;
        }
        ReplyMsg((struct Message*)IMsg);
      }
    }
    // if we have submitted a sendIO() to the console device check
    // to see if a) the signal was from the console or b) check to see if the request
    // has been completed,  this is usefull if you get a serial signal AND the
    // computer was just about to send us a console signal..
    if (ConFlag && ((ReturnedSigs & ConSigs) || CheckIO((struct IORequest *)ConRead)))
    {
      WaitIO((struct IORequest *)ConRead);
      ConFlag=FALSE;
      if (ConRead->io_Actual)
      {
//        ConWriteData(ConBuffer,ConRead->io_Actual);
        DumpData(ConBuffer,ConRead->io_Actual);
        SerWriteData(ConBuffer,ConRead->io_Actual);
      }
    }

    // same as above except for serial instead of console..

    if (SerFlag && ((ReturnedSigs & SerSigs) || CheckIO((struct IORequest *)SerRead)))
    {
      // get the one byte of data we requested..
      WaitIO((struct IORequest *)SerRead);
      SerFlag=FALSE;
      SerBuffer[0]=SerialInChar;
      ConWriteData(SerBuffer,1); // and write it to the console..
//      DumpData(SerBuffer,1);
      // then see if there's any more data to be read
      // if there is write it to the console until there's no more left..
      // nomally you might not want to do it like this as there is no way
      // for the user to abort it!

      SerRead->IOSer.io_Command  = SDCMD_QUERY;
      SerRead->IOSer.io_Actual = 0;
      DoIO((struct IORequest*)SerRead);
      do
      {
        // any data ?
        if (SerRead->IOSer.io_Actual)
        {
          // yup! read it then!
          SerRead->IOSer.io_Command  = CMD_READ;
          SerRead->IOSer.io_Data     = &SerBuffer[0]; // be explicit, the [0] is not REALLY needed tho..
                                       // don't forget not to overflow our buffer!
          SerRead->IOSer.io_Length   = SerRead->IOSer.io_Actual>2048 ? 2048 : SerRead->IOSer.io_Actual ;
          DoIO((struct IORequest*)SerRead);

          SerBufLen=SerRead->IOSer.io_Actual;
          ConWriteData(SerBuffer,SerBufLen);
//          DumpData(SerBuffer,SerBufLen);
        }
        // send another query!
        SerRead->IOSer.io_Command  = SDCMD_QUERY;
        SerRead->IOSer.io_Actual = 0;
        DoIO((struct IORequest*)SerRead);
      }
      while (SerRead->IOSer.io_Actual); // keep checking until no data exists..
    }
  }
  // quit!
  if (SerFlag) cancelser();
  if (ConFlag) cancelcon();
}


void main(int argc, char *argv[])
{
  if (argc!=3)
  {
    puts("Usage: CONSOLE <device> <unit>");

  }
  else
  {
    OpenLibs();

    if (Scr=LockPubScreen(NULL))
    {

      if (Win=OpenWindowTags(NULL,
                             WA_Width, 640,
                             WA_Height, 256,
                             WA_MaxWidth,65530,
                             WA_MaxHeight,65530,
                             WA_MinWidth,100,
                             WA_MinHeight,100,
                             WA_Title,"ASync Console.device and Serial.device By Hydra/TSN/LSD",
                             WA_Flags,WFLG_CLOSEGADGET|WFLG_DRAGBAR|WFLG_SIZEGADGET|WFLG_SIZEBRIGHT|WFLG_DEPTHGADGET,
                             WA_IDCMP,IDCMP_CLOSEWINDOW,
                             (TAG_DONE)))
      {

        if (ConRPort=CreatePort(0,0))
        {
          if (ConWPort=CreatePort(0,0))
          {
            if(ConWrite = (struct IOStdReq *) CreateExtIO(ConWPort,(LONG)sizeof(struct IOStdReq)))
            {
              if(ConRead = (struct IOStdReq *) CreateExtIO(ConRPort,(LONG)sizeof(struct IOStdReq)))
              {
                if(!(OpenConsole(ConWrite,ConRead,Win)))
                {
                  if (SerPort=CreatePort(0,0) )
                  {
                    if (SerWrite=(struct IOExtSer *) CreateExtIO(SerPort,(ULONG)sizeof(struct IOExtSer)) )
                    {
                      SerWrite->io_SerFlags       = SERF_RAD_BOOGIE|SERF_XDISABLED|SERF_7WIRE;
                      if (!(OpenDevice(argv[1],atoi(argv[2]),(struct IORequest *)SerWrite,0) ))
                      {
                        SerWrite->IOSer.io_Command  = SDCMD_SETPARAMS;
                        SerWrite->io_SerFlags       |= SERF_XDISABLED;
                        SerWrite->io_Baud           = 19200;
                        DoIO((struct IORequest *)SerWrite);

                        if (SerRead=(struct IOExtSer *) AllocMem(sizeof(struct IOExtSer),MEMF_PUBLIC) )
                        {
                          memcpy(SerRead,SerWrite,sizeof(struct IOExtSer));
                          HandleIt();
                          FreeMem(SerRead,sizeof(struct IOExtSer));
                        }
                        CloseDevice((struct IORequest *)SerWrite);
                      } else puts("Can't open device!");
                      DeleteExtIO((struct IORequest*)SerWrite);
                    }
                    DeletePort(SerPort);
                  }
                  CloseDevice((struct IORequest*)ConWrite);
                } else puts("cant open console device!");
                DeleteExtIO((struct IORequest*)ConRead);
              }
              DeleteExtIO((struct IORequest*)ConWrite);
            }
            DeletePort(ConWPort);
          }
          DeletePort(ConRPort);
        }

        CloseWindow(Win);
      }


      UnlockPubScreen(NULL,Scr);
    }
    CloseLibs();
  }
}