
/*
 *  GSM interface module
 *
 *  (ME 45) Siemens
 *  (M  35) Siemens
 *
 *  Peter M. Dambier  2002-09-27
 */

#include <stdio.h>
#include "gsmdev.h"

#define BDOS 224

#define COM_BASE  com_base
#define COM_IER   COM_BASE+1
#define COM_IIF   COM_BASE+2
#define COM_LCR   COM_BASE+3
#define COM_MCR   COM_BASE+4
#define COM_LSR   COM_BASE+5
#define COM_MSR   COM_BASE+6
#define COM_LATCH COM_BASE+7

static int com_base;
static int my_seg;
static int bdos_seg;
static int bdos_bx;
static int x_seg;
static int x_off;


/*
 *  BDOS call
 */
 
static int bdos_call( fun, parm )
    int fun, parm;
{
#asm
    push    es
    push    bp
    mov     cx,[bp+4]
    mov     dx,[bp+6]
    int     224
    pop     bp
    mov     word bdos_bx_,bx
    mov     word bdos_seg_,es
    pop     es
#
}                                                                                                            


/*
 * get cp/m system area
 */

static system_init()
{
    my_seg   = _showds();
    bdos_call( 0x31, 0, 0 );
    x_seg    = bdos_seg;
    x_off    = bdos_bx;
    bdos_seg = my_seg;
}


/*
 * get CP/M clock
 */

clock_get( buffer )
   char buffer[];
{
   system_init();
   _lmove( 17, x_off + 32, x_seg, buffer, my_seg );
   buffer[ 17 ] = 0;
}


/*
 * set CP/M clock
 */

clock_set( buffer )
   char buffer[];
{
   system_init();
   _lmove( 17, buffer, my_seg, x_off + 32, x_seg );
   buffer[ 17 ] = 0;
}


/*
 *  set ko-timer
 */

static ko_set( time )
    int time;
{
#asm
    push    es
    push    di
;
    mov     di,40h
    mov     es,di
    mov     ax,[bp+4]
    mov     es:[di],al
;
    pop     di
    pop     es
#
}


/*
 *  get ko-timer
 */

static ko_get()
{
#asm
    push    es
    push    di
;
    mov     di,40h
    mov     es,di
    mov     ax,[bp+4]
    mov     al,es:[di]
    xor     ah,ah
;
    pop     di
    pop     es
#
}


/*
 *  delay
 */

static delay( cnt )
    int cnt;
{
    ko_set( cnt );

    while( ko_get() )
        ;
}


/*
 *  read port
 */
 
static int port_in( port )
    int port;
{
#asm
    mov     dx,[bp+4]   ;port
    in      al,dx
    xor     ah,ah
#
}
 
 
/*
 *  write port
 */
 
static int port_out( port, val )
    int port, val;
{
#asm
    mov     dx,[bp+4]   ;port
    mov     ax,[bp+6]   ;value
    out     dx,al
#
}                                                                                                            

/*
 * set baud rate
 */

static set_baud( cnt )
    int cnt;
{
    port_out( COM_LCR, 0x80 );      /* acces baud rate counter */
    port_out( COM_BASE, cnt );      /* low baud count */
    port_out( COM_IER, cnt >> 8 );  /* high baud count */
    port_out( COM_LCR, 0x00 );      /* access data & IER */
}


/*
 * init com port
 */

com_init( port )
   int port;
{
   com_base = port;

   set_baud( 6 );               /* 19200 baud */
   port_out( COM_LCR, 0x07 );   /* 8 bit + 2 stop bits */
   port_out( COM_MCR, 0x02 );   /* -DTR +RTS */
   port_out( COM_IER, 0x00 );   /* no ints */
   port_out( COM_IIF, 0xc1 );   /* enable fifo */
   delay( 54 );
   port_out( COM_MCR, 0x03 );   /* +DTR +RTS */
}


/*
 * stop com port
 */

com_stop()
{
   port_out( COM_MCR, 0x02 );   /* -DTR +RTS */
   delay( 54 );
   port_out( COM_MCR, 0x00 );   /* -DTR -RTS */
}


/*
 * exchange com string
 */

com_exch( outbuf, inbuf, len )
   char *inbuf;
   char *outbuf;
   int len;
{
   int cnt, stat, error, clk, clk2;
   char xchar;

   ko_set( 24 );
   cnt     = 1;
   clk     = ko_get();
   clk2    = 0;

   while( clk )
   {
      if( len <= cnt  )
         break;

      stat  = port_in( COM_LSR );
      error = stat & 0x8e;

      if( ( stat & 1 ) == 1 )   /* char read ? */
      {
         xchar   = port_in( COM_BASE ); 
         *inbuf  = xchar; 
         cnt++;
         inbuf++;
         ko_set( 24 );
      }

      if( error )   /* error ? */
      {
         *inbuf  = '?'; 
         cnt++;
         inbuf++;

         if( ( error & 0x80 ) == 0x80 )
         {
            *inbuf  = 'i'; 
            cnt++;
            inbuf++;
         }

         if( ( error & 0x10 ) == 0x10 )
         {
            *inbuf  = 'b'; 
            cnt++;
            inbuf++;
         }

         if( ( error & 0x08 ) == 0x08 )
         {
            *inbuf  = 'f'; 
            cnt++;
            inbuf++;
         }

         if( ( error & 0x04 ) == 0x04 )
         {
            *inbuf  = 'p'; 
            cnt++;
            inbuf++;
         }

         if( ( error & 0x02 ) == 0x02 )
         {
            *inbuf  = 'o'; 
            cnt++;
            inbuf++;
         }
      }

      if( *outbuf )    /* something to send ? */
      {
         if( clk2 != clk )                 /* 18.2 chars / second    */
         {
            if( ( stat & 0x40 ) == 0x40 )  /* tx hold register empty */
            {
               stat = port_in( COM_MSR );

               if( ( stat & 0x10 ) == 0x10 )  /* CTS */
               {
                  port_out( COM_BASE, *outbuf );
                  outbuf++;
                  clk2 = clk;
               }
            }
         }
      }

      clk = ko_get();
   }

   *inbuf = 0;
   return( cnt );
}



