/**
 * @file ctlrinfo.cc
 *
 * ControllerInfo - Getting, evaluating and printing out information about a
 * CAPI controller.
 *
 * Copyright: 2003 Thomas Wintergerst. All rights reserved.
 *
 * $FreeBSD$
 * $Id: ctlrinfo.cc,v 1.1.2.1 2006/02/28 21:35:41 thomas Exp $
 * Project  CAPI for BSD
 * Target   capitest - Test tool for the functionality of CAPI for BSD
 * @date    20.08.2003
 * @author  "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * </p>
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

// System includes
#include <iomanip>
#include <sstream>

// Import includes

#define __CTLRINFO__

// Local includes
#ifndef CTLRINFO_H
#  include "ctlrinfo.h"
#endif





// === Private definitions ===============================================





// === Definitions for public declarations ===============================





// === Prototypes for private functions ==================================





// === Implementation of class members ===================================





// --- Class for handling controller information -------------------------

/// The table to translate controller profile global option into strings.
const char *CControllerInfo::sm_aGlobOptStrings [32] =
   {
      "Internal controller support",
      "External controller support",
      "Handset support",
      "DTMF support",
      "Supplementary services support",
      "Channel allocation support",
      "Support for B-protocol parameter B-channel operation",
      "Line interconnection (switching) support",
      "Echo cancellation"
   };
      
/// The table to translate B1 protocol numbers into strings.
const char *CControllerInfo::sm_aB1ProtStrings [32] =
   {
      "64 kbit/s with HDLC framing",
      "64 kbit/s bit-transparent operation with byte framing",
      "V.110 asynchronous operation with start/stop byte framing",
      "V.110 synchronous operation with HDLC framing",
      "T.30 modem for Group 3 fax",
      "64 kbit/s inverted with HDLC framing",
      "56 kbit/s bit-transparent operation with byte framing",
      "Modem with all negotiations",
      "Modem asynchronous operation with start/stop byte framing",
      "Modem synchronous operation with HDLC framing"
   };

/// The table to translate B2 protocol numbers into strings.
const char *CControllerInfo::sm_aB2ProtStrings [32] =
   {
      "ISO 7776 (X.75 SLP)",
      "Transparent",
      "SDLC",
      "LAPD in accordance with Q.921 for D-channel X.25 (SAPI 16)",
      "T.30 for Group 3 fax",
      "Point-to-Point Protocol (PPP)",
      "Transparent (ignoring framing errors of B1 protocol)",
      "Modem error correction and compression (V.42bis or MNP5)",
      "ISO 7776 (X.75 SLP) modified to support V.42bis compression",
      "V.120 asynchronous mode",
      "V.120 asynchronous mode supporting V.42bis",
      "V.120 bit-transparent mode",
      "LAPD in accordance with Q.921 including free SAPI selection"
   };

/// The table to translate B3 protocol numbers into strings.
const char *CControllerInfo::sm_aB3ProtStrings [32] =
   {
      "Transparent",
      "T.90NL with compatibility to T.70NL, in accordance with T.90 Appendix II",
      "ISO 8208 (X.25 DTE-DTE)",
      "X.25 DCE",
      "T.30 for Group 3 fax",
      "T.30 for Group 3 fax with extensions",
      NULL,
      "Modem"
   };





/**
 * Constructor.
 */

CControllerInfo::CControllerInfo (void)
{
   // initialize members by simply requesting data about non-existing controller
   // null
   std::ostringstream oss;
   Init (0, oss);
   
} // CControllerInfo::CControllerInfo





/**
 * Destructor.
 */

CControllerInfo::~CControllerInfo (void)
{
   // nothing to do
   
} // CControllerInfo::~CControllerInfo





/**
 * Initialize the information about the controller specified.
 */

unsigned CControllerInfo::Init
   (unsigned      uCtlrNum,
    std::ostream &es)
{
   m_uCtlr = uCtlrNum;
   memset (&m_profile, 0, sizeof (m_profile));
   memset (&m_drvInfo, 0, sizeof (m_drvInfo));
   memset (m_szManufacturer, 0, sizeof (m_szManufacturer));
   memset (m_szSerialNumber, 0, sizeof (m_szSerialNumber));
   m_uManuMajor = 0;
   m_uManuMinor = 0;
   m_uBsdMajor  = 0;
   m_uBsdMinor  = 0;
   
   if (m_uCtlr != 0)
   {
      unsigned uRes;

      uRes = GetCtlrData (es);
      if (uRes != CAPI_OK)
      {
         m_uCtlr = 0;
         return (uRes);
      }
   }
   
   return (CAPI_OK);
} // CControllerInfo::Init





