//          задача опpоса UMC800
#include  "complex.h"
#include  "screen.h"

#define  MAX_NDAT  120         // max колич. запраш.данных

dword takt_cpu(void);
#pragma aux takt_cpu = "db 0Fh,31h "\
                       modify [EDX] \
                       value [EAX]  ;

extern word_s setting(analog *a_ptr,float work_f);
extern void koeff_sc(analog *a_ptr);
extern byte * z_db(byte *x_db,int len);
extern word_s numrec, lenrec, fh, N_MAN;
extern char  *recfil;

word_s scanU800(controller *ptr_c,byte *mask,word_s lask,byte *mans,word_s lans);
word form_ks(unsigned char *st,word_s len);
extern float float_intel(byte *bufr);
void request_U800(controller *ptr_c);
void release_U800(controller *ptr_c);

char no_mem_tasku800[] = "TASKU800.C - Мало памяти";

//-------------------------------------------------------------------

void taskU800(controller *ptr_c)
{
  extern dword time_virt[];
  word_s i, k;
  word_s l_ask, l_ans;
  word_s kz, begin, val;
  dword takt_old;
  float valf;
  byte *ask, *ans;
  analog *ptr_a;
  digit *ptr_d;

  l_ask = 14+MAX_NDAT*2;          // max длина буфера запроса
  l_ans = 12+MAX_NDAT*4;          // max длина буфера ответа

  ask = (byte *)calloc(1,l_ask);                    // буффер запроса blk
  ans = (byte *)calloc(1,l_ans);                    // буффер ответов

  if(ask==NULL || ans==NULL) { eprintf(RED_,no_mem_tasku800); return; }

//  Формирование запроса входов Блоков и Переменных

  l_ask=0;
  ask[0]=0x10; ask[1]=0x02; ask[2]=0x01; ask[3]=0xFF; ask[4]=0xB5;
  ask[5]=0x00; ask[6]=0x03;
  ask[7]=0;                       // здесь будет колич. запрашиваемых данных
  ask[8]=0x00; ask[9]=0x02;
  k=10;

  for(i=0, ptr_a=ptr_c->a_ptr; i < ptr_c->num_ap; i++, ptr_a++) {
    if(ptr_a->mod_cod==M_INP || !ptr_a->nomin_var) continue;  // не задан вход
    ask[k++]=ptr_a->nomin_var;   // номер (алго)блока
    ask[k++]=0x01;               // вход
    l_ask++;                     // счетчик колич. данных
  }

  for(i=0, ptr_d=ptr_c->d_ptr; i < ptr_c->num_dp; i++, ptr_d++) {
    if(ptr_d->nom_var > 0) {
      ask[k++]=ptr_d->nom_var;       // номер (алго)блока
      ask[k++]=0x01;                 // вход
      l_ask++;                       // счетчик колич. данных
    }
    if(ptr_d->nom_vr2 > 0) {
      ask[k++]=ptr_d->nom_vr2;       // номер (алго)блока
      ask[k++]=0x01;                 // вход
      l_ask++;                       // счетчик колич. данных
    }
    if(ptr_d->nom_vr3 > 0) {
      ask[k++]=ptr_d->nom_vr3;       // номер (алго)блока
      ask[k++]=0x01;                 // вход
      l_ask++;                       // счетчик колич. данных
    }
    if(ptr_d->nom_vr4 > 0) {
      ask[k++]=ptr_d->nom_vr4;       // номер (алго)блока
      ask[k++]=0x01;                 // вход
      l_ask++;                       // счетчик колич. данных
    }

    if(ptr_d->nom_dout > 0) {
      ask[k++]=0xFB;               // признак того, что это переменная
      ask[k++]=ptr_d->nom_dout-1;  // номер переменной-1
      l_ask++;                     // счетчик колич. данных
    }
    if(ptr_d->nom_dot2 > 0) {
      ask[k++]=0xFB;               // признак того, что это переменная
      ask[k++]=ptr_d->nom_dot2-1;  // номер переменной-1
      l_ask++;                     // счетчик колич. данных
    }
    if(ptr_d->nom_dot3 > 0) {
      ask[k++]=0xFB;               // признак того, что это переменная
      ask[k++]=ptr_d->nom_dot3-1;  // номер переменной-1
      l_ask++;                     // счетчик колич. данных
    }
  }

  ask[k++]=0; ask[k++]=0;       // здесь будет KS
  ask[k++]=0x10; ask[k++]=0x03;
  ask[7]=l_ask;                 // количество данных
  l_ask=k;                      // длина запроса в байтах
  *(word_s *)(ask+l_ask-4)=form_ks(ask+2,l_ask-6);
  l_ans=ask[7]*4+12;

  begin = 1;

  while(!endrun) {
/******************************************
    wait_flag_set(ptr_c->flag, 0L);
    clear_flag(ptr_c->flag);
*******************************************/
    t_delay(ptr_c->period);

//-----------------
    if(yes_P5)takt_old=takt_cpu();
//-----------------
    request_U800(ptr_c);
    kz = scanU800(ptr_c,ask,l_ask,ans,l_ans);
    release_U800(ptr_c);

//    Разборка ответа  и  ПЕРВИЧНАЯ  ОБРАБОТКА  ИНФОРМАЦИИ

    k=8;

    for(i=0, ptr_a=ptr_c->a_ptr; i < ptr_c->num_ap; i++, ptr_a++) {
      if(ptr_a->mod_cod==M_INP || !ptr_a->nomin_var) continue; // не задан вх
      if(kz) { ptr_a->novalid=1;  continue; }
      ptr_a->novalid=0;
      if(ptr_a->nolog) { k+=4; continue; }    // если логич. запpет обpаб.
      valf=float_intel(ans+k); k+=4;

if(valf > ptr_a->max_sc) { valf=ptr_a->max_sc; ptr_a->novalid=1; }
else if(valf < ptr_a->min_sc) { valf=ptr_a->min_sc; ptr_a->novalid=1; }
val=(float)ADC_SC*(valf-ptr_a->min_sc)/(ptr_a->max_sc-ptr_a->min_sc);
/********
      if(valf > 100.0) { valf=100.0; ptr_a->novalid=1; }
      else if(valf < 0.0) { valf=0.0; ptr_a->novalid=1; }
      val=valf*ADC_SC/100.0;
*******/
      if(ptr_a->var_cod == val && !begin) ptr_a->dif_var = 0;
      else {
        ptr_a->dif_var = 1;
        ptr_a->var_cod = val;
        ptr_a->var_tech = valtec(ptr_a,ptr_a->var_cod);
        if(ptr_a->min_reg && val < ptr_a->min_reg) ptr_a->bound_reg = 1;
        else if(ptr_a->max_reg && val > ptr_a->max_reg) ptr_a->bound_reg = 2;
        else ptr_a->bound_reg = 0;
        if(ptr_a->min_al && val < ptr_a->min_al) ptr_a->bound_al = 1;
        else if(ptr_a->max_al && val > ptr_a->max_al) ptr_a->bound_al = 2;
        else ptr_a->bound_al = 0;
      }
    }

    for(i=0, ptr_d=ptr_c->d_ptr; i < ptr_c->num_dp; i++, ptr_d++) {
      if(kz) { ptr_d->novalid=1;  continue; }
      if(ptr_d->nolog) { k+=4; continue; }    // если логич. запpет обpаб.

      if(ptr_d->nom_var > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_par == val) ptr_d->dif_par = 0;
        else { ptr_d->dif_par = 1;  ptr_d->val_par = val; }
#if (COUNT)
        if(ptr_d->reg_tim) {
          if(ptr_d->val_par) ptr_d->count_tim+=ptr_c->period;
          else               ptr_d->count_stop+=ptr_c->period;
        }
#endif
      }

      if(ptr_d->nom_vr2 > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_pr2 == val) ptr_d->dif_pr2 = 0;
        else { ptr_d->dif_pr2 = 1;  ptr_d->val_pr2 = val; }
      }

      if(ptr_d->nom_vr3 > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_pr3 == val) ptr_d->dif_pr3 = 0;
        else { ptr_d->dif_pr3 = 1;  ptr_d->val_pr3 = val; }
      }

      if(ptr_d->nom_vr4 > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_pr4 == val) ptr_d->dif_pr4 = 0;
        else { ptr_d->dif_pr4 = 1;  ptr_d->val_pr4 = val; }
      }

