#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#define NAME_DATA_BUF           "/dev/omr2000_driver1"
#define NAME_STA_CTL            "/dev/omr2000_driver2"
#define MMAP_SIZE2              0x2000           //  two pages sizes
unsigned char *data_buf_base,*base;
#define cutm0  999
int  autocutm0=0;                 // wait for "k" for long time, m0=0
int  atime1=1;                    // atime1=1, allowed enter time1
FILE *fp,*fp1;
int  count_int1=0;                // int_1 counter, as a timer 0~100000
int  iflookint1=0;                // if display int1 counter

int  closetime1=0;                 // close time1 temp.
int  iftestomr=0;                 // 0,1   --- telnet mode
#define testomrspeed    50        // 1/4 second

int  ofch;                        // same time, software faster to reach
                                  // judge paper_long_short point
int  testno;
int  cmdo=0,tableno=255;          // do mask or not
unsigned char mask[8000];         // 160*10*5

int  old_int1;
char c63;                         // out map filename: c63.map  64~127
int  fch=0;                       // int_0 counter,  max=100
int  job=0;
unsigned char keyin[4];           // only can readin 3 char + <0a>
unsigned char keyin_value;        // sscanf(&keyin[1],"%x",&keyin_value)
//unsigned char omrmap[150*2048]; // assume max pic_memory   fch max is f99
unsigned char *omrmap;
unsigned char dummy,aa[6400][48]; // 2048*150/48=6400
int mapip;                        // while fch==1, mapip=0; 1st block not read

#define uptime        900          // 900*5 4.5second
#define thick_err     9
#define offtime       600*200      // howlong noaction, cutoff power (10min)
#define f99           149
#define default_p14   31
int offpower,power;
int paperyes,pstatb,opstat;
int pthick0,pthick,thickc,thick8,ss;
int paper14=31;                           // ********
int pshort,plong,pdeep;
int tankup,tankdn,pstat,tankia,tanki1;    // 1,2,4,8,0x80
unsigned char reg8[9];                    // 20101224

int drea, hontinu, direct,  error, gdone,cdone;
int delaydown, papercount=0, paperstat;
int paus, pdown, speed, tankposi, tkwait, wrerr;
int e7time,t4time,ltnp,down10;
int m1count=0;

char *par_int="0809b02078203d2801160001000000";
int  par15[15];
char s41[42];
#define p3     3        // ignor  value
#define sigma  3        // bias,  edge, m20
#define sig20  3        // bias,  edge, m20
#define m5     3        // 0-m5 no 3bit out
#define p6     8        // mark minum width 8 poshort  ~15,16
#define hwmax 30
#define hw     6
int  bar,p40,p60,tpt11;
int  bip,jp,x_c,x_w,c,cc,n41,bias3;     // for cut used, ip also for bar()
char e[48]={'#'}, slip[41],bias[41],c_xpeak[41];
char f1[14], f2[70], f3[16]={"192.168.1.121"};
char version[10]={"0101227df"};

char a[99],b[512];                      // output data
char tab[160][41], p6080[41];           // p60 adjust,  p6080 dead
int  posi[160];
int  mta[108]={
0x455,0x545,0x554,0x116,0x125,0x215,0x152,0x161,0x251,0x512,0x521,0x611,
0x059,0x149,0x158,0x095,0x185,0x194,0x590,0x509,0x518,0x491,0x581,0x848,
0x815,0x905,0x914,0x851,0x941,0x950,0x446,0x464,0x644,0x026,0x206,0x224,
0x062,0x242,0x260,0x422,0x602,0x620,0x04a,0x068,0x248,0x086,0x0a4,0x284,
0x884,0x428,0x608,0x482,0x4a0,0x488,0x806,0x824,0xa04,0x842,0x860,0xa40,
0x8c0,0x530,0xe00,0x017,0x035,0x107,0x134,0x305,0x314,0x053,0x071,0x143,
0x170,0x341,0x350,0x710,0x503,0xc80,0x701,0x2c0,0x01d,0x10d,0x11c,0x0d1,
0x1c1,0x1d0,0xc11,0xd01,0xd10,0x44c,0x4c4,0xc44,0x00e,0x02c,0x20c,0x0c2,
0x0e0,0xc02,0xc20,0x08c,0x0c8,0x80c,0xc08,0x431,0x413,0x419,0x680,0x40a};
unsigned int crc,crctab[256]={
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,0x8c48,0x9dc1,
0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,0x1081,0x0108,0x3393,0x221a,
0x56a5,0x472c,0x75b7,0x643e,0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,
0xf9ff,0xe876,0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,0x3183,0x200a,
0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,0xbdcb,0xac42,0x9ed9,0x8f50,
0xfbef,0xea66,0xd8fd,0xc974,0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,
0x2732,0x36bb,0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,0xdecd,0xcf44,
0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,0x6306,0x728f,0x4014,0x519d,
0x2522,0x34ab,0x0630,0x17b9,0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,
0x8a78,0x9bf1,0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,0x8408,0x9581,
0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,0x0840,0x19c9,0x2b52,0x3adb,
0x4e64,0x5fed,0x6d76,0x7cff,0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,
0xf1bf,0xe036,0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,0x2942,0x38cb,
0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,0xb58b,0xa402,0x9699,0x8710,
0xf3af,0xe226,0xd0bd,0xc134,0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,
0x5cf5,0x4d7c,0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,0xd68d,0xc704,
0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,0x5ac5,0x4b4c,0x79d7,0x685e,
0x1ce1,0x0d68,0x3ff3,0x2e7a,0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,
0x8238,0x93b1,0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,0x7bc7,0x6a4e,
0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78};

#define  white8 8
#define  p10    9                      // median line= lowest_peak-10
#define  m60   55
#define  m40   40

int fd1,fd2,t4,next=0;
fd_set myreadfds;

int  ip1=0,ip2=0;                      // uart_data buffer pointer
char ubuf[1024];
int  usk=0,u_sendmap;                  // upload image (uart)
char ua[24];
int  fd;                               // for uart begin

#include <termios.h>                        // END with a char (<=13)
#define OMR_UART_SPEED  57600
#define MODE_OUT_IGNORE_NLCR
int speed_arr[] = {B115200, B57600, B38400, B19200, B9600, B4800};
int name_arr[]  = {115200, 57600, 38400, 19200, 9600, 4800};
void set_omr_uart_speed(int fd, int speed)
{
  int   i, status;
  struct termios  arr;
  tcgetattr(fd, &arr);
  for (i = 0; i < sizeof(speed_arr)/sizeof(int); i++) {
    if(speed == name_arr[i]) {
      tcflush(fd, TCIOFLUSH);
      cfsetispeed(&arr, speed_arr[i]);
      cfsetospeed(&arr, speed_arr[i]);
      status = tcsetattr(fd, TCSANOW, &arr);
      if(status != 0){ perror("tcsetattr fd:"); return;}
      tcflush(fd,TCIOFLUSH);
      break;
    }
  }
}

