/*-- vtmain.c -----------------------------------------------------------
|
| A simple program that receives messages from DeluxeVideo III through
| an ARexx message port.
|
| It simulates a VCR controller by receiving messages for tape movement
| such as REWIND, FORWARD, INDEX, RECORD, STOP, PLAY, and PAUSE
|
| This program doesn't really control a VCR; but if your VCR has a
| computer interface, use this program as a template for writing
| your own controller.
|
| DeluxeVideo packs the following data into each message:
|
| Arg[]  data
|
|   0    Command text from the message effect
|   1    video_time = time relative to the script (in jiffies)
|   2    scene_time = time relative to the scene (in jiffies)
|   3    effect_time = time relative to the start of effect (in jiffies)
|   4    effect_dur = duration of the message effect (in jiffies)
|   5    Effect code = a string.
|
| If an effect has a non-zero duration, messages are sent once per time
| step during the effect.  From the effect_time and effect_dur, you can
| compute a percentage of full effect like this:
|
|    per_cent = (effect_time * 100L) / effect_dur
|
| Here's how to decode the effect code. Just look for the following three
| characters in the effect code:
|
|  Char  Meaning
|   S    Start
|   C    Continue
|   F    Finish
|
| Start means the effect has just started and this is the first message
| from it.  You should do whatever you need to initialize this action.
|
| Continue means the effect is continuing and this message is neither the
| first nor the last.
|
| Finish means this is the last mesage you will receive related to the
| effect, so do whatever you need to finalize this action.
|
| Date      Who Changes
| --------- --- ---------------------------------------------------------
| 07-Oct-88 mrp Created from fancydemo.c
+--------------------------------------------------------------------------*/
#include <exec/types.h>
#include <exec/ports.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

#include "storage.h"
#include "rxslib.h"

/*---------------------- Rexx related declarations ----------------------*/
#define PORTNAME "VTRPort"
struct RexxLib *RexxSysBase;
struct MsgPort *rexxPort;

/*--------------------- Window related declarations --------------------*/
#define WINDOW_SPEC "CON:0/12/320/80/VTR Controller/c"
BPTR hWin;
struct MsgPort *dosPort;
struct StandardPacket *dosMsg;
#define BUFFLEN 100
char buff[BUFFLEN + 1];

/*--------------------- Output related declarations --------------------*/
#define START_MSG  "Ready for messages, type ^\\ to end.\n"
#define FINISH_MSG "All done.\n"
#define BAD_CMD "Unknown command"

/*------------------------- Simulated commands -------------------------*/
#define NUMCMDS 8
char *command[NUMCMDS] = {"REWIND", "FORWARD", "INDEX", "RECORD", "STOP",
                          "PLAY", "PAUSE", "STEP"};
char *cmd_err = "VTRTest unknown command";
char *index_err = "VTRTest INDEX failure";

/*-----------------------------------------------------------------------
| DoCommand()
| 
| 
+-----------------------------------------------------------------------*/
char *DoCommand(msg, cmd)
struct RexxMsg *msg;
char *cmd;
   {
   char *err = NULL;
   int i, j;
   char *s;
   long time, stime, etime, edur, percent;
   BOOL start, contin, finish;

   /* Convert to upper case and echo to the window */
   strupr(cmd);
   i = 0;
   while ((i < NUMCMDS) && (strcmp(cmd, command[i]) != 0)) i++;
   if (i < NUMCMDS) Write(hWin, command[i], strlen(command[i]));
   if (msg)
      {
      for(j = 1; j < 16; j++)
         {
         if (s = (char *)msg->rm_Args[j])
            {
            if (j == 1) stcd_i(s, &time);
            if (j == 2) stcd_i(s, &stime);
            if (j == 3) stcd_i(s, &etime);
            if (j == 4) stcd_i(s, &edur);
            if (j == 5)
               {
               strupr(s);
               start = (BOOL)(stpchr(s, 'S'));
               contin = (BOOL)(stpchr(s, 'C'));
               finish = (BOOL)(stpchr(s, 'F'));
               }
            Write(hWin, " ", 1);
            Write(hWin, s, strlen(s));
            }
         }
      }
   else
      {
      time = stime = etime = edur = 0;
      start = finish = TRUE;
      contin = FALSE;
      }
   Write(hWin, "\n", 1L);

   /* Compute percentage */
   if (start && !finish) percent = 0;
   else if (finish) percent = 100;
   else if (edur) percent = (etime * 100L) / edur;
   else percent = 100;

   switch(i)
      {
      /* The user should always send these messages and wait because
         they all take time to perform.  In this example, the actions
         are simulated by a short delay. */
      case 0: /* Rewind to beginning of tape */
         Delay(150);
         break;
      case 1: /* Forward move tape forward at normal speed */
         Delay(25);
         break;
      case 2: /* Index skip forward to next index mark */
         /* Simulate an error by returning an error code */
         err = index_err;
         break;
      case 3: /* Record begin recording */
         Delay(25);
         break;
      case 4: /* Stop recording and stop tape movement */
         Delay(25);
         break;
      case 5: /* Play */
         Delay(25);
         break;
      case 6: /* Pause */
         Delay(25);
         break;
      case 7: /* Step forward one frame and pause */
         Delay(10);  
         break;
      default:
         err = cmd_err;
         break;
      }
   return(err);
   }

