// ccusb.cs
//
// csc /t:module /addmodule:w32device.netmodule ccusb.cs

using System;

public class CCUSB
{
  static string devusb = @"\\?\USB#Vid_0be3&Pid_0020#";
  static string devdriver = @"#{69910468-8802-11d3-abc7-a756b2fdfb29}\";
  static string ccep0 = @"if0pipe0";
  static string ccep2 = @"if0pipe2";
  static string devnam = "";

  private bool IO
   (Byte [] sbuf, int nSend, ref int nSent,
    Byte [] rbuf, int nRecv, ref int nRcvd )
  {
    W32Device fri = new W32Device();
    W32Device fro = new W32Device();
    

    nSent = nRcvd = 0;
    if( nSend > 0 )
    {
      if( fro.Open( devusb + devnam + devdriver + ccep2 ) )
      {
        fro.Write(sbuf, nSend, ref nSent);
        fro.Close(); 
      }
      else
        return false;
    }
    if( nRecv > 0 )
    {
      if( fri.Open( devusb + devnam + devdriver + ccep0 ) )
      {
        fri.Read(rbuf, nRecv, ref nRcvd);
        fri.Close();
      }
    }
    else
      return false;
    return true;
  }

  public bool Open(String nam)
  {
    devnam = nam;
    return true;
  }

  public bool Close()
  {
    return true;
  }

  public Byte GetId()
  {
    Byte [] ibf = new Byte [2];
    Byte [] obf = new Byte [2];

    int bytesSent = 0;
    int bytesRecv = 0;

    obf[0] = 0x0e;
    if( !IO(obf, 1, ref bytesSent, ibf, 1, ref bytesRecv) )
      ibf[0] = 0xff;
    return ibf[0];
  }

  public int GetLAM()
  {
    int lamdat = 0;
    Byte [] ibf = new Byte [4];
    Byte [] obf = new Byte [2];

    int bytesSent = 0;
    int bytesRecv = 0;

    obf[0] = 0x0d;
    if( IO(obf, 1, ref bytesSent, ibf, 3, ref bytesRecv) )
      lamdat = ((ibf[2] & 255) * 256 + (ibf[1] & 255)) * 256 + (ibf[0] & 255);
    else
      lamdat = -1;
    return lamdat;
  }

  public int Z()
  {
    Byte [] ibf = new Byte [2];
    Byte [] obf = new Byte [2];

    int bytesSent = 0;
    int bytesRecv = 0;

    obf[0] = 0x06;
    if( !IO(obf, 1, ref bytesSent, ibf, 0, ref bytesRecv) )
      return 0;
    return 1;
  }

  public int C()
  {
    Byte [] ibf = new Byte [2];
    Byte [] obf = new Byte [2];

    int bytesSent = 0;
    int bytesRecv = 0;

    obf[0] = 0x07;
    if( !IO(obf, 1, ref bytesSent, ibf, 0, ref bytesRecv) )
      return 0;
    return 1;
  }

  public int NAF(int n, int a, int f)
  {
    int retval = 0;

    Byte [] obf = new Byte [6];
    Byte [] ibf = new Byte [6];

    int bytesSent = 0;
    int bytesRecv = 0;
    obf[0] = 17;    // 24bit single transfer with status
    obf[1] = (Byte)(n & 31);
    obf[2] = (Byte)(a & 15);
    obf[3] = (Byte)(f & 31);
    if( !IO(obf, 4, ref bytesSent, ibf, 4, ref bytesRecv) )
      return (-1);
    if( bytesRecv == 0 )
      return (-1);
    if( bytesRecv == 1 )
    {
      ibf[3] = ibf[0]; ibf[0] = ibf[1] = ibf[2] = 0;
    }
    else if( bytesRecv == 2 )
    {
      ibf[3] = ibf[1]; ibf[1] = ibf[2] = 0;
    }
    else if( bytesRecv == 3 )
    {
      ibf[3] = ibf[2]; ibf[2] = 0;
    }
    retval = (((ibf[3] & 255) * 256 + (ibf[2] & 255)) * 256
             + (ibf[1] & 255)) * 256 + (ibf[0] & 255);
    return retval;
  }

  public int NAF(int n, int a, int f, int d)
  {
    int retval = 0;

    Byte [] obf = new Byte [8];
    Byte [] ibf = new Byte [6];

    int bytesSent = 0;
    int bytesRecv = 0;
    obf[0] = 17;    // 24bit single transfer with status
    obf[1] = (Byte)(n & 31);
    obf[2] = (Byte)(a & 15);
    obf[3] = (Byte)(f & 31);
    obf[4] = (Byte)(d & 255);
    obf[5] = (Byte)((d >> 8) & 255);
    obf[6] = (Byte)((d >> 16) & 255);
    if( !IO(obf, 7, ref bytesSent, ibf, 4, ref bytesRecv) )
      return (-1);
    if( bytesRecv == 0 )
      return (-1);
    if( bytesRecv == 1 )
    {
      ibf[3] = ibf[0]; ibf[0] = ibf[1] = ibf[2] = 0;
    }
    else if( bytesRecv == 2 )
    {
      ibf[3] = ibf[1]; ibf[1] = ibf[2] = 0;
    }
    else if( bytesRecv == 3 )
    {
      ibf[3] = ibf[2]; ibf[2] = 0;
    }
    retval = (((ibf[3] & 255) * 256 + (ibf[2] & 255)) * 256
             + (ibf[1] & 255)) * 256 + (ibf[0] & 255);
    return retval;
  }
}