int set_omr_uart_parity(int fd,int databits,int stopbits,int parity)
{
  struct termios options;
  if(tcgetattr(fd,&options)!= 0) {
    perror("SetupSerial 1");
    return -1;
  }
  options.c_cflag &= ~CSIZE;
  switch (databits) {
    case 7:  options.c_cflag |= CS7; break;
    case 8:  options.c_cflag |= CS8; break;
    default: printf("Unsupported data size\n"); return 0;
  }
  switch (parity) {
    case 'n':
    case 'N':
          options.c_cflag &= ~PARENB;//close parity
          options.c_iflag &= ~INPCK; //close input paerty
          break;
    case 'o':
    case 'O':
          options.c_cflag |= (PARODD | PARENB);//enable odd parity
          options.c_iflag |= INPCK;//enable input parity
          break;
    case 'e':
    case 'E':                                     //even
          options.c_cflag |= PARENB;
          options.c_cflag &= ~PARODD;
          options.c_iflag |= INPCK;
          break;
    default:  printf("Unsupported parity\n"); return (-1);
  }
  switch(stopbits) {
    case 1:   options.c_cflag &= ~CSTOPB;break;
    case 2:   options.c_cflag |= CSTOPB; break;
    default:  printf("Unsupported stop bits\n"); return (-1);
  }
        options.c_cflag |= CLOCAL | CREAD;
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        options.c_oflag &= ~OPOST;
        options.c_oflag &= ~(ONLCR | OCRNL);           // ignore cr
//      options.c_iflag &= ~(BRKINT | ICRNL | INLCR | ISTRIP | IXON);
        options.c_iflag &= ~(BRKINT | ICRNL | IXON);
        tcflush(fd,TCIFLUSH);
  if (tcsetattr(fd, TCSANOW, &options) != 0) {
    perror("SetupSerial:");    return (-1);
  }
  return 0;
}                                             // for uart end

static void omr2000_handler( int signo )      // 5ms interupt
{
  int k;
  struct timeval tv_value;

  unsigned char c;
  for(k=0;k<9;k++)reg8[k]=base[0x1000+k];            // 20101224
  c=(reg8[0]>>1)&6;  reg8[0]&=0xf9;   reg8[0]|=c;    // re_order C31 format
  c=0; if(reg8[1]&1)c|=0x80; if(reg8[0]&2)c|=0x40; reg8[1]=c|(reg8[8]&0x3f);

  t4++; t4&=3;
  if(t4==0){
    if(next)next--;  if(base[0x1000]&0x08)next=4;
    if(next){
      FD_ZERO(&myreadfds); FD_SET(fd1, &myreadfds);
      tv_value.tv_sec = 0; tv_value.tv_usec = 8000;          //8ms timeout
      k = select(fd2, &myreadfds, NULL, NULL, &tv_value);
      if((k > 0) && (FD_ISSET(fd1, &myreadfds)))  {
l10:
        fch++; if(fch==1){ mapip=0;   c63++;  if(c63>=128)c63=65; }
        k = read(fd1, omrmap+mapip, 2048);
        if(k){  mapip+=k; if(mapip>f99*2048)mapip-=2048; goto l10; }
        else fch--;
      }
    }
    if(next==1){ for(k=1;k<=48;k++)omrmap[mapip-k]=0x7f;
      if(fch>3)ofch=fch;  fch=0; }
  }

  count_int1++; if(count_int1==100000)count_int1=0;
  if(count_int1%2000==0){
    if(iflookint1)printf("int_1 coming 2000 times(10s)\n");
  }
  if(closetime1)closetime1--;              // for uart 'd' command
  if( atime1 && closetime1==0) time1();
  if(usk){                      // uart upload image, 5ms_24 byte = 4.8k/s
    k=24; if(usk<24)k=usk; usk-=k;                  // may k=25~28
    write(fd,&omrmap[u_sendmap],k); u_sendmap+=k;
  }
  if(ip1!=ip2){  k=0;                       // uart upload data
lip:
    ip2++; ip2&=0x3ff; ua[k++]=ubuf[ip2];
    if(ip1!=ip2 && k<24)goto lip;
    write(fd,ua,k);
  }
}

putubuf(char *a, int len)
{  int i;  for(i=0;i<len;i++){ ip1++; ip1&=0x3ff; ubuf[ip1]=a[i]; } }

main()
{
  struct sigaction sigact, oldact;
  omrmap=(char *)aa-1;                             // map_data_array
  sigact.sa_handler = omr2000_handler;
  sigemptyset(&sigact.sa_mask );
  sigact.sa_flags = 0;
  if(sigaction(SIGIO,&sigact,&oldact)<0){perror("sigaction error");exit(0);}
  fd2 = open(NAME_STA_CTL, O_RDWR | O_NONBLOCK);
  if(fd2<0){ printf("open /dev/omr2000_driver2 failed\n"); return (-1); }
  else { base =
         (char *)mmap(0,MMAP_SIZE2,PROT_READ|PROT_WRITE,MAP_SHARED,fd2,0);
    if(base==0){ close(fd2); return(-1); }
    fcntl(fd2, F_SETOWN, getpid());
    fcntl(fd2, F_SETFL, fcntl(fd2, F_GETFL) | FASYNC);
  }
  fd1 = open(NAME_DATA_BUF, O_RDWR | O_NONBLOCK);
  if(fd1<0){
    printf("open /dev/omr2000_driver1 failed\n"); close(fd2);
    munmap((void*)base,MMAP_SIZE2);  return (-1);
  }
  fd2 = fd1+1;

  fd = open("/dev/ttyAM1", O_RDWR | O_NOCTTY | O_NONBLOCK);  // for uart
  if (fd== -1) { perror("Can't Open Serial Port"); exit(0); }
  set_omr_uart_speed(fd, OMR_UART_SPEED);
  if(set_omr_uart_parity(fd,7,1,'O') < 0)  {
    printf("Set Parity Error\n"); exit (0);
  }

  base[0x1807]=0x80;  getpar();                    // here need delay
  fp=fopen("table.dat","rb");
  if(fp){ fread(mask,1,8000,fp); fclose(fp); swap4(mask,8000); }
  base[0x1807]=0;                delayms(200);     // reset reg.
  base[0x1805]=power=255;                          // power on
  clearh_err();       delayms(200);
  base[0x1800]=base[0x1802]=0;
  param15();
  ss=paper14; c63=64;
  base[0x1806]=0x80;                               // 20101227
CUT1:
  if(hontinu==255)hontinu=0;
  if(paperstat)write_paper();
  ifkey();                                         // telnet keyboard in
  ifuart();                                        // uart   char     in
  write_error(0); if(error)goto CUT1;
  if(fch<4)goto CUT1;
  if(iftestomr)testomr(); else if(cdone==0 && fch<f99) cut();
  goto CUT1;
}