/**
 * Check for completed initialization for a controller.
 */

bool CControllerInfo::IsInitialized (void)
{
   return (m_uCtlr != 0);
} // CControllerInfo::IsInitialized





/**
 * Print out general information about the stored controller.
 */

void CControllerInfo::Print
   (std::ostream &os)
{
   os << "Controller " << m_uCtlr << std::endl;
   os << '\t' << std::left << std::setw (28) << "Name:"
      << m_drvInfo.szCtlrName << std::endl;
   os << '\t' << std::left << std::setw (28) << "Manufacturer:"
      << m_szManufacturer << std::endl;

   os << '\t' << std::left << std::setw (28) << "Number of B-channels:"
      << m_profile.wNumBChannels << std::endl;
   os << '\t' << std::left << std::setw (28) << "Global options:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwGlobalOptions << std::dec << std::setfill (' ')
      << std::endl;

   os << '\t' << std::left << std::setw (28) << "B1 protocol support:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwB1ProtocolSupport << std::dec << std::setfill (' ')
      << std::endl;
   os << '\t' << std::left << std::setw (28) << "B2 protocol support:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwB2ProtocolSupport << std::dec << std::setfill (' ')
      << std::endl;
   os << '\t' << std::left << std::setw (28) << "B3 protocol support:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwB3ProtocolSupport << std::dec << std::setfill (' ')
      << std::endl;

} // CControllerInfo::Print





/**
 * Print out detailed information about the stored controller.
 */

void CControllerInfo::PrintDetailed
   (std::ostream &os)
{
   os << "Controller " << m_uCtlr << std::endl;
   os << '\t' << std::left << std::setw (28) << "Name:"
      << m_drvInfo.szCtlrName << std::endl;
   os << '\t' << std::left << std::setw (28) << "Manufacturer:"
      << m_szManufacturer << std::endl;

   os << '\t' << std::left << std::setw (28) << "Type of controller:"
      << m_drvInfo.szCtlrTypeName << std::endl;
   os << '\t' << std::left << std::setw (28) << "Driver name:"
      << m_drvInfo.szDriverName << std::endl;
   os << '\t' << std::left << std::setw (28) << "Driver unit number:"
      << m_drvInfo.wDrvUnitNum << std::endl;

   if (m_drvInfo.wNumPorts != 1)
   {
      os << '\t' << std::left << std::setw (28) << "Number of ISDN ports:"
         << m_drvInfo.wNumPorts << std::endl;
      os << '\t' << std::left << std::setw (28) << "Port number for controller:"
         << m_drvInfo.wPortIdx << std::endl;
   }
   
   os << '\t' << std::left << std::setw (28) << "BSD driver version:"
      << m_uBsdMajor << '.' << m_uBsdMinor << std::endl;
   os << '\t' << std::left << std::setw (28) << "Manuf. firmware version:"
      << m_uManuMajor << '.' << m_uManuMinor << std::endl;
   os << '\t' << std::left << std::setw (28) << "Serial number:"
      << m_szSerialNumber << std::endl;

   os << '\t' << std::left << std::setw (28) << "Number of B-channels:"
      << m_profile.wNumBChannels << std::endl;
   os << '\t' << std::left << std::setw (28) << "Global options:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwGlobalOptions << std::dec << std::setfill (' ')
      << std::endl;

   PrintGlobalOptions (os);
   
   os << '\t' << std::left << std::setw (28) << "B1 protocol support:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwB1ProtocolSupport << std::dec << std::setfill (' ')
      << std::endl;

   PrintB1ProtocolSupport (os);
   
   os << '\t' << std::left << std::setw (28) << "B2 protocol support:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwB2ProtocolSupport << std::dec << std::setfill (' ')
      << std::endl;

   PrintB2ProtocolSupport (os);
   
   os << '\t' << std::left << std::setw (28) << "B3 protocol support:"
      << "0x" << std::hex << std::right << std::setw (8) << std::setfill ('0')
      << m_profile.dwB3ProtocolSupport << std::dec << std::setfill (' ')
      << std::endl;

   PrintB3ProtocolSupport (os);
   
   os << std::endl;
   
} // CControllerInfo::PrintDetailed





/**
 * Get all data about a controller from CAPI.
 */

