#include "cmon.h"
#include "vfd.h"

#define IS   ==
#define AINT !=
#define AND  &&
#define OR   ||

/* carmon 0.2: tach function with bargraph and non-averaged numeric display */
/* carmon 0.3: tach function with bargraph, averaged numeric display, and
   rolling time graph */

void vfd_draw_num( unsigned char bitmap[8][128], int x, int y, int data, int mode );
void vfd_copychar( unsigned char bitmap[8][128], int x, int y, int charcode, int mode );

static unsigned char vfd_wp = 1;
static unsigned char vfd_dp = 0;

void tach_init_itu() 
{ /* tach_init_itu */
  /* locals */

  /* body */
  /* using TIOCA3/B3, TCLKA */
  TIOR3 = 0x5D;  /* 0101 1101 */ /* grb, gra capture falling edge */
  TCR3 = 0x2C;  /* 0010 1100 */ /* ext clock A, falling edge, clear on capt */
  TFCR = 0x4F;  /* 0100 1111 */ /* normal mode with buffering on GRA/B */
  TMDR = 0x00;  /* 0000 0000 */
  TSNC = 0x60;  /* timers operate asynchronously */
  TSTR = 0x68;  /* start unit 3 counting */
} /* tach_init_itu */

void vfd_draw_num( unsigned char bitmap[8][128], int x, int y, int data, int mode ) { /* vfd_draw_num */
  /* locals */
  unsigned char  bcd_num[30];
  int i;

  /* body */
  /* handle minus sign */
  if( data < 0 ) {
    vfd_copychar( bitmap, x, y, V_HYPHEN, mode ); 
    x += 8;
    data = -data;
  } /* if */
  
  i = 0;
  while( data ) {
    bcd_num[i] = data % 10;
    data /= 10;
    i++;
  } /* while */
  i = i - 1;

  for( ; i >= 0; i-- ) {
    vfd_copychar( bitmap, x, y, bcd_num[i] + V_0, mode );
    x += 8;
  } /* for */

} /* vfd_draw_num */


void vfd_draw_rect( unsigned char start[8][128], int x1, int y1, int x2, int y2 ) 
{ /* vfd_draw_rect */
  /* locals */
  int  i;
  int temp;
  int yindex, ybitplace, ybit;
  
  /* body */
  if( x1 > x2 ) {
    temp = x1;
    x1 = x2;
    x2 = temp;
  } /* if */
  if( y1 > y2 ) {
    temp = y1;
    y1 = y2;
    y2 = temp;
  } /* if */
  
  x1 &= 0x7F;
  x2 &= 0x7F;
  y1 &= 0x3F;
  y2 &= 0x3F;

  /* x-dir bottom (along y1) */
  yindex = y1 >> 3;
  ybitplace = y1 & 0x7;
  ybitplace = ~ybitplace & 0x7;
  ybit = 0x1 << ybitplace;

  for( i = x1; i < x2; i++ ) {
    start[yindex][i] |= ybit;
  } /* for */

  /* x-dir top (along y2) */
  yindex = y2 >> 3;
  ybitplace = y2 & 0x7;
  ybitplace = ~ybitplace & 0x7;
  ybit = 0x1 << ybitplace;

  for( i = x1; i < x2; i++ ) {
    start[yindex][i] |= ybit;
  } /* for */

  /* y-dir parallels */
  for( i = y1; i <= y2; i++ ) {
    start[ (i >> 3) ][ x1 ] |= (0x1 << (~(i & 0x7) & 0x7));
    start[ (i >> 3) ][ x2 ] |= (0x1 << (~(i & 0x7) & 0x7));
  } /* for */

} /* vfd_draw_rect */


void vfd_draw_filled_rect( unsigned char start[8][128], int x1, int y1, int x2, int y2 ) 
{ /* vfd_draw_filled_rect */
  /* locals */
  int  i, j;
  int temp;
  int yindex, ybitplace, ybit;
  
  /* body */
  if( x1 > x2 ) {
    temp = x1;
    x1 = x2;
    x2 = temp;
  } /* if */
  if( y1 > y2 ) {
    temp = y1;
    y1 = y2;
    y2 = temp;
  } /* if */
  
  x1 &= 0x7F;
  x2 &= 0x7F;
  y1 &= 0x3F;
  y2 &= 0x3F;

  /* y-dir parallels */
  for( i = y1; i < y2; i++ ) {
    yindex = i >> 3;
    ybit = (0x1 << (~(i & 0x7) & 0x7));
    for( j = x1; j < x2; j++ ) {
      start[ yindex ][ j ] |= ybit;
    } /* for */
  } /* for */

} /* vfd_draw_filled_rect */