getpar()
{
  int i;
  fp=fopen("w.dat","rb");   if(fp)fclose(fp);
   else { fp=fopen("w.dat","wb"); for(i=1;i<42;i++)s41[i]=0;
   s41[0]=default_p14; fwrite(s41,1,42,fp); fclose(fp); }
  reads41();

  fp=fopen("p15.dat","rb"); if(fp)fclose(fp);
   else { fp=fopen("p15.dat","wb"); fwrite(par_int,1,30,fp); fclose(fp); }

  fp=fopen("map_upip.dat","r");  if(fp){ fgets(f3,16,fp); fclose(fp);
  for(i=0;i<16;i++)if(f3[i]<=32){ f3[i]=0; break; } }
}

reads41()
{
  fp=fopen("w.dat","rb");
   fread(s41,1,42,fp);
   paper14=s41[0];
   fclose(fp);
}

int kb_string(unsigned char *key_value)
{
  int slen;
  slen = fcntl(STDIN_FILENO, F_GETFL, 0);
  if(slen < 0) { printf("get stdin_fileno state failed\n"); return (-1); }
  else {
    slen |= O_NONBLOCK;
    if(fcntl(STDIN_FILENO, F_SETFL, slen) < 0) {
      printf("change stdin_fileno state failed\n");
      return (-2);
    }
  }
  slen = read(STDIN_FILENO, key_value, sizeof(key_value));
  return(slen);
}

ifkey()
{
  int i,j,k;  unsigned char c;
  k = kb_string(keyin);  if(k<2)return;
  c=keyin[0];
  if(k>2){  keyin[k]=0; sscanf(&keyin[1],"%x",&keyin_value); }
  if(c=='?'){
    printf("**0    paper-club motor control  00/01/02\n");
    printf("**1    if look counter of int_1\n");
    printf("**6/7  set area/speed                 ?XX\n");
    printf("**8/9  set motor/clutch enable     ?80/00\n");
    printf("**a/b  show all_state/version\n");
    printf("**c    save map\n");
    printf("**d    test_OMR_GDT           d00/d14/dXX\n");
    printf("**e    inquire ERR message\n");
    printf("**h    countine scan\n");
    printf("**i/j  stop_motor/show_paper_counter\n");
    printf("**k    one_paper scan\n");
    printf("**l/m  show slip/real_paper_thick\n");
    printf("**q/r  QUIT/clear_ERROR\n");
    return; }
  if(c=='0'){                                 // order tank stop/up/down
    if(keyin_value == 1)  {
      if(tankup==0) base[0x1806] = 0xc0;
    } else if(keyin_value == 2) {
      if(tankdn==0) base[0x1806] = 0x80;
      base[0x1800]=base[0x1802]=fch=0;
    } else base[0x1806] = 0; return; }
  if(c=='1'){ iflookint1=1-iflookint1; return; }  // if look int_1 or not
  if(c=='6'){ base[0x1405] = keyin_value; return; }
  if(c=='7'){ base[0x1407] = keyin_value; return; }
  if(c=='8'){ base[0x1800] = keyin_value; return; }
  if(c=='9'){ base[0x1802] = keyin_value; return; }
  if(c=='a'){                        // display stat_reg
    for(i=0;i<8;i++)printf("%02x ",reg8[i]);
    printf(" job_%d fch_%d t4t_%d psh_%d ip: %d_%d\n",
             job,fch,t4time,pshort,ip1,ip2);
    return; }
  if(c=='b'){ printf("version: %s\n",version); return; }
  if(c=='c'){                        // save memory pic as file
    sprintf(f1,"/tmp/%03d.map",c63);
    printf("file_len: %d     named: %s\n",mapip,f1);
    fp=fopen(f1,"wb"); fwrite(omrmap,1,mapip,fp); fclose(fp);
    sprintf(f2,"/usr/bin/tftp -p -l %s -r %s %s &",f1,&f1[5],f3);
    if(fork() == 0){ system(f2); exit(1); } else wait(&k);

      sprintf(f1,"/tmp/%03d",c63);
      sprintf(f2,"/usr/bin/tftp -p -l %s -r %s %s &",f1,&f1[5],f3);
      if(fork() == 0){ system(f2); exit(1); } else wait(&k);
      sprintf(f2,"ls -l %s\n",f1);
      if(fork() == 0){ system(f2); exit(1); } else wait(&k);

      sprintf(f1,"/tmp/000");
      fp=fopen(f1,"wb"); fwrite(ubuf,1,1024,fp); fclose(fp);
      sprintf(f2,"/usr/bin/tftp -p -l %s -r %s %s &",f1,&f1[5],f3);
      if(fork() == 0){ system(f2); exit(1); } else wait(&k);
        printf("%d \n",ip1);

    printf("send_file done!\n");
    return; }
  if(c=='d'){ iftestomr=1;    old_int1=atime1=0;
              testno=keyin_value; if(testno>30)testno=30;
              j=testno+22;  if(j>41)j=41;
              for(i=testno;i<j;i++)printf("%02d ",i); printf("\n");
              for(i=testno;i<j;i++)printf("---"); printf("\n");
    return; }   // testomr
  if(c=='e'){ wrerr=255; return; }   // inqure error mess
  if(c=='h'){                        // continue 'k'
    speed=255;
    if(hontinu)hontinu--; if(hontinu>10)hontinu=255;
    if(pstat)kinh(0); return;  }
  if(c=='i'){ error=9; base[0x1800]=base[0x1802]=0; return; } // pc want stop M
  if(c=='j'){                        // write_down total paper_counter
    fp=fopen("p_count.dat","r");
    if(fp){ fscanf(fp,"%d",&j); fclose(fp); printf("paper_count: %d\n",j); }
    else printf("paper_count: < 30 \n"); return; }
  if(c=='k'){                        // normal scan command
    if(error || job==0){ speed=0; hontinu=255; kinh(1); } return; }
  if(c=='l'){ for(i=1;i<n41;i++)printf("%d ",slip[i]); printf("\n"); return; }
  if(c=='m'){ printf("ss: %d\n",ss); return; }
  if(c=='q')exit(0);     // exit
  if(c=='r'){ clearh_err(); hontinu=wrerr=255; return; }  // clear err
}

kinh(int k)
{
  if(k==0 || paus)goto kinh0;
paozi:
  base[0x1800]=base[0x1802]=0x80;
kinh0:
  write_error(1);  if(error)clearh_err();
  gdone=paus;    paus=255;   error=0;
  if(base[0x1000]&0x88)goto paozi;    // ia,i1
}

clearh_err()
{
  base[0x1800]=0x80;
  iftestomr=atime1=0;
  while( base[0x1000]&0x88)delayms(1);
  atime1=1;
  paus=tkwait=paperstat=255; error=0;
  job=cdone=fch=0;
}