unsigned CControllerInfo::GetCtlrData
   (std::ostream &es)
{
   unsigned uRes;

   uRes = capi20_get_profile (m_uCtlr, &m_profile);
   if (uRes != CAPI_OK)
   {
      es << "Error getting profile for controller " << m_uCtlr << ": 0x"
         << std::hex << std::setfill ('0') << std::right << std::setw (4)
         << uRes << std::dec << std::setfill (' ');
      return (uRes);
   }
   
   uRes = capi20_get_manufacturer (m_uCtlr, (unsigned char *) m_szManufacturer);
   if (uRes != CAPI_OK)
   {
      es << "Error getting manufacturer for controller " << m_uCtlr << ": 0x"
         << std::hex << std::setfill ('0') << std::right << std::setw (4)
         << uRes << std::dec << std::setfill (' ');
      return (uRes);
   }

   uRes = capi20_get_version (m_uCtlr,
                              NULL, NULL,
                              &m_uManuMajor, &m_uManuMinor,
                              &m_uBsdMajor, &m_uBsdMinor);
   if (uRes != CAPI_OK)
   {
      es << "Error getting version data for controller " << m_uCtlr << ": 0x"
         << std::hex << std::setfill ('0') << std::right << std::setw (4)
         << uRes << std::dec << std::setfill (' ');
      return (uRes);
   }

   uRes = capi20_get_serial_number (m_uCtlr,
                                    (unsigned char *) m_szSerialNumber);
   if (uRes != CAPI_OK)
   {
      es << "Error getting serial number of controller " << m_uCtlr << ": 0x"
         << std::hex << std::setfill ('0') << std::right << std::setw (4)
         << uRes << std::dec << std::setfill (' ');
      return (uRes);
   }

   uRes = capi20_get_ctlr_driver_info (m_uCtlr, &m_drvInfo);
   if (uRes != CAPI_OK)
   {
      es << "Error getting driver info for controller " << m_uCtlr << ": 0x"
         << std::hex << std::setfill ('0') << std::right << std::setw (4)
         << uRes << std::dec << std::setfill (' ');
      return (uRes);
   }

   return (CAPI_OK);
} // CControllerInfo::GetCtlrData





/**
 * Print out a readable version of the global options.
 */

void CControllerInfo::PrintGlobalOptions
   (std::ostream &os)
{
   int i;
   
   for (i = 0; i < 32; ++i)
   {
      if ((m_profile.dwGlobalOptions & (1 << i)) == 0)
      {
         continue;
      }
      
      if (sm_aGlobOptStrings [i] != NULL)
      {
         os << "\t\t" << sm_aGlobOptStrings [i] << std::endl;
      }
      else
      {
         os << "\t\tUnknown global option bit #" << i << std::endl;
      }
   }
   
} // CControllerInfo::PrintGlobalOptions





/**
 * Print out a readable version of the supported B1 protocols.
 */

void CControllerInfo::PrintB1ProtocolSupport
   (std::ostream &os)
{
   int i;
   
   for (i = 0; i < 32; ++i)
   {
      if ((m_profile.dwB1ProtocolSupport & (1 << i)) == 0)
      {
         continue;
      }
      
      if (sm_aB1ProtStrings [i] != NULL)
      {
         os << "\t\t" << sm_aB1ProtStrings [i] << std::endl;
      }
      else
      {
         os << "\t\tUnknown B1 protocol bit #" << i << std::endl;
      }
   }
   
} // CControllerInfo::PrintB2ProtocolSupport





/**
 * Print out a readable version of the supported B2 protocols.
 */

void CControllerInfo::PrintB2ProtocolSupport
   (std::ostream &os)
{
   int i;
   
   for (i = 0; i < 32; ++i)
   {
      if ((m_profile.dwB2ProtocolSupport & (1 << i)) == 0)
      {
         continue;
      }
      
      if (sm_aB2ProtStrings [i] != NULL)
      {
         os << "\t\t" << sm_aB2ProtStrings [i] << std::endl;
      }
      else
      {
         os << "\t\tUnknown B2 protocol bit #" << i << std::endl;
      }
   }
   
} // CControllerInfo::PrintB2ProtocolSupport





/**
 * Print out a readable version of the supported B3 protocols.
 */

void CControllerInfo::PrintB3ProtocolSupport
   (std::ostream &os)
{
   int i;
   
   for (i = 0; i < 32; ++i)
   {
      if ((m_profile.dwB3ProtocolSupport & (1 << i)) == 0)
      {
         continue;
      }
      
      if (sm_aB3ProtStrings [i] != NULL)
      {
         os << "\t\t" << sm_aB3ProtStrings [i] << std::endl;
      }
      else
      {
         os << "\t\tUnknown B3 protocol bit #" << i << std::endl;
      }
   }
   
} // CControllerInfo::PrintB3ProtocolSupport





// === Implementation of public functions ================================





// === Implementation of private functions ===============================
