/*->c.serial */

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

#include "h.os"
#include "h.wimp"
#include "h.bbc"
#include "h.flex"
#include "h.swis"
#include "h.kernel"

#include "h.wos"
#include "h.main"
#include "h.ram"
#include "h.mym"
#include "h.xext"
#include "h.config"
#include "h.key"
#include "h.pr"
#include "h.script"
#include "h.def"

#include "h.serialdev"

#include "h.serial"

/*****************************************************************************/

char bitrev[256]=
{
0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255
};


/***************************************************************************/
/*

 Code to handle serial port

*/
/***************************************************************************/

static int getswi=OS_SerialOp;
static int getr0=4;
static int getchannel=0;
static int getport;


static int putswi=OS_SerialOp;
static int putr0=3;
static int putchannel=0;
static int putport;

static int serialblockmode;

#define BLOCKSIZE 0x100
#define BLOCKMASK 0xFF



static char putbuff[BLOCKSIZE];
static char getbuff[BLOCKSIZE];
static int  putwrite;
static int  putread;
static int  getwrite;
static int  getread;




int ss_swix(int swicode,int r0,int r1,int r2)
{
 _kernel_swi_regs rx;
 int              carry;

 rx.r[0]=r0;
 rx.r[1]=r1;
 rx.r[2]=r2;

 _kernel_swi_c(swicode,&rx,&rx,&carry);

 return(carry?-1:rx.r[1]);
}


int ss_swix2(int swicode,int r0,int r1,int r2)
{
 _kernel_swi_regs rx;

 rx.r[0]=r0;
 rx.r[1]=r1;
 rx.r[2]=r2;

 _kernel_swi(swicode,&rx,&rx);

 return(rx.r[0]);
}



static void blockinit(void)
{
 putwrite=putread=0;
 getwrite=getread=0;
}



static int blockread(int port,char * data,int n)
{
 return(ss_swix2(getswi,getr0,(int)data,n));
 port=port;
}


static int blockwrite(int port,char * data,int n)
{
 return(ss_swix2(putswi,putr0,(int)data,n));
 port=port;
}



/* attempt to write n bytes of data, return number of bytes written */

static int putwriteblock(char * data,int n)
{
 if(putchannel==3) return(blockwrite(putr0,data,n));
 else
 if(putchannel==4) return(sdevblockwrite(putport,data,n));
 else              return(n);
}



/* attempt to flush put buffer, return bytes written */

static int putflush(void)
{
 int wr;

 wr=0;

 if(putread!=putwrite)
 {
  if(putread>putwrite)
  {
   wr=putwriteblock(putbuff+putread,BLOCKSIZE-putread);
   if(!wr) return(wr);
   putread=(putread+wr) & BLOCKMASK;
  }

  if(putwrite>putread)
  {
   wr=putwriteblock(putbuff+putread,putwrite-putread);
   putread=(putread+wr) & BLOCKMASK;
  }
 }

 return(wr);
}


void blockzero(void)
{
 putflush();
}


/* return -1 if failed */

static int blockput(int byte)
{
 int next;

 next=(putwrite+1) & BLOCKMASK;

 if(next==putread && !putflush()) return(-1);

 putbuff[putwrite]=byte;
 putwrite=next;

 if(!scriptpoll || !serialblockmode)
 {
  while(putread!=putwrite) putflush();
 }

 return(byte);
}


/* return -1 or byte */

static int blockget(void)
{
 int byte;

 if(getwrite==getread)
 {
  getread=getwrite=0;
  if(getchannel==3) getwrite=blockread(getr0,getbuff,BLOCKMASK);
  else
  if(getchannel==4) getwrite=sdevblockread(getport,getbuff,BLOCKMASK);
 }

 if(getwrite==getread)
 {
  return(-1);
 }
 else
 {
  byte=getbuff[getread];
  getread=(getread+1) & BLOCKMASK;
  return(byte);
 }
}


/* return -1 or byte */

int getbytelo(void)
{
/* {
  static FILE * fp;
  int           byte;
  static int    count;

  if(isshift) return(-1);

  if(!fp) fp=fopen("testinput","rb");
  if(count++>10) {if(scriptpoll) pollzt();count=0;}
  if(fp)  byte=getc(fp);
  else    byte=-1;

  return(byte);
 } */

 if(!getchannel) return(ss_swix(getswi,getr0,0,0));
 else
 if(getchannel==2) return(serialdevget(getport));
 else
 if(getchannel==3 || getchannel==4) return(blockget());
 else
 if(getchannel==1)
 {
  int byte;
  if(xexec("getbyte",NULL,NULL,&byte)) return(byte);
  else                                 return(-1);
 }
 else return(-1);
}