delayms(int k)            // unit: 1.02 mili_second
{ int i; float x; for(i=0;i<k*8;i++)x=sqrt(2.); }

param15()
{
  short i;
  fp=fopen("p15.dat","rb");
  fread(b,1,30,fp); fclose(fp);
  for(i=0;i<15;i++) sscanf(&b[i*2],"%2x",&par15[i]);

  base[0x1809]  =255;             // ifcutm2 on
  base[0x1405]  =par15[0];        // area
  base[0x1407]  =par15[1];        // speed
//  base[0x1406]  =par15[2];      // long       origion: fe
//  base[0x1404]  =par15[3];      // short                0
  plong=f99;                      // 2
  pshort=20;                      // 3
  pdeep=20;                       // not use yet
  pthick=255;                     // if(par15[4]==0)not detect thick,
  if(par15[4])pthick=paper14*par15[4]*15/1000;    // if>pthick, stop
                                 // threshold enlarge 1.5 times
  pdown=par15[5]<<4;
  p60=par15[6];
  p40=par15[7];
  bar=par15[8];
//  delaym1=par15[9];
  tpt11=par15[10];
}

write_error(int k)
{
  char c='%',c2[3];                                    //  20101224
  if(k||wrerr){
    printf("%c%d",c,error);
    sprintf(c2,"%c%d",c,error); write(fd,c2,2);        //  20101224
    wrerr=0; write_paper();
  }
}

write_paper()                                          //  20101224
{
//  if(pstat)printf("+\n"); else printf("-\n");
  char c;   if(pstat)c='+'; else c='-';
  printf("%c\n",c);  write(fd,&c,1);
  paperstat=0;
}

time1()                             // interupt,  5ms once
{
  atime1=0;                         // disable int1
  if(delaydown)delaydown--;
  tankop(0);
  if(m1count)m1count--; else AUTOCR();
  if(error){  base[0x1800]=base[0x1802]=0; }
  if(pstat==0 && hontinu==2)base[0x1802]=paus=0;
  atime1=1;                         // enable int1
}

AUTOCR()
{
  int i,r0,r1;
  if(job==0 && fch==0 && (base[0x1000]&0x40)){
    autocutm0++; if(autocutm0>cutm0) base[0x1800]=0;
  } else autocutm0=0;
  if(job)goto AUTO;                // job only using this route
  if(gdone==0 || hontinu>1)return; // if 'k', gdone!=0, hontinu!=0
  gdone=0;
  if(pstat==0)return;              //     if no paper
  pthick0=base[0x1008];            // take paper_bias
  job=4;  thickc=0; t4time=999;    // set job, jin_zi time
  if(pthick0==0)base[0x1008];
AUTO:
  if(job==5)goto taske;            // job:  when gdone!=0, 4-->job, 0-->gdone
taskd:                             // job=4
  if(drea==0 && tankup==0)return;  // check Pon, if not rets
  t4time--;  if(t4time==0){
//    printf("up_%d dn_%d pstat_%d ia_%d i1_%d\n",
//            tankup,tankdn,pstat,tankia,tanki1);
    if(pstat)perr(3); else job=0;
    return; }
  if(t4time==998)base[0x1800]=base[0x1802]=0x80;  // open motor M0,M2
  if(tankia)base[0x1802]=0;        // if ia, stop M2, ifcutm2..
  delaydown=120;
  if(tanki1==0)return;             // wait I1=1
  job=5;  papercount++; thick8=0;
  return;

taske:                             // job=5
  thick8++;
  if(thick8>10){
    r1=pthick0-base[0x1008];
    if(r1>pthick){ thickc++;
      if(thickc>thick_err){ perr(6); return; }   // check paper
    } else { thickc=0;
      if(thick8==18){ if(r1<0)thick8--; else ss=r1; }
    }
  }
  if(fch>plong ){ perr(4);  return; } // check_long
  if(tankia || tanki1)return;         // if ia =0 or i1=0
// sometime soft finished early than here, so fch==0 already
  r0=fch; if(r0==0)r0=ofch;
  if(r0<pshort){ perr(5);  return; } // check_short
  pshort=r0-10; plong=r0+10; if(plong>f99)plong=f99;
  if(pthick!=255)renew_pthick();      // if pthick=255, not detect gram
//  cdone=job=fch=0;
  cdone=job=0;
  if(speed){ hontinu++; gdone=255; m1count=par15[9]; }
}

tankop(int k)
{                               // k= 0/1, if(1)downonly
  int r0,r1;
l000:                           // for get I1 correct
  r0=base[0x1000];
// tank up & down;
  tankup=   r0&1;
  tankdn=  (r0&2)?1:0;
  paperyes=(r0&4)?1:0;
  tankia=  (r0&8)?1:0;
  tanki1=  (r0&0x80)?1:0;
  r1=base[0x1000];
// get paperyes,pstat
  pstatb=((pstatb<<1)+paperyes)&31;
  if(pstatb==0)pstat=0; if(pstatb==31)pstat=1;
  if(r0!=base[0x1000] || r0!=r1 )goto l000;
// off_power: if(pstat not chang for a long time & job=0)off_power
  if(pstat==opstat && job==0)offpower++; else offpower=0;
  opstat=pstat;
  if(offpower==0 && power==0)base[0x1805]=power=255;       // open power
  else {                                        // down, up a little, close
    if(offpower==offtime-600)if(tankdn==0)base[0x1806]=0x80;
    if(offpower==offtime-12)base[0x1806]=0xc0;
    if(offpower==offtime)base[0x1805]=base[0x1806]=power=0;
    if(offpower>=offtime-600)return;            // close all
  }
// tankposi:  =0_down,  =2_up;   =1 wait a little ( put or get paper in run);
// while start down, off M2
  if(k)goto tankdown1;
  if(tkwait!=1 || paperyes)goto tankop11;
  if((base[0x1003] & 4)==0)goto downagain;      // if tank  power ?
tankop11:
  ltnp++; if(ltnp!=700)goto tankop10;           // 4 second
  if(tankposi!=1)goto tankop10;
downagain:
  base[0x1806]=0x80;                            // down --->
  tankposi=0; tkwait=255;
tankop10:
  if(down10)down10--;
  if(paperyes)goto tankop0;
  if(down10==70)base[0x1802]=0;
  if(down10==1)base[0x1800]=base[0x1806]=0;
tankop0:
  if(down10)return;
  if(tankposi)goto tankop1;                     // if paper yes while down
  if(pstat==0)goto tankop1;
  base[0x1800]=0;
  goto paper3;
tankop1:
  if(delaydown)tkwait=delaydown;
  if(tankposi!=2)goto tankwait;
  if(tankup)goto tankwait;
  if(pstat)goto tankwait;
  tkwait=pdown;
  tankposi=0;                                   // downtank
  goto tankdown1;
tankwait:
  if(tankposi)goto tankwait0;
  if(pdown-tkwait==128)base[0x1802]=0;
tankwait0:
  if(tkwait)tkwait--;
  if(tkwait)return;
  if(error || tankposi==0)base[0x1800]=0;
  if(pstat)goto paper_yes;               // to see if no paper
  if(tankposi)goto tankdown;
  if(tankup)goto tankdown;
  base[0x1802]=job=drea=0;
  return;
tankdown:                                       // if(np&posiyes) down
  if(job==0)goto tankok;
  if(job==4)return;
  if(tanki1)return;
tankok:
  if(drea==0)goto tankok1;
  drea-=15;
  if(drea)return;
tankok1:
  if(paperyes)base[0x1802]=0;
  tkwait=pdown;
  tankposi=0;
tankdown1:
  if(direct==0)goto tankdown11;
  if((base[0x1003] & 2)==0)goto tankdown11;      // moving ?
  paperstat=255;
  base[0x1806]=0;
tankdown11:
  direct=0;
  base[0x1806]=0x80;
  drea=0;
  down10=90;     // tank down how deep ?  more big more deep
  e7time=0;
//     base[0x1800]=0;
  if(papercount<100)return;
  fp1=fopen("p_count.dat","r");
  if(fp1){ fscanf(fp1,"%d",&r0); fclose(fp1); } else r0=0;
  fp1=fopen("p_count.dat","w");
  r0+=papercount;
  fprintf(fp1,"%d",r0); fclose(fp1);
  papercount=0;
  return;
paper_yes:
  ltnp=0;  if(error)return;             // if error, no UP
  if(tankposi)goto uptank;
paper3:
  tkwait=pdown>>1;
  tankposi=1;
  return;
uptank:
  if(tankposi==2)goto up_00;
  tankposi=0;
  if(pstat==0)return;
  tankposi=2;
  down10=128;
up_00:
  if(direct==255)goto up_000;
  paperstat=255;
  if((base[0x1003] & 2)==0)goto up_000;     // moving ?
  base[0x1806]=0xc0;
up_000:
  direct=255;
  base[0x1806]=0xc0;
  if(tankup==0)goto up_01;
  e7time=0;
  return;
up_01:
  e7time++;
  if(e7time>uptime)perr(7);
}