#define MAX_GRAPH_HEIGHT 20
#define RPM_OFFSET 650

void vfd_draw_rpmhistory( unsigned char start[8][128], unsigned int rpmhist[128], unsigned int rpmhist_index ) {
  /* vfd_draw_rpmhistory */
  /* locals */
  int x, y, i;
  int height;
  unsigned int max_rpm, height_factor;
  int rpmhist_index_norm;
  int rpm_intermediate;

  /* body */
  /* rpmhist[128] is a circular history buffer of RPM values with time 
     rpmhist_index is the index of the "current" rpm value. Indices less
     than rpmhist_index are increasingly "older" rpm values, until it wraps
     back around to 128, and decreases to rpmhist_index + 1. Thus, the
     oldest value is rpmhist_index + 1, the newest value is rpmhist_index,
     and the second newest is rpmhist_index - 1, all modulo 128.
     */
  max_rpm = 0;
  for( i = 0; i < 128; i++ ) {
    if( rpmhist[i] > max_rpm )
      max_rpm = rpmhist[i];
  } /* for */

  max_rpm -= RPM_OFFSET;
  if( max_rpm < 0 )
    max_rpm = 0;

  if( max_rpm < 3000 ) {
    height_factor = 3000 / MAX_GRAPH_HEIGHT;
  }
  else if( max_rpm < 4500 ) {
    height_factor = 4500 / MAX_GRAPH_HEIGHT;
  }
  else {
    height_factor = 6000 / MAX_GRAPH_HEIGHT;
  }
  
  for( i = 0; i < 128; i++ ) {
    rpmhist_index_norm = rpmhist_index - i;
    if( rpmhist_index_norm < 0 )
      rpmhist_index_norm += 128;
    rpm_intermediate = (rpmhist[rpmhist_index_norm] - RPM_OFFSET) / height_factor;
    if( rpm_intermediate < 0 )
      rpm_intermediate = 0;
    vfd_draw_rect( start, 127 - i, 0, 127 - i, rpm_intermediate );
  } /* for */
  
} /* vfd_draw_rpmhistory */

#define TCLKA_FREQ (19531)    /* in hertz */
#define RPM_MAX  6000
#define NUMAVE   20

