/*  VT1500 Device Driver for Linux, Version 1.0.5
 *  Copyright (C) 1995  M. Gutschke
 *
 *  At the time of writing my e-mail address is:
 *	Internet: gutschk@uni-muenster.de
 *  My snail mail address is:
 *	Markus Gutschke
 *	Schlage 5a
 *	48268 Greven-Gimbte
 *	Germany
 *  If you like this software, I would appreciate if you sent me a postcard
 *  from your hometown. Under the terms of the GNU general public license
 *  you are free to include this program into (commercial) software
 *  distributions (e.g. putting it onto CD-ROM); nonetheless, I would really
 *  appreciate if you dropped me a short note (sending me a sample copy of
 *  your distribution would be even more appreciated!)
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "logdos.h"

static void printstate(const char *state,int size,char *msg,...)
{
  int i;
  va_list arg;

  va_start(arg,msg);
#ifdef TERSEMESSAGES
  fprintf(stderr,"\n/* ");
  vfprintf(stderr,msg,arg);
  fprintf(stderr," */\n");
#else
  fprintf(stderr,"\n/* ");
  vfprintf(stderr,msg,arg);
  fprintf(stderr,"\n *\n * data:  ");
  for (i = 0; i < size; i++) {
     putc("  __"[((state[i]&2)>>1)+((state[i]&8)>>2)],stderr);
     putc(" _ _"[((state[i]&2)>>1)+((state[i]&8)>>2)],stderr);
     putc(" _ _"[((state[i]&2)>>1)+((state[i]&8)>>2)],stderr); }
  fprintf(stderr,"\n *        ");
  for (i = 0; i < size; i++) {
     putc("_|  "[((state[i]&2)>>1)+((state[i]&8)>>2)],stderr);
     putc("_ | "[((state[i]&2)>>1)+((state[i]&8)>>2)],stderr);
     putc("_ _ "[((state[i]&2)>>1)+((state[i]&8)>>2)],stderr); }
  fprintf(stderr,"\n *"
                 "\n * clock: ");
  for (i = 0; i < size; i++) {
     putc("  __"[((state[i]&1)   )+((state[i]&4)>>1)],stderr);
     putc(" _ _"[((state[i]&1)   )+((state[i]&4)>>1)],stderr);
     putc(" _ _"[((state[i]&1)   )+((state[i]&4)>>1)],stderr); }
  fprintf(stderr,"\n *        ");
  for (i = 0; i < size; i++) {
     putc("_|  "[((state[i]&1)   )+((state[i]&4)>>1)],stderr);
     putc("_ | "[((state[i]&1)   )+((state[i]&4)>>1)],stderr);
     putc("_ _ "[((state[i]&1)   )+((state[i]&4)>>1)],stderr); }
  fprintf(stderr,"\n */\n");
#endif
  va_end(arg);
  fflush(stderr);
  return;
}

void logDos(void)
{
  /* decode I2C encoded data stream; this information can be obtained from */
  /* running dosemu in debug mode                                          */
  /* c.f. tvcontrol.c for a summary on the I2C bus protocoll               */
  char buffer[257],hex[128],laststate[22];
  int  i,state = 0,clock = 1,data = 0,rcv = 0,start = 0,bits = 0;

  for (i = 10; i--; ) {hex[i+'0'] = i; hex[i+'a'] = hex[i+'A'] = i+10;}
  memset(laststate,0,sizeof(laststate));
  printf("static unsigned short DATA[] = {"); fflush(stdout);
  while (fgets(buffer,256,stdin))
    if (!strncmp(buffer,"outb [0x300] 0x",15)) {
      int newclock =    hex[(int)((unsigned char)buffer[16])] & 1;
      int newdata  = !!(hex[(int)((unsigned char)buffer[16])] & 2);
      if (clock == newclock && data == newdata)
	continue;
      #if 0
      fprintf(stderr,"%s",buffer); fflush(stderr);
      #endif
      state = (state&0xf0)|(((((data<<1)|clock)<<1)|newdata)<<1)|newclock;
      memmove(laststate,laststate+1,sizeof(laststate)-1);
      laststate[sizeof(laststate)-1] = state;
      clock = newclock;
      data  = newdata;
      switch (state) {
      case 0x21: /* data: low,   clock: raise */
      case 0x31: /* data: low,   clock: raise */
	break;
      case 0x22: /* data: raise, clock: low   */
      case 0x32: /* data: raise, clock: low   */
	break;
      case 0x14: /* data: low,   clock: fall  */
	/* command separator: start of data */
	state = 0x20;
	break;
      case 0x24: /* data: low,   clock: fall  */
	/* low bit */
	if (bits++ >= 8)
	  goto sync;
	rcv <<= 1;
	break;
      case 0x34: /* data: low,   clock: fall  */
      case 0x3e: /* data: high,  clock: fall  */
	if (bits++ >= 8) {
	  fprintf(stderr,"/* Read one byte */");
	  start = bits = rcv = 0; }
	break;
      case 0x07: /* data: raise, clock: high  */
      case 0x27: /* data: raise, clock: high  */
      case 0x37: /* data: raise, clock: high  */
	/* command separator: end of data */
	state = 0x00;
	break;
      case 0x28: /* data: fall,  clock: low   */
      case 0x38: /* data: fall,  clock: low   */
	break;
      case 0x2b: /* data: high,  clock: raise */
      case 0x3b: /* data: high,  clock: raise */
	break;
      case 0x2d: /* data: fall,  clock: high  */
      case 0x3d: /* data: fall,  clock: high  */
        #if PICKY
	printstate(laststate,sizeof(laststate),"Missing end of command mark");
        #endif
	/* fall thru */
      case 0x0d: /* data: fall,  clock: high  */
	/* command separator: start of data */
	if (bits)
	  printstate(laststate,sizeof(laststate),
		     "Discarding %d bit%s (0x%02x)",
		     bits,bits == 1 ? "" : "s",rcv);
	rcv = bits = 0;
	start++;
	state = 0x10;
	break;
      case 0x2e: /* data: high,  clock: fall  */
	/* high bit */
	if (bits++ >= 8) {
          #ifndef NOSYNCONLOW
	sync:
          #endif
	  if (bits > 9) {
	    printstate(laststate,sizeof(laststate),
		       "Discarding %d bit%s (0x%02x)",
		       bits-9,bits == 10 ? "" : "s",rcv & ((1 << (bits-9))-1));
	    rcv >>= bits-9; }
	  if (start) putchar('\n');
	  if (start && rcv & 1) {
	    printf("/* Reading from address: */ 0x%04x,",
		   (rcv & 0xFF)|(start ? 0x8000 : 0x0000));
	    fflush(stdout);
	    start = bits = rcv = 0;
	    state = 0x30; }
	  else {
	    printf("0x%04x,",(rcv & 0xFF)|(start ? 0x8000 : 0x0000));
	    fflush(stdout);
	    start = bits = rcv = 0; } }
	else
	  rcv = (rcv << 1) | 1;
	break;
      default:
	printstate(laststate,sizeof(laststate),"Illegal state 0x%02x",state);
	break; } }
  printf("\n0xFFFF};\n"); fflush(stdout);
  exit(0);
}