#if (PROTOC)
      if(ptr_d->archive) {
        if(ptr_d->dif_par) {
          val=ptr_d->val_par;
          val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x1000;
          c_write_wpipe(event_chn, val);
        }
        if(ptr_d->dif_pr2) {
          val=ptr_d->val_pr2;
          val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x2000;
          c_write_wpipe(event_chn, val);
        }
        if(ptr_d->dif_pr3) {
          val=ptr_d->val_pr3;
          val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x3000;
          c_write_wpipe(event_chn, val);
        }
        if(ptr_d->dif_pr4) {
          val=ptr_d->val_pr4;
          val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x4000;
          c_write_wpipe(event_chn, val);
        }
      }
#endif

      if(ptr_d->nom_dout > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_out == val) ptr_d->dif_out = 0;
        else  { ptr_d->dif_out = 1;  ptr_d->val_out = val; }
      }

      if(ptr_d->nom_dot2 > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_ot2 == val) ptr_d->dif_ot2 = 0;
        else  { ptr_d->dif_ot2 = 1;  ptr_d->val_ot2 = val; }
      }

      if(ptr_d->nom_dot3 > 0) {
        valf=float_intel(ans+k); k+=4;
        if(valf < 0.5) val=0; else val=1;
        if(ptr_d->val_ot3 == val) ptr_d->dif_ot3 = 0;
        else  { ptr_d->dif_ot3 = 1;  ptr_d->val_ot3 = val; }
      }

      ptr_d->novalid=0;
    }
    if(!kz) begin = 0;
  //------------
    if(yes_P5)time_virt[(ptr_c-c_ptr)] = takt_cpu() - takt_old;
  //------------
  }
}
//-----------------------------------------------------------------