/*-----------------------------------------------------------------------
| SendReadPacket()
| Send a packet to read from the console window
+-----------------------------------------------------------------------*/
void SendReadPacket()
   {
   struct FileHandle *hFile;
   hFile = (struct FileHandle*)(hWin << 2);
   dosMsg->sp_Pkt.dp_Arg1 = hFile->fh_Arg1;
   dosMsg->sp_Pkt.dp_Arg2 = (long)buff;
   dosMsg->sp_Pkt.dp_Arg3 = BUFFLEN;
   dosMsg->sp_Pkt.dp_Type = ACTION_READ;
   dosMsg->sp_Pkt.dp_Port = dosPort;
   PutMsg(hFile->fh_Type, dosMsg);
   }

/*-----------------------------------------------------------------------
| HandleMessages()
| 
| 
+-----------------------------------------------------------------------*/
void HandleMessages()
   {
   char *err;
   BOOL done = FALSE;
   BOOL waiting = FALSE;
   struct RexxMsg *rexxMsg;
   Write(hWin, START_MSG, (long)sizeof(START_MSG));
   while (!done)
      {
      if (!waiting)
         {
         SendReadPacket();
         waiting = TRUE;
         }
      Wait((1 << dosPort->mp_SigBit) | (1 << rexxPort->mp_SigBit));
      if (GetMsg(dosPort))
         {
         waiting = FALSE;
         if (dosMsg->sp_Pkt.dp_Res1 == 0)
            {
            done = TRUE;
            Write(hWin, FINISH_MSG, (long)sizeof(FINISH_MSG));
            Delay(200);
            }
         else
            {
            buff[dosMsg->sp_Pkt.dp_Res1 - 1] = 0;
            if (err = DoCommand(NULL, buff))
               Write(hWin, err, (long)strlen(err));
            }
         }
      while (rexxMsg = (struct RexxMsg *) GetMsg(rexxPort))
         {
         if (err = DoCommand(rexxMsg, rexxMsg->rm_Args[0]))
            {
            /* Return an error */
            rexxMsg->rm_Result1 = 5L;
            rexxMsg->rm_Result2 = 0L;
            }
         else
            {
            /* No error */
            rexxMsg->rm_Result1 = 0L;
            rexxMsg->rm_Result2 = 0L;
            }
         ReplyMsg(rexxMsg);
         }
      }
   }

/*-----------------------------------------------------------------------
| main()
| The main program
+-----------------------------------------------------------------------*/
main(argc,argv)
int argc;
char **argv;
   {
   if (RexxSysBase = (struct RexxLib *)OpenLibrary(RXSNAME, 0L))
      {
      if (hWin = (BPTR)Open(WINDOW_SPEC, MODE_NEWFILE))
         {
         if (dosPort = (struct MsgPort*)CreatePort(NULL, 0L))
            {
            if (dosMsg = (struct StandardPacket *)
               AllocMem(sizeof(struct StandardPacket), 0L))
               {
               dosMsg->sp_Msg.mn_Node.ln_Name = (char *)&(dosMsg->sp_Pkt);
               dosMsg->sp_Pkt.dp_Link = &(dosMsg->sp_Msg);
               if (!FindPort(PORTNAME) &&
                  (rexxPort = (struct MsgPort *)CreatePort(PORTNAME, 0L)) )
                  {
                  HandleMessages();
                  DeletePort(rexxPort);
                  }
               FreeMem(dosMsg, sizeof(struct StandardPacket));
               }
            DeletePort(dosPort);
            }
         Close(hWin);
         }
      CloseLibrary(RexxSysBase);
      }
   else printf("Can't load REXX library\n");
   return(0L);
   }