void vfd_test_bars() {
  /* vfd_test_bars */
  /* locals */
  int x1, x2, y1, y2, xtext, ytext, rpmbar;
  int i, j, x;
  unsigned char bitmap[8][128];
  unsigned short pbd;
  unsigned short ticks;
  unsigned int rpm;
  int samples, rpmsample;
  unsigned int rpmhist[128];
  unsigned int rpmhist_index = 0;
  int rpmhist_index_norm = 0;
  unsigned long tavg_rpm;

  /* body */
  /* set intensity to 100% */
  pbd = 0xFFF3;
  PBDR = pbd;
  pbd = 0xFFF2;
  PBDR = pbd;
  pbd = 0xFFF0;
  PBDR = pbd;
  pbd = 0xFFF0;
  PBDR = pbd;
  pbd = 0xFFF2;
  PBDR = pbd;
  pbd = 0xFFF3;
  PBDR = pbd;
  pbd = 0x3FF3;
  PBDR = pbd;

  x1 = 10;
  x2 = 118;
  y1 = 21;
  y2 = 37;
  xtext = 16;
  ytext = 26;

  for( i = x1; i < x2; i += 10 ) {

    for( x = 0; x < 8; x++ ) {
      for( j = 0; j < 128; j++ ) {
	bitmap[x][j] = 0;
      } /* for */
    } /* for */
      
    vfd_draw_rect( bitmap, x1, y1, x2, y2 );
    vfd_draw_filled_rect( bitmap, x1, y1, i, y2 );
    vfd_draw_num( bitmap, xtext, ytext, (i-x1) * (RPM_MAX / (x2-x1)), 
		  BLT_XOR );
    vfd_display_bitmap( bitmap );
  }

  for( i = x2; i > x1; i -= 10 ) {

    for( x = 0; x < 8; x++ ) {
      for( j = 0; j < 128; j++ ) {
	bitmap[x][j] = 0;
      } /* for */
    } /* for */

    vfd_draw_rect( bitmap, x1, y1, x2, y2 );
    vfd_draw_filled_rect( bitmap, x1, y1, i, y2 );
    vfd_draw_num( bitmap, xtext, ytext, (i-x1) * (RPM_MAX / (x2-x1)),
		  BLT_XOR );
    vfd_display_bitmap( bitmap );
  }

  for( i = 0; i < 128; i++ ) {
    rpmhist[i] = 0;
  }

  while(1) {
    /* clear out bitmap */
      for( x = 0; x < 8; x++ ) {
	for( j = 0; j < 128; j++ ) {
	  bitmap[x][j] = 0;
	} /* for */
      } /* for */

      /* calculate rpm */
      ticks = BRA3;
      rpm = (15 * TCLKA_FREQ) / ticks;
      rpm = rpm * 2; /* double RPMs because both edges are ignition */
      rpmsample += rpm;

      if( rpm < 6 ) 
	rpm = 0;   /* handle 0 case */
      /* rpm actually only goes down to like 4 */

      /* now we have a real rpm value, enter it into the rpmhist[] buffer */
      rpmhist[rpmhist_index] = rpm;
      tavg_rpm = 0;
      for( i = 0; i < 4; i++ ) {
	rpmhist_index_norm = rpmhist_index - i;
	if( rpmhist_index_norm < 0 ) 
	  rpmhist_index_norm += 128;
	tavg_rpm += (unsigned long) rpmhist[rpmhist_index_norm];
      } /* for */
      vfd_draw_rpmhistory( bitmap, rpmhist, rpmhist_index );
  
      rpmhist_index = (rpmhist_index + 1) % 128;

      /* use time-average RPMs now on the display */
      rpm = (unsigned int) ((tavg_rpm / 4) & ~0x7);

      /* figure out graphic position */
      rpmbar = ((rpm * (x2 - x1)) / RPM_MAX) + x1;

      vfd_draw_rect( bitmap, x1, y1, x2, y2 );
      vfd_draw_filled_rect( bitmap, x1, y1, rpmbar, y2 );
      vfd_draw_num( bitmap, xtext, ytext, rpm, BLT_XOR );
      vfd_display_bitmap( bitmap );
  } /* while */

} /* vfd_test_bars */


void vfd_write_byte( int x, int y, unsigned char data ) {
  /* locals */
  register unsigned short pad, pbd, address;
  
  /* body */
  pad = 0x0000;
  pbd = 0x0003; /* BRAD | WRITE_N */

  address = ((x << 3) & 0x3F8) | (y & 0x7);
  pad |= (address << (A1_BIT - 1));
  if( address & 0x1 ) {
    pad |= A0;
  } /* if */
  if( address & 0x40 ) {     /* 0100 0000 */
    pad |= A6;
  } /* if */
  pad |= CLEAR_N;
  PADR = pad;

  pbd |= ((data & 0xC0) << (D6_BIT - 6));
  pbd |= ((data & 0x3F) << D0_BIT);
  if( vfd_dp IS 1 ) {
    pbd |= DP0;
  }
  if( vfd_wp IS 1 ) {
    pbd |= WP0;
  }

  PBDR = pbd;

  pbd &= ~WRITE_N; /* flip write_n low */
  PBDR = pbd;

  pbd |= WRITE_N; /* flip write_n high again */
  PBDR = pbd;
    
} /* vfd_write_byte */

void vfd_display_bitmap( unsigned char start[8][128] ) {
  /* vfd_display_bitmap */
  /* locals */
  int i, j;
  unsigned short pbd;

  /* body */
  for( i = 127; i >= 0; i-- ) {
    for( j = 0; j < 8; j++ ) {
      vfd_write_byte( i, j, (unsigned char) start[j][i] );
    } /* for */
  } /* for */
  if( vfd_wp IS 0 ) {
    vfd_wp = 1;
    vfd_dp = 0;
  }
  else {
    vfd_wp = 0;
    vfd_dp = 1;
  }
  vfd_write_byte( i, j, (unsigned char) start[j][i] );

} /* vfd_display_bitmap */


void vfd_clear() {
  /* vfd_clear */
  /* locals */
  unsigned short pbd;
  unsigned short pad;

  /* body */
  vfd_init();
  tach_init_itu();
  pad = 0x0001;
  pbd = 0x0003;
  
  /* blank the first page */
  pad = 0x0000;
  PBDR = pbd;
  PADR = pad;
  pad = 0x0001;
  PADR = pad;

  /* blank the second page */
  pbd = 0xC003;
  pad = 0x0000;
  PBDR = pbd;
  PADR = pad;
  pad = 0x0001;
  PADR = pad;

  /* set intensity to 100% */
  pbd = 0x3FF3;
  PBDR = pbd;
  pbd = 0x3FF2;
  PBDR = pbd;
  pbd = 0x3FF0;
  PBDR = pbd;
  pbd = 0x3FF0;
  PBDR = pbd;
  pbd = 0x3FF2;
  PBDR = pbd;
  pbd = 0x3FF3;
  PBDR = pbd;

} /* vfd_clear */

void vfd_init() {
  /* vfd_init */
  /* locals */
  
  /* body */
  /* 0000 0010 0000 0000 */
  PACR1 = 0x0200;  /* port 8 high bits all I/O */

  /* 1011 1111 1000 0000 */
  PACR2 = 0xBF80;

  /* output if 1, input if 0 */
  /* 1111 1111 1000 0111 */
  PAIOR = 0xFF87;

  /* 0000 0000 1010 0000 */
  PBCR1 = 0x00A0;

  /* 0000 0000 1010 0000 */
  PBCR2 = 0x00A0;

  /* 1111 0011 1111 0011 */
  PBIOR = 0xF3F3;
  
  /* 0000 0000 0000 0011 */
  PADR = 0x0001;

  PBDR = 0x0003;
} /* vfd_init */




void vfd_copychar( unsigned char bitmap[8][128], int x, int y, int charcode, int mode ) {
  /* vfd_copychar */
  /* locals */
  int i;
/* the VFD charmap itself (8x8 font) */
unsigned char chargen[ 128 ][ 8 ] = {
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 000 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* '-' */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 000 1111 */
  { 0, 0, 0, 0x3E, 0x51, 0x49, 0x45, 0x3E },  /* '0' */
  { 0, 0, 0, 0, 0x42, 0x7F, 0x40, 0 }, /* '1' */
  { 0, 0, 0, 0x42, 0x61, 0x51, 0x49, 0x46 }, /* '2' */
  { 0, 0, 0, 0x21, 0x41, 0x45, 0x4B, 0x31 }, /* '3' */
  { 0, 0, 0, 0x18, 0x14, 0x12, 0x7F, 0x10 }, /* '4' */
  { 0, 0, 0, 0x27, 0x45, 0x45, 0x45, 0x39 }, /* '5' */
  { 0, 0, 0, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, /* '6' */
  { 0, 0, 0, 0x01, 0x01, 0x79, 0x05, 0x03 },  /* '7' */ /* 001 0111 */
  { 0, 0, 0, 0x36, 0x49, 0x49, 0x49, 0x36 }, /* '8' */
  { 0, 0, 0, 0x06, 0x49, 0x49, 0x29, 0x1E }, /* '9' */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 001 1111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 010 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 010 1111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 011 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 011 1111 */

  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 100 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 100 1111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 101 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 101 1111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 110 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 110 1111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 111 0111 */
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0 },  /* 111 1111 */
};

  /* body */
  /* catch overflows */
  if( (x > 127) OR (x < 0) ) 
    return;
  if( (y > (63 - 8)) OR (y < 0) )
    return;

  for( i = 0; i < 8; i++ ) {
    if( ( x + i ) > 127 ) {
      continue;
    } /* if */
    switch( mode ) {
    case BLT_AND:
      bitmap[ y >> 3 ][ x + i ] &= chargen[ charcode ][ i ];
      break;

    case BLT_OR:
      bitmap[ y >> 3 ][ x + i ] |= chargen[ charcode ][ i ];
      break;
      
    case BLT_XOR:
      bitmap[ y >> 3 ][ x + i ] ^= chargen[ charcode ][ i ];
      break;

    case BLT_EQUALS:
    default:
      bitmap[ y >> 3 ][ x + i ] = chargen[ charcode ][ i ];
      break; 
    }
  }
} /* vfd_copychar */