/*
int getbyte(void)
{
 return(getbytelo()); 
}
 */



static int stripdles;
static int escdle;
static int dleindex;

#define MAXDLES 128

static char dlebuffer[MAXDLES];



void maskdle(int fp)
{
 stripdles=stack[fp];
 escdle=dleindex=0;
}



int getdle(int fp)     /* NB Called with 0 below */
{
 if(dleindex>0)
 {
  return(dlebuffer[--dleindex]);
 }

 return(-1);
 fp=fp;
}





int getbyte(void)
{
 int byte;

 if(stripdles)
 {
  if(escdle==2)
  {
   escdle=0;
   byte=DLE;
  }
  else
  {
   byte=getbytelo();
   if(byte!=-1) debuggetc(byte);

   if(escdle)
   {
    if(byte==DLE)
    {
     escdle=2;
    }
    else
    {
     if(dleindex<MAXDLES)
     {
      dlebuffer[dleindex++]=byte;
     }
     byte=-1;
     escdle=0;
    }
   }
   else
   if(byte==DLE)
   {
    escdle=1;
    byte=-1;
   }
  }
  return(byte);
 }
 else
 {
  byte=getbytelo();
  if(byte!=-1) debuggetc(byte);
  return(byte);
 }
}



int getbytet(int max)
{
 int timeout=max+clock();
 int code;

 do
 {
  if((code=getbyte())!=-1) break;
  if(scriptstop()) break;
  if(scriptpoll) pollzt();
 }
 while(clock()<timeout);

 return(code);
}



int getdlet(int fp)
{
 int timeout;
 int code;

 timeout=stack[fp]+clock();

 do
 {
  code=getdle(0);
  if(code!=-1) 
  {
  /* dprintf(1,"getdle index=%d",dleindex); */
   break;
  }
  getbytet(0);
 }
 while(clock()<timeout);

 return(code);
}




void getallbytes(int fp)
{
 while(getbyte()!=-1);
 fp=fp;
}


static void outbytelo(int byte)
{
 if(!putchannel)
 {
  while(ss_swix(putswi,putr0,byte,0)==-1)
  {
   if(scriptpoll) pollzt();
  }
 }
 else
 if(putchannel==2)
 {
  while(serialdevput(byte,putport)==-1)
  {
   if(scriptpoll) pollzt();
  }
 }
 else
 if(putchannel==3 || putchannel==4)
 {
  while(blockput(byte)==-1)
  {
   if(scriptpoll) pollzt();
  }
 }
 else
 if(putchannel==1)
 {
  while(1)
  {
   if(xexec("putbyte",NULL,&byte,&byte))
   {
    if(byte!=-1) break;
   }
   else break;

   if(scriptpoll) pollzt();
  }
 }
}


int outbyte(int byte)
{     
 serialblockmode=0;
 outbytelo(byte);
 debugputc(byte);
 return(0);
}


int outbyteb(int byte)
{
 outbytelo(byte);
 debugputc(byte);
 return(0);
}


void setblockmode(void)
{
 if(putchannel==3 || putchannel==4)
 {
  serialblockmode=1;
 }
}


void clrblockmode(void)
{
 if(putchannel==3 || putchannel==4)
 {
  serialblockmode=0;
  putflush();
 }
}



void setchannel(int fp)
{
 if(stack[fp]==0)
 {
  if(stack[fp+1]==1)
  {
   putchannel=1;
  }
  else
  if(stack[fp+1]==2 || stack[fp+1]==4)
  {
   putchannel=stack[fp+1];
   putport=stack[fp+3];
  }
  else
  {
   putswi=stack[fp+2];
   putr0=stack[fp+3];
   putchannel=stack[fp+1];
  }
 }
 else
 if(stack[fp]==1)
 {
  if(stack[fp+1]==1)
  {
   getchannel=1;
  }
  else
  if(stack[fp+1]==2 || stack[fp+1]==4)
  {
   getchannel=stack[fp+1];
   getport=stack[fp+3];
  }
  else
  {
   getswi=stack[fp+2];
   getr0=stack[fp+3];
   getchannel=stack[fp+1];
  }
 }


 if(putchannel==3 || putchannel==4) addzeroevent(BLOCKZERO);
 else                               remzeroevent(BLOCKZERO);
 blockinit();
}



int reversebyte(int fp)
{
 return(bitrev[stack[fp] & 0xFF]);
}


/* set up serial system */

void serialset(void) 
{


}


/* convert string and send it to line, return 0 if OK, else 1 */

int convertstringline(char * string)
{
 return(expandmacro(outbyte,string));
}

