home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / emulator / appleonamiga / txt / applecomm.mod < prev    next >
Text File  |  1995-02-27  |  23KB  |  733 lines

  1. MODULE AppleComm;
  2.  
  3. FROM SYSTEM IMPORT ADDRESS,ADR,CAST,LONGSET,SHORTSET,TAG;
  4.  
  5. FROM Base37 IMPORT A,B,N;
  6.  
  7. IMPORT
  8.  ACASLReq,ACGadgets,a:Audio,d:DosD,D:DosL,e:ExecD,E:ExecL,ES:ExecSupport,Hardware,Heap
  9.  ,G:GraphicsL,i:IntuitionD,I:IntuitionL,R,s:Serial;
  10.  
  11. CONST
  12.  errNoChipMem="Not enough chip memory for audio";
  13.  errSetParms="Error setting serial parameters";
  14.  errNoMsgPort="Error creating MsgPort";
  15.  errNoRequest="Error creating IORequest";
  16.  errNoDevice="Error opening device";
  17.  errClear="Error clearing device";
  18.  errReset="Error resetting device";
  19.  errRead="Error reading from device";
  20.  errQuery="Error querying device";
  21.  windowTitle="AppleComm";
  22.  screenTitle="AppleComm V0.1, 03-Jan-1993";
  23.  errNoWindow="Error opening window";
  24.  trackStatus="Track: %2ld  Length: %5ld";
  25.  writeStatus="Writing %8ld byte";
  26.  sendStatus="Sending AmigaComm(%5ld)";
  27.  clearStatus="                        ";
  28.  romStatus="Receiving ROMs          ";
  29.  diskRequest="Receive Disk File";
  30.  errNoFile="Error opening file";
  31.  gadRetryCancel="Retry|Cancel";
  32.  errWriteFile="Error writing file";
  33.  errDiskTooLarge="Disk does not fit in buffer";
  34.  gadOk="Ok";
  35.  errReceive="ReceiveError";
  36.  basicRomFile="PROGDIR:BASIC";
  37.  diskPromFile="PROGDIR:DISK";
  38.  errNoBasic="Error opening "+basicRomFile;
  39.  errWriteBasic="Error writing "+basicRomFile;
  40.  errNoDisk="Error opening "+diskPromFile;
  41.  errWriteDisk="Error writing "+diskPromFile;
  42.  errNoDiskMem="Not enough contiguous memory";
  43.  alreadyPlaying="Already sending AmigaComm";
  44.  errStop="Error stopping device";
  45.  errStart="Error starting device";
  46.  
  47. CONST
  48.  numTracks=35;
  49.  statusL=20; statusH=90;
  50.  
  51. VAR
  52.  serIOR:s.IOExtSerPtr;
  53.  serPortR:e.MsgPortPtr;
  54.  
  55. PROCEDURE SetBaud(baud:LONGCARD);
  56. BEGIN
  57.  serIOR^.ioSer.command:=s.setParams;
  58.  serIOR^.baud:=baud;
  59.  serIOR^.rBufLen:=8192;
  60.  INCL(serIOR^.serFlags,s.radBoogie);
  61.  E.DoIO(serIOR);
  62.  A(serIOR^.ioSer.error=0,errSetParms);
  63. END SetBaud;
  64.  
  65. PROCEDURE OpenSer;
  66. BEGIN
  67.  serIOR:=NIL; serPortR:=NIL;
  68. (*
  69.  create first a port for the serial.device to communicate with
  70. *)
  71.  serPortR:=E.CreateMsgPort();
  72.  N(serPortR,errNoMsgPort);
  73. (*
  74.  create a request block,appropriate to serial.device
  75. *)
  76.  serIOR:=E.CreateIORequest(serPortR,SIZE(s.IOExtSer));
  77.  N(serIOR,errNoRequest);
  78. (*
  79.  open the serial device
  80. *)
  81.  serIOR^.serFlags:=s.SerFlagSet{};
  82.  E.OpenDevice(ADR(s.serialName),0,serIOR,LONGSET{});
  83.  A(serIOR^.ioSer.error=0,errNoDevice);
  84. (*
  85.  Initialize serial port
  86. *)
  87.  serIOR^.ioSer.command:=e.clear;
  88.  E.DoIO(serIOR);
  89.  A(serIOR^.ioSer.error=0,errClear);
  90.  serIOR^.ioSer.command:=e.reset;
  91.  E.DoIO(serIOR);
  92.  A(serIOR^.ioSer.error=0,errReset);
  93.  SetBaud(9600);
  94. END OpenSer;
  95.  
  96. PROCEDURE QueueRead(adr:ADDRESS; len:LONGINT);
  97. BEGIN
  98.  serIOR^.ioSer.command:=e.read;
  99.  serIOR^.ioSer.length:=len;
  100.  serIOR^.ioSer.data:=adr;
  101.  E.SendIO(serIOR);
  102. END QueueRead;
  103.  
  104. PROCEDURE GetQueued;
  105. BEGIN
  106.  E.WaitIO(serIOR);
  107. END GetQueued;
  108.  
  109. PROCEDURE Read(adr:ADDRESS; len:LONGINT);
  110. BEGIN
  111.  serIOR^.ioSer.command:=e.read;
  112.  serIOR^.ioSer.length:=len;
  113.  serIOR^.ioSer.data:=adr;
  114.  E.DoIO(serIOR);
  115.  A(serIOR^.ioSer.error=0,errRead);
  116. END Read;
  117.  
  118. PROCEDURE QueryReadBuffer(VAR len:LONGINT);
  119. BEGIN
  120.  serIOR^.ioSer.command:=s.query;
  121.  E.DoIO(serIOR);
  122.  A(serIOR^.ioSer.error=0,errQuery);
  123.  len:=serIOR^.ioSer.actual;
  124. END QueryReadBuffer;
  125.  
  126. CONST
  127.  allChannels="\x0F"; (* Allocate all channels, we don't want any interference *)
  128.  
  129. VAR
  130.  audioPort:e.MsgPortPtr;
  131.  audioIO:ARRAY [0..3] OF a.IOAudioPtr;
  132.  playing:BOOLEAN;
  133.  
  134. PROCEDURE Play(adr:ADDRESS; size:CARDINAL);
  135. VAR
  136.  channel:[0..3];
  137.  unit:ADDRESS;
  138. BEGIN
  139.  audioIO[0]^.request.command:=e.stop;
  140.  unit:=15;
  141.  audioIO[0]^.request.unit:=unit; (* stops all channels *)
  142.  E.DoIO(audioIO[0]);
  143.  A(audioIO[0]^.request.error=0,errStop);
  144.  FOR channel:=0 TO 3 DO
  145.   audioIO[channel]^.request.command:=e.write;
  146.   audioIO[channel]^.request.flags:=a.pervol;
  147.   CASE channel OF
  148.   |0: unit:=1;
  149.   |1: unit:=2;
  150.   |2: unit:=4;
  151.   |3: unit:=8;
  152.   END;
  153.   audioIO[channel]^.request.unit:=ADDRESS(unit);
  154.   audioIO[channel]^.data:=adr;
  155.   audioIO[channel]^.length:=size;
  156.   audioIO[channel]^.period:=E.execBase^.eClockFrequency DIV 800;
  157.   audioIO[channel]^.volume:=64;
  158.   audioIO[channel]^.cycles:=1;
  159.   ES.BeginIO(audioIO[channel]);
  160.  END;
  161.  audioIO[0]^.request.command:=e.start;
  162.  unit:=15;
  163.  audioIO[0]^.request.unit:=unit; (* starts all channels *)
  164.  E.DoIO(audioIO[0]);
  165.  A(audioIO[0]^.request.error=0,errStart);
  166.  playing:=TRUE;
  167. END Play;
  168.  
  169. PROCEDURE CloseAudio;
  170. VAR
  171.  channel:[0..3];
  172.  unit:ADDRESS;
  173. BEGIN
  174.  IF audioIO[0]#NIL THEN
  175.   IF audioIO[0]^.request.device#NIL THEN
  176.    IF playing THEN
  177.     audioIO[0]^.request.command:=e.reset;
  178.     unit:=15;
  179.     audioIO[0]^.request.unit:=unit; (* reset all channels *)
  180.     E.DoIO(audioIO[0]);
  181.     A(audioIO[0]^.request.error=0,errReset);
  182.     playing:=FALSE;
  183.    END;
  184.    E.CloseDevice(audioIO[0]);
  185.   END;
  186.   FOR channel:=0 TO 3 DO
  187.    E.DeleteIORequest(audioIO[channel]); audioIO[channel]:=NIL;
  188.   END;
  189.  END;
  190.  IF audioPort#NIL THEN E.DeleteMsgPort(audioPort); audioPort:=NIL; END;
  191. END CloseAudio;
  192.  
  193. PROCEDURE OpenAudio;
  194. VAR
  195.  channel:[0..3];
  196. BEGIN
  197.  FOR channel:=0 TO 3 DO audioIO[channel]:=NIL; END;
  198.  audioPort:=NIL; playing:=FALSE;
  199. (*
  200.  create first a port for the audio.device to communicate with
  201. *)
  202.  audioPort:=E.CreateMsgPort();
  203.  N(audioPort,errNoMsgPort);
  204. (*
  205.  create a request block,appropriate to audio.device
  206. *)
  207.  FOR channel:=0 TO 3 DO
  208.   audioIO[channel]:=E.CreateIORequest(audioPort,SIZE(a.IOAudio));
  209.   N(audioIO[channel],errNoRequest);
  210.  END;
  211. (*
  212.  Open the audio device and allocate all left channels with highest
  213.  priotity. We have to block out any interference, otherwise our
  214.  data transmission will be disturbed.
  215. *)
  216.  audioIO[0]^.length:=SIZE(allChannels);
  217.  audioIO[0]^.data:=ADR(allChannels);
  218.  audioIO[0]^.request.command:=a.allocate;
  219.  audioIO[0]^.request.flags:=a.noWait;
  220.  audioIO[0]^.request.message.node.pri:=127;
  221.  E.OpenDevice(ADR(a.audioName),0,audioIO[0],LONGSET{});
  222.  A(audioIO[0]^.request.error=0,errNoDevice);
  223.  FOR channel:=1 TO 3 DO (* clone IORequests *)
  224.   audioIO[channel]^.allocKey:=audioIO[0]^.allocKey;
  225.   audioIO[channel]^.request.device:=audioIO[0]^.request.device;
  226.  END;
  227. END OpenAudio;
  228.  
  229. CONST
  230.  tagEnd=0;
  231.  
  232. VAR
  233.  window:i.WindowPtr;
  234.  
  235. PROCEDURE OpenWindow;
  236. VAR
  237.   tagBuffer:ARRAY [1..19] OF LONGCARD;
  238. BEGIN
  239.   (* Window öffnen *)
  240.   window:=I.OpenWindowTagList(
  241.    NIL,TAG(tagBuffer
  242.    ,i.waTitle,ADR(windowTitle)
  243.    ,i.waScreenTitle,ADR(screenTitle)
  244.    ,i.waTop,50,i.waInnerHeight,110,i.waLeft,100,i.waInnerWidth,240
  245.    ,i.waFlags,i.WindowFlagSet{
  246.     i.windowDrag,i.windowDepth,i.windowClose,i.activate,i.noCareRefresh,i.gimmeZeroZero
  247.    }
  248.    ,i.waIDCMP,i.IDCMPFlagSet{i.gadgetUp,i.closeWindow}
  249.    ,i.waGadgets,ACGadgets.gadgets
  250.    ,tagEnd
  251.   ));
  252.   A(window#NIL,errNoWindow);
  253. END OpenWindow;
  254.  
  255. TYPE
  256.  DiskBuffer=ARRAY [0..250000] OF SHORTCARD;
  257.  
  258. VAR
  259.  receiveState:(idle,trkLength,trkRead,receiveRoms);
  260.  currentTrack:SHORTCARD;
  261.  trackLength:INTEGER;
  262.  buffer:POINTER TO DiskBuffer;
  263.  bufferIndex:LONGINT;
  264.  
  265. PROCEDURE Request(text,gadgets:ARRAY OF CHAR; parms:ADDRESS):LONGINT;
  266. VAR
  267.  easy:i.EasyStruct;
  268.  idcmp:i.IDCMPFlagSet;
  269. BEGIN
  270.  easy.structSize:=SIZE(i.EasyStruct);
  271.  easy.flags:=LONGSET{};
  272.  easy.title:=ADR(windowTitle);
  273.  easy.textFormat:=ADR(text);
  274.  easy.gadgetFormat:=ADR(gadgets);
  275.  idcmp:=i.IDCMPFlagSet{};
  276.  RETURN I.EasyRequestArgs(window,easy,idcmp,parms);
  277. END Request;
  278.  
  279. TYPE
  280.  String=RECORD
  281.   s:ARRAY [0..99] OF CHAR;
  282.   i:SHORTCARD;
  283.  END;
  284.  StringPtr=POINTER TO String;
  285.  
  286. PROCEDURE PutCh(str{R.A3}:StringPtr; ch{R.D0}:CHAR);
  287. BEGIN
  288.  str^.s[str^.i]:=ch; INC(str^.i);
  289. END PutCh;
  290.  
  291. PROCEDURE TrkStatus(trk,len:LONGCARD);
  292. VAR
  293.  buf:ARRAY [1..2] OF LONGCARD;
  294.  line:String;
  295. BEGIN
  296.  line.s:=""; line.i:=0;
  297.  E.RawDoFmt(
  298.   ADR(trackStatus),TAG(buf,trk,len)
  299.   ,ADR(PutCh),ADR(line)
  300.  );
  301.  G.Move(window^.rPort,statusL,statusH);
  302.  G.Text(window^.rPort,ADR(line.s),line.i-1);
  303. END TrkStatus;
  304.  
  305. PROCEDURE WrtStatus(len:LONGCARD);
  306. VAR
  307.  buf:ARRAY [1..2] OF LONGCARD;
  308.  line:String;
  309. BEGIN
  310.  line.s:=""; line.i:=0;
  311.  E.RawDoFmt(
  312.   ADR(writeStatus),TAG(buf,len)
  313.   ,ADR(PutCh),ADR(line)
  314.  );
  315.  G.Move(window^.rPort,statusL,statusH);
  316.  G.Text(window^.rPort,ADR(line.s),line.i-1);
  317. END WrtStatus;
  318.  
  319. PROCEDURE ClrStatus;
  320. BEGIN
  321.  G.Move(window^.rPort,statusL,statusH);
  322.  G.Text(window^.rPort,ADR(clearStatus),24);
  323. END ClrStatus;
  324.  
  325. PROCEDURE RomStatus;
  326. BEGIN
  327.  G.Move(window^.rPort,statusL,statusH);
  328.  G.Text(window^.rPort,ADR(romStatus),24);
  329. END RomStatus;
  330.  
  331. PROCEDURE SendStatus(len:LONGCARD);
  332. VAR
  333.  buf:ARRAY [1..2] OF LONGCARD;
  334.  line:String;
  335. BEGIN
  336.  line.s:=""; line.i:=0;
  337.  E.RawDoFmt(
  338.   ADR(sendStatus),TAG(buf,len)
  339.   ,ADR(PutCh),ADR(line)
  340.  );
  341.  G.Move(window^.rPort,statusL,statusH);
  342.  G.Text(window^.rPort,ADR(line.s),line.i-1);
  343. END SendStatus;
  344.  
  345. PROCEDURE SaveDisk;
  346. VAR
  347.  f:d.FileHandlePtr;
  348.  name:ARRAY [0..99] OF CHAR;
  349.  ret:LONGINT;
  350.  save:BOOLEAN;
  351. BEGIN
  352.  name:="";
  353.  LOOP
  354.   save:=ACASLReq.FileReq(name,diskRequest,"",TRUE);
  355.   IF save THEN
  356.    f:=D.Open(ADR(name),d.newFile);
  357.    IF f=NIL THEN
  358.     ret:=Request(errNoFile,gadRetryCancel,NIL);
  359.    ELSE
  360.     WrtStatus(bufferIndex);
  361.     IF D.Write(f,ADR(buffer^[0]),bufferIndex)#bufferIndex THEN
  362.      (* Error writing *)
  363.      ClrStatus;
  364.      ret:=Request(errWriteFile,gadRetryCancel,NIL);
  365.     ELSE
  366.      ClrStatus;
  367.      ret:=0; (* all done, we can exit. *)
  368.     END;
  369.     D.Close(f);
  370.    END;
  371.    IF ret=0 THEN EXIT; END;
  372.   ELSE
  373.    EXIT;
  374.   END;
  375.  END;
  376. END SaveDisk;
  377.  
  378. PROCEDURE ReceiveDisk;
  379. BEGIN
  380.  currentTrack:=0; bufferIndex:=0; trackLength:=0;
  381.  receiveState:=trkLength;
  382. (*
  383.  Queue a read for the length field preceeding the first track.
  384. *)
  385.  TrkStatus(currentTrack,trackLength);
  386.  QueueRead(ADR(buffer^[0]),2);
  387. END ReceiveDisk;
  388.  
  389. PROCEDURE StartTrackRead;
  390. VAR
  391.  len:CARDINAL;
  392. BEGIN
  393.  E.WaitIO(serIOR);
  394.  trackLength:=buffer^[bufferIndex]+256*buffer^[bufferIndex+1];
  395.  INC(bufferIndex,2);
  396.  A(bufferIndex+trackLength+2<=SIZE(DiskBuffer),errDiskTooLarge);
  397. (*
  398.  Queue a read for the buffer size plus the two following length bytes.
  399. *)
  400.  receiveState:=trkRead;
  401.  TrkStatus(currentTrack,trackLength);
  402.  QueueRead(ADR(buffer^[bufferIndex]),trackLength+2);
  403. END StartTrackRead;
  404.  
  405. PROCEDURE ToNextTrack;
  406. VAR
  407.  dummy:LONGINT;
  408. BEGIN
  409.  E.WaitIO(serIOR);
  410.  INC(bufferIndex,trackLength);
  411.  IF trackLength#INTEGER(buffer^[bufferIndex]+256*buffer^[bufferIndex+1]) THEN
  412.   (* transmission error, finals length and intial length do not match *)
  413.   dummy:=Request(errReceive,gadOk,NIL);
  414.   ClrStatus;
  415.  ELSE
  416.   INC(bufferIndex,2); (* position past final length information *)
  417.   INC(currentTrack);
  418.   IF currentTrack<numTracks THEN
  419.    (* queue for length of next track *)
  420.    receiveState:=trkLength; trackLength:=0;
  421.    TrkStatus(currentTrack,trackLength);
  422.    QueueRead(ADR(buffer^[bufferIndex]),2);
  423.   ELSE
  424.    (* we got all tracks *)
  425.    receiveState:=idle;
  426.    ClrStatus;
  427.    SaveDisk;
  428.   END;
  429.  END;
  430. END ToNextTrack;
  431.  
  432. PROCEDURE SaveRoms;
  433. VAR
  434.  f:d.FileHandlePtr;
  435.  name:ARRAY [0..99] OF CHAR;
  436.  ret:LONGINT;
  437.  save:BOOLEAN;
  438. BEGIN
  439.  receiveState:=idle;
  440.  name:=basicRomFile;
  441.  f:=D.Open(ADR(name),d.newFile);
  442.  IF f=NIL THEN
  443.   ret:=Request(errNoBasic,gadOk,NIL);
  444.  ELSE
  445.   WrtStatus(03000H);
  446.   IF D.Write(f,ADR(buffer^[4]),03000H)#03000H THEN
  447.    (* Error writing *)
  448.    ClrStatus;
  449.    ret:=Request(errWriteBasic,gadOk,NIL);
  450.   ELSE
  451.    ClrStatus;
  452.   END;
  453.   D.Close(f);
  454.  END;
  455.  name:=diskPromFile;
  456.  f:=D.Open(ADR(name),d.newFile);
  457.  IF f=NIL THEN
  458.   ret:=Request(errNoDisk,gadOk,NIL);
  459.  ELSE
  460.   WrtStatus(0100H);
  461.   IF D.Write(f,ADR(buffer^[03008H]),0100H)#0100H THEN
  462.    (* Error writing *)
  463.    ClrStatus;
  464.    ret:=Request(errWriteDisk,gadOk,NIL);
  465.   ELSE
  466.    ClrStatus;
  467.   END;
  468.   D.Close(f);
  469.  END;
  470. END SaveRoms;
  471.  
  472. PROCEDURE ReceiveRoms;
  473. BEGIN
  474.  RomStatus; receiveState:=receiveRoms;
  475.  QueueRead(ADR(buffer^[0]),12552);
  476. END ReceiveRoms;
  477.  
  478. TYPE
  479.  AmigaCommArray=ARRAY [1..0587H] OF SHORTCARD;
  480.  
  481. CONST
  482.  amigaComm=AmigaCommArray{
  483.   020H,058H,0FCH,0ADH,058H,0C0H,020H,064H,085H,020H,001H,00DH,009H,007H,001H,003H
  484.   ,00FH,00DH,00DH,020H,016H,030H,02EH,031H,02CH,020H,031H,039H,039H,032H,020H,002H
  485.   ,019H,020H,003H,00CH,001H,015H,004H,009H,00FH,020H,00EH,009H,005H,004H,005H,012H
  486.   ,020H,000H,0A9H,005H,085H,024H,0A9H,008H,020H,05BH,0FBH,020H,064H,085H,0D2H,0A0H
  487.   ,0ADH,0A0H,0D3H,0C5H,0CEH,0C4H,0A0H,0C2H,0C1H,0D3H,0C9H,0C3H,0AFH,0C4H,0C9H,0D3H
  488.   ,0CBH,0A0H,0A8H,0D0H,0A9H,0D2H,0CFH,0CDH,000H,0A9H,005H,085H,024H,0A9H,00AH,020H
  489.   ,05BH,0FBH,020H,064H,085H,0C4H,0A0H,0ADH,0A0H,0D3H,0C5H,0CEH,0C4H,0A0H,0C4H,0C9H
  490.   ,0D3H,0CBH,000H,0A9H,005H,085H,024H,0A9H,00EH,020H,05BH,0FBH,020H,064H,085H,0C8H
  491.   ,0A0H,0ADH,0A0H,0C8H,0C5H,0CCH,0D0H,000H,0A9H,005H,085H,024H,0A9H,012H,020H,05BH
  492.   ,0FBH,020H,064H,085H,0D1H,0A0H,0ADH,0A0H,0D1H,0D5H,0C9H,0D4H,000H,0ADH,000H,0C0H
  493.   ,010H,0FBH,02CH,010H,0C0H,0C9H,0D2H,0F0H,015H,0C9H,0C4H,0F0H,069H,0C9H,0C8H,0F0H
  494.   ,00AH,0C9H,0D1H,0D0H,0E8H,020H,058H,0FCH,04CH,0D0H,003H,04CH,04BH,081H,0A9H,000H
  495.   ,085H,024H,0A9H,002H,020H,05BH,0FBH,020H,042H,0FCH,0A9H,005H,085H,024H,0A9H,009H
  496.   ,020H,05BH,0FBH,020H,064H,085H,0D4H,0D2H,0C1H,0CEH,0D3H,0C6H,0C5H,0D2H,0D2H,0C9H
  497.   ,0CEH,0C7H,0A0H,0C2H,0C1H,0D3H,0C9H,0C3H,0A0H,0D2H,0CFH,0CDH,0A0H,0C1H,0CEH,0C4H
  498.   ,000H,0A9H,005H,085H,024H,0A9H,00BH,020H,05BH,0FBH,020H,064H,085H,0C4H,0C9H,0D3H
  499.   ,0CBH,0A0H,0D0H,0D2H,0CFH,0CDH,0A0H,0D4H,0CFH,0A0H,0C1H,0CDH,0C9H,0C7H,0C1H,000H
  500.   ,020H,0F7H,082H,04CH,000H,080H,0A9H,000H,085H,024H,0A9H,002H,020H,05BH,0FBH,020H
  501.   ,042H,0FCH,0A9H,005H,085H,024H,0A9H,009H,020H,05BH,0FBH,020H,064H,085H,0D4H,0D2H
  502.   ,0C1H,0CEH,0D3H,0C6H,0C5H,0D2H,0A0H,0C4H,0C9H,0D3H,0CBH,0A0H,0D4H,0CFH,0A0H,0C1H
  503.   ,0CDH,0C9H,0C7H,0C1H,000H,020H,039H,083H,04CH,000H,080H,0A9H,000H,085H,024H,0A9H
  504.   ,002H,020H,05BH,0FBH,020H,042H,0FCH,020H,064H,085H,08DH,08DH,0D7H,0C9H,0D4H,0C8H
  505.   ,0A0H,0D4H,0C8H,0C9H,0D3H,0A0H,0D0H,0D2H,0CFH,0C7H,0D2H,0C1H,0CDH,0A0H,0D9H,0CFH
  506.   ,0D5H,0A0H,0C3H,0C1H,0CEH,0A0H,0D4H,0D2H,0C1H,0CEH,0D3H,0CDH,0C9H,0D4H,0A0H,0D4H
  507.   ,0C8H,0C5H,08DH,0C3H,0CFH,0CEH,0D4H,0C5H,0CEH,0D4H,0D3H,0A0H,0CFH,0C6H,0A0H,0D4H
  508.   ,0C8H,0C5H,0A0H,0C2H,0C1H,0D3H,0C9H,0C3H,0AFH,0CDH,0CFH,0CEH,0C9H,0D4H,0CFH,0D2H
  509.   ,0A0H,0D2H,0CFH,0CDH,0A0H,0C1H,0CEH,0C4H,08DH,0D9H,0CFH,0D5H,0D2H,0A0H,0C4H,0C9H
  510.   ,0D3H,0CBH,0D3H,0A0H,0D4H,0CFH,0A0H,0C8H,0C5H,0A0H,0C1H,0CDH,0C9H,0C7H,0C1H,0ACH
  511.   ,0A0H,0D3H,0CFH,0A0H,0D9H,0CFH,0D5H,0A0H,0C3H,0C1H,0CEH,0A0H,0D5H,0D3H,0C5H,08DH
  512.   ,0D4H,0C8H,0C5H,0A0H,0C1H,0D0H,0D0H,0CCH,0C5H,0A0H,0B2H,0A0H,0C5H,0CDH,0D5H,0CCH
  513.   ,0C1H,0D4H,0CFH,0D2H,0A0H,0D4H,0C8H,0C5H,0D2H,0C5H,0AEH,08DH,08DH,0D2H,0A9H,0A0H
  514.   ,0C5H,0D8H,0D0H,0C5H,0C3H,0D4H,0D3H,0A0H,0D9H,0CFH,0D5H,0A0H,0C8H,0C1H,0D6H,0C5H
  515.   ,0A0H,0C1H,0A0H,0C4H,0C9H,0D3H,0CBH,0A0H,0C3H,0CFH,0CEH,0D2H,0CFH,0CCH,0CCH,0C5H
  516.   ,0D2H,0A0H,0C9H,0CEH,08DH,0A0H,0A0H,0A0H,0D3H,0CCH,0CFH,0D4H,0A0H,0B6H,0ACH,0A0H
  517.   ,0C1H,0CEH,0C4H,0A0H,0D4H,0D2H,0C1H,0CEH,0D3H,0CDH,0C9H,0D4H,0D3H,0A0H,0A4H,0C3H
  518.   ,0B6H,0B0H,0B0H,0ADH,0A4H,0C3H,0B6H,0C6H,0C6H,08DH,0A0H,0A0H,0A0H,0C1H,0CEH,0C4H
  519.   ,0A0H,0A4H,0C4H,0B0H,0B0H,0B0H,0ADH,0A4H,0C6H,0C6H,0C6H,0C6H,0A0H,0D4H,0CFH,0A0H
  520.   ,0D4H,0C8H,0C5H,0A0H,0C1H,0CDH,0C9H,0C7H,0C1H,08DH,08DH,0C4H,0A9H,0A0H,0D4H,0D2H
  521.   ,0C1H,0CEH,0D3H,0CDH,0C9H,0D4H,0D3H,0A0H,0D4H,0C8H,0C5H,0A0H,0C3H,0CFH,0CEH,0D4H
  522.   ,0C5H,0CEH,0D4H,0D3H,0A0H,0CFH,0C6H,0A0H,0D4H,0C8H,0C5H,0A0H,0C4H,0C9H,0D3H,0CBH
  523.   ,08DH,0A0H,0A0H,0A0H,0C9H,0CEH,0A0H,0D4H,0C8H,0C5H,0A0H,0C3H,0D5H,0D2H,0D2H,0C5H
  524.   ,0CEH,0D4H,0A0H,0C4H,0D2H,0C9H,0D6H,0C5H,0A0H,0D4H,0CFH,0A0H,0D4H,0C8H,0C5H,0A0H
  525.   ,0C1H,0CDH,0C9H,0C7H,0C1H,08DH,0A0H,0A0H,0A0H,0D9H,0CFH,0D5H,0A0H,0C3H,0C1H,0CEH
  526.   ,0A7H,0D4H,0A0H,0C3H,0C8H,0C1H,0CEH,0C7H,0C5H,0A0H,0D3H,0CCH,0CFH,0D4H,0AFH,0C4H
  527.   ,0D2H,0C9H,0D6H,0C5H,08DH,08DH,08DH,0D0H,0D2H,0C5H,0D3H,0D3H,0A0H,0C1H,0CEH,0D9H
  528.   ,0A0H,0CBH,0C5H,0D9H,0A0H,0D4H,0CFH,0A0H,0D2H,0C5H,0D4H,0D5H,0D2H,0CEH,0A0H,0D4H
  529.   ,0CFH,0A0H,0CDH,0C1H,0C9H,0CEH,0A0H,0CDH,0C5H,0CEH,0D5H,000H,02CH,000H,0C0H,010H
  530.   ,0FBH,02CH,010H,0C0H,04CH,000H,080H,0A9H,000H,085H,0FAH,0A9H,030H,085H,0FBH,0A9H
  531.   ,000H,085H,0FCH,0A9H,0D0H,085H,0FDH,020H,024H,083H,020H,0D3H,084H,0A9H,000H,085H
  532.   ,0FCH,0A9H,0C6H,085H,0FDH,0A9H,000H,085H,0FAH,0A9H,001H,085H,0FBH,020H,024H,083H
  533.   ,020H,0D3H,084H,060H,0A5H,0FCH,020H,03FH,085H,0A5H,0FDH,020H,03FH,085H,0A5H,0FAH
  534.   ,020H,03FH,085H,0A5H,0FBH,020H,03FH,085H,060H,020H,0A3H,084H,0A9H,000H,085H,0F7H
  535.   ,0A9H,002H,085H,024H,0A9H,00CH,020H,05BH,0FBH,020H,042H,0FCH,020H,064H,085H,0D2H
  536.   ,0C5H,0C1H,0C4H,0A0H,0D4H,0D2H,0C1H,0C3H,0CBH,0A0H,0A4H,000H,0A5H,0F7H,020H,0DAH
  537.   ,0FDH,020H,06CH,084H,0A9H,002H,085H,024H,0A9H,00CH,020H,05BH,0FBH,020H,09CH,0FCH
  538.   ,0A5H,0F7H,020H,0DAH,0FDH,020H,0ACH,083H,0A9H,002H,085H,024H,0A9H,00CH,020H,05BH
  539.   ,0FBH,020H,09CH,0FCH,020H,064H,085H,0D4H,0D2H,0C1H,0CEH,0D3H,0CDH,0C9H,0D4H,0A0H
  540.   ,0D4H,0D2H,0C1H,0C3H,0CBH,0A0H,0A4H,000H,0A5H,0F7H,020H,0DAH,0FDH,020H,0D3H,084H
  541.   ,0E6H,0F7H,0A5H,0F7H,0C9H,023H,0F0H,003H,04CH,040H,083H,060H,0A9H,000H,085H,0FEH
  542.   ,0A9H,040H,085H,0FFH,020H,034H,084H,0A5H,0FEH,085H,0FCH,0A5H,0FFH,085H,0FDH,018H
  543.   ,0A5H,0FEH,069H,07CH,085H,0FEH,0A5H,0FFH,069H,015H,085H,0FFH,018H,0A5H,0FEH,069H
  544.   ,001H,085H,0FEH,0A5H,0FFH,069H,000H,085H,0FFH,020H,034H,084H,020H,025H,084H,0D0H
  545.   ,0EBH,038H,0A5H,0FEH,0E5H,0FCH,085H,0FAH,0A5H,0FFH,0E5H,0FDH,085H,0FBH,018H,0A5H
  546.   ,0FEH,069H,001H,085H,0FEH,0A5H,0FFH,069H,000H,085H,0FFH,038H,0A5H,0FCH,0E9H,001H
  547.   ,085H,0FCH,0A5H,0FDH,0E9H,000H,085H,0FDH,0A0H,000H,0A5H,0FAH,091H,0FCH,091H,0FEH
  548.   ,0C8H,0A5H,0FBH,091H,0FCH,091H,0FEH,018H,0A5H,0FAH,069H,004H,085H,0FAH,0A5H,0FBH
  549.   ,069H,000H,085H,0FBH,060H,0A0H,003H,0A2H,008H,0C8H,0B1H,0FCH,0D1H,0FEH,0D0H,003H
  550.   ,0CAH,0D0H,0F6H,060H,0A0H,000H,0E6H,0FEH,0D0H,007H,0E6H,0FFH,010H,003H,04CH,02DH
  551.   ,0FFH,0B1H,0FEH,0C9H,0FFH,0D0H,0EDH,0C8H,0B1H,0FEH,0C9H,0D5H,0D0H,0E6H,0C8H,0B1H
  552.   ,0FEH,0C9H,0AAH,0D0H,0DFH,0C8H,0B1H,0FEH,0C9H,096H,0D0H,0D8H,0A0H,00CH,0B1H,0FEH
  553.   ,0C9H,0DEH,0D0H,0D0H,0C8H,0B1H,0FEH,0C9H,0AAH,0D0H,0C9H,060H,0A5H,0F7H,0A0H,004H
  554.   ,091H,0F8H,0A9H,000H,0A0H,00CH,091H,0F8H,020H,0B1H,084H,0A0H,001H,0B1H,0F8H,0AAH
  555.   ,0BDH,089H,0C0H,0BDH,08EH,0C0H,0A9H,000H,085H,0FEH,0A9H,040H,085H,0FFH,0A0H,000H
  556.   ,0BDH,08CH,0C0H,010H,0FBH,091H,0FEH,0E6H,0FEH,0D0H,0F5H,0E6H,0FFH,010H,0F1H,0BDH
  557.   ,088H,0C0H,060H,020H,0E3H,003H,084H,0F8H,085H,0F9H,0A0H,003H,0A9H,000H,091H,0F8H
  558.   ,060H,0A4H,0F8H,0A5H,0F9H,020H,0D9H,003H,008H,0A0H,001H,0B1H,0F8H,0AAH,0C8H,0B1H
  559.   ,0F8H,0A0H,010H,091H,0F8H,08AH,088H,091H,0F8H,0A0H,00EH,0B1H,0F8H,0A0H,003H,091H
  560.   ,0F8H,028H,060H,0A5H,0FCH,085H,0FEH,0A5H,0FDH,085H,0FFH,0A9H,000H,085H,024H,0A9H
  561.   ,016H,020H,05BH,0FBH,020H,064H,085H,0C2H,0D9H,0D4H,0C5H,0D3H,0A0H,0D4H,0CFH,0A0H
  562.   ,0D4H,0D2H,0C1H,0CEH,0D3H,0C6H,0C5H,0D2H,0A0H,0A4H,000H,0A5H,024H,048H,0A6H,0FAH
  563.   ,0A5H,0FBH,020H,041H,0F9H,068H,085H,024H,0A0H,000H,0B1H,0FEH,020H,03FH,085H,018H
  564.   ,0A5H,0FEH,069H,001H,085H,0FEH,0A5H,0FFH,069H,000H,085H,0FFH,038H,0A5H,0FAH,0E9H
  565.   ,001H,085H,0FAH,0A5H,0FBH,0E9H,000H,085H,0FBH,0A5H,0FAH,0D0H,0DBH,0A5H,024H,048H
  566.   ,0A5H,0FBH,0A2H,000H,020H,041H,0F9H,068H,085H,024H,0A5H,0FBH,0D0H,0CAH,060H,0A2H
  567.   ,00AH,049H,0FFH,02CH,059H,0C0H,04CH,05BH,085H,04AH,090H,008H,0A4H,000H,02CH,059H
  568.   ,0C0H,04CH,05BH,085H,0EAH,02CH,058H,0C0H,04CH,05BH,085H,0A0H,011H,088H,0D0H,0FDH
  569.   ,0CAH,0D0H,0E6H,060H,068H,085H,0F5H,068H,085H,0F6H,098H,048H,0A0H,000H,0E6H,0F5H
  570.   ,0D0H,002H,0E6H,0F6H,0B1H,0F5H,0F0H,006H,020H,0EDH,0FDH,04CH,06EH,085H,068H,0A8H
  571.   ,0A5H,0F6H,048H,0A5H,0F5H,048H,060H
  572.  };
  573.  
  574. CONST
  575.  audioSize=65000;
  576.  
  577. TYPE
  578.  AudioBuffer=ARRAY [0..audioSize-1] OF SHORTINT;
  579.  
  580. VAR
  581.  audioBuffer:POINTER TO AudioBuffer;
  582.  sendACStatus:(acIdle,setup,transmit,cleanup);
  583.  
  584. PROCEDURE SendAmigaComm;
  585. CONST
  586.  headerSize=4000;
  587.  trailerSize=100;
  588. VAR
  589.  bit:[0..7];
  590.  check,data:SHORTSET;
  591.  dummy:LONGINT;
  592.  i,n:CARDINAL;
  593. BEGIN
  594.  IF sendACStatus=acIdle THEN
  595.   sendACStatus:=setup;
  596.   Heap.AllocMem(audioBuffer,SIZE(AudioBuffer),TRUE);
  597.   N(audioBuffer,errNoChipMem);
  598. (*
  599.  Write Header
  600. *)
  601.   FOR i:=0 TO headerSize-1 DO
  602.    audioBuffer^[6*i]:=127;
  603.    audioBuffer^[6*i+1]:=127;
  604.    audioBuffer^[6*i+2]:=127;
  605.    audioBuffer^[6*i+3]:=-128;
  606.    audioBuffer^[6*i+4]:=-128;
  607.    audioBuffer^[6*i+5]:=-128;
  608.   END;
  609. (*
  610.  Start Mark
  611. *)
  612.   i:=headerSize*6;
  613.   audioBuffer^[i]:=127; audioBuffer^[i+1]:=-128; INC(i,2);
  614. (*
  615.  Data
  616. *)
  617.   check:=SHORTSET{0..7};
  618.   FOR n:=1 TO SIZE(AmigaCommArray) DO
  619.    data:=CAST(SHORTSET,amigaComm[n]);
  620.    check:=check/data;
  621.    FOR bit:=7 TO 0 BY -1 DO
  622.     IF bit IN data THEN
  623.      audioBuffer^[i]:=127; audioBuffer^[i+1]:=127;
  624.      audioBuffer^[i+2]:=-128; audioBuffer^[i+3]:=-128; INC(i,4);
  625.     ELSE
  626.      audioBuffer^[i]:=127; audioBuffer^[i+1]:=-128; INC(i,2);
  627.     END;
  628.    END;
  629.   END;
  630. (*
  631.  Checksum
  632. *)
  633.   FOR bit:=7 TO 0 BY -1 DO
  634.    IF bit IN check THEN
  635.     audioBuffer^[i]:=127; audioBuffer^[i+1]:=127;
  636.     audioBuffer^[i+2]:=-128; audioBuffer^[i+3]:=-128; INC(i,4);
  637.    ELSE
  638.     audioBuffer^[i]:=127; audioBuffer^[i+1]:=-128; INC(i,2);
  639.    END;
  640.   END;
  641. (*
  642.  Trailer (except the first transition not really needed)
  643. *)
  644.   FOR n:=1 TO trailerSize DO
  645.    audioBuffer^[i]:=127; audioBuffer^[i+1]:=127; audioBuffer^[i+2]:=127;
  646.    audioBuffer^[i+3]:=-128; audioBuffer^[i+4]:=-128; audioBuffer^[i+5]:=-128;
  647.    INC(i,6);
  648.   END;
  649.   sendACStatus:=transmit;
  650.   INCL(Hardware.ciaa.pra,Hardware.led);
  651.   Play(audioBuffer,i);
  652.   SendStatus(i);
  653.  ELSE
  654.   dummy:=Request(alreadyPlaying,gadOk,NIL);
  655.  END;
  656. END SendAmigaComm;
  657.  
  658. PROCEDURE EndAmigaComm;
  659. VAR
  660.  channel:[0..3];
  661. BEGIN
  662.  sendACStatus:=cleanup;
  663.  IF playing THEN
  664.   FOR channel:=0 TO 3 DO E.WaitIO(audioIO[channel]); END;
  665.  END;
  666.  EXCL(Hardware.ciaa.pra,Hardware.led);
  667.  Heap.Deallocate(audioBuffer);
  668.  ClrStatus;
  669.  sendACStatus:=acIdle;
  670. END EndAmigaComm;
  671.  
  672. VAR
  673.  id:INTEGER;
  674.  msg:i.IntuiMessagePtr;
  675.  quit:BOOLEAN;
  676.  audBit,serBit,winBit:SHORTCARD;
  677.  signals,waitSignals:LONGSET;
  678. BEGIN
  679.  Heap.Allocate(buffer,SIZE(DiskBuffer));
  680.  N(buffer,errNoDiskMem);
  681.  OpenWindow;
  682.  OpenSer;
  683.  OpenAudio;
  684.  quit:=FALSE;
  685.  audBit:=audioPort^.sigBit;
  686.  serBit:=serPortR^.sigBit;
  687.  winBit:=window^.userPort^.sigBit;
  688.  waitSignals:=LONGSET{audBit,serBit,winBit};
  689.  REPEAT
  690.   signals:=E.Wait(waitSignals);
  691.   IF serBit IN signals THEN
  692.    CASE receiveState OF
  693.    | trkLength: StartTrackRead;
  694.    | trkRead: ToNextTrack;
  695.    | receiveRoms: SaveRoms;
  696.    END;
  697.   END;
  698.   IF winBit IN signals THEN
  699.    LOOP
  700.     msg:=E.GetMsg(window^.userPort);
  701.     IF msg=NIL THEN EXIT END;
  702.     IF i.closeWindow IN msg^.class THEN quit:=TRUE; id:=0; END;
  703.     IF i.gadgetUp IN msg^.class THEN
  704.      id:=i.GadgetPtr(msg^.iAddress)^.gadgetID;
  705.     ELSE
  706.      id:=0;
  707.     END;
  708.     E.ReplyMsg(msg);
  709.     CASE id OF
  710.     | 0: (* no gadget pressed *)
  711.     | 1: ReceiveDisk;
  712.     | 2: ReceiveRoms;
  713.     | 3: SendAmigaComm;
  714.     END;
  715.    END;
  716.   END;
  717.   IF audBit IN signals THEN
  718.    IF sendACStatus=transmit THEN EndAmigaComm; ELSE HALT; END;
  719.   END;
  720.  UNTIL quit;
  721. CLOSE
  722.  CloseAudio;
  723.  IF serIOR#NIL THEN
  724.   E.AbortIO(serIOR); E.WaitIO(serIOR);
  725.   E.CloseDevice(serIOR);
  726.   E.DeleteIORequest(serIOR);
  727.   serIOR:=NIL;
  728.  END;
  729.  IF serPortR#NIL THEN E.DeleteMsgPort(serPortR); serPortR:=NIL; END;
  730.  IF window#NIL THEN I.CloseWindow(window); window:=NIL; END;
  731.  IF buffer#NIL THEN Heap.Deallocate(buffer); END;
  732. END AppleComm.
  733.