/*
    EIBD eib bus access and management daemon
    Copyright (C) 2005-2007 Martin Koegler <mkoegler@auto.tuwien.ac.at>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "tpdu.h"
#include "apdu.h"

TPDU *
TPDU::fromPacket (const CArray & c)
{
  try
  {
    if (c () >= 1)
      {
	if ((c[0] & 0xfc) == 0)
	  return new T_DATA_XXX_REQ_PDU (c);
	if (c[0] == 0x80)
	  return new T_CONNECT_REQ_PDU (c);
	if (c[0] == 0x81)
	  return new T_DISCONNECT_REQ_PDU (c);
	if ((c[0] & 0xC3) == 0xC2)
	  return new T_ACK_PDU (c);
	if ((c[0] & 0xC3) == 0xC3)
	  return new T_NACK_PDU (c);
	if ((c[0] & 0xC0) == 0x40)
	  return new T_DATA_CONNECTED_REQ_PDU (c);
      }
  }
  catch (Exception e)
  {
    return new T_UNKNOWN_PDU (c);
  }
  return new T_UNKNOWN_PDU (c);
}


/* T_UNKNOWN  */

T_UNKNOWN_PDU::T_UNKNOWN_PDU ()
{
}

T_UNKNOWN_PDU::T_UNKNOWN_PDU (const CArray & c):pdu (c)
{
}

CArray T_UNKNOWN_PDU::ToPacket ()
{
  return pdu;
}

String T_UNKNOWN_PDU::Decode ()
{
  String
  s ("Unknown TPDU: ");
  unsigned
    i;

  if (pdu () == 0)
    return "empty TPDU";

  for (i = 0; i < pdu (); i++)
    addHex (s, pdu[i]);

  return s;
}

/* T_DATA_XXX_REQ  */

T_DATA_XXX_REQ_PDU::T_DATA_XXX_REQ_PDU ()
{
}

T_DATA_XXX_REQ_PDU::T_DATA_XXX_REQ_PDU (const CArray & c):data (c)
{
  if (c () < 1)
    throw
    Exception (PDU_WRONG_FORMAT);
}

CArray T_DATA_XXX_REQ_PDU::ToPacket ()
{
  assert (data () > 0);
  CArray
  pdu (data);
  pdu[0] = (pdu[0] & 0x3);
  return pdu;
}

String T_DATA_XXX_REQ_PDU::Decode ()
{
  APDU *
    a = APDU::fromPacket (data);
  String
  s ("T_DATA_XXX_REQ ");
  s += a->Decode ();
  delete
    a;
  return s;
}

/* T_DATA_CONNECTED_REQ  */

T_DATA_CONNECTED_REQ_PDU::T_DATA_CONNECTED_REQ_PDU ()
{
  serno = 0;
}

T_DATA_CONNECTED_REQ_PDU::T_DATA_CONNECTED_REQ_PDU (const CArray & c):data (c)
{
  if (c () < 1)
    throw
    Exception (PDU_WRONG_FORMAT);
  serno = (c[0] >> 2) & 0x0f;
}

CArray T_DATA_CONNECTED_REQ_PDU::ToPacket ()
{
  assert (data () > 0);
  assert ((serno & 0xf0) == 0);
  CArray
  pdu (data);
  pdu[0] = (pdu[0] & 0x3) | 0x40 | ((serno & 0x0f) << 2);
  return pdu;
}

String T_DATA_CONNECTED_REQ_PDU::Decode ()
{
  assert ((serno & 0xf0) == 0);
  APDU *
    a = APDU::fromPacket (data);
  String
  s ("T_DATA_CONNECTED_REQ serno:");
  addHex (s, serno);
  s += a->Decode ();
  delete
    a;
  return s;
}

/* T_CONNECT_REQ  */

T_CONNECT_REQ_PDU::T_CONNECT_REQ_PDU ()
{
}

T_CONNECT_REQ_PDU::T_CONNECT_REQ_PDU (const CArray & c)
{
  if (c () != 1)
    throw Exception (PDU_WRONG_FORMAT);
}

CArray T_CONNECT_REQ_PDU::ToPacket ()
{
  uchar
    c = 0x80;
  return CArray (&c, 1);
}

String T_CONNECT_REQ_PDU::Decode ()
{
  return "T_CONNECT_REQ";
}

/* T_DISCONNECT_REQ  */

T_DISCONNECT_REQ_PDU::T_DISCONNECT_REQ_PDU ()
{
}

T_DISCONNECT_REQ_PDU::T_DISCONNECT_REQ_PDU (const CArray & c)
{
  if (c () != 1)
    throw Exception (PDU_WRONG_FORMAT);
}

CArray T_DISCONNECT_REQ_PDU::ToPacket ()
{
  uchar
    c = 0x81;
  return CArray (&c, 1);
}

String T_DISCONNECT_REQ_PDU::Decode ()
{
  return "T_DISCONNECT_REQ";
}

/* T_ACK */

T_ACK_PDU::T_ACK_PDU ()
{
  serno = 0;
}

T_ACK_PDU::T_ACK_PDU (const CArray & c)
{
  if (c () != 1)
    throw Exception (PDU_WRONG_FORMAT);
  serno = (c[0] >> 2) & 0x0f;
}

CArray T_ACK_PDU::ToPacket ()
{
  assert ((serno & 0xf0) == 0);
  uchar
    c = 0xC2 | ((serno & 0x0f) << 2);
  return CArray (&c, 1);
}

String T_ACK_PDU::Decode ()
{
  assert ((serno & 0xf0) == 0);
  String
  s ("T_ACK Serno:");
  addHex (s, serno);
  return s;
}

/* T_NACK  */

T_NACK_PDU::T_NACK_PDU ()
{
  serno = 0;
}

T_NACK_PDU::T_NACK_PDU (const CArray & c)
{
  if (c () != 1)
    throw Exception (PDU_WRONG_FORMAT);
  serno = (c[0] >> 2) & 0x0f;
}

CArray T_NACK_PDU::ToPacket ()
{
  assert ((serno & 0xf0) == 0);
  uchar
    c = 0xC3 | ((serno & 0x0f) << 2);
  return CArray (&c, 1);
}

String T_NACK_PDU::Decode ()
{
  assert ((serno & 0xf0) == 0);
  String
  s ("T_NACK Serno:");
  addHex (s, serno);
  return s;
}


syntax highlighted by Code2HTML, v. 0.9.1