perr(int k)
{
  error=k;
  job=cdone=base[0x1800]=base[0x1802]=fch=0;
  tankposi=1;
  wrerr=tkwait=255;
//  param15();
  plong=f99; pshort=20; pthick=255;   
  if(par15[4])pthick=paper14*par15[4]*15/1000;    
  tankop(1);                                // do tankdown only
}

renew_pthick()
{
  int r1,r3,r4;
  r1=(ss*51)>>5; r3=pthick<<1; r4=pthick>>1;
  if(r1>r3)r1=r3; if(r1<r4)r1=r4;
  pthick=(pthick*3+r1)>>2;
}

cut()
{
  int i,j,k,l, k20,k33, nx,ns,ipeak,xpeak,xpeak0,x_w0;
  int ipp,dp,dx,sx,sz,shift,blank_line;
  char  m42,m441,m442,m45,m47,points, warning, sort[9];

  if(hontinu==255)hontinu=0;
  ipp= blank_line= jp= nx=  crc=0;
  n41=41;  shift=64;
  m42=m45=m47=m441=0; m442=63;

  for(i=0;i<n41;i++){ bias[i]=p60; slip[i]=0; }
  for(i=0;i<160;i++)for(j=0;j<41;j++)tab[i][j]=0;
    sprintf(f1,"/tmp/%03d",c63);
    fp1=fopen(f1,"wb");
  sprintf(f1,"%03d.map",c63);
L99:
  ipeak=0;
L3:
  if(next==0 || error )goto L10;                 // map total arrived
                                                 // 20101227
  if((fch-2)*2048/48<nx) goto L3;                // data not arrived yet
L10:
//    if(next==1)printf("%d\n",nx);
  nx++;  cc=aa[nx][0];
  if(cc>63 || nx>6399 || error ){                // 20101227
    i=0;  if(m441-m442>=2)i=1;
    j=0;  if(m441>0x2c+3 || m442<0x2c-3)j=1;
    a[0]='*';   a[1]=error;
    warning=m42;
    if(m441>47 || m442< 41)warning|=2;
    if(m441-m442>=2)warning|=4;
    if(m45)warning|=8;
    if(m47)warning|=16;
    a[2]=warning;
    a[3]=crc&0x7f; a[4]=(crc>>8)&0x7f;    // crc
    a[5]=shift;
    a[6]=ofch;   a[7]=0;                   // paper_length
    a[8]=ss*100/paper14; a[9]=0;          // paper_gram
    a[10]=c63;
    a[11]=aa[0][43];
    putubuf(a,12);
      fwrite(a,1,12,fp1);
    if(bar)do_bar();
    if(jp)printf("produce file: %s black_mark: %d\n",f1,jp-1);
      fclose(fp);
    return;
  }
  if((aa[nx][47]&0x3f)!=63){
     printf("******bad_pic %d line \n",nx);
//     error=9;
     cdone=1; return; }
  if(nx<255){
    if(aa[nx][41]<=0x20)m42=1;
    if(aa[nx][43]> m441)m441=aa[nx][43];
    if(aa[nx][43]< m442)m442=aa[nx][43];
    if(aa[nx][44]>1)    m45=1;
    if(aa[nx][46]< 0x3e)m47=1;
  }
  if(cc+2>=p40 && ipp==0)goto L3;              // for 1ST black
  ipp=255;
  if(jp==0){                                   // find 1st mark
    for(i=0;i<n41;i++) if(bias[i]>aa[nx][i])bias[i]=aa[nx][i];
    if(cc>p40 && ipeak==0){  ipeak=1;  ns=nx-1; }     // find left_edge
    if(ipeak==1 && cc<p40) {                          // find right_edge
      x_c=xpeak=(ns+nx)>>1;  x_w=6;
      if(nx-ns <p6 )goto L99;
      for(i=1;i<n41;i++){                             // cal slip
        k=sx=cc=0;
        for(j=xpeak-x_w;j<=xpeak+x_w;j++){
          sz=aa[j][i];  if(sz>cc)cc=sz;
          k+=(sz*j);    sx+=sz;
        }
        if(sx<1)sx=1;   xpeak=(k*2/sx+1)>>1;
        slip[i]=xpeak-x_c;                             // if end
        l=aa[xpeak][i]-cc;
        if(l<0)l=-l; if(l>sigma)slip[i]=slip[i-1];
        cc=cc*3/4; l=0; k=xpeak-30; if(k<10)k=10;
        for(j=xpeak;j>k;j--)if(cc>aa[j][i])goto l31;
        l=1;
l31:
        if(l!=1)l=l; else slip[i]=slip[i-1];
        if(i==15 && l==1)goto l30;                     // no black line
        if(i>15 && l==1 && aa[xpeak][i]>=p40)break;
      }
      n41=i-1; blank_line=1;
l30:
      if(blank_line==0)for(i=0;i<n41;i++)slip[i]=s41[i+1]; jp=1;
    }
  }
  if(jp!=0){
    if(cc>p40 && ipeak==0){  ipeak=1;  ns=nx-1;    }   // find left
    if(ipeak==1 && cc<p40) {                           // find right
      xpeak0=xpeak;    xpeak=(ns+nx)>>1;
      posi[jp]=xpeak;  if(nx-ns <p6 )goto L99;         // for fine line
      x_w=(nx-ns)>>1;  if(x_w>hwmax)x_w=hwmax;
      if(nx-ns-3 > dp && tpt11==1 && jp>3){
        xpeak=xpeak0; nx=xpeak+(dp*5)/4;  xpeak0=nx+dp/2;
        for(i=nx;i<xpeak0;i++)aa[i][0]=bias[0];
        goto L3;
      }
      l=xpeak-xpeak0;
      if(jp==2){ dp=l; dx=nx-ns+3; }
      if(jp==3 && l<dp){ dp=l; dx=nx-ns+3; }
      if(tpt11==1 && jp>3 && nx-ns>dx) xpeak=xpeak0+dp;
      if(jp==1){
        p40=(aa[xpeak][0]-bias[0])/2+bias[0];
        if(p40>45)p40=45; if(p40<36)p40=36;
      }
      for(i=1;i<n41;i++){
        if(p60-bias[i]<10){ n41=i; break; }
        k=xpeak+slip[i];
        c= points=0; bias3=3*(p60-bias[i])/15+bias[i];  // find peak
        for(j=k-x_w;j<=k+x_w;j++){
          if(aa[j][i]>c){ c=aa[j][i]; x_c=j; }          // find posi
          if(aa[j][i]>bias3)points++;
        }
        calcck20(i);
        if(cc<=1){
          l=0; for(j=k-4;j<=k+4;j++)sort[l++]=aa[j][i];
          for(j=0;j<8;j++)for(l=j+1;l<9;l++)if(sort[j]>sort[l]){
            k20=sort[l]; sort[l]=sort[j]; sort[j]=k20;
          }
          j=bias[i]-sort[4]; if(j<0)j=-j;
          bias[i]=(j<=sigma)?sort[4]:(bias[i]+sort[4])/2;
        }
        if(cc<p3)cc=0; else if( points*3 < x_w*2 )jduge(i,k);
        if(cc>m5){
          k20=findk(i,20);   k33=findk(i,33); if(k20==0)k20=1;
          k=40-(k33*24/k20); k=findk(i,k);
          l=k/6; if(l>7)l=7; l<<=4;   cc|=l;
        }
        a[i]=cc; c_xpeak[i]=x_c-xpeak;
      }
      for(j=n41-1;j>2;j--)if(a[j]!=0)break;
      enmask(j,jp,blank_line);
      encom(j);
      if(blank_line==0)goto l50;
      for(i=1;i<=j;i++)if(a[i]==0)goto l50;
      shift=c_xpeak[j]-slip[j];
l50:
      if(jp<159)jp++;  ipeak=0;
    }
  }
  goto L3;
}

