/* Laser Disk Player program *\ ** Copyright Ron M. Battle 1991 ** ** HyperBorea Studio B ** ** Manx Aztec C v5.2a ** ** May be freely distributed for non-commercial use ** ** *Revision History* ** **---------------------------------------------------** ** DATE VERSION COMMENTS ** **---------------------------------------------------** ** 02-22-92 1.31 Add SerialUnit ** ** 02-15-92 1.3 Can run from WorkBench, ** ** help key supported, ** ** better error reporting, ** ** ToolType defaults, ** ** Thanx to Larry Shultz and ** ** Brian Berg for LDP.info icons ** ** 10-13-91 1.21 Dressed up remote with examples** ** from Brian Berg ** ** 04-21-91 1.2 Generic Player revisions for ** ** Hitachi, Pioneer, Sony ** ** 09-29-90 1.1 Added ARexx interface ** ** Thanx to GS & BH for FancyDemo** ** 02-25-90 1.0 Sony players only ** **---------------------------------------------------** ** The onscreen controller only uses a subset of ** ** commands. This synchronous implementation is ** ** not slick, could have better error checking, ** ** but it WORKS!! ** ** It would be nice to have more control over the ** ** serial device's buffer. As it stands, the min ** ** size is 512 bytes! This makes it more ** ** difficult to keep track of lid openings,etc. ** ** Since I'm synchronous, I don't check! ** ** You could get around this by doing a continual ** ** serial read with parameters for terminator char ** ** and number of chars expected on the read. You ** ** would need to modify the main event loop to also ** ** wait for a message from mySerPort, but would be ** ** better to set up a new message port for serial ** ** reads! Use SendIO() for asynchronous reads, ** ** when read done GetMsg(), get any errors from this** ** msg then SendIO() another read, etc.! ** ** ** ** REMOTE CONTROLLER COMMANDS: ** ** ** ** CL Clear commands ** ** Index Toggle index display ON/OFF ** ** <<< >>> Scan ** ** << >> Fast ** ** <| |> Slow ** ** | < > | Step ** ** < > Play ** ** Search Search Hitachi&Sony: Srch Frame# Enter ** ** Pioneer: Frame# Srch ** ** Enter Enter For Hitachi&Sony players only ** ** Log Log saves note and frame# in ** ** ram:LDP.log ** ** M+ Memorize current frame number ** ** MR Search for memorized frame number ** ** Still Still frame ** ** Eject Eject disc ** ** ** ** You can also enter numbers into the display and ** ** press return for a search. ** ** If you don't do the commands in the proper ** ** sequence, you might hang the controller. If you ** ** don't like that.......CHANGE IT! ** ** This controller also takes exclusive control ** ** of the serial.device. Shared access never worked ** ** properly! ** ** ** \* */ #include #include #include #include #include #include #include #include #include #include #include #include "tinystring.h" /* The C routine index() causes contention */ #include "gadgets.h" #include "video.h" /* this header would not pre-compile properly */ /* #define DEBUG 1 */ #define HELP 95 /* raw keycode for Help button */ /* defaults for serial device */ #define READ_BITS 8 #define WRITE_BITS 8 #define STOP_BITS 1 #define MIN_BAUD 1200 #define MAX_BAUD 9600 #define MIN_UNIT 0 #define MAX_UNIT 31 /* errors */ #define NO_ERR 0 #define READ_EXTIO_ERR 1 #define DEVICE_ERR 2 #define WRITEPORT_ERR 3 #define WRITE_EXTIO_ERR 4 #define INT_ERR 5 /* error opening intuition library */ #define WIN_ERR 6 /* error opening window */ #define REXX_ERR 7 /* error creating rexx port */ #define ILIB_ERR 8 /* error opening icon library */ char *ErrStr[] = { "NONE!", "Allocating read i/o block! ", "Opening serial device! ", "Creating write port! ", "Allocating write i/o block! ", "Opening Intuition library!", "Opening window!", "Creating rexx port!", "Opening icon library!" }; #define MAXIN 6 /* size of in-buffers */ #define MAXOUT 22 /* size of out-buffer */ #define LDP_1000A 2 /* for SonyModel */ #define OTHER 1 /* means 180,1200,1500, or 2000 models */ #define ASLEEP 0 /* ldp not ready */ #define MAX_FRAME 54000 /* highest frame # */ #define MAX_FRAME_STR "54000" /* " " string */ #define D7 128 /* bit 7, used for masking */ #define D6 64 #define D5 32 #define D4 16 #define D3 8 #define D2 4 #define D1 2 #define D0 1 #define NOT_READY (D5 | D3 | D2) /* if any bits set: NOT READY */ #define REVERSE 0 #define FORWARD 1 #define ADD 1 #define NEW 0 #define DTEXT 0 #define DNUM 1 /* ARexx stuff */ #define HOST_PORT_NAME "LDP" struct MsgPort *rexx_port = NULL ; ULONG RexxSigMask ; /* signal mask used for WAIT() */ IMPORT struct Gadget EjectGad ; /* first gadget in list */ IMPORT struct Gadget NumDisplayGad, TextDisplayGad ; IMPORT struct Gadget EnterGad ; /* will be disabled if pioneer player! */ IMPORT UBYTE NumBuff[NUMLEN], TextBuff[TEXTLEN] ; struct MsgPort *mySerPort = NULL ; struct IOExtSer *mySerReq = NULL ; char ScratchBuff[MAXOUT] ; char inbuff[MAXIN], outbuff[MAXOUT], StatusBuffer[MAXIN] ; char *version = "$VER: LDP by HyperBorea Studio B V1.31__22.02.92(" ; char *CmdTerm = NULL ; /* command terminator */ char *PlayerMode = NULL ; /* frame mode only for now */ char MemAddr[MAXIN] ; /* address for remote memorize */ char CurrentAddr[MAXIN] ; /* current address of player */ char *GadStr[] = { "","","","","","","","","","", "Eject","Enter","Search","Still","Clear","Index","Rplay","Fplay", "Rstep","Fstep","Rslow","Fslow", "Rfast","Ffast","Rscan","Fscan", "Memorize","Msearch","Log to ram:*","",""} ; struct Window *wp=NULL ; struct IntuitionBase *IntuitionBase=NULL ; struct IconBase *IconBase=NULL ; ULONG wakeupmask, UserSigMask ; BOOL FscanDOWN = FALSE ; BOOL RscanDOWN = FALSE ; BOOL SearchPRESSED = FALSE ; BOOL SerDeviceACTIVE = FALSE ; BOOL LdpREADY = TRUE ; BOOL IndexON = TRUE ; BOOL ReversePolish = FALSE ; /* Pioneer players do arg,verb */ BOOL RemoteON = TRUE ; /* onscreen remote controller */ BOOL TimeToExit = FALSE ; /* used to exit ProcessEvents() */ USHORT CurrentCmd = 0 ; /* Current Command */ USHORT SonyModel = OTHER; /* default */ USHORT BaudRate = 1200 ; /* Fixed baud rate for SONY LDP-1000A */ USHORT PlayerType = sony ; /* default player */ USHORT ReturnBytes ; /* number of bytes returned from command */ USHORT AddrBytes ; /* number of bytes returned address query */ USHORT StatBytes ; /* number of bytes returned status query */ USHORT SerialUnit ; /* serial port unit number */ char HelpStr[] = {"\n\ Laser Disc Player by Ron M. Battle HyperBorea Studio B\n\ ------------------------------------------------------------------------------\n\ CLI USAGE: run ldp -bBaud -pPlayerType -rRemoteOn/Off -uSerialUnit#\n\ example: run ldp -b1200 -pSony -rOn -u0 (DEFAULT)\n\ WB USAGE: ToolTypes: BAUD PLAYER REMOTE WINDOW UNIT\n\ example: BAUD=4800 PLAYER=PIONEER REMOTE=ON WINDOW=CON:20/20/320/70/LDP!\n\ Public Port: LDP (case sensitive)\n\ Note: On remote, click in text area, enter note and press LOG,\n\ current frame# and note will be saved to ram:LDP.log\n\ Help: Press Help key on keyboard!\n\ ARexx cmds:\n\ address (returns frame# as 32 bit integer) baud rate (set baud rate)\n\ clear (clear all commands) eject (open door) enter (terminate some commands)\n\ forward howfast (step/slow/fast/scan/normal) frame (set frame mode)\n\ index toggle (on/off) init (initialize player) play start end (play sequence)\n\ quit (shut down program) ready (returns 1 if player ready)\n\ reverse howfast (step/slow/fast/scan/normal) search frame# (ASCII digits)\n\ still (still frame)\n\ vplayer type (set player type: sony/hitachi/pioneer/none, returns 32 bit int)\n\n\ \n CLI ARexx example: rx 'address LDP play 5000 5100'\n\ ------------------------------------------------------------------------------\n\n"}; struct NewWindow LdpWindow= { 10,10, /* window XY origin relative to TopLeft of screen */ 200,162, /* window width and height */ 0,3, /* detail and block pens */ GADGETDOWN+GADGETUP+CLOSEWINDOW+RAWKEY, /* IDCMP flags */ WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH+WINDOWSIZING, &EjectGad, /* first gadget in gadget list */ NULL, /* custom CHECKMARK imagery */ (UBYTE *)"Sony LDP", /* window title */ NULL, /* custom screen pointer */ NULL, /* custom bitmap */ 144,12, /* minimum width and height */ 0,0, /* maximum width and height */ WBENCHSCREEN /* destination screen type */ }; void UpdateDisplay(char *dstring, int how, int which) { long gadpos ; struct Gadget *gadptr ; struct StringInfo *strgad ; char *buffptr ; if (which == DTEXT) { gadptr = &TextDisplayGad ; buffptr = (char *)TextBuff; } else { gadptr = &NumDisplayGad ; buffptr = (char *)NumBuff; }; strgad=(struct StringInfo *)NumDisplayGad.SpecialInfo ; gadpos = RemoveGadget(wp,gadptr) ; /* don't change before removing! */ if (how == ADD) { /* add to existing string */ if ((SHORT)strgad->NumChars < (NUMLEN-1)) { strcat((char *)buffptr,dstring) ; } else strcpy((char *)buffptr,dstring) ; /* start over if too many! */ } else { strcpy((char *)buffptr,dstring) ; /* new string */ }; AddGadget(wp,gadptr,gadpos) ; RefreshGList(gadptr,wp,NULL,gadpos) ; } void SetBaud(USHORT rate) /* set baud rate and 8N1 */ { LONG error ; if (rate>MAX_BAUD || rateio_Baud = rate ; mySerReq->io_ReadLen = READ_BITS ; mySerReq->io_WriteLen = WRITE_BITS ; mySerReq->io_StopBits = STOP_BITS ; mySerReq->IOSer.io_Command = SDCMD_SETPARAMS ; if ((error = DoIO((struct IORequest *)mySerReq)) != 0L) { printf("SetBaud error = %ld\n",error) ; }; } LONG ReadSer(char *data, USHORT length) { LONG error = 0L ; USHORT i ; for (i=0; iIOSer.io_Data = (APTR)data ; mySerReq->IOSer.io_Length = (ULONG)length ; mySerReq->IOSer.io_Command = CMD_READ ; if ((error = DoIO((struct IORequest *)mySerReq)) != 0L) { printf("ReadSer err# %ld\n",error) ; }; #ifdef DEBUG printf(" ReadHex= %X %X %X %X %X \n", inbuff[0],inbuff[1],inbuff[2],inbuff[3],inbuff[4]) ; #endif return (error) ; } LONG WriteSer(char c) { LONG error ; outbuff[0] = c ; outbuff[1] = '\0'; /* null terminate just in case! */ #ifdef DEBUG printf(" SendChar= %s\n",outbuff) ; #endif mySerReq->IOSer.io_Data = (APTR)outbuff ; /* change to once only!! */ mySerReq->IOSer.io_Length = 1L ; mySerReq->IOSer.io_Command = CMD_WRITE ; if ((error = DoIO((struct IORequest *)mySerReq)) != 0L) { printf("WriteSer err# %ld\n",error); }; return (error) ; } LONG SendString(char *buff) { LONG err,len ; len = (long)strlen(buff) ; #ifdef DEBUG printf(" SendStr=%s\n",buff) ; #endif mySerReq->IOSer.io_Data = (APTR)buff ; mySerReq->IOSer.io_Length = len ; mySerReq->IOSer.io_Command = CMD_WRITE ; if ((err = DoIO((struct IORequest *)mySerReq)) != 0L) { printf("Write to serial port err# %ld\n",err); }; return (err) ; } USHORT Ask_Sony_Model(UBYTE byt) /* returns LDP_1000A or OTHER or SLEEPING */ { LONG err, count ; USHORT model, status = FALSE ; model = (byt & D7) ; if (model == 0) model = LDP_1000A ; status = !(byt & NOT_READY) ; if (status == FALSE) model = ASLEEP ; return(model) ; } void MyCleanup(USHORT err) { if (err) printf("LDP stopped because: ERROR %s\n",ErrStr[err]) ; if ( (CheckIO(mySerReq)==FALSE)&&(err != WRITEPORT_ERR) ) { AbortIO((struct IORequest *)mySerReq) ; /* abort any pending requests */ WaitIO((struct IORequest *)mySerReq) ; }; if (SerDeviceACTIVE) CloseDevice((struct IORequest *)mySerReq) ; if (wp != NULL) CloseWindow(wp) ; if (IntuitionBase != NULL) CloseLibrary(IntuitionBase) ; if (mySerReq != NULL) DeleteExtIO((struct IORequest *)mySerReq); if (mySerPort != NULL) DeletePort(mySerPort) ; if (rexx_port != NULL) DeletePort(rexx_port) ; puts(" Please turn OFF the player when DONE!"); } /* ARexx routines */ void SetupRexxPort(void) { struct MsgPort *the_port=NULL ; Forbid() ; if (FindPort(HOST_PORT_NAME)) { Permit() ; printf("A public port called '%s' already exists!\n",HOST_PORT_NAME) ; the_port=NULL ; } the_port = CreatePort(HOST_PORT_NAME,0L) ; Permit() ; if (the_port != NULL) { RexxSigMask = (1L<mp_SigBit) ; /* setup signal bit */ rexx_port = the_port ; } else { MyCleanup(REXX_ERR) ; exit(FALSE) ; } } void ReplyRexxMessage(struct RexxMsg *rexxmessage, long result) { rexxmessage->rm_Result1 = result ; rexxmessage->rm_Result2 = 0L ; ReplyMsg((struct Message *)rexxmessage) ; } void DoSimpleCmd(char *cmd) { strcpy(outbuff,cmd) ; /* now build output buffer */ strcat(outbuff,CmdTerm) ; SendString(outbuff) ; /* send string to serial port */ ReadSer(inbuff,ReturnBytes); /* see what player returns */ } void ClearSerialBuffer(void) { ULONG error ; mySerReq->IOSer.io_Command = CMD_CLEAR; /* clear out device buffer */ if ((error = DoIO((struct IORequest *)mySerReq)) != 0L) { printf("Clear serial buffer error# %ld\n",error); } } long GetAddress(char *cmd) /* return player address as long int */ { USHORT x,*intp ; int y ; long addr=0 ; ClearSerialBuffer() ; /* now build output buffer */ strcpy(outbuff,cmd) ; /* command */ strcat(outbuff,CmdTerm) ; /* command terminator, if any */ SendString(outbuff) ; /* send string to serial port */ ReadSer(inbuff,AddrBytes) ; /* see what player returns */ if(PlayerType == hitachi) { intp = (USHORT *)(inbuff+1) ; /* skip past echo, hi-lo bytes follow */ addr = (long)*intp ; /* convert to long int */ y = sprintf(CurrentAddr,"%ld\0",addr); /* save addr as string */ } else { inbuff[5] = '\0' ; /* null terminate string */ strcpy(CurrentAddr,inbuff); /* save current address */ addr = atol(inbuff) ; /* convert string to signed long integer */ }; return(addr) ; } void SetIndex(char *toggle) { int offset = on ; /* default */ char *cmd ; if (toggle != NULL) { if(strncmp(toggle,indexstr[off],2L)==0) offset = off ; }; /* now set a pointer to the correct index cmd */ cmd = Player[PlayerType].index[offset] ; /* now build output buffer */ strcpy(outbuff,cmd) ; strcat(outbuff,CmdTerm) ; /* add any cmd terminator */ SendString(outbuff) ; /* send string to serial port */ ReadSer(inbuff,ReturnBytes); /* see what player returns */ } void Step1KA(int direction) /* Sony 1000A won't do single command stepping */ { /* Actually the 2000 wouldn't either so all */ /* sonys now use this routine! */ /* has problems when stepping near frame 1-2 */ if (direction==FORWARD) { /* forward step */ WriteSer('='); /* send F-STEP */ ReadSer(inbuff,1) ; /* expect ACK */ WriteSer('O'); /* send STILL */ } else { /* reverse step */ WriteSer('M'); /* send R-STEP */ ReadSer(inbuff,1); WriteSer('O'); /* send STILL command, last ReadSer from Go() */ } } void Go(int direction, char *speed) /* tried to be generic except for Step-1KA */ { int i=0,HowFast=0 ; USHORT type=PlayerType,TotSpeeds=NUMSPEEDS-1 ; /* now change string into an index */ while ((i < TotSpeeds) && (strncmp(speed,speedstr[i],3L) !=0)) i++ ; HowFast = i ; /* if no match, defaults to normal */ if (direction==FORWARD) strcpy(outbuff,Player[type].forward[HowFast]); else strcpy(outbuff,Player[type].reverse[HowFast]); strcat(outbuff,CmdTerm) ; /* add any terminator */ if ((type==sony)&&(HowFast==step)) Step1KA(direction); else SendString(outbuff) ; ReadSer(inbuff,ReturnBytes) ; } void GoSearch(char *addr) { char *cmd,*temp,*fmode,*entercmd ; long num ; num = atol(addr) ; if (num<1) addr="1" ; /* error checking */ if (num>54000) addr="54000" ; cmd = Player[PlayerType].generic[search] ; /* get the search cmd */ fmode = PlayerMode ; /* get current mode cmd */ entercmd = Player[PlayerType].generic[enter]; /* get enter cmd */ if (ReversePolish == TRUE) { /* pioneer players are like this */ strcpy(outbuff,fmode) ; /* frame mode first */ strcat(outbuff,addr) ; /* put address in second */ strcat(outbuff,cmd) ; /* now add the command */ strcat(outbuff,CmdTerm); /* add any terminator */ SendString(outbuff) ; /* send the whole thing */ ReadSer(inbuff,ReturnBytes); /* expect R and CR */ } else { if (PlayerType == sony) { /* sony players */ strcpy(ScratchBuff,fmode); /* frame mode first */ strcat(ScratchBuff,cmd) ; /* put command in next */ strcat(ScratchBuff,addr) ; /* now add the address */ strcat(ScratchBuff,entercmd); /* add the enter cmd */ strcat(ScratchBuff,CmdTerm) ;/* add terminator */ for(temp=ScratchBuff; *temp!='\0'; temp++) { WriteSer(*temp) ; /* send single char */ ReadSer(inbuff,ReturnBytes); /* expect ACK each time */ }; ReadSer(inbuff,1) ; /* expect completion code */ } /* end if sony */ else { /* hitachi players */ strcpy(outbuff,cmd) ; /* put command in first */ strcat(outbuff,fmode) ; /* frame mode next */ strcat(outbuff,cmd) ; /* put command in next */ strcat(outbuff,addr) ; /* now add the address */ strcat(outbuff,entercmd); /* add the enter cmd */ SendString(outbuff) ; /* send the whole thing */ ReadSer(inbuff,2) ; /* expect enter and job done */ } /* else hitachi */ } /* else reverse polish */ } /* proc */ BOOL CheckReady(void) { char *cmd ; BOOL ok=TRUE,myIO ; ClearSerialBuffer() ; /* make sure no garbage left over in buffer */ cmd = Player[PlayerType].generic[ready] ; /* now build output buffer */ strcpy(outbuff,cmd) ; /* command */ strcat(outbuff,CmdTerm) ; /* cmd terminator, if any */ SendString(outbuff) ; /* send string to serial port */ mySerReq->IOSer.io_Data = (APTR)inbuff ; mySerReq->IOSer.io_Length = (ULONG)StatBytes ; mySerReq->IOSer.io_Command = CMD_READ ; SendIO((struct IORequest *)mySerReq) ; /* asynchronous */ Delay(4L) ; /* 4/60 sec delay */ myIO = CheckIO((struct IORequest *)mySerReq) ; /* see if done */ if (myIO == FALSE) { Delay(600L) ; /* wait about 10 more seconds */ myIO = CheckIO((struct IORequest *)mySerReq) ; if (myIO == FALSE) { AbortIO((struct IORequest *)mySerReq) ; SonyModel = ASLEEP ; return(FALSE) ; } } ; GetMsg(mySerPort) ; /* recycle message */ switch (PlayerType) { case sony : /* Bit7 is zero for LDP-1000A */ #ifdef DEBUG printf(" StatusIn= %d\n",*inbuff) ; #endif SonyModel = Ask_Sony_Model(inbuff[0]) ; if (SonyModel == ASLEEP) ok = FALSE ; break ; case hitachi : ok = TRUE ; /* no ready status available! */ break ; case pioneer : /* buffer contents might be P01,P02,P06,etc. */ #ifdef DEBUG printf(" StatusIn= %s\n",inbuff) ; #endif /* if (inbuff[2] < '4') ok = FALSE ; */ ok = TRUE ; /* Don't look at what is returned! */ break ; default : break ; } ; return (ok) ; } void InitPlayer(void) { char *temp, *MyInit ; if (PlayerType != none) { SetBaud(BaudRate) ; ReversePolish = Player[PlayerType].rp ; /* as in PIONEER! */ CmdTerm = Player[PlayerType].term ; /* set up command terminator */ PlayerMode = Player[PlayerType].generic[frame]; /* frame mode default */ ReturnBytes = Player[PlayerType].returnbytes; /* command return bytes */ StatBytes = Player[PlayerType].statbytes; /* # status bytes returned */ AddrBytes = Player[PlayerType].addrbytes; /* # address '' '' */ MyInit = Player[PlayerType].generic[init] ; if (PlayerType==hitachi) DoSimpleCmd(MyInit) ; LdpREADY = CheckReady() ; if (LdpREADY) { if (PlayerType != sony) Go(FORWARD,"normal") ; /* spin it up */ if (PlayerType == pioneer) DoSimpleCmd(MyInit); if (PlayerType == sony) { /* can't send whole string at once */ for (temp=MyInit; *temp != '\0'; temp++) { WriteSer(*temp) ; /* send single char */ ReadSer(inbuff,ReturnBytes); /* expect ACK each time */ } } SetIndex("on") ; /* set on-screen display */ GoSearch("1") ; /* now go to first frame */ } } else LdpREADY = FALSE ; } void PlaySequence(char *start,char *end) /* I got tired of being GENERIC! */ { /* The following is BRUTE FORCE! */ char *temp,*entercmd,*searchcmd,*repeatcmd,*playcmd,*mem1 ; USHORT x ; long startnum,endnum ; entercmd = Player[PlayerType].generic[enter] ; searchcmd = Player[PlayerType].generic[search] ; repeatcmd = Player[PlayerType].generic[repeat] ; mem1 = Player[PlayerType].special1 ; /* hitachi */ startnum = atol(start) ; endnum = atol(end) ; if (startnum<1) start="1" ; /* error checking */ if (startnum>54000) start="27000" ; if (endnum<1) end ="1" ; if (endnum>54000) end="27000" ; startnum = atol(start) ; endnum = atol(end) ; switch (PlayerType) { case sony : SendString(PlayerMode) ; ReadSer(inbuff,1) ; SendString(searchcmd) ; ReadSer(inbuff,1) ; for(temp=start; *temp!='\0'; temp++) { WriteSer(*temp) ; /* send single char */ ReadSer(inbuff,1); /* expect ACK each time */ }; SendString(entercmd) ; ReadSer(inbuff,1) ; ReadSer(inbuff,1) ; /* expect completion code */ SendString(repeatcmd) ; ReadSer(inbuff,1) ; for(temp=end; *temp!='\0'; temp++) { WriteSer(*temp) ; /* send single char */ ReadSer(inbuff,1); /* expect ACK each time */ }; SendString(entercmd) ; ReadSer(inbuff,1) ; SendString("1") ; ReadSer(inbuff,1) ; SendString(entercmd) ; ReadSer(inbuff,1) ; ReadSer(inbuff,1) ; /* get completion code */ break ; case pioneer : /* ok to send up to 20 char in one command, CR terminated */ if (startnum < endnum) playcmd = Player[pioneer].forward[normal] ; else playcmd = Player[pioneer].reverse[normal] ; strcpy(outbuff,PlayerMode) ; /* frame mode */ strcat(outbuff,start) ; /* put search address */ strcat(outbuff,searchcmd); /* put SEarch command */ strcat(outbuff,CmdTerm) ; /* CR terminator */ SendString(outbuff); ReadSer(inbuff,ReturnBytes); strcpy(outbuff,end); /* put play to address */ strcat(outbuff,"SM"); /* Stop Marker */ strcat(outbuff,playcmd) ; /* put multi-speed command */ strcat(outbuff,CmdTerm) ; /* terminate command (CR) */ SendString(outbuff) ; /* send commands to player */ ReadSer(inbuff,ReturnBytes); /* expect back R and CR */ break ; case hitachi : /* ok to send as a string */ strcpy(outbuff,searchcmd) ; /* search command first */ strcat(outbuff,PlayerMode); /* frame command next */ strcat(outbuff,start) ; /* now start address */ strcat(outbuff,mem1) ; /* remember this location */ strcat(outbuff,end) ; /* now end address */ strcat(outbuff,entercmd) ; /* terminate with enter */ SendString(outbuff) ; /* send it out */ ReadSer(inbuff,2) ; /* expect ENTER & JOB END */ break ; /* JOB END = SEARCH+80H */ default : break ; } /* switch */ } /* proc */ long DoCommand(char *cmd, char *arg1, char *arg2) { int c=0,i ; long result= 0 ; char *current= NULL ; /* pointer to current command */ /* now check only the 1st 3 letters of command and increment cmd index */ while ((c < NUMCMDS) && (strncmp(cmd, VideoCmd[c],3) != 0)) c++ ; CurrentCmd = c ; /* global variable, use to index into generic commands */ current = Player[PlayerType].generic[CurrentCmd]; switch (c) { case address : if (LdpREADY) { result = GetAddress(current) ; }; break ; case baud : /* set baud rate of AMIGA serial port */ /* laser player should MATCH rate! */ /* usual rates are 1200,4800,9600 */ if (arg1 != NULL) { BaudRate = (USHORT)atoi(arg1); /* convert str->int */ SetBaud(BaudRate) ; } ; result = (long)BaudRate ; /* return long integer */ break ; case clear : if (LdpREADY) { ClearSerialBuffer() ; DoSimpleCmd(current) ; }; break ; case eject : if (LdpREADY) DoSimpleCmd(current) ; break ; case enter : if (LdpREADY) DoSimpleCmd(current) ; break ; case forward : if (LdpREADY) Go(FORWARD,arg1) ; break ; case frame : if (LdpREADY) DoSimpleCmd(current) ; break ; case index : if (LdpREADY) SetIndex(arg1) ; break ; case init : InitPlayer() ; result = (long)LdpREADY ; break ; case play : if (LdpREADY) PlaySequence(arg1,arg2) ; break ; case quit : TimeToExit = TRUE ; /* shutdown the program */ break ; /* useful if no remote! */ case ready : result = (long)CheckReady() ; break ; case reverse : if (LdpREADY) Go(REVERSE,arg1) ; break ; case search : if (LdpREADY) GoSearch(arg1) ; break ; case still : if (LdpREADY) DoSimpleCmd(current) ; break ; case vplayer : /* select video player type */ /* echo back or return current player if no arg1 */ if(arg1 != NULL) { result = (long)(*arg1); /* echo char if not illegal */ switch(*arg1) { /* *arg1 is 1st char of string! */ case 's' : PlayerType = sony ; InitPlayer() ; break ; case 'p' : PlayerType = pioneer ; InitPlayer() ; break ; case 'h' : PlayerType = hitachi ; InitPlayer() ; break ; case 'n' : PlayerType = none ; LdpREADY = FALSE ; break ; default : result = (long)*PlayerStr[PlayerType] ; break ; /* return current if illegal */ } /* switch */ } /* if */ else result = (long)*PlayerStr[PlayerType] ; if(wp!=NULL)SetWindowTitles(wp,PlayerStr[PlayerType],NULL); break ; default : puts("ILLEGAL command!!") ; result = 255L ; break ; }; return(result) ; } void execute_command(struct RexxMsg *rexxmessage) { char *token[4], *temp ; /* token[0]=Command, others=arguments */ int err ; /* this routine crashes system if total */ USHORT x ; /* tokens not 1 greater! */ long result=0 ; /* eg: cmd arg1 arg2 tokens=3+1 */ for (x=0; x<4; token[x]=NULL,x++) ; /* clear out token buffer */ token[0] = (char *)rexxmessage->rm_Args[0] ; /* parse ARexx string, */ token[0] = strtok(token[0],(char *)" ,") ; /* look for space or , */ for (x=1; (token[x] = strtok(NULL,(char *)" ,")) != NULL; x++) ; for (x=0; x<4; x++) { /* convert all strings to lower-case */ strlwr(token[x]) ; } ; result = DoCommand(token[0],token[1],token[2]) ; ReplyRexxMessage(rexxmessage,result) ; } /* Process Gadgets */ void ProcessGadgetUp(USHORT mygad) { char *addrcmd=Player[PlayerType].generic[address] ; char ThisChar[2], *num, PriorStr[TEXTLEN] ; LONG temp ; FILE *NoteFile ; switch (mygad) { case Memorize : strcpy(PriorStr,(char *)TextBuff); /* save prior info */ UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; temp=GetAddress(addrcmd) ; addrcmd=strcpy(MemAddr,CurrentAddr); /* save MemAddr */ UpdateDisplay(MemAddr,NEW,DNUM) ; Delay(30L) ; UpdateDisplay(PriorStr,NEW,DTEXT) ; break ; case Msearch : UpdateDisplay(MemAddr,NEW,DNUM) ; UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; GoSearch(MemAddr) ; break ; case Log : strcpy(PriorStr,(char *)TextBuff) ; /* save note */ UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; /* logging */ temp=GetAddress(addrcmd) ; /* show current address */ UpdateDisplay(CurrentAddr,NEW,DNUM) ; NoteFile = fopen("ram:LDP.log","a") ; /* save to file */ fprintf(NoteFile,"%s %s\n",CurrentAddr,PriorStr) ; fclose(NoteFile) ; Delay(30L) ; UpdateDisplay(PriorStr,NEW,DTEXT) ; /* reshow note */ break ; case Index : IndexON ^= TRUE ; /* toggle on/off */ if (IndexON) SetIndex("on"); else SetIndex("off"); break ; case NumDisplay : if (PlayerType == pioneer) { UpdateDisplay("Search",NEW,DTEXT) ; SearchPRESSED = TRUE ; GoSearch((char *)NumBuff) ; } else { if (SearchPRESSED) { SearchPRESSED = FALSE ; UpdateDisplay(GadStr[Enter],NEW,DTEXT) ; if (PlayerType == hitachi) { SendString((char *)NumBuff) ; } else { /* sony players */ for (num=(char *)NumBuff; *num !='\0'; num++) { WriteSer(*num) ; ReadSer(inbuff,1) ; } }; SendString(Player[PlayerType].generic[enter]); /* expect back ACK,COMPLETION or ECHO,JOB DONE */ ReadSer(inbuff,2) ; } else { UpdateDisplay("Search/Enter",NEW,DTEXT) ; GoSearch((char *)NumBuff) ; } }; break ; case Search : if ((SearchPRESSED==TRUE) && (PlayerType!=pioneer)) { UpdateDisplay("ERROR!",NEW,DTEXT) ; break ; }; UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; SearchPRESSED = TRUE ; if (PlayerType != pioneer) UpdateDisplay("",NEW,DNUM); else SendString((char *)NumBuff); DoSimpleCmd(Player[PlayerType].generic[search]); if (PlayerType == hitachi) { DoSimpleCmd(Player[hitachi].generic[frame]) ; }; break ; case Still : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; DoSimpleCmd(Player[PlayerType].generic[still]) ; Delay(1L) ; temp=GetAddress(addrcmd) ; /* show current address */ UpdateDisplay(CurrentAddr,NEW,DNUM) ; break ; case Clear : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; UpdateDisplay("",NEW,DNUM) ; ClearSerialBuffer() ; DoSimpleCmd(Player[PlayerType].generic[clear]) ; SearchPRESSED = FALSE ; break ; case Enter : UpdateDisplay(GadStr[mygad],NEW,DTEXT); if (SearchPRESSED) { /* send buff next */ SearchPRESSED = FALSE ; if (PlayerType == hitachi) { SendString((char *)NumBuff) ; } else { /* for sony: send single chars */ for (num=(char *)NumBuff; *num !='\0'; num++) { WriteSer(*num) ; ReadSer(inbuff,1) ; } }; SendString(Player[PlayerType].generic[enter]); /* expect back ACK,COMPLETION or ECHO,JOB DONE */ ReadSer(inbuff,2) ; } else UpdateDisplay("ERROR!",NEW,DTEXT) ; break ; case Eject : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; DoSimpleCmd(Player[PlayerType].generic[eject]) ; break ; case Fplay : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(FORWARD,"normal") ; break ; case Rplay : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(REVERSE,"normal") ; break ; case Fslow : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(FORWARD,"slow") ; break ; case Rslow : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(REVERSE,"slow") ; break ; case Ffast : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(FORWARD,"fast") ; break ; case Rfast : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(REVERSE,"fast") ; break ; case Fscan : FscanDOWN = FALSE ; /* scan button UP is still frame */ DoSimpleCmd(Player[PlayerType].generic[still]) ; Delay(4L) ; temp=GetAddress(addrcmd) ; /* show current address */ UpdateDisplay(CurrentAddr,NEW,DNUM) ; break ; case Rscan : RscanDOWN = FALSE ; DoSimpleCmd(Player[PlayerType].generic[still]) ; Delay(4L) ; temp=GetAddress(addrcmd) ; /* show current address */ UpdateDisplay(CurrentAddr,NEW,DNUM) ; break ; case Fstep : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(FORWARD,"step"); Delay(1L) ; temp=GetAddress(addrcmd) ; /* show current address */ UpdateDisplay(CurrentAddr,NEW,DNUM) ; break ; case Rstep : UpdateDisplay(GadStr[mygad],NEW,DTEXT) ; Go(REVERSE,"step"); Delay(1L) ; temp=GetAddress(addrcmd) ; /* show current address */ UpdateDisplay(CurrentAddr,NEW,DNUM) ; break ; case Zero: case One: case Two: case Three: case Four: ThisChar[0] = (mygad+48) ; ThisChar[1] = '\0' ; UpdateDisplay(ThisChar,ADD,DNUM) ; /* accumulate chars in NumBuff */ break ; case Five: case Six: case Seven: case Eight: case Nine: ThisChar[0] = (mygad+48) ; ThisChar[1] = '\0' ; UpdateDisplay(ThisChar,ADD,DNUM) ; break ; default : break ; } /* switch */ } /* proc */ void ProcessGadgetDown(USHORT mygad) { switch (mygad) { case Fscan : UpdateDisplay("Fscan ",NEW,DTEXT) ; FscanDOWN = TRUE ; Go(FORWARD,"scan") ; break ; case Rscan : UpdateDisplay("Rscan ",NEW,DTEXT) ; RscanDOWN = TRUE ; Go(REVERSE,"scan") ; break ; default : break ; } /* switch */ } /* proc */ void ProcessEvents(void) { struct IntuiMessage *eventptr ; struct RexxMsg *rexxmessage ; ULONG class ; USHORT code, mygad ; struct Gadget *GadPtr ; SHORT y ; while (!TimeToExit) { wakeupmask = Wait(UserSigMask | RexxSigMask) ; /* now wait for events... */ if (wakeupmask & RexxSigMask) { /* process Rexx commands */ while ( (rexxmessage = (struct RexxMsg *)GetMsg(rexx_port)) ) { execute_command(rexxmessage) ; } } ; if (wakeupmask & UserSigMask) { /* process remote controller commands */ while ( (eventptr = (struct IntuiMessage *)GetMsg(wp->UserPort)) ) { class = eventptr->Class ; code = eventptr->Code ; /* Save values of interest */ GadPtr = (struct Gadget *)eventptr->IAddress ; y = eventptr->MouseY ; ReplyMsg( (struct Message *) eventptr ) ; /* Reply QUICKLY! */ mygad = GadPtr->GadgetID ; switch (class) { case GADGETUP : if (LdpREADY) { ProcessGadgetUp(mygad) ; }; break ; case GADGETDOWN : if (LdpREADY) { ProcessGadgetDown(mygad) ; }; break ; case CLOSEWINDOW : TimeToExit = TRUE ; break ; case RAWKEY : if (code == HELP) printf("%s",HelpStr) ; break ; default : break ; } /* switch */ } /* while */ } /* if UserSigMask */ } ; /* while timetoexit */ while ( (eventptr = (struct IntuiMessage *)GetMsg(wp->UserPort)) ) { ReplyMsg( (struct Message *) eventptr ) ; /* clear out intuition messages */ }; while ( (rexxmessage = (struct RexxMsg *)GetMsg(rexx_port)) ) { ReplyMsg( (struct Message *) rexxmessage) ; /* clear out arexx messages */ } } /* proc */ void SetupPorts(void) { LONG i, error,unit=(long)SerialUnit ; BYTE *b, *c ; mySerPort = CreatePort("mySerialPort",0L) ; if (mySerPort == NULL) { MyCleanup(WRITEPORT_ERR) ; exit(FALSE) ; }; i = (LONG)sizeof(struct IOExtSer) ; mySerReq = (struct IOExtSer *)CreateExtIO(mySerPort,i) ; if (mySerReq == NULL) { MyCleanup(READ_EXTIO_ERR) ; exit(FALSE) ; } ; mySerReq->io_SerFlags = (SERF_RAD_BOOGIE | SERF_7WIRE); /* FAST I/O! */ error = OpenDevice("serial.device",unit,(struct IORequest *)mySerReq,0L) ; if (error != 0) { MyCleanup(DEVICE_ERR) ; exit(FALSE) ; } else SerDeviceACTIVE = TRUE ; } void OpenLibs(void) { IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",0L); if (IntuitionBase == NULL) { MyCleanup(INT_ERR) ; exit(FALSE) ; } } void InitWindow(void) { LdpWindow.Title = (UBYTE *)PlayerStr[PlayerType] ; if (SonyModel == LDP_1000A) LdpWindow.Title = (UBYTE *)"SONY-1KA" ; if (LdpREADY == FALSE) { strcpy(ScratchBuff,(char *)LdpWindow.Title) ; strcat(ScratchBuff," ASLEEP!") ; LdpWindow.Title = (UBYTE *)ScratchBuff ; } ; if ((wp = OpenWindow(&LdpWindow)) == NULL) { MyCleanup(WIN_ERR) ; exit(FALSE) ; } ; if (PlayerType == pioneer) OffGadget(&EnterGad,wp,NULL); /* disable Enter */ if (LdpREADY != TRUE) UpdateDisplay("RESTART!",NEW,DTEXT) ; UserSigMask = (1L << wp->UserPort->mp_SigBit) ; /* set up signal for events */ } void SetPlayer(char *type) { switch (*type) { /* look at first character */ case 's' : PlayerType = sony ; break ; case 'p' : PlayerType = pioneer ; break ; case 'h' : PlayerType = hitachi ; break ; case 'n' : PlayerType = none ; break ; default : PlayerType = sony ; /* default player is sony */ break ; } /* switch */ } void ParseCmdLine(char *arg[]) /* global variables will be modified */ { USHORT i ; char *temp,*baud,*remote,*player,*unit ; if (strcmp(arg[1],"?")==0) { /* give help */ printf("%s",HelpStr) ; arg[1]="-pnone" ; }; for (i=0; arg[i] != NULL ; i++) { /* convert to lower-case first */ for (temp = arg[i]; *(temp) != '\0'; temp++) *temp=tolower(*temp) ; if ((baud = strchr(arg[i],'b'))!= NULL) { /* look for baud rate */ baud++ ; /* increment pointer past 'b' */ BaudRate = (USHORT)atoi(baud) ; /* convert string to integer value */ } ; if ((player = strchr(arg[i],'p'))!= NULL) { /* look for player name */ player++ ; /* increment pointer past 'p' */ SetPlayer(player) ; }; /* if */ if ((remote = strchr(arg[i],'r'))!= NULL) { /* look for remote toggle*/ remote++ ; /* increment pointer past 'r' */ if (strncmp(remote,indexstr[off],2L)==0) RemoteON = FALSE ; }; if ((unit = strchr(arg[i],'u'))!= NULL) { /* look for serial unit# */ unit++ ; /* increment pointer past 'u' */ SerialUnit = (USHORT)atoi(unit) ; /* convert str to integer */ if (SerialUnit < MIN_UNIT || SerialUnit > MAX_UNIT) SerialUnit = MIN_UNIT ; } /* if */ } /* for loop */ } /* proc */ void GetTooltypes(struct WBStartup *msg) { struct WBArg *arg ; struct DiskObject *diskobj ; char **toolarray ; /* pointer to an array of string pointers */ char *value ; if ((IconBase = OpenLibrary(ICONNAME,1L)) == NULL) { MyCleanup(ILIB_ERR) ; exit(FALSE) ; }; arg=msg->sm_ArgList; /* get argument list from WB startup msg */ diskobj = GetDiskObject(arg->wa_Name) ; /* now get info from icon */ toolarray = diskobj->do_ToolTypes ; /* setup ToolType array */ value = FindToolType(toolarray,"PLAYER") ; strlwr(value) ; /* convert to lower case */ SetPlayer(value) ; /* setup player type */ value = FindToolType(toolarray,"BAUD") ; BaudRate = (USHORT)atoi(value) ; /* setup baud rate */ if (BaudRate == 0) BaudRate = MIN_BAUD ; value = FindToolType(toolarray,"REMOTE") ; if (stricmp(value,"OFF")==0) RemoteON = FALSE ; /* setup onscreen display */ else RemoteON = TRUE ; value = FindToolType(toolarray,"UNIT") ; SerialUnit = (USHORT)atoi(value) ; /* setup serial unit# */ if (SerialUnit < MIN_UNIT || SerialUnit > MAX_UNIT) SerialUnit = MIN_UNIT ; FreeDiskObject(diskobj); /* cleanup */ CloseLibrary(IconBase) ; } /* ******* MAIN PROGRAM ****** */ main(int argc, char *argv[]) { puts("") ; if (argc > 1) ParseCmdLine(argv) ; /* cmd line startup */ else if (argc == 0) GetTooltypes((struct WBStartup *)argv) ; /* WB startup */ puts(" Default is SONY 1200Baud RemoteON") ; OpenLibs() ; SetupPorts() ; ClearSerialBuffer() ; SetupRexxPort() ; puts(" Waiting......") ; InitPlayer() ; if (RemoteON) InitWindow() ; /* show controller on screen */ if (!LdpREADY) puts(" Need to RESTART!") ; else puts(" Player READY!") ; ProcessEvents() ; /* Main loop */ MyCleanup(NO_ERR) ; }