/*
 ******************************************************************************
 *  Copyright 1993 DeltaLink bv. All Rights Reserved.
 ******************************************************************************
 *
 * DeltaLink H1 Communication Protocol Driver
 *
 * File:  h1encode.c
 *
 * This file contains the encoded exception write function of the H1 protocol
 *
 */
#include  <stdlib.h>
#include  <stdio.h>
#include  <memory.h>

#include  <flib.h>
#include  <comtp4.h>

#include <imx.h>
#include <imx_fmt.h>

/* defines for encoded data */

#define E_FLAG           'M'        /* merker */
#define E_DB             'D'        /* data block */
#define E_DX             'X'        /* extra data block */
#define E_TIMER          'T'        /* timer */
#define E_COUNTER        'Z'        /* counter */
#define E_OUTPUT         'A'        /* output */
#define E_INPUT          'E'        /* input */
#define E_PERIPHERAL     'P'        /* analog output */
#define E_EPERIPHERAL    'Q'        /* extra analog output */
#define E_SYSTEM         'S'        /* system words (BS) */

char s5_type[] = { 'D', 'M', 'E', 'A', 'P', 'Z', 'T', 'S', 'L', 'X', 'X', 'Q'};

#define E_BIT            'F'        /* bit */
#define E_BYTE           'B'        /* byte */
#define E_DL             'L'        /* left byte */
#define E_DR             'R'        /* right byte */
#define E_WORD           'W'        /* word */
#define E_LONG           'D'        /* long */


/*-----------------------------------------------------------------------------
 * FUNCTION: int h1encode( JOB *, DS *, DS *, uint, uint, void *)
 *
 * PURPOSE: This function sets the receive and send buffer and then performs 
 *          a FETCH operation with the SIEMENS PLC.
 -----------------------------------------------------------------------------*/
int h1encode( H1_DEV *device, H1_DS *ds, uint code )
{

  ENCODE *encode = (ENCODE *)((char *)device->buf[COM_WRITE] + sizeof( H1_HDR));
  char   *data = (char *)encode + sizeof( ENCODE);


  /* save data to destination */
  memset( data, 0, IMX_LONG_BND);
  memcpy( data, ( char *)encode, ds->length * ds->boundary);

  /* update ds length to maximum data size */
  ds->length = IMX_LONG_BND / ds->boundary;

  /* check range of start address */
  /*if (ds->start > 255) return H1_NOT_ENCODE;*/

  /* mark a new incoming command for PLC */
  encode->chg_flag = 0xff;

  /*
   * set the org, type and address of the element depending on the type of PLC
   */
  if (ds->db_no)
  {

    if (ds->type >= H1_D20)
    {
      encode->org     = s5_type[0];
      encode->db_no   = ((ds->type - H1_D20 +1 ) * 256) + ds->db_no;
    }
    else
    {
      encode->org     = s5_type[ds->type -1];
      encode->db_no   = ds->db_no;
    }

    encode->address = ds->start;
  }
  else
  {

    encode->org     = (char)ds->type;

    encode->db_no   = ds->db_no;
    encode->address = ds->start;
  }

  ds->length += (sizeof( ENCODE) / ds->boundary);

  /*
   * evaluate the code parameter
   */
  if (code < CDE_NIBBLE)
  {                   
    
    /* perform a bit operation */
    encode->type = E_BIT;
    encode->bit  = (uchar)(code - CDE_B0_15);
  }
  else if (code < CDE_BYTE)
    return H1_NOT_ENCODE;

  else if (code < CDE_SIGNED)
  {

    switch( code)
    {

      case CDE_BYTE:
      case CDE_UBYTE:

        if (ds->boundary > 1)
          encode->type = E_DR;
        else
          encode->type = E_BYTE;

        break;

      case CDE_BYTE + 8:
      case CDE_UBYTE + 8:

        encode->type = E_DL;

        break;
      default:
        return H1_NOT_ENCODE;
    }
  }
  else if (code < CDE_LONG)
  {

    switch( code)
    {

      case CDE_SIGNED:
      case CDE_UNSIGNED:

        encode->type = E_WORD;
        break;

      default:
        return H1_NOT_ENCODE;
    }
  }
  else if(code < CDE_DOUBLE_IEEE_FLT)
  {

    encode->type = E_LONG;
  }
  else
    return H1_NOT_ENCODE;

#ifdef HOST_LOW_2_HIGH
  swab( ( char *)&encode->db_no, ( char *)&encode->db_no, 2);
  swab( ( char *)&encode->address, ( char *)&encode->address, 2);
#endif

  return 0;
} //h1encode