jduge(int i,int k)
{
  int j;
  if(aa[k-x_w][i]>=bias3){
    for(j=k-x_w;j>=k+2*x_w;j--){
      if(aa[j][i]>c)c=aa[j][i]; if(aa[j][i]<bias3){ calcck20(i); return; }
    } cc=0;
  }
  if(aa[k+x_w][i]>=bias3){
    for(j=k+x_w;j<=k+2*x_w;j++){
      if(aa[j][i]>c)c=aa[j][i]; if(aa[j][i]<bias3){ calcck20(i); return; }
    } cc=0;
  }
}

calcck20(int i)
{
  int j;
  cc=(c-bias[i])*15/(p60-bias[i]);  if(cc>15)cc=15; if(cc<0)cc=0;
  j=cc; if(j<10)j=0; tab[jp][i]=j;            // for bar
}

int findk(int i, int kk)
{
  int j,k,m20,m80;
l20:
  k=0;
  m80=(c-bias[i])*9/10+bias[i];
  m20=(c-bias[i])*kk/100; if(m20<sig20)m20=sig20; m20+=bias[i];
  for(j=x_c;j>x_c-p60;j--){
    if(aa[j][i]<m80)k++; if(c<aa[j][i]){ c=aa[j][i]; goto l20; }
    if(aa[j][i]<m20)break;
  }
  for(j=x_c;j<x_c+p60;j++){
    if(aa[j][i]<m80)k++; if(c<aa[j][i]){ c=aa[j][i]; goto l20; }
    if(aa[j][i]<m20)break;
  }
  return(k);
}

do_bar()
{
  int i,j;
  for(j=2;j<jp-1;j++) for(i=1;i<n41;i++){
    if(tab[j][i]==0)continue;
    if(tab[j-1][i]+tab[j+1][i]==0)tab[j][i]=0;
  }
  a[0]='&';  bip=2;
  for(j=2;j<jp-8;j++)                     // 2nd line -- marks-8 line
    for(i=1;i<n41-1;i++)if(tab[j][i]!=0)search(i,j);
  a[1]=bip-2;
  putubuf(a,bip);
    fwrite(a,1,bip,fp1);
}

search(int i,int j)
{
  int jj,k,bipsave,row1,row2,row3;
  for(k=j;k<jp;k++){ tab[k][i-1]=0; if(tab[k][i]==0)break; tab[k][i]=0; }
  row1=posi[j];   row2=posi[k--];
  if(k+1!=jp){ if(row2-row1<150)return;} else row2=row1+350;
  bipsave=bip;  a[bip++]=j; a[bip++]=i;
  jj=mark(row1,row2,i,bip); a[bip++]=jj;
  row1=i+1; if(row1>=n41)row1=n41-1;
  row2=i+2; if(row2>=n41)row2=n41-1;
  row3=i+3; if(row3>=n41)row3=n41-1;
  if(jj==0 || jj==4)
    for(jj=j;jj<=k;jj++)tab[jj][row1]=tab[jj][row2]=tab[jj][row3]=0;
  else bip=bipsave;
}

int mark(int row1,int row2,int col)
{
  int i,j,k,l,bs, zm,row,mz,zp, checkcode, codesort, rsh[100],slp[100];
  row=row2-row1+60;                                 // row1-30  row2+30
  for(i=0;i<row;i++)b[i]=aa[row1-30+i][col];
  mz=m60;
  for(i=0;i<row-10;i++){
    if(b[i]<m40 || b[i]<b[i-1] || b[i]<b[i+1])continue; if(b[i]<mz)mz=b[i];
  }
  bs=0;
  for(i=60;i<row-60;i++){
    if(b[i]>=mz || b[i]>b[i-1] || b[i]>b[i+1])continue; if(b[i]>bs)bs=b[i];
  }
  bs=(mz-bs+1)/2; if(bs>p10)bs=p10; zm=mz-bs;
  zp= j= slp[0]=0;
  for(i=0;i<row;i++){
    if(zp==0 && b[i]<zm)continue;                  // head
    if(zp==0){ zp=1;  slp[j++]=calm(i,zm); }
    if(zp==1){ if(b[i]<zm){ slp[j++]=calm(i,zm); zp=2; } continue; }
    if(zp==2)  if(b[i]>zm){ slp[j++]=calm(i,zm); zp=1; }
  }
  j--; for(i=1;i<j;i++)rsh[i-1]=(slp[i]-slp[i-1]+17)/33;
  l=0; k=j; if(rsh[1]>white8)l=2; if(rsh[k-2]>white8)k=k-2;
  mz=(k-l)/6;
  if(mz==0){ printf("bad_bar_data\n"); return; }
  zm=(slp[mz*6+l]-slp[l])/(11*mz);
  for(i=l+1;i<=k;i++){
    bs=slp[i]-slp[i-1];
    if(bs<(zm*3/4)){ bs=(zm-bs)/2; slp[i]+=bs; slp[i-1]-=bs; }
  }
  j=0; for(i=l+1;i<=k;i++)slp[j++]=slp[i]-slp[i-1];
  if(slp[3]<slp[j-4])                              // reversed
    for(i=0;i<j/2;i++) { bs=slp[i]; slp[i]=slp[j-i-1]; slp[j-i-1]=bs;}
  for(i=0;i<j-1;i+=6){
    zp=(slp[i]+slp[i+1]+slp[i+2]+slp[i+3]+slp[i+4]+slp[i+5]+zm/2)/11;
    for(l=i;l<i+6;l++){
      slp[l]=(slp[l]+zp/2)/zp; if(slp[l]==0)slp[l]=1; if(slp[l]>=5)slp[l]=4;
    }
  }
  for(i=zp=l=0;i<j;i+=6){
    bs=0; for(k=0;k<6;k++){bs<<=2; bs|=slp[l++]-1;}  slp[zp++]=bs;
  } zp--;
  checkcode= l= bs=0;
  for(i=0;i<zp;i++){
    for(j=0;j<107;j++)if(slp[i]==mta[j])goto l10;
    return(1);
l10:
    slp[l++]=j;
  } l--;
  codesort=slp[0]-102;
  if(codesort<1 || codesort >3)return(2);        // no head
  if(slp[l]!=106)return(3);                      // no end
  for(i=1;i<l;i++)checkcode+=slp[i-1]*(i-1);  checkcode+=slp[0];
  checkcode%=103;
  l--;  if(checkcode!=slp[l])bs=4;               // err of check code
  for(i=1;i<l;i++)
  if(codesort==3){
    if(slp[i]==102)continue;                     // 40923 for UCC/EAN
    if(slp[i]>=100)codesort=2;
    else { a[bip++]=slp[i]/10+48; a[bip++]=slp[i]%10+48; }
  } else { if(slp[i]==99)codesort=3; else a[bip++]=slp[i]+32; }
  return(bs);
}

int calm(int i,int zm)
{
  if(b[i]==b[i-1])return i*10;
  return  i*10-(b[i]-zm)*10/(b[i]-b[i-1]);
}

enmask(int jj,int ip,int blank_line)
{
  int i,j,k,l; unsigned char m;
  if(cmdo==0 || blank_line==0)return;
  if(ip==2){ tableno=255;
    j=k=0; for(i=1;i<=jj;i++)if((a[i]&0xf)>10){ k++; j=i;}
    if(k>1)return;        // in 2nd line, only 0~1 mark
    if(j>9)return;        // only <=10 tables, mark posi <10
    tableno=j;
    return;
  }
  if(tableno==255)return;
  k=(tableno*160+ip-1)*5;
  for(i=0,j=1;i<5;i++){
    m=mask[k+i];
    for(l=0;l<8;l++){ b[j++]=m&0x80?0x7f:0; m<<=1; }
  }
  for(i=1;i<=jj;i++)a[i]&=b[i];
}

encom(int jj)
{
  int i,j,k,l,m;
  char d[7]={64,32,16,8,4,2,1};
  for(i=0;i<322;i++)b[i]=0; j=0;
  for(i=1;i<=jj;i++){
    if(a[i]){ b[j++]=1; for(k=0;k<7;k++)b[j++]=(a[i]&d[k])?1:0; }  else j++;
  }
  k=(j-1)/7+1; for(i=j=0;i<k;i++){ for(l=m=0;l<7;l++)m=m*2+b[j++]; e[i+2]=m; }
  for(i=k+1;i>1;i--)if(e[i])break;
  k=i+1;  e[1]=k-2;
  if(k>4 && e[2]==0 && e[3]==0){
    for(i=4;i<k;i++)if(e[i])break;
    e[2]=i-2; l=3;  for(j=i;j<k;j++)e[l++]=e[j];
    k=l; e[1]=k+62;
  }
  for(i=0;i<k;i++)crc=(crc>>8)^crctab[(crc^e[i])&0xff];
  putubuf(e,k);
   fwrite(e,1,k,fp1);
}

testomr()
{
  int i,j,k;
  if(count_int1 - old_int1 < testomrspeed)return;
  old_int1=count_int1;  k=mapip+100;
  for(i=0;i<99;i++)a[i]=omrmap[k+i];
  for(k=0;k<48;k++)if(a[k]==0x3f)break; k++; if(a[k]==0x3f)k++;
  k+=testno;
  j=testno+22; if(j>41)j=41;
  for(i=testno;i<j;i++)printf("%02d ",a[k++]); printf("\r");
  fflush(stdout);
}

