PROGRAM SDSLoad;

{ Written By Sid (SJones@hort.cri.nz) Any comments on the  }
{ following code!? are appreciated, even if they are insulting. }
{ It's the only way I'll learn                                  }
{                                                               }
{ Written with reference to EMUs SYS-EX documentation, and SDS  }


USES    Midi, crt;

TYPE    NameOfFile   = STRING[60];

CONST   { ID's }
        Emu          = $18;
        Emax         = $02;  { emax 1 only ?}

        { System Exclusive Commands }
        SysExStart   = $F0;
        EOX          = $F7;
        ReqReady     = $08;
        SendReady    = $38;

        { Values for Emax status, Follows SDS protocol}
        EmaxACK      = $7F;
        EmaxNAK      = $7E;
        EmaxCAN      = $7D;
        EmaxWAIT     = $7C;

        { Sizes and Positions in SDS Data }
        HeaderSize   =  21;  { as per SDS }
        PacketSize   = 127;  {     "      }
        PacketNoPos  =   5;  {     "      }
        CheckSumPos  = 126;  {     "      }

VAR     MidiData      : INTEGER;
        TheName       : NameOfFile;
        FromF         : FILE;
        NumRead       : WORD;
        HeaderBuffer  : ARRAY[1..HeaderSize] OF BYTE;
        PacketBuffer  : ARRAY[1..PacketSize] OF BYTE;
        EmaxStatus    : INTEGER;


PROCEDURE Welcome;
BEGIN
  ClrScr;
  WriteLn('Written By Sid (SJones@hort.cri.nz) with reference to Emax 1 ');
  WriteLn('SYS-EX manual, midi port routines were modified from a listing in ');
  WriteLn('Inside Turbo Pascal, Source compiled with Turbo Pascal 6.0 However ');
  WriteLn('I think the program could also be compiled with lower versions.');
  WriteLn;
  WriteLn('Source will be available from the EMAX ftp site');
  WriteLn;
  WriteLn('       sweaty.palm.cri.nz  (161.66.1.11)  in emax/sds ');
  WriteLn;
  WriteLn('Please report any bugs to me at the above email address');
  WriteLn;
END;

PROCEDURE ClearBit;
{ Clear a bit of the screen }
BEGIN
  GotoXY(1,23);ClrEol;
  GotoXY(1,24);ClrEol;
END;


PROCEDURE MyHALT;
{ Halts the program and closes the one open file }
BEGIN
  Close(fromF);
  HALT;
END;


FUNCTION FileExists(FileName: NameOfFile) : BOOLEAN;
{ Check if file is present }
VAR
  f: FILE;
BEGIN
  {$I-}  Assign(f, FileName);
         Reset(f);  Close(f);
  {$I+}  FileExists := IOResult = 0;
END;


PROCEDURE Init;
{ Set up MIDI interface, may be specific for MPU-401     }
{ type interface I have no way to check other interfaces }
BEGIN
  Write('Resetting MPU INTERFACE');
  ResetMIDIInterface;             { reset }
  SendMIDICommand (UARTMode);     { set to UART mode }
  WriteLn('.......Reset Successful!');
  WriteLn;
END;


PROCEDURE CheckReady;
{ ask the Emax if it's ready to recieve data, a bit of dumbness      }
{ as suits the Emax i.e. writes e's to the screen until emax replies }
VAR
  junk : INTEGER;
BEGIN
  Write('Wh');
  SendMidiData(SysExStart);   { these 5 statements are the }
  SendMidiData(Emu);          { request to send            }
  SendMidiData(Emax);
  SendMidiData(ReqReady);
  SendMidiData(EOX);
  REPEAT
    junk := GetMidiData;    { loop until Emax is Ready }
    Write('e');
  UNTIL junk = SendReady;
  WriteLn('re''s EMAX.............      Emax is ready');
  WriteLn;
END;


PROCEDURE GetfileNameAndOpen (VAR TheName : NameOfFile);
{ Opens file and sets record size to 1, Blockreads can then be set to }
{ the header size and packet size                                     }
BEGIN
  ClearBit;
  Write('Name of the Sample Dump File :- ');
  ReadLn(TheName);ClrEol;
  IF NOT FileExists(TheName) THEN
    REPEAT
      ClearBit;
      Write('Can''t find the file ', TheName, ' enter again : ');
      ReadLn(TheName);
      ClrEol;
    UNTIL FileExists(TheName);
  Assign(FromF, TheName);
  Reset(FromF, 1); { Record size = 1 }
END;


FUNCTION GetEmaxStatus : INTEGER;
{ Handshaking Messages from SDS protocol }
VAR
  Junk : INTEGER;
BEGIN
  Junk := GetMidiData;          { Should be F0 }
  Junk := GetMidiData;          {     "     7E }
  Junk := GetMidiData;          {     "     channel number }

  GetEmaxStatus := GetMidiData; {     "     essential byte of message }

  Junk := GetMidiData;          {     "     packet number byte }
  Junk := GetMidiData;          {     "     F7 }
END;


PROCEDURE ReadHeader;
{ read the 21 bytes of header into buffer }
BEGIN
  WriteLn('Reading Header from ', FileSize(FromF), ' bytes...');
  BlockRead(FromF, HeaderBuffer, SizeOf(HeaderBuffer), NumRead);
END;


FUNCTION ReplyToHeader: BOOLEAN; FORWARD;
{ forward declaration of ReplyToHeader so that }
{ it is visible to SendHeader                  }


PROCEDURE SendHeader;
{ send the header information to Emax, emax should reply }
{ Check the messages coming back using ReplyToHeader     }
VAR
  i : BYTE;
BEGIN
  WriteLn('Sending, Emax clock thing should be revolving on front panel');
  FOR i := 1 TO HeaderSize DO
    BEGIN
      SendMidiData(HeaderBuffer[i]);
      Delay(5); { may not be necessary EMU think so }
    END;
  REPEAT UNTIL ReplyToHeader;
END;


FUNCTION ReplyToHeader: BOOLEAN;
{ a bit of a cludge but it seems to work! read the midiport and look for }
{ the status byte corresponding to EmaxACK, EmaxNAK, EmaxCAN or EmaxWAIT }
VAR
  Status : INTEGER;
BEGIN
  ReplyToHeader := FALSE;
  Status := EmaxWAIT;
  WHILE Status = EmaxWAIT DO
    BEGIN
      Status := GetEmaxStatus;
      CASE Status OF
        EmaxACK  : BEGIN
                     WriteLn('Header Accepted, Sample will start to load');
                     ReplyToHeader := TRUE;
                     EXIT;
                   END;
        EmaxNAK  : BEGIN
                     WriteLn('Emax did''t acknowledge :- retrying');
                     EXIT;
                   END;
        EmaxWAIT : WriteLn('waiting for Emax ');
      END;{case}
    END; {while}
  IF Status = EmaxCAN THEN
    BEGIN
      Write('Emax has cancelled after receiving the header  ');
      Write('There is probably not enough available ');
      WriteLn('memory in EMAX.......       Exiting');
      MyHALT;
   END;
END;


PROCEDURE ReadDataPacket;
{ Read the data packet into buffer no checks are made of checksum }
BEGIN
  BlockRead(FromF, PacketBuffer, SizeOf(PacketBuffer), NumRead);
END;


FUNCTION ReplyToPacket : BOOLEAN; FORWARD;
{ Forward declaration so it's visible to SendDataPacket }


PROCEDURE SendDataPacket;
{  send the packets to Emax, Emax should send reply   }
{ Check the messages coming back using ReplyToHeader  }
VAR
  i : BYTE;
BEGIN
  FOR i := 1 TO PacketSize DO
    SendMidiData(PacketBuffer[i]);
  REPEAT UNTIL ReplyToPacket;
END;


FUNCTION ReplyToPacket : BOOLEAN;
{ a bit of a cludge but it seems to work! read the midiport and look for }
{ the status byte corresponding to EmaxACK, EmaxNAK, EmaxCAN or EmaxWAIT }
VAR
  Status : INTEGER;
BEGIN
  ReplyToPacket := FALSE;
  Status := EmaxWAIT;
  WHILE Status = EmaxWAIT DO
    BEGIN
      Status := GetEmaxStatus;
      CASE Status OF
        EmaxACK  : BEGIN
                     ReplyToPacket := TRUE;
                     EXIT;
                   END;
        EmaxNAK  : BEGIN
                     WriteLn('Got a NAK retrying');
                     EXIT;
                   END;
        EmaxWAIT : WriteLn('waiting for Emax');
      END;
    END;
  IF Status = EmaxCAN  THEN
    BEGIN
      WriteLn('Emax has Cancelled the dump ..... Exiting');
      MyHALT;
    END;
  END;

PROCEDURE ReadAndSendPackets;
{ Reads and sends the blocks read, provides some indication  }
{ loading, approx 45 seconds for 100Kbytes, writing the dots }
{ causes no appreciable increse in the net loading time      }
{ Closes file when finished                                  }
VAR
  Count : WORD;
BEGIN
  Count := 1;
  REPEAT
    ReadDataPacket;
    SendDataPacket;
    Count := Count + 1;
    IF Count MOD 20 = 0 THEN Write('.');
  UNTIL Eof(FromF) OR (NumRead = 0);
  Close(FromF);
END;


PROCEDURE ByeBye;
BEGIN
  WriteLn;
  WriteLn('All Done press a key');
  REPEAT UNTIL KeyPressed;
  ClrScr;
  WriteLn('If you got to here then the SDS sample MAY have loaded correctly it ');
  WriteLn('should be on key A1.  You will have to go to PRESET DEFINITION');
  WriteLn('EDIT ASSIGMENT to move it onto the keyboard.');
END;


BEGIN
  Welcome;
  Init;
  CheckReady;
  GetFileNameAndOpen(TheName);
  ReadHeader;
  SendHeader;
  ReadAndSendPackets;
  ByeBye;
END.
