/*
 * FreeBox USB
 *
 * Exemple d'interface IOCTL pour le pilote USB 1.2.2.0 minimum
 *
 * Copyright (C) 2004 Freebox http://www.freebox.fr/
 *
 * Mise à jour: 07/10/2004
 * Pondu par TJ
 */

#define STRICT
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>

#include "fbxusbDevice.h"


DWORD ioctl_get( HANDLE hDevice, long IoControlCode,
                        LPVOID lpOutBuffer, DWORD nOutBufferSize )
{
  DWORD dwBytesReturned;

  if ( DeviceIoControl(hDevice,
                       IoControlCode,                  // numero de fonction appelé
                       NULL, 0,                        // rien en entrée
                       lpOutBuffer, nOutBufferSize,    // buffer de sortie, taille buffer
                       &dwBytesReturned,               // taille du buffer en sortie
                       NULL) )                         // reponse synchrone
  {
    if ( dwBytesReturned <= nOutBufferSize )
    {
      // taille retournée acceptable

      return( 0 );      // pas d'erreur
    }

    return( 1 );        // c'est une erreur
  }

  return( GetLastError() );
}



int fbxusb_show( BOOL show_version, BOOL show_inout, BOOL show_iopool, BOOL show_debug )
{
  int retval = 0;
  HANDLE hDevice;

  // Ouvrir le "Device" du pilote FreeBox

  hDevice = CreateFile("\\\\.\\" FBXUSB_DEVICE_NAME,
                    0,
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL);


  if (hDevice == INVALID_HANDLE_VALUE)
  {
    DWORD dwError = GetLastError();

    if ( dwError==2 )
    {
      printf("Peripherique introuvable!\n");
      printf("Le pilote FreeBox USB n'est pas charge ou est trop ancien\n");
    }
    else
    {
      printf("Erreur inconnue: %u\n",dwError);
    }
  }
  else
  {
    // le "Device" est ouvert

    retval = 1;

    if ( show_version )
    {
      // Informations générales d'abord
      FBXUSB_IOCTL_DRIVER_INFO dinf;
      DWORD dwResult;

      printf("Driver Info\n");
      printf("-----------\n");

      if ( 0!=(dwResult=ioctl_get(hDevice,IOCTL_FBXUSB_GET_DRIVER_INFO,&dinf,sizeof(dinf))) )
      {
        printf("Error = %u\n",dwResult);
      }
      else
      {
        printf("Pilote version: %u.%u.%u.%u  ", (BYTE)(dinf.version>>24),(BYTE)(dinf.version>>16),(BYTE)(dinf.version>>8),(BYTE)(dinf.version) );

        if ( !(dinf.flags & (FBXUSB_IOCTL_DEVINFO_FLAG_32BITS+FBXUSB_IOCTL_DEVINFO_FLAG_64BITS)) )
        {
          printf("Windows 9X\n");
        }
        else
        {
          if ( dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_32BITS ) printf("Windows 2000/XP (32 bits)\n");
          if ( dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_64BITS ) printf("Windows 64 bits\n");
        }

        printf("NOBLAST:%d DESCOK:%d V4SPEC:%d INIT:%d HALT:%d RESET:%d SHUTDOWN:%d\n",
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_NOBLAST)!=0,
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_DESCOK)!=0,
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_V4SPEC)!=0,
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_INIT)!=0,
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_HALT)!=0,
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_RESET)!=0,
                (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_SHUTDOWN)!=0
              );

        printf("FreeBox v:%u  RH1:%08X  ST:%I64X\n", (BYTE)(dinf.fbx_version>>24), dinf.flags_RH1, dinf.systime );

        if ( dinf.flags & (FBXUSB_IOCTL_DEVINFO_FLAG_BETA+FBXUSB_IOCTL_DEVINFO_FLAG_DEBUG) )
        {
          show_debug = TRUE;

          printf("--- Version BETA:%d DEBUG:%d ---\n",
                 (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_BETA)!=0,
                 (dinf.flags & FBXUSB_IOCTL_DEVINFO_FLAG_DEBUG)!=0
                );
        }
      }

      printf("\n");
    }

    if ( show_inout )
    {
      // Information sur les communications avec la FreeBox
      FBXUSB_IOCTL_INOUT_INFO ioinf;
      DWORD dwResult;

      printf("In/Out Info\n");
      printf("-----------\n");

      if ( 0!=(dwResult=ioctl_get(hDevice,IOCTL_FBXUSB_GET_INOUT_INFO,&ioinf,sizeof(ioinf))) )
      {
        printf("Erreur = %u\n",dwResult);
      }
      else
      {
        printf("Reception: %I64u octets en %I64u paquets (Erreur: %I64u Reset: %I64u)\n", ioinf.rcv_bytes, ioinf.rcv_ok, ioinf.rcv_err, ioinf.rcv_reset );
        printf("Emission: %I64u octets en %I64u paquets (Erreur: %I64u)\n", ioinf.xmit_bytes, ioinf.xmit_ok, ioinf.xmit_err );
        printf("Paquets recus elimines par le controle Anti-Blaster: %I64u paquets\n", ioinf.rcv_noblast );
      }

      printf("\n");
    }

    if ( show_iopool )
    {
      // Information sur les entrailles du pilote
      FBXUSB_IOCTL_IOPOOL_INFO iopinf;
      DWORD dwResult;

      printf("I/O POOL Info\n");
      printf("-------------\n");

      if ( 0!=(dwResult=ioctl_get(hDevice,IOCTL_FBXUSB_GET_IOPOOL_INFO,&iopinf,sizeof(iopinf))) )
      {
        printf("Erreur = %u\n",dwResult);
      }
      else
      {
        printf("Taille du pool d'emission: %u\n", iopinf.xmit_pool_size );
        printf("Nombre maximum de boucle en emission: %u\n", iopinf.xmit_loop_max );
        printf("Taille du pool de reception: %u\n", iopinf.rcv_pool_size );
        printf("Vitesse du lien reseau virtuel: %u Mb/s\n", iopinf.linkspeed );
        printf("Adresse MAC virtuelle: %02X:%02X:%02X:%02X:%02X:%02X\n",
               iopinf.MAC_address[0], iopinf.MAC_address[1], iopinf.MAC_address[2],
               iopinf.MAC_address[3], iopinf.MAC_address[4], iopinf.MAC_address[5]
               );
        printf("Niveau courant de la pile de reception: %u (%u%% libre)\n", iopinf.rcv_stack,((iopinf.rcv_stack*100)/iopinf.rcv_pool_size) );
        printf("Niveau le plus bas atteind: %u (%u%% libre)\n", iopinf.rcv_lo_stack,((iopinf.rcv_lo_stack*100)/iopinf.rcv_pool_size) );
        printf("Niveau de queue d'emission: %u  (plus haut atteind: %u)\n", iopinf.xmit_queue, iopinf.xmit_hi_queue );
        printf("Nombre de paquets en cours d'envoi: %u (plus haut atteind: %u)\n", iopinf.xmit_loop, iopinf.xmit_hi_loop );
        printf("Nombre de boucle en emission: %u (plus haut atteind: %u)\n", iopinf.xmit_lcount, iopinf.xmit_hi_lcount );

        if ( show_debug )
        {
          printf("DEBUG RX: %u %u %u %u\n", iopinf.dbg_RX[0], iopinf.dbg_RX[1], iopinf.dbg_RX[2], iopinf.dbg_RX[3] );
        }
      }

      printf("\n");
    }

    // fermer le "Device"
    CloseHandle( hDevice );
  }


  return( retval );
}