// for uart
ifuart()
{
  int i,j,k,l;
  unsigned char c,d;
  k=read(fd,&c,1); if(k<=0)return; 
/*
  if(c=='?'){
    printf("**a/b  show all_state/version\n");
    printf("**c/d  save map/test_OMR_GDT\n");
    printf("**e/f  inquire ERR message/read cutdf.out\n");
    printf("**h/i  countine scan/stop_motor\n");
    printf("**j/k  show_paper_counter/one_paper scan\n");
    printf("**l/m  show&write slip/real_paper_thick\n");
    printf("**n/o  show  param15/   use mask\n");
    printf("**p/q  write param15/un_use mask\n");
    printf("**r/t  clear_ERROR/test(42-47)\n");
    printf("**u/v  write/show user1_mess u.dat\n");
    printf("**x/y  write/show user2_mess x.dat\n");
    printf("**w/z  write/show paper,slip,omr_mess,w.dat\n");
    printf("**|    write table.out\n");
    return; }
*/
  if(c<'0')return;                            // 20101224 start
  if(c>='0' && c<='8'){
    j=c&0xf;   b[0]=j;  d=reg8[j];
    if(d&0x80){ b[0]+=0x10; d&=0x7f; }
    b[1]=d;    uart_line(b,2);
  }
  if(c<0x50 || c=='S' || c=='[' || c=='T' || c==92)return; // no such command
  if(c>=0x60)goto kin3;
  if(c=='X')tkwait=255;
  if(c==']' && (reg8[0]&2) ){ tkwait=255; base[0x1806]=0x80; }
  k=c&15; i=c&7;
  if(k==14){ 
lll: j=read(fd,&d,1); if(j<=0)goto lll;
    j= d | 0x80; }
  else { j=0; if(c>=8)j=255; }
  base[0x1800+i]=j;
  return;                                     // 201214 end

kin3:
  if(c=='a'){    // display 8 stat_reg, send no+value,
                 // if(value>127) no+10h, value&127,    send 16 btye
    for(i=0,j=0;i<16;i+=2,j++){
      b[i]=j; d=reg8[j];                          // 20101224
      if(d&0x80){ b[i]+=0x10; d&=0x7f; }
      b[i+1]=d;
    }
    uart_line(b,16);    return;
  }
  if(c=='b'){ uart_line(version,9); return; }
  if(c=='c'){                        // upload memory pic
    read(fd,&d,1);                   // read "c" 2nd par, 0~3
    usk=32768;                       // do job in 5ms interupt
    u_sendmap=usk*d;    return;
  }
  if(c=='d'){
    base[0x1800]=0x80;  closetime1=255;     // open M1
    for(i=0;i<99;i++)a[i]=omrmap[mapip+i];
    for(k=0;k<48;k++)if(a[k]==0x3f)break;
    uart_line(&a[k],48);    return;
  }                                  // testomr
  if(c=='e'){ wrerr=255; return; }   // inqure error mess
  if(c=='h'){                        // continue 'k'
    speed=255;
    if(hontinu)hontinu--; if(hontinu>10)hontinu=255;
    if(pstat)kinh(0); return;
  }
  if(c=='i'){ error=9; base[0x1800]=base[0x1802]=0; return; } // pc want stop M
  if(c=='j'){                        // write_down total paper_counter
    fp=fopen("p_count.dat","r");
    if(fp){ fscanf(fp,"%d",&j); fclose(fp); sprintf(b,"%7d",j); }
    else sprintf(b,"   < 30");
    uart_line(b,7);    return;
  }
  if(c=='k'){                        // normal scan command
    if(error || job==0){ speed=0; hontinu=255; kinh(1); } return; }
  if(c=='l'|| c=='m'){               // real_slip/real_thick --->file
    if(c=='l'){ for(i=1;i<42;i++)b[i]=slip[i-1]; b[0]=paper14; }
    if(c=='m'){ for(i=0;i<42;i++)b[i]=s41[i];    b[0]=ss; }
    uart_line(b,42);  return;
  }
  if(c=='r'){ clearh_err(); hontinu=wrerr=255; return; }  // clear err
  if(c=='o'){ cmdo=1; return; }
  if(c=='q'){ cmdo=0; return; }
  if(c=='t'){
    for(i=9000;i<9099;i++)if(omrmap[i]==63)break; i-=8;
      uart_line(&omrmap[i],9); return; }    // send 9 anyway.
  if(c=='u' || c=='x' || c=='w' || c=='p'){          // write
    get_line(b,128);  strcpy(f1,"?.dat"); f1[0]=c;
    if(c=='p')strcpy(f1,"p15.dat");
    fp=fopen(f1,"wb"); fwrite(b,1,128,fp); fclose(fp);
    if(c=='p')param15();
    if(c=='w')reads41();    return;
  }
  if(c=='v' || c=='y' || c=='z' || c=='n'){
    strcpy(f1,"u.dat"); if(c=='y')f1[0]='x'; if(c=='z')f1[0]='w';
    if(c=='n')strcpy(f1,"p15.dat");
    fp=fopen(f1,"rb");    if(fp){ fread(b,1,128,fp); fclose(fp); }
    else  sprintf(b,"You have not written down ANY message yet!\n");
    uart_line(b,128);  return;
  }

  if(c=='f' || c=='|'){                //  download 1a crc*2 ver*2 file
    write(fd,&c,1);
    k=get1a();                         //  receive file with end 1A
    d='e'; if(k)d='o'; write(fd,&d,1);
       printf("%c\n",d);
    if(d=='e')return;
    strcpy(f1,"cutdf"); if(c=='|')strcpy(f1,"table.dat");
    ch1a(f1);    return;
  }
}

uart_line(char *b,int k)
{
  int i=0,j=64;
  if(k<j)write(fd,b,k);
  else {
l10: if(i+j>k)j=k-i; write(fd,&b[i],j);
    i+=j; if(i==k)return;  usleep(1000); goto l10;
  }
}

get_line(char *b, int m)
{
  int i,j=0,k;
l10:   k= read(fd,a,99);  if(k<=0)goto l10;
  for(i=0;i<k;i++)b[j++]=a[i]; if(j<m)goto l10;
}

int get1a()
{
  unsigned int crc=0,j;
  int i=0,k;  char c,e[2];
  fp=fopen("1.1","wb");
l10:  k= read(fd,&c,1);  if(k<=0)goto l10;
  crc=(crc>>8)^crctab[(crc^c)&0xff];
  e[i++]=c; if(i==2){ k=(e[0]-48)<<4|(e[1]-48); fputc(k,fp); i=0; }
  if(c!=0x1a)goto l10;
  fclose(fp);  crc&=0x7f7f;
  usleep(1000);
  read(fd,&k,2);
    printf("CRC: %4x %4x\n",k,crc);
  j=0; if(k==crc)j=1;
  return(j);
}

ch1a(char *f1)
{
  int k;
  if(f1[0]=='c'){
  if(fork() == 0){ system("chmod 755 1.1"); exit(1); } else wait(&k); }
  sleep(1);                      // else, 2nd job done early than 1st_job
  sprintf(a,"mv 1.1 %s",f1);
  if(fork() == 0){ system(a); exit(1); } else wait(&k);
  if(f1[0]=='t'){
    fp=fopen(f1,"rb"); fread(mask,1,8000,fp); swap4(mask,8000); fclose(fp);
  }
}

swap4(char *a,int k)          // due to c31 interger*4's format
{
  int i; char c;
  for(i=0;i<k;i+=4){
    c=a[i];a[i]=a[i+3];a[i+3]=c;
    c=a[i+1];a[i+1]=a[i+2];a[i+2]=c;
  }
}