word_s scanU800(controller *ptr_c,byte *mask,word_s lask,byte *mans,word_s lans)
{
              // mask[4]==0xB5 - можно использовать, как признак опроса
              // mask[4]==0x7В - можно использовать, как признак команды

  word_s i, kz, rept, bst;

  rept=1;
  BEGN:
         rept--;
         if(rept < 0) { kz=-1; goto END; }
         for(i=0; i < lans; i++) mans[i]=0x00;
         while(v24_receive(ptr_c->port,4L) != -1);
/***
printf("ZAPR: lask=%3d lans=%3d\n",lask,lans);
for(i=0; i<lask; i++) printf("%02X ",mask[i]); printf("\n");
***/
         for(i=0; i<lask; i++) {
           v24_send(ptr_c->port,mask[i],2L);
           if(i > 0 && i < lask-2)
             if(mask[i]==0x10) v24_send(ptr_c->port,mask[i],2L);
         }
         i=0;
         kz=v24_receive(ptr_c->port,40L);
         if(kz==-1) goto BEGN;
         mans[i]=kz;

         for(bst=0, i=1; i < lans; i++) {
           kz=v24_receive(ptr_c->port,2L);
           if(kz==-1) break;
           //if(kz==0x10 && mans[i-1]==0x10) { i--; continue; }
           if(kz==0x10) {
             if(bst) { bst=0; i--; continue; }
             else bst=1;
           }
           else bst=0;
           mans[i]=kz;
         }

         while(i && mans[i-1] != 0x03 && mans[i-2] != 0x10) i--; // отбр.хвост
         if(i != lans || mans[0] != 0x10 || mans[1] != 0x02) goto BEGN;
         if(mans[2] != 0xff || mans[3] != 0x01 || mans[4] != mask[4]) goto BEGN;
         if(mans[lans-2] != 0x10 || mans[lans-1] != 0x03) goto BEGN;
         if(*(word *)(mans+lans-4) != form_ks(mans+2,lans-6)) goto BEGN;

         for(i=8; i < lans-4; i++) if(mans[i] != 0) break; // проверка прогр.
         if(i >= lans-4) goto BEGN;                  // если программирование

         for(i=8; i < lans-4; i+=4)   // 7f 80 00 01 - признак программир.
           if(mans[i]==0x7f && mans[i+1]==0x80 &&
              mans[i+2]==0x00 && mans[i+3]==0x01) goto BEGN;

         kz=0;
  END:
/***
printf("OTV : lask=%3d lans=%3d  kz=%5d\n",lask,lans,kz);
for(i=0; i<lans; i++) printf("%02X ",mans[i]); printf("\n");
kz=-1;
***/
         if(kz) kz=-1;
         ptr_c->kz=kz;
         kz_com(kz,ptr_c);
         return kz;
}
//-------------------------------------------------------------------