int main( int argc, char *argv[] )
{
  int retval = 0;
  BOOL show_version = TRUE;
  BOOL show_inout = FALSE;
  BOOL show_iopool = FALSE;
  BOOL show_debug = FALSE;
  BOOL show_help = FALSE;

  printf("fbxuview (c) 2004 FreeBox SA\n");

  if ( argc<=1 )
  {
    printf("(afficher l'aide: fbxuview -help)\n");
  }
  else
  {
    int i;
    char *arg;

    for( i=1; i<argc; i++ )
    {
      arg = argv[i];

      if ( (stricmp(arg,"-help")==0) || (stricmp(arg,"/?")==0) || (stricmp(arg,"-?")==0) )
      {
        show_help = TRUE;
      }

      if ( stricmp(arg,"-inout")==0 ) show_inout = TRUE;

      if ( stricmp(arg,"-iopool")==0 ) show_iopool = TRUE;

      if ( stricmp(arg,"-nover")==0 ) show_version = FALSE;

      if ( stricmp(arg,"-debug")==0 ) show_debug = TRUE;

      if ( stricmp(arg,"-all")==0 )
      {
        show_inout = show_iopool = show_version = show_debug = TRUE;
      }
    }
  }

  printf("\n");

  if ( show_help )
  {
    printf("-help   : cette aide (et aussi -? ou /?)\n");
    printf("-inout  : voir les informations sur les transmissions\n");
    printf("-iopool : voir les informations sur les \"pool\" d'echange\n");
    printf("-nover  : ne pas afficher les informations de version\n");
    printf("-debug  : info de debug (quand elle existe)\n");
    printf("-all    : tout voir\n");
    printf("\n");
  }
  else
  {
    retval = fbxusb_show(show_version,show_inout,show_iopool,show_debug);
  }

  return( retval );
}