word_s switch_U800(controller *p_c,digit *p_d,word_s nom_do,byte val_do)
{
  word_s kz, l_ask, l_ans;
  byte ans[16];
  static byte set_vd_U800[20] =
    { 0x10,2,1,0xff,0x7d,0x80,3,1,0,2,0xfb,0,0,0,0,0,0,0,0x10,3 };

/************
  if(nom_do==p_d->nom_dout && val_do==p_d->val_out ||
     nom_do==p_d->nom_dot2 && val_do==p_d->val_ot2 ||
     nom_do==p_d->nom_dot3 && val_do==p_d->val_ot3) return 0;
**************/

  l_ask=20;
  l_ans=11;
  set_vd_U800[11]=nom_do-1;
  if(val_do) {
    set_vd_U800[12]=0x3f;
    set_vd_U800[13]=0x80;
    set_vd_U800[14]=set_vd_U800[15]=0;
  }
  else set_vd_U800[12]=set_vd_U800[13]=set_vd_U800[14]=set_vd_U800[15]=0;
  *(word_s *)(set_vd_U800+l_ask-4)=form_ks(set_vd_U800+2,l_ask-6);

  request_U800(p_c);
  kz = scanU800(p_c,set_vd_U800,l_ask,ans,l_ans);
  // if(kz) kz=scanU800(p_c,set_vd_U800,l_ask,ans,l_ans);            // 2 и более на одну PC

  if(val_do && (p_d->type_com==1 || nom_do==p_d->nom_dot3)) {
    t_delay(20L);
    set_vd_U800[12]=set_vd_U800[13]=set_vd_U800[14]=set_vd_U800[15]=0;
    *(word_s *)(set_vd_U800+l_ask-4)=form_ks(set_vd_U800+2,l_ask-6);
    kz = scanU800(p_c,set_vd_U800,l_ask,ans,l_ans);
    // if(kz) kz=scanU800(p_c,set_vd_U800,l_ask,ans,l_ans);
  }
  release_U800(p_c);
  return kz;
}
//-------------------------------------------------------------------

word form_ks(unsigned char *st,word_s len)
{
  word i,j,ks;

  ks=0xffff;
  for(i=0; i<len; i++) {
    ks ^= st[i];
    for(j=0; j<8; j++) {
      if(ks&1) { ks >>= 1; ks ^= 0xA001; }
      else ks >>= 1;
    }
  }
  return ks;
}
/*-------------------------------------------------------------------*/

void request_U800(controller *ptr_c)
{
  word_s i;

  request_resource(ptr_c->port_rsc,0L);     // захват поpта-pесурса
  tsk_outp(ptr_c->basaddr+7,3);            // on this port
  tsk_outp(ptr_c->basaddr+4,0x02);       // освободить сеть   RTS:=1
  for(i=0; i<10; i++) {
    if((tsk_inp(ptr_c->basaddr+6) & 0x10)) break;  // если свободна сеть
    tsk_outp(ptr_c->basaddr+7,0);            // off this port
    t_delay(2L);
    tsk_outp(ptr_c->basaddr+7,3);            // on this port
  }
  tsk_outp(ptr_c->basaddr+4,0x00);       // занять сеть   RTS:=0
}
/*-------------------------------------------------------------------*/

void release_U800(controller *ptr_c)
{
  tsk_outp(ptr_c->basaddr+4,0x02);       // освободить сеть   RTS:=1
  tsk_outp(ptr_c->basaddr+7,0);          // off this port
  release_resource(ptr_c->port_rsc);       // освоб.поpта-pесуpса
}
/*-------------------------------------------------------------------*/
insert_A_U800(analog * a_ptr)
{
   word_s i, work_i;
   float work_f;
   byte *x_db;

   for(i=0; i < numrec; i++, a_ptr++) {
     read(fh, recfil, lenrec);
     a_ptr->novalid = 1;
     strncpy(a_ptr->cipher, (x_db = recfil + 1), 9);
     strncpy(a_ptr->name, (x_db+= 9), 25);
     strncpy(a_ptr->unit, (x_db+= 25), 9);
     sscanf(x_db+= 9, "%1hd", &work_i);    a_ptr->type_sc = (byte)work_i;
     sscanf(z_db(x_db+= 1,8), "%8f", &a_ptr->min_sc);
     sscanf(z_db(x_db+= 8,8), "%8f", &a_ptr->max_sc);
     koeff_sc(a_ptr);
     sscanf(z_db(x_db+= 8,8), "%8f", &work_f);    a_ptr->min_reg = setting(a_ptr,work_f);
     sscanf(z_db(x_db+= 8,8), "%8f", &work_f);    a_ptr->max_reg = setting(a_ptr,work_f);
     sscanf(z_db(x_db+= 8,8), "%8f", &work_f);    a_ptr->min_al = setting(a_ptr,work_f);
     sscanf(z_db(x_db+= 8,8), "%8f", &work_f);    a_ptr->max_al = setting(a_ptr,work_f);
     sscanf(z_db(x_db+= 8,2), "%2hd", &work_i);    a_ptr->param1 =(byte)work_i;
     sscanf(z_db(x_db+= 2,3), "%3hd", &work_i);    a_ptr->nomin_var =(byte)work_i;
     sscanf(x_db+= 3, "%1hd", &work_i);    a_ptr->type_mech = (byte)work_i;
     if(a_ptr->type_mech==M_INP) {
       if(a_ptr->k_scale > 0) a_ptr->novalid = 0;
       a_ptr->type_mech=0; a_ptr->mod_cod=M_INP;
       N_MAN += 1;
     }
     sscanf(z_db(x_db+= 1,2), "%2hd", &work_i);   a_ptr->param2 = (byte)work_i;
     sscanf(z_db(x_db+= 2,2), "%2hd", &work_i);    a_ptr->nom_set = (byte)work_i;
     sscanf(z_db(x_db+= 2,2), "%2hd", &work_i);    a_ptr->nomout_out = (byte)work_i;
     sscanf(z_db(x_db+= 2,2), "%2hd", &work_i);   a_ptr->nomin_pos = (byte)work_i;
     sscanf(x_db+= 2, "%1hd", &work_i);   a_ptr->sum_ysr = work_i;
  }
}
/*-------------------------------------------------------------------*/
insert_D_U800(digit * d_ptr)
{
   word_s i, work_i;
   byte *x_db;

   for(i=0; i < numrec; i++, d_ptr++) {
     read(fh, recfil, lenrec);
     d_ptr->novalid = 1;
     strncpy(d_ptr->cipher, (x_db = recfil + 1), 9);
     strncpy(d_ptr->name, (x_db += 9), 25);
     sscanf(x_db+= 25, "%1hd", &work_i);     d_ptr->type_par = (byte)work_i;
     sscanf(x_db+= 1, "%1hd", &work_i);      d_ptr->archive = work_i;
     sscanf(x_db+= 1, "%1hd", &work_i);      d_ptr->reg_tim = work_i;
     sscanf(z_db(x_db+= 1,2), "%2hd", &work_i);      d_ptr->param1 = (byte)work_i;
     sscanf(z_db(x_db+= 2,3), "%3hd", &d_ptr->nom_var);
     if(!d_ptr->nom_var) d_ptr->nom_var =-1;
     sscanf(z_db(x_db+= 3,3), "%3hd", &d_ptr->nom_vr2);
     if(!d_ptr->nom_vr2) d_ptr->nom_vr2 =-1;
     sscanf(z_db(x_db+= 3,3), "%3hd", &d_ptr->nom_vr3);
     if(!d_ptr->nom_vr3) d_ptr->nom_vr3 =-1;
     sscanf(z_db(x_db+= 3,3), "%3hd", &d_ptr->nom_vr4);
     if(!d_ptr->nom_vr4) d_ptr->nom_vr4 =-1;
     sscanf(x_db+= 3, "%1hd", &work_i);      d_ptr->type_com = (byte)work_i;
     sscanf(z_db(x_db+= 1,3), "%3hd", &work_i);
     if(work_i) d_ptr->nom_dout=work_i; else d_ptr->nom_dout=-1;
     sscanf(z_db(x_db+= 3,3), "%3hd", &work_i);
     if(work_i) d_ptr->nom_dot2=work_i; else d_ptr->nom_dot2=-1;
     sscanf(z_db(x_db+= 3,3), "%3hd", &work_i);
     if(work_i) d_ptr->nom_dot3=work_i; else d_ptr->nom_dot3=-1;
   }
}
//--------------- Инициаллиизация контроллера -----------------------
void enable_U800(void)
{
 word_s l_chan= 512,i;
 nearptr p_chan;
 controller * ptr_c;

 for(i = 0, ptr_c = c_ptr; i < c_num; i++, ptr_c++)
 {
  if(ptr_c->period==0 || ptr_c->typcontr!=U800 ) continue;

  p_chan=calloc(1,l_chan);
  tsk_outp(ptr_c->basaddr+7,3);                // on port
  ptr_c->nomport=v24_define_port(ptr_c->basaddr,ptr_c->IRQ_line,ptr_c->vector);
  ptr_c->port=v24_install(ptr_c->nomport,0,p_chan,l_chan,NULL,256);
  if(!ptr_c->port){ ptr_c->period=0;ptr_c->kz=-1; eprintf(RED_,"Не могу инициализ. COM%d",ptr_c->nomport);continue;}
  v24_change_baud(ptr_c->port,(long)ptr_c->baud);
  v24_change_parity(ptr_c->port, PAR_NONE);
  v24_change_wordlength(ptr_c->port, 8);
  v24_change_stopbits(ptr_c->port, 1);
  v24_receive(ptr_c->port,2L);
 }
}
//--------------- Выключение контроллера -----------------------
void disable_U800(void)
{
 word_s i;
 controller *ptr_c;

 for(i = 0, ptr_c = c_ptr; i < c_num; i++, ptr_c++)
 {
  if(ptr_c->typcontr==U800 && ptr_c->period) tsk_outp(ptr_c->basaddr+7,0);
 